mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-09-30 05:23:12 +08:00
Merge branch 'master' into fs_svg
# Conflicts: # src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp # src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp # src/slic3r/GUI/Jobs/EmbossJob.cpp # src/slic3r/GUI/Jobs/EmbossJob.hpp # src/slic3r/GUI/SurfaceDrag.cpp
This commit is contained in:
commit
382a0fe1e3
7
.github/ISSUE_TEMPLATE/config.yml
vendored
7
.github/ISSUE_TEMPLATE/config.yml
vendored
@ -1,7 +1,10 @@
|
||||
contact_links:
|
||||
- name: PrusaSlicer Manual and Support
|
||||
- name: Do you need Support?
|
||||
url: https://www.prusa3d.com/page/prusaslicer-support-form_233563/
|
||||
about: If you are not sure whether what you are reporting is a bug, please contact our support team first. We are providing full 24/7 customer support.
|
||||
- name: PrusaSlicer Manual
|
||||
url: https://help.prusa3d.com/en/article/customer-support_2287/
|
||||
about: If you are not sure that what you are reporting is really a bug, please, consult the manual first.
|
||||
about: We have a comprehensive customer support page and help documentation that could be helpful for troubleshooting.
|
||||
- name: PrusaPrinters Forum
|
||||
url: https://forum.prusaprinters.org/forum/prusaslicer/
|
||||
about: Please get in touch on our PrusaPrinters Community Forum! (Not an official support channel.)
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -87,6 +87,7 @@ src/slic3r/GUI/UpdateDialogs.cpp
|
||||
src/slic3r/GUI/WipeTowerDialog.cpp
|
||||
src/slic3r/GUI/wxExtensions.cpp
|
||||
src/slic3r/Utils/AstroBox.cpp
|
||||
src/slic3r/Utils/AppUpdater.cpp
|
||||
src/slic3r/Utils/Duet.cpp
|
||||
src/slic3r/Utils/FixModelByWin10.cpp
|
||||
src/slic3r/Utils/FlashAir.cpp
|
||||
@ -101,6 +102,7 @@ src/libslic3r/ExtrusionEntity.cpp
|
||||
src/libslic3r/Flow.cpp
|
||||
src/libslic3r/Format/3mf.cpp
|
||||
src/libslic3r/Format/AMF.cpp
|
||||
src/libslic3r/Format/SLAArchiveReader.cpp
|
||||
src/libslic3r/GCode/PostProcessor.cpp
|
||||
src/libslic3r/miniz_extension.cpp
|
||||
src/libslic3r/Preset.cpp
|
||||
@ -113,3 +115,4 @@ src/libslic3r/PrintBase.cpp
|
||||
src/libslic3r/PrintConfig.cpp
|
||||
src/libslic3r/Zipper.cpp
|
||||
src/libslic3r/PrintObject.cpp
|
||||
src/libslic3r/PrintObjectSlice.cpp
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,4 +1,5 @@
|
||||
min_slic3r_version = 2.6.0-alpha5
|
||||
1.9.0-alpha1 Added profiles for Original Prusa MK4.
|
||||
1.9.0-alpha0 Updated output filename format.
|
||||
1.7.0-alpha2 Updated compatibility condition in some filament profiles (Prusa XL).
|
||||
1.7.0-alpha1 Added profiles for Original Prusa XL. Added filament profile for Prusament PETG Tungsten 75%.
|
||||
@ -8,10 +9,12 @@ min_slic3r_version = 2.6.0-alpha1
|
||||
1.6.0-alpha1 Updated FW version notification. Decreased min layer time for PLA.
|
||||
1.6.0-alpha0 Default top fill set to monotonic lines. Updated infill/perimeter overlap values. Updated output filename format. Enabled dynamic overhang speeds.
|
||||
min_slic3r_version = 2.5.1-rc0
|
||||
1.6.3 Added SLA materials.
|
||||
1.6.2 Updated compatibility condition in some filament profiles (Prusa XL).
|
||||
1.6.1 Added filament profile for Prusament PETG Tungsten 75%. Updated Prusa XL profiles.
|
||||
1.6.0 Added Original Prusa XL profiles. Updated acceleration settings for Prusa MINI. Updated infill/perimeter overlap values.
|
||||
min_slic3r_version = 2.5.0-alpha0
|
||||
1.5.9 Added SLA materials.
|
||||
1.5.8 Added filament profile for Prusament PETG Tungsten 75%. Updated FW version notification.
|
||||
1.5.7 Added filament profile for Prusament PETG Carbon Fiber and Fiberthree F3 PA-GF30 Pro.
|
||||
1.5.6 Updated FW version notification (MK2.5/MK3 family). Added filament profile for Kimya PEBA-S.
|
||||
|
File diff suppressed because it is too large
Load Diff
BIN
resources/profiles/PrusaResearch/MK4_thumbnail.png
Normal file
BIN
resources/profiles/PrusaResearch/MK4_thumbnail.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 68 KiB |
101
resources/profiles/PrusaResearch/mk4.svg
Normal file
101
resources/profiles/PrusaResearch/mk4.svg
Normal file
@ -0,0 +1,101 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg id="svg3128" xmlns="http://www.w3.org/2000/svg" width="710.1" height="596.7" viewBox="0 0 710.1 596.7">
|
||||
<line id="line2794" x1=".7" y1=".7" x2=".7" y2="596" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: 1.4px;"/>
|
||||
<line id="line2796" x1="142.4" y1=".7" x2="142.4" y2="595.6" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: 1.4px;"/>
|
||||
<line id="line2798" x1="284.2" y1=".7" x2="284.2" y2="595.6" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: 1.4px;"/>
|
||||
<line id="line2800" x1="709.4" y1="596" x2="709.4" y2=".7" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: 1.4px;"/>
|
||||
<line id="line2802" x1="1.2" y1="581.8" x2="709.4" y2="581.8" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: 1.4px;"/>
|
||||
<line id="line2804" x1=".7" y1="596" x2="709.4" y2="596" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: 1.4px;"/>
|
||||
<line id="line2806" x1="1.2" y1="440.1" x2="709.4" y2="440.1" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: 1.4px;"/>
|
||||
<line id="line2808" x1="1.2" y1="298.4" x2="709.4" y2="298.4" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: 1.4px;"/>
|
||||
<line id="line2810" x1="1.2" y1="156.6" x2="709.4" y2="156.6" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: 1.4px;"/>
|
||||
<line id="line2812" x1="1.2" y1="14.9" x2="709.4" y2="14.9" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: 1.4px;"/>
|
||||
<line id="line2814" x1="709.4" y1=".7" x2=".7" y2=".7" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: 1.4px;"/>
|
||||
<line id="line2816" x1="425.9" y1=".7" x2="425.9" y2="499.4" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: 1.4px;"/>
|
||||
<line id="line2818" x1="425.9" y1="522.5" x2="425.9" y2="595.7" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: 1.4px;"/>
|
||||
<line id="line2820" x1="567.6" y1=".7" x2="567.6" y2="499.4" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: 1.4px;"/>
|
||||
<line id="line2822" x1="567.6" y1="522.5" x2="567.6" y2="527.7" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: 1.4px;"/>
|
||||
<line id="line2824" x1="567.6" y1="548.6" x2="567.6" y2="595.4" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: 1.4px;"/>
|
||||
<line id="line2826" x1="85.8" y1=".7" x2="85.8" y2="595.9" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: .4px;"/>
|
||||
<line id="line2828" x1="114.1" y1=".7" x2="114.1" y2="595.9" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: .4px;"/>
|
||||
<line id="line2830" x1="170.8" y1=".7" x2="170.8" y2="595.9" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: .4px;"/>
|
||||
<line id="line2832" x1="199.1" y1=".7" x2="199.1" y2="595.9" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: .4px;"/>
|
||||
<line id="line2834" x1="227.5" y1=".7" x2="227.5" y2="595.9" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: .4px;"/>
|
||||
<line id="line2836" x1="255.8" y1=".7" x2="255.8" y2="595.9" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: .4px;"/>
|
||||
<line id="line2838" x1="312.5" y1=".7" x2="312.5" y2="595.9" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: .4px;"/>
|
||||
<line id="line2840" x1="340.9" y1=".7" x2="340.9" y2="595.9" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: .4px;"/>
|
||||
<line id="line2842" x1="681" y1=".7" x2="681" y2="595.9" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: .4px;"/>
|
||||
<line id="line2844" x1="29.1" y1=".7" x2="29.1" y2="595.9" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: .4px;"/>
|
||||
<line id="line2846" x1="57.4" y1=".7" x2="57.4" y2="595.9" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: .4px;"/>
|
||||
<line id="line2848" x1="1.5" y1="468.4" x2="709.4" y2="468.4" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: .4px;"/>
|
||||
<line id="line2850" x1="1.5" y1="496.8" x2="709.4" y2="496.8" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: .4px;"/>
|
||||
<line id="line2852" x1="1.5" y1="525.1" x2="709.4" y2="525.1" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: .4px;"/>
|
||||
<line id="line2854" x1="1.5" y1="553.5" x2="709.4" y2="553.5" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: .4px;"/>
|
||||
<line id="line2856" x1="1.5" y1="411.7" x2="709.4" y2="411.7" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: .4px;"/>
|
||||
<line id="line2858" x1="1.5" y1="383.4" x2="709.4" y2="383.4" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: .4px;"/>
|
||||
<line id="line2860" x1="1.5" y1="355" x2="709.4" y2="355" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: .4px;"/>
|
||||
<line id="line2862" x1="1.5" y1="326.7" x2="709.4" y2="326.7" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: .4px;"/>
|
||||
<line id="line2864" x1="1.5" y1="270" x2="709.4" y2="270" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: .4px;"/>
|
||||
<line id="line2866" x1="1.5" y1="241.6" x2="709.4" y2="241.6" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: .4px;"/>
|
||||
<line id="line2868" x1="1.5" y1="213.3" x2="709.4" y2="213.3" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: .4px;"/>
|
||||
<line id="line2870" x1="1.5" y1="185" x2="709.4" y2="185" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: .4px;"/>
|
||||
<line id="line2872" x1="1.5" y1="128.3" x2="709.4" y2="128.3" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: .4px;"/>
|
||||
<line id="line2874" x1="1.5" y1="99.9" x2="709.4" y2="99.9" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: .4px;"/>
|
||||
<line id="line2876" x1="1.5" y1="71.6" x2="709.4" y2="71.6" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: .4px;"/>
|
||||
<line id="line2878" x1="1.5" y1="43.2" x2="709.4" y2="43.2" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: .4px;"/>
|
||||
<line id="line2880" x1="369.2" y1=".7" x2="369.2" y2="522.6" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: .4px;"/>
|
||||
<line id="line2882" x1="369.2" y1="522.6" x2="369.2" y2="595.7" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: .4px;"/>
|
||||
<line id="line2884" x1="397.6" y1=".7" x2="397.6" y2="499.4" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: .4px;"/>
|
||||
<line id="line2886" x1="397.5" y1="522.6" x2="397.5" y2="595.7" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: .4px;"/>
|
||||
<line id="line2888" x1="454.2" y1=".7" x2="454.2" y2="499.4" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: .4px;"/>
|
||||
<line id="line2890" x1="454.3" y1="522.6" x2="454.3" y2="595.6" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: .4px;"/>
|
||||
<line id="line2892" x1="482.6" y1=".7" x2="482.6" y2="499.4" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: .4px;"/>
|
||||
<line id="line2894" x1="482.6" y1="522.6" x2="482.6" y2="595.6" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: .4px;"/>
|
||||
<line id="line2896" x1="510.9" y1=".7" x2="510.9" y2="499.4" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: .4px;"/>
|
||||
<line id="line2898" x1="510.9" y1="522.6" x2="510.9" y2="595.6" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: .4px;"/>
|
||||
<line id="line2900" x1="539.3" y1=".7" x2="539.3" y2="499.4" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: .4px;"/>
|
||||
<line id="line2902" x1="539.3" y1="522.6" x2="539.3" y2="595.6" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: .4px;"/>
|
||||
<line id="line2904" x1="596" y1=".7" x2="596" y2="499.4" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: .4px;"/>
|
||||
<line id="line2906" x1="624.3" y1=".7" x2="624.3" y2="499.4" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: .4px;"/>
|
||||
<line id="line2908" x1="652.7" y1=".7" x2="652.7" y2="522.5" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: .4px;"/>
|
||||
<line id="line2910" x1="652.7" y1="522.5" x2="652.7" y2="527.7" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: .4px;"/>
|
||||
<line id="line2912" x1="652.6" y1="548.3" x2="652.6" y2="596" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: .4px;"/>
|
||||
<line id="line2914" x1="624.3" y1="522.5" x2="624.3" y2="527.7" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: .4px;"/>
|
||||
<line id="line2916" x1="624.3" y1="548.3" x2="624.3" y2="596" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: .4px;"/>
|
||||
<line id="line2918" x1="596" y1="522.5" x2="596" y2="527.7" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: .4px;"/>
|
||||
<line id="line2920" x1="596" y1="548.3" x2="596" y2="596" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: .4px;"/>
|
||||
<path id="path3098" d="m548.6,532h2.1v4.8h0c.1-.2.3-.4.5-.6.2-.2.4-.3.7-.5.2-.1.5-.2.8-.3.3,0,.5-.1.8,0,.7,0,1.3.1,1.9.4.5.2,1,.6,1.4,1.1.4.5.6,1,.8,1.6.2.6.3,1.3.3,1.9,0,.6,0,1.2-.2,1.8-.2.6-.4,1.1-.7,1.6-.7,1-1.8,1.5-3,1.5-.3,0-.6,0-1,0-.3,0-.6-.1-.9-.2-.3-.1-.5-.3-.8-.5-.2-.2-.4-.5-.6-.8h0v1.3h-2v-12.9Zm7.2,8.2c0-.4,0-.8-.2-1.2-.1-.4-.3-.7-.5-1-.2-.3-.5-.6-.8-.7-.3-.2-.7-.3-1.1-.3-.8,0-1.5.3-2,.9-.5.7-.7,1.6-.7,2.4,0,.4,0,.9.2,1.3.1.4.3.7.5,1,.2.3.5.5.8.7.3.2.7.3,1.1.2.4,0,.8,0,1.2-.3.3-.2.6-.4.8-.7.2-.3.4-.7.5-1,0-.4.1-.8.1-1.2Z" style="fill: #fff;"/>
|
||||
<path id="path3100" d="m558.5,535.6h2.2l2.4,7h0l2.4-7h2.1l-3.6,9.8c-.2.4-.3.8-.5,1.2-.2.4-.4.7-.6,1-.2.3-.5.5-.9.7-.4.2-.9.3-1.3.3-.5,0-1,0-1.4-.1v-1.7h.5c.2,0,.3,0,.5,0,.2,0,.4,0,.6,0,.1,0,.3-.1.4-.3.1-.1.2-.3.3-.4,0-.2.1-.4.2-.5l.2-.7-3.5-9.2Z" style="fill: #fff;"/>
|
||||
<path id="path3102" d="m581.1,540.8c0,.5,0,1.1-.1,1.6,0,.5-.3,1-.6,1.4-.3.4-.8.8-1.3,1-.7.3-1.5.4-2.2.4-.6,0-1.2,0-1.7-.3-.5-.2-.9-.5-1.2-.9-.3-.4-.6-.8-.7-1.3-.1-.5-.2-1.1-.2-1.6v-.7h2.2v.7c0,.6,0,1.2.4,1.7.3.4.9.7,1.4.6.3,0,.6,0,.9-.2.2-.1.4-.3.6-.5.1-.2.2-.5.3-.8,0-.4,0-.7,0-1.1v-8.8h2.2v8.7Z" style="fill: #fff;"/>
|
||||
<path id="path3104" d="m587.8,545.1c-.7,0-1.4-.1-2-.4-.6-.2-1.1-.6-1.5-1-.4-.4-.7-1-.9-1.5-.2-.6-.3-1.3-.3-2,0-.7,0-1.4.3-2,.2-.6.5-1.1.9-1.5.4-.4.9-.8,1.5-1,1.3-.5,2.7-.5,4,0,.6.2,1.1.6,1.5,1,.4.4.7,1,.9,1.5.2.6.3,1.3.3,2,0,.7,0,1.4-.3,2-.2.6-.5,1.1-.9,1.5-.4.4-.9.8-1.5,1-.6.3-1.3.4-2,.4Zm0-1.6c.4,0,.8,0,1.2-.3.3-.2.6-.4.8-.8.2-.3.4-.7.5-1.1.1-.4.2-.8.2-1.2,0-.4,0-.8-.2-1.2,0-.4-.3-.7-.5-1-.2-.3-.5-.6-.8-.8-.7-.4-1.6-.4-2.4,0-.3.2-.6.4-.8.8-.2.3-.4.6-.5,1,0,.4-.1.8-.2,1.2,0,.4,0,.8.2,1.2,0,.4.3.7.5,1.1.2.3.5.6.8.8.4.2.8.3,1.2.3h0Z" style="fill: #fff;"/>
|
||||
<path id="path3106" d="m595.7,541.9c0,.5.3,1,.7,1.3.4.2.9.4,1.4.4.2,0,.4,0,.7,0,.2,0,.5,0,.7-.2.2,0,.4-.2.5-.4.3-.4.2-.9,0-1.3-.2-.2-.4-.3-.7-.4-.3-.1-.7-.2-1-.3l-1.1-.2c-.4,0-.7-.2-1.1-.3-.4-.1-.7-.3-1-.5-.3-.2-.5-.5-.6-.9-.2-.4-.3-.8-.2-1.2,0-.5.1-.9.4-1.3.2-.3.6-.6.9-.8.4-.2.8-.4,1.3-.4.4,0,.9-.1,1.3-.1.5,0,.9,0,1.4.2.4,0,.8.3,1.2.5.4.2.7.5.9.9.2.4.4.9.4,1.3h-2.1c0-.4-.3-.8-.7-1-.4-.2-.8-.3-1.2-.2-.2,0-.3,0-.5,0-.2,0-.4,0-.6.1-.2,0-.3.2-.4.3-.1.1-.2.3-.2.5,0,.2,0,.5.3.6.2.2.4.3.7.4.3.1.7.2,1,.3l1.1.2c.4,0,.7.2,1.1.3.4.1.7.3,1,.5.3.2.5.5.7.8.2.4.3.8.3,1.2,0,.5-.1,1-.4,1.4-.3.4-.6.7-1,.9-.4.2-.9.4-1.3.5-.5.1-1,.2-1.5.2-.5,0-1.1,0-1.6-.2-.5-.1-.9-.3-1.3-.6-.4-.3-.7-.6-.9-1-.2-.4-.3-.9-.3-1.4h2Z" style="fill: #fff;"/>
|
||||
<path id="path3108" d="m605.1,540.8c0,.3,0,.7.2,1,0,.3.3.6.5.9.2.3.5.5.8.6.4.2.7.2,1.1.2.5,0,1.1,0,1.5-.3.4-.3.7-.7.8-1.2h1.9c0,.5-.3.9-.6,1.3-.3.4-.6.7-1,1-.4.3-.8.5-1.2.6-.5.1-1,.2-1.5.2-.7,0-1.3-.1-1.9-.4-.5-.2-1-.6-1.4-1-.4-.4-.7-1-.9-1.5-.2-.6-.3-1.3-.3-2,0-.6.1-1.3.3-1.9.2-.6.5-1.1.9-1.6.8-1,2-1.5,3.3-1.5.7,0,1.4.1,2,.5.6.3,1.1.7,1.5,1.2.4.5.7,1.1.8,1.7.2.7.2,1.3.1,2h-6.9Zm4.8-1.3c0-.3,0-.6-.2-.9-.1-.3-.3-.6-.5-.8-.2-.2-.4-.4-.7-.5-.3-.1-.6-.2-.9-.2-.3,0-.7,0-1,.2-.3.1-.5.3-.8.5-.2.2-.4.5-.5.8-.1.3-.2.7-.2,1h4.8Z" style="fill: #fff;"/>
|
||||
<path id="path3110" d="m612.6,535.6h1.5v-.8c0-.5,0-1,.2-1.4.1-.3.3-.6.6-.8.2-.2.5-.3.8-.4.3,0,.7-.1,1,0,.5,0,.9,0,1.4,0v1.6c-.1,0-.3,0-.4,0h-.5c-.3,0-.5,0-.7.2-.2.2-.3.5-.3.8v1h1.7v1.5h-1.7v7.8h-2v-7.8h-1.5v-1.5Z" style="fill: #fff;"/>
|
||||
<path id="path3112" d="m624.5,532h5.7c.8,0,1.5.1,2.2.4.5.2,1,.6,1.3,1,.3.4.5.8.6,1.3.1.4.2.9.2,1.3,0,.4,0,.9-.2,1.3-.1.5-.3.9-.6,1.3-.4.4-.8.8-1.3,1-.7.3-1.5.4-2.2.4h-3.4v4.9h-2.2v-12.9Zm2.2,6.1h3.3c.3,0,.5,0,.8-.1.3,0,.5-.2.7-.3.2-.2.4-.4.5-.7.1-.3.2-.7.2-1,0-.3,0-.7-.2-1-.2-.5-.7-.9-1.2-1-.3,0-.6,0-.8,0h-3.3v4.2Z" style="fill: #fff;"/>
|
||||
<path id="path3114" d="m636.2,535.6h1.9v1.8h0c0-.3.2-.5.4-.7.2-.2.4-.5.6-.7.2-.2.5-.4.8-.5.3-.1.6-.2.9-.2h.8v2h-.4c-.1,0-.3,0-.5,0-.7,0-1.3.3-1.8.8-.2.3-.4.6-.5,1-.1.4-.2.9-.2,1.4v4.4h-2v-9.3Z" style="fill: #fff;"/>
|
||||
<path id="path3116" d="m650.7,544.9h-2v-1.3h0c-.3.5-.7.9-1.1,1.1-.5.3-1,.4-1.5.4-1,0-1.9-.2-2.7-.9-.6-.8-.9-1.8-.8-2.7v-5.9h2v5.7c0,.6.1,1.2.5,1.7.3.3.8.5,1.3.5.4,0,.7,0,1.1-.2.3-.1.5-.3.7-.5.2-.2.3-.5.4-.8,0-.3.1-.7.1-1v-5.4h2v9.3Z" style="fill: #fff;"/>
|
||||
<path id="path3118" d="m654.4,541.9c0,.5.3,1,.7,1.2.4.2.9.4,1.4.4.2,0,.4,0,.7,0,.2,0,.5,0,.7-.2.2,0,.4-.2.5-.4.1-.2.2-.4.2-.6,0-.2-.1-.5-.3-.7-.2-.2-.4-.3-.7-.4-.3-.1-.7-.2-1-.3l-1.1-.2c-.4,0-.7-.2-1.1-.3-.4-.1-.7-.3-1-.5-.3-.2-.5-.5-.7-.8-.2-.4-.3-.8-.3-1.2,0-.5.1-.9.4-1.3.2-.3.6-.6.9-.8.4-.2.8-.4,1.3-.4.4,0,.9-.1,1.3-.1.5,0,.9,0,1.4.2.4.1.8.3,1.2.5.4.2.7.5.9.9.2.4.4.9.4,1.3h-2.1c0-.4-.3-.8-.7-1-.4-.2-.8-.3-1.2-.2-.2,0-.3,0-.5,0-.2,0-.4,0-.5.1-.2,0-.3.2-.4.3-.1.1-.2.3-.2.5,0,.2,0,.5.3.6.2.2.4.3.7.4.3.1.7.2,1,.3l1.1.2c.4,0,.7.2,1.1.3.4.1.7.3,1,.5.3.2.5.5.7.8.2.4.3.8.3,1.2,0,.5-.1,1-.4,1.4-.3.4-.6.7-1,.9-.4.2-.9.4-1.3.5-.5.1-1,.2-1.5.2-.6,0-1.1,0-1.6-.2-.5-.1-.9-.3-1.3-.6-.4-.3-.7-.6-.9-1-.2-.4-.3-.9-.3-1.4h2.1Z" style="fill: #fff;"/>
|
||||
<path id="path3120" d="m670,542.8c0,.2,0,.4,0,.5,0,.1.2.2.4.2h.5v1.4h-.3c0,0-.3.2-.3.2h-.4c-.1,0-.2,0-.3,0-.3,0-.7,0-1-.2-.3-.2-.5-.5-.5-.9-.4.4-.9.7-1.5.9-.6.2-1.1.3-1.7.3-.4,0-.8,0-1.2-.2-.4-.1-.7-.3-1-.5-.3-.2-.5-.5-.7-.8-.2-.4-.3-.8-.3-1.2,0-.5,0-1,.3-1.4.2-.3.5-.6.8-.8.4-.2.7-.4,1.2-.4.4,0,.9-.2,1.3-.2.3,0,.7-.1,1.1-.2.3,0,.6,0,.9-.2.2,0,.4-.2.6-.3.2-.2.2-.4.2-.7,0-.2,0-.5-.2-.7-.1-.2-.3-.3-.5-.4-.2,0-.4-.2-.6-.2-.2,0-.4,0-.7,0-.5,0-1,.1-1.4.4-.4.3-.6.7-.6,1.1h-2c0-.5.2-1,.4-1.5.3-.4.6-.7,1-1,.4-.2.9-.4,1.3-.5.5-.1,1-.2,1.5-.2.5,0,.9,0,1.3.2.4,0,.8.2,1.2.5.3.2.6.5.8.8.2.4.3.8.3,1.2v4.8Zm-2.2-2.6c-.3.2-.7.3-1.2.4-.5,0-.9.1-1.4.2-.2,0-.4,0-.6.2-.2,0-.4.1-.5.3-.2.1-.3.3-.4.5,0,.2-.1.4-.1.7,0,.2,0,.4.2.6.1.2.3.3.5.4.2,0,.4.2.6.2.2,0,.4,0,.6,0,.2,0,.5,0,.7,0,.3,0,.5-.2.8-.3.2-.1.4-.3.6-.5.2-.2.2-.5.2-.8v-1.5Z" style="fill: #fff;"/>
|
||||
<g>
|
||||
<path d="m385.6,511.3c0-1.3.2-2.6.6-3.7s1-2.1,1.7-3c.7-.9,1.7-1.5,2.8-2,1.1-.5,2.3-.7,3.7-.7s2.6.2,3.7.7c1.1.5,2,1.2,2.8,2s1.3,1.8,1.7,3,.6,2.4.6,3.7-.2,2.5-.6,3.6-1,2.1-1.7,2.9c-.7.8-1.7,1.5-2.8,2-1.1.5-2.3.7-3.7.7s-2.6-.2-3.7-.7c-1.1-.5-2-1.1-2.8-2-.7-.8-1.3-1.8-1.7-2.9-.4-1.1-.6-2.3-.6-3.6Zm3.9,0c0,.7.1,1.5.3,2.2.2.7.4,1.3.9,1.9.4.6.9,1,1.5,1.4s1.4.5,2.2.5,1.6-.2,2.2-.5,1.1-.8,1.5-1.4c.4-.6.6-1.2.9-1.9.2-.7.3-1.4.3-2.2s-.1-1.5-.3-2.3c-.2-.7-.4-1.4-.9-1.9-.4-.6-.9-1-1.5-1.4-.6-.3-1.4-.5-2.2-.5s-1.6.2-2.2.5c-.6.3-1.1.8-1.5,1.4s-.6,1.2-.9,1.9c-.2.7-.3,1.5-.3,2.3Z" style="fill: #959998;"/>
|
||||
<path d="m404.8,502.3h9.6c.8,0,1.5.1,2.1.4.6.3,1.2.6,1.6,1.1.4.4.8,1,1.1,1.6.2.6.4,1.2.4,1.9,0,1.1-.2,1.9-.6,2.7-.4.7-1.2,1.4-2.1,1.7h0c.5.2.9.4,1.2.6s.6.6.8,1c.2.4.3.8.4,1.2s.2.9.2,1.3,0,.6,0,1,0,.8.1,1.2c0,.4.1.8.2,1.1.1.4.2.7.4.9h-3.9c-.1-.3-.2-.6-.3-.9,0-.3-.1-.7-.1-1.1s0-.7-.1-1.2c0-.4,0-.7-.1-1.1-.1-.9-.4-1.6-.9-2s-1.1-.6-2.1-.6h-3.9v6.9h-3.9v-17.7Zm3.9,8.1h4.3c.9,0,1.6-.2,2-.6.4-.4.7-1.1.7-1.9s-.2-1.5-.7-1.9-1.1-.6-2-.6h-4.3v5Z" style="fill: #959998;"/>
|
||||
<path d="m421.8,502.3h3.9v17.8h-3.9v-17.8Z" style="fill: #959998;"/>
|
||||
<path d="m441,518.1c-.7.9-1.5,1.5-2.3,1.9s-1.7.5-2.6.5c-1.4,0-2.6-.2-3.7-.7-1.1-.5-2-1.1-2.8-2-.7-.8-1.3-1.8-1.7-2.9-.4-1.1-.6-2.3-.6-3.6s.2-2.6.6-3.7,1-2.1,1.7-3c.7-.9,1.7-1.5,2.8-2,1.1-.5,2.3-.7,3.7-.7s1.8.1,2.7.4c.9.3,1.6.7,2.3,1.2s1.3,1.2,1.7,2,.7,1.7.9,2.7h-3.7c-.2-1-.7-1.7-1.4-2.2s-1.5-.7-2.4-.7-1.6.2-2.2.5-1.1.8-1.5,1.4c-.4.6-.6,1.2-.9,1.9-.2.7-.3,1.5-.3,2.3s.1,1.5.3,2.2c.2.7.4,1.3.9,1.9.4.6.9,1,1.5,1.4.6.3,1.4.5,2.2.5,1.3,0,2.3-.3,3-1s1.1-1.6,1.3-2.9h-3.9v-2.9h7.5v9.6h-2.5l-.4-2Z" style="fill: #959998;"/>
|
||||
<path d="m446.3,502.3h3.9v17.8h-3.9v-17.8Z" style="fill: #959998;"/>
|
||||
<path d="m452.7,502.3h3.9l7.4,11.9h0v-11.9h3.7v17.8h-3.9l-7.4-11.9h0v11.9h-3.7v-17.8Z" style="fill: #959998;"/>
|
||||
<path d="m475.1,502.3h4l6.6,17.8h-4l-1.4-3.9h-6.6l-1.4,3.9h-3.9l6.7-17.8Zm-.4,10.9h4.6l-2.2-6.5h0l-2.3,6.5Z" style="fill: #959998;"/>
|
||||
<path d="m486.5,502.3h3.9v14.5h8.6v3.3h-12.6v-17.8h0Z" style="fill: #959998;"/>
|
||||
</g>
|
||||
<g>
|
||||
<path d="m506.9,502.3h8c1.1,0,2.1.2,2.8.5s1.4.7,1.9,1.3c.5.5.9,1.2,1.1,1.8.2.7.3,1.4.3,2.1s-.1,1.4-.3,2.1-.6,1.3-1.1,1.8c-.5.5-1.1,1-1.9,1.3s-1.7.5-2.8.5h-4.1v6.4h-3.9v-17.8Zm3.9,8.4h3c.4,0,.9,0,1.3-.1.4,0,.8-.2,1.1-.4.3-.2.6-.5.7-.8.2-.3.3-.8.3-1.4s-.1-1-.3-1.4c-.2-.3-.4-.6-.7-.8-.3-.2-.7-.3-1.1-.4s-.9-.1-1.3-.1h-3v5.3Z" style="fill: #fff;"/>
|
||||
<path d="m522.2,502.3h9.6c.8,0,1.5.1,2.1.4.6.3,1.2.6,1.6,1.1.4.4.8,1,1.1,1.6.2.6.4,1.2.4,1.9,0,1.1-.2,1.9-.6,2.7-.4.7-1.2,1.4-2.1,1.7h0c.5.2.9.4,1.2.6s.6.6.8,1c.2.4.3.8.4,1.2s.2.9.2,1.3,0,.6,0,1,0,.8.1,1.2c0,.4.1.8.2,1.1.1.4.2.7.4.9h-3.9c-.1-.3-.2-.6-.3-.9,0-.3-.1-.7-.1-1.1s0-.7-.1-1.2c0-.4,0-.7-.1-1.1-.1-.9-.4-1.6-.9-2s-1.1-.6-2.1-.6h-3.9v6.9h-3.9v-17.7Zm3.9,8.1h4.3c.9,0,1.5-.2,2-.6.4-.4.7-1.1.7-1.9s-.2-1.5-.7-1.9-1.1-.6-2-.6h-4.3v5Z" style="fill: #fff;"/>
|
||||
<path d="m554.1,513.3c0,2.4-.7,4.2-2,5.4-1.4,1.2-3.2,1.8-5.6,1.8s-4.3-.6-5.6-1.8c-1.3-1.2-2-3-2-5.4v-11.1h3.9v11.1c0,.5,0,1,.1,1.4,0,.5.3.9.5,1.3.3.4.6.6,1.1.9.5.2,1.1.3,1.9.3,1.4,0,2.3-.3,2.9-.9s.8-1.6.8-2.9v-11.1h3.9v11h0Z" style="fill: #fff;"/>
|
||||
<path d="m559.1,514.2c0,.6.1,1.1.3,1.5.2.4.5.7.9,1s.8.4,1.3.6,1,.2,1.5.2.7,0,1.1-.1.8-.2,1.1-.3.6-.4.9-.7c.2-.3.3-.6.3-1.1s-.2-.9-.5-1.2-.7-.5-1.2-.7c-.5-.2-1.1-.4-1.7-.5s-1.3-.3-1.9-.5c-.7-.2-1.3-.4-1.9-.6-.6-.2-1.2-.5-1.7-.9s-.9-.9-1.2-1.4c-.3-.6-.5-1.3-.5-2.1s.2-1.7.6-2.4.9-1.2,1.5-1.7,1.4-.8,2.1-1,1.6-.3,2.4-.3,1.8.1,2.7.3,1.6.5,2.3,1,1.2,1.1,1.6,1.8.6,1.6.6,2.6h-3.8c0-.5-.1-1-.3-1.3s-.4-.6-.7-.8-.7-.3-1.1-.4-.9-.1-1.3-.1-.6,0-1,.1c-.3,0-.6.2-.9.3-.3.2-.5.4-.6.6s-.2.6-.2.9,0,.6.2.9c.1.2.4.4.8.6s.9.4,1.6.5c.7.2,1.6.4,2.7.7.2,0,.5.1.9.2.3.1.7.2,1.1.4.4.2.8.4,1.2.6.4.2.7.5,1.1.9.3.4.6.8.8,1.3.2.5.3,1.1.3,1.8s-.2,1.6-.5,2.3c-.3.7-.8,1.3-1.4,1.8s-1.4.9-2.3,1.2c-.9.3-2,.4-3.2.4s-1.9-.1-2.9-.4-1.7-.6-2.4-1.2-1.3-1.2-1.7-2c-.4-.8-.6-1.7-.6-2.8h3.8Z" style="fill: #fff;"/>
|
||||
<path d="m576.5,502.3h4l6.6,17.8h-4l-1.4-3.9h-6.6l-1.4,3.9h-3.9l6.7-17.8Zm-.4,10.9h4.6l-2.2-6.5h0l-2.3,6.5Z" style="fill: #fff;"/>
|
||||
</g>
|
||||
<g>
|
||||
<path d="m594.3,502.3h5.5l4.1,12.2h0l3.9-12.2h5.5v17.8h-3.7v-12.6h0l-4.4,12.6h-3l-4.4-12.5h0v12.5h-3.7v-17.8h0Z" style="fill: #ed6b21;"/>
|
||||
<path d="m616,502.3h3.9v7.4l6.9-7.4h4.9l-6.9,7,7.6,10.7h-4.9l-5.3-8-2.2,2.3v5.7h-3.9v-17.8Z" style="fill: #ed6b21;"/>
|
||||
<path d="m638.4,516.1h-7.4v-3.2l7.6-10.2h3.2v10.5h2.3v2.9h-2.3v4h-3.4v-4h0Zm0-9h0l-4.5,6.1h4.6v-6.1Z" style="fill: #ed6b21;"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 20 KiB |
BIN
resources/profiles/PrusaResearch/mk4_bed.stl
Normal file
BIN
resources/profiles/PrusaResearch/mk4_bed.stl
Normal file
Binary file not shown.
@ -1,3 +1,5 @@
|
||||
min_slic3r_version = 2.6.0-alpha5
|
||||
1.0.1 General rework. Fix start gcodes.
|
||||
min_slic3r_version = 2.6.0-alpha0
|
||||
1.0.0 Initial Rigid3D bundle
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
name = Rigid3D
|
||||
# Configuration version of this file. Config file will only be installed, if the config_version differs.
|
||||
# This means, the server may force the PrusaSlicer configuration to be downgraded.
|
||||
config_version = 1.0.0
|
||||
config_version = 1.0.1
|
||||
# Where to get the updates from?
|
||||
config_update_url = https://files.prusa3d.com/wp-content/uploads/repository/PrusaSlicer-settings-master/live/Rigid3D/
|
||||
# changelog_url = https://files.prusa3d.com/?latest=slicer-profiles&lng=%1%
|
||||
@ -64,7 +64,7 @@ bridge_angle = 0
|
||||
bridge_flow_ratio = 1
|
||||
bridge_speed = 60
|
||||
brim_separation = 0
|
||||
brim_type = no_brim
|
||||
brim_type = outer_only
|
||||
brim_width = 0
|
||||
clip_multipart_objects = 1
|
||||
compatible_printers =
|
||||
@ -75,19 +75,19 @@ dont_support_bridges = 1
|
||||
draft_shield = disabled
|
||||
elefant_foot_compensation = 0
|
||||
ensure_vertical_shell_thickness = 0
|
||||
external_perimeter_extrusion_width = 0.45
|
||||
external_perimeter_extrusion_width = 0
|
||||
external_perimeter_speed = 50%
|
||||
external_perimeters_first = 1
|
||||
extra_perimeters = 1
|
||||
extruder_clearance_height = 20
|
||||
extruder_clearance_radius = 20
|
||||
extrusion_width = 0.45
|
||||
extrusion_width = 0
|
||||
fill_angle = 45
|
||||
fill_density = 10%
|
||||
fill_pattern = line
|
||||
first_layer_acceleration = 0
|
||||
first_layer_acceleration_over_raft = 0
|
||||
first_layer_extrusion_width = 0.42
|
||||
first_layer_extrusion_width = 0
|
||||
first_layer_height = 0.2
|
||||
first_layer_speed = 50%
|
||||
first_layer_speed_over_raft = 30
|
||||
@ -105,8 +105,8 @@ infill_anchor = 2.5
|
||||
infill_anchor_max = 12
|
||||
infill_every_layers = 1
|
||||
infill_extruder = 1
|
||||
infill_extrusion_width = 0.45
|
||||
infill_first = 1
|
||||
infill_extrusion_width = 0
|
||||
infill_first = 0
|
||||
infill_only_where_needed = 0
|
||||
infill_overlap = 25%
|
||||
infill_speed = 60
|
||||
@ -124,11 +124,11 @@ mmu_segmented_region_max_width = 0
|
||||
notes =
|
||||
only_retract_when_crossing_perimeters = 0
|
||||
ooze_prevention = 0
|
||||
output_filename_format = {input_filename_base}_{layer_height}mm_{initial_filament_type}_{printer_model}_{print_time}.gcode
|
||||
output_filename_format = {input_filename_base}_{layer_height}mm_{initial_filament_type}_{printer_model}.gcode
|
||||
overhangs = 1
|
||||
perimeter_acceleration = 0
|
||||
perimeter_extruder = 1
|
||||
perimeter_extrusion_width = 0.45
|
||||
perimeter_extrusion_width = 0
|
||||
perimeter_speed = 60
|
||||
perimeters = 2
|
||||
post_process =
|
||||
@ -139,7 +139,7 @@ raft_first_layer_density = 90%
|
||||
raft_first_layer_expansion = 3
|
||||
raft_layers = 0
|
||||
resolution = 0
|
||||
seam_position = rear
|
||||
seam_position = random
|
||||
single_extruder_multi_material_priming = 1
|
||||
skirt_distance = 6
|
||||
skirt_height = 1
|
||||
@ -147,14 +147,14 @@ skirts = 0
|
||||
slice_closing_radius = 0.049
|
||||
slicing_mode = regular
|
||||
small_perimeter_speed = 15
|
||||
solid_infill_below_area = 70
|
||||
solid_infill_below_area = 0
|
||||
solid_infill_every_layers = 0
|
||||
solid_infill_extruder = 1
|
||||
solid_infill_extrusion_width = 0.45
|
||||
solid_infill_extrusion_width = 0
|
||||
solid_infill_speed = 100%
|
||||
spiral_vase = 0
|
||||
standby_temperature_delta = -5
|
||||
support_material = 0
|
||||
support_material = 1
|
||||
support_material_angle = 0
|
||||
support_material_auto = 1
|
||||
support_material_bottom_contact_distance = 0
|
||||
@ -164,7 +164,7 @@ support_material_closing_radius = 2
|
||||
support_material_contact_distance = 0.2
|
||||
support_material_enforce_layers = 0
|
||||
support_material_extruder = 1
|
||||
support_material_extrusion_width = 0.35
|
||||
support_material_extrusion_width = 0
|
||||
support_material_interface_contact_loops = 0
|
||||
support_material_interface_extruder = 1
|
||||
support_material_interface_layers = 3
|
||||
@ -174,7 +174,7 @@ support_material_interface_speed = 100%
|
||||
support_material_pattern = rectilinear
|
||||
support_material_spacing = 2.5
|
||||
support_material_speed = 60
|
||||
support_material_style = grid
|
||||
support_material_style = organic
|
||||
support_material_synchronize_layers = 0
|
||||
support_material_threshold = 0
|
||||
support_material_with_sheath = 1
|
||||
@ -182,7 +182,7 @@ support_material_xy_spacing = 50%
|
||||
thick_bridges = 0
|
||||
thin_walls = 1
|
||||
top_fill_pattern = monotonic
|
||||
top_infill_extrusion_width = 0.4
|
||||
top_infill_extrusion_width = 0
|
||||
top_solid_infill_speed = 100%
|
||||
top_solid_min_thickness = 0.8
|
||||
travel_speed = 80
|
||||
@ -408,7 +408,7 @@ pause_print_gcode = M0
|
||||
printer_settings_id =
|
||||
printer_technology = FFF
|
||||
printer_variant = 0.4
|
||||
remaining_times = 1
|
||||
remaining_times = 0
|
||||
retract_before_travel = 2
|
||||
retract_before_wipe = 0%
|
||||
retract_layer_change = 0
|
||||
@ -438,7 +438,7 @@ bed_shape = 0x0,200x0,200x200,0x200
|
||||
max_print_height = 190
|
||||
printer_model = Zero2
|
||||
printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_RIGID3D\nPRINTER_MODEL_ZERO2\nPRINTER_HAS_HEATEDBED\n
|
||||
start_gcode = G21\nG92 E0\nG28\nM420 S1\nM107\nG90\nG1 X10.0 Y0.1 Z0.3 F3000.0\nG1 X190.0 Y0.1 Z0.3 F1500.0 E15\nG1 X190 Y0.4 Z0.3 F3000.0\nG1 X10.0 Y0.4 Z0.3 F1500.0 E30\nG1 Z2.0 F1500.0\nG92 E0\n
|
||||
start_gcode = G21\nG92 E0\nM140 S[first_layer_bed_temperature]\nM104 S[first_layer_temperature]\nG28\nM420 S1\nM107\nG90\nM190 S[first_layer_bed_temperature]\nM109 S[first_layer_temperature]\nG1 X10.0 Y0.1 Z0.3 F3000.0\nG1 X190.0 Y0.1 Z0.3 F1500.0 E15\nG1 X190 Y0.4 Z0.3 F3000.0\nG1 X10.0 Y0.4 Z0.3 F1500.0 E30\nG1 Z2.0 F1500.0\nG92 E0\n
|
||||
end_gcode = G1 X0 Y180\nM107\nG91\nG0 Z20\nT0\nG1 E-1\nM104 T0 S0\nG90\nG92 E0\nM140 S0\nM84\nM300 S2093 P150\nM300 S2637 P150\nM300 S3135 P150\nM300 S4186 P150\nM300 S3135 P150\nM300 S2637 P150\nM300 S2793 P150\nM300 S2349 P150\nM300 S1975 P150\nM300 S2093 P450\n
|
||||
|
||||
[printer:Rigid3D Zero3]
|
||||
@ -447,7 +447,7 @@ bed_shape = 0x0,200x0,200x200,0x200
|
||||
max_print_height = 200
|
||||
printer_model = Zero3
|
||||
printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_RIGID3D\nPRINTER_MODEL_ZERO3\nPRINTER_HAS_HEATEDBED\n
|
||||
start_gcode = G21\nG92 E0\nG28\nM420 S1\nM107\nG90\nG1 X10.0 Y0.1 Z0.3 F3000.0\nG1 X190.0 Y0.1 Z0.3 F1500.0 E15\nG1 X190 Y0.4 Z0.3 F3000.0\nG1 X10.0 Y0.4 Z0.3 F1500.0 E30\nG1 Z2.0 F1500.0\nG92 E0\n
|
||||
start_gcode = G21\nG92 E0\nM140 S[first_layer_bed_temperature]\nM104 S[first_layer_temperature]\nG28\nM420 S1\nM107\nG90\nM190 S[first_layer_bed_temperature]\nM109 S[first_layer_temperature]\nG1 X10.0 Y0.1 Z0.3 F3000.0\nG1 X190.0 Y0.1 Z0.3 F1500.0 E15\nG1 X190 Y0.4 Z0.3 F3000.0\nG1 X10.0 Y0.4 Z0.3 F1500.0 E30\nG1 Z2.0 F1500.0\nG92 E0\n
|
||||
end_gcode = G92 E0\nT0\nG1 F1800 E-2\nG27 P2\nM107\nM104 T0 S0\nM140 S0\nG90\nG92 E0\nM18\n
|
||||
|
||||
[printer:Rigid3D Mucit]
|
||||
@ -456,7 +456,7 @@ bed_shape = 0x0,150x0,150x150,0x150
|
||||
max_print_height = 150
|
||||
printer_model = Mucit
|
||||
printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_RIGID3D\nPRINTER_MODEL_MUCIT\n
|
||||
start_gcode = G21\nG92 E0\nG28\nM420 S1\nM107\nG90\nG1 X10.0 Y0.1 Z0.3 F3000.0\nG1 X140.0 Y0.1 Z0.3 F1500.0 E10\nG1 X140 Y0.4 Z0.3 F3000.0\nG1 X10.0 Y0.4 Z0.3 F1500.0 E20\nG1 Z2.0 F1500.0\nG92 E0\n
|
||||
start_gcode = G21\nG92 E0\nM140 S[first_layer_bed_temperature]\nM104 S[first_layer_temperature]\nG28\nM420 S1\nM107\nG90\nM190 S[first_layer_bed_temperature]\nM109 S[first_layer_temperature]\nG1 X10.0 Y0.1 Z0.3 F3000.0\nG1 X140.0 Y0.1 Z0.3 F1500.0 E10\nG1 X140 Y0.4 Z0.3 F3000.0\nG1 X10.0 Y0.4 Z0.3 F1500.0 E20\nG1 Z2.0 F1500.0\nG92 E0\n
|
||||
end_gcode = G1 X0 Y140\nM107\nG91\nG0 Z20\nT0\nG1 E-2\nM104 T0 S0\nG90\nG92 E0\nM140 S0\nM84\nM300 S2093 P150\nM300 S2637 P150\nM300 S3135 P150\nM300 S4186 P150\nM300 S3135 P150\nM300 S2637 P150\nM300 S2793 P150\nM300 S2349 P150\nM300 S1975 P150\nM300 S2093 P450\n
|
||||
|
||||
[printer:Rigid3D Mucit2]
|
||||
@ -465,5 +465,5 @@ bed_shape = 0x0,150x0,150x150,0x150
|
||||
max_print_height = 150
|
||||
printer_model = Mucit2
|
||||
printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_RIGID3D\nPRINTER_MODEL_MUCIT2\nPRINTER_HAS_HEATEDBED\n
|
||||
start_gcode = G21\nG92 E0\nG28\nM420 S1\nM107\nG90\nG1 X10.0 Y0.1 Z0.3 F3000.0\nG1 X140.0 Y0.1 Z0.3 F1500.0 E10\nG1 X140 Y0.4 Z0.3 F3000.0\nG1 X10.0 Y0.4 Z0.3 F1500.0 E20\nG1 Z2.0 F1500.0\nG92 E0\n
|
||||
start_gcode = G21\nG92 E0\nM140 S[first_layer_bed_temperature]\nM104 S[first_layer_temperature]\nG28\nM420 S1\nM107\nG90\nM190 S[first_layer_bed_temperature]\nM109 S[first_layer_temperature]\nG1 X10.0 Y0.1 Z0.3 F3000.0\nG1 X140.0 Y0.1 Z0.3 F1500.0 E10\nG1 X140 Y0.4 Z0.3 F3000.0\nG1 X10.0 Y0.4 Z0.3 F1500.0 E20\nG1 Z2.0 F1500.0\nG92 E0\n
|
||||
end_gcode = G92 E0\nT0\nG1 F1800 E-2\nG27 P2\nM107\nM104 T0 S0\nM140 S0\nG90\nG92 E0\nM18\n
|
||||
|
@ -70,6 +70,7 @@ class _Item {
|
||||
|
||||
int binid_{BIN_ID_UNSET}, priority_{0};
|
||||
bool fixed_{false};
|
||||
std::function<void(_Item&)> on_packed_;
|
||||
|
||||
public:
|
||||
|
||||
@ -205,6 +206,23 @@ public:
|
||||
sl::vertex(sh_, idx) = v;
|
||||
}
|
||||
|
||||
void setShape(RawShape rsh)
|
||||
{
|
||||
sh_ = std::move(rsh);
|
||||
invalidateCache();
|
||||
}
|
||||
|
||||
void setOnPackedFn(std::function<void(_Item&)> onpackedfn)
|
||||
{
|
||||
on_packed_ = onpackedfn;
|
||||
}
|
||||
|
||||
void onPacked()
|
||||
{
|
||||
if (on_packed_)
|
||||
on_packed_(*this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Calculate the shape area.
|
||||
*
|
||||
|
@ -901,6 +901,7 @@ public:
|
||||
|
||||
if(can_pack) {
|
||||
ret = PackResult(item);
|
||||
item.onPacked();
|
||||
merged_pile_ = nfp::merge(merged_pile_, item.transformedShape());
|
||||
} else {
|
||||
ret = PackResult(best_overfit);
|
||||
|
@ -340,12 +340,6 @@ std::string AppConfig::load(const std::string &path)
|
||||
// Error while parsing config file. We'll customize the error message and rethrow to be displayed.
|
||||
// ! But to avoid the use of _utf8 (related to use of wxWidgets)
|
||||
// we will rethrow this exception from the place of load() call, if returned value wouldn't be empty
|
||||
/*
|
||||
throw Slic3r::RuntimeError(
|
||||
_utf8(L("Error parsing PrusaSlicer config file, it is probably corrupted. "
|
||||
"Try to manually delete the file to recover from the error. Your user profiles will not be affected.")) +
|
||||
"\n\n" + AppConfig::config_path() + "\n\n" + ex.what());
|
||||
*/
|
||||
return ex.what();
|
||||
}
|
||||
}
|
||||
|
@ -522,44 +522,6 @@ static bool has_missing_twin_edge(const SkeletalTrapezoidationGraph &graph)
|
||||
return false;
|
||||
}
|
||||
|
||||
inline static std::unordered_map<Point, Point, PointHash> try_to_fix_degenerated_voronoi_diagram_by_rotation(
|
||||
Geometry::VoronoiDiagram &voronoi_diagram,
|
||||
const Polygons &polys,
|
||||
Polygons &polys_rotated,
|
||||
std::vector<SkeletalTrapezoidation::Segment> &segments,
|
||||
const double fix_angle)
|
||||
{
|
||||
std::unordered_map<Point, Point, PointHash> vertex_mapping;
|
||||
for (Polygon &poly : polys_rotated)
|
||||
poly.rotate(fix_angle);
|
||||
|
||||
assert(polys_rotated.size() == polys.size());
|
||||
for (size_t poly_idx = 0; poly_idx < polys.size(); ++poly_idx) {
|
||||
assert(polys_rotated[poly_idx].size() == polys[poly_idx].size());
|
||||
for (size_t point_idx = 0; point_idx < polys[poly_idx].size(); ++point_idx)
|
||||
vertex_mapping.insert({polys_rotated[poly_idx][point_idx], polys[poly_idx][point_idx]});
|
||||
}
|
||||
|
||||
segments.clear();
|
||||
for (size_t poly_idx = 0; poly_idx < polys_rotated.size(); poly_idx++)
|
||||
for (size_t point_idx = 0; point_idx < polys_rotated[poly_idx].size(); point_idx++)
|
||||
segments.emplace_back(&polys_rotated, poly_idx, point_idx);
|
||||
|
||||
voronoi_diagram.clear();
|
||||
construct_voronoi(segments.begin(), segments.end(), &voronoi_diagram);
|
||||
|
||||
#ifdef ARACHNE_DEBUG_VORONOI
|
||||
{
|
||||
static int iRun = 0;
|
||||
dump_voronoi_to_svg(debug_out_path("arachne_voronoi-diagram-rotated-%d.svg", iRun++).c_str(), voronoi_diagram, to_points(polys), to_lines(polys));
|
||||
}
|
||||
#endif
|
||||
|
||||
assert(Geometry::VoronoiUtilsCgal::is_voronoi_diagram_planar_intersection(voronoi_diagram));
|
||||
|
||||
return vertex_mapping;
|
||||
}
|
||||
|
||||
inline static void rotate_back_skeletal_trapezoidation_graph_after_fix(SkeletalTrapezoidationGraph &graph,
|
||||
const double fix_angle,
|
||||
const std::unordered_map<Point, Point, PointHash> &vertex_mapping)
|
||||
@ -626,6 +588,56 @@ VoronoiDiagramStatus detect_voronoi_diagram_known_issues(const Geometry::Voronoi
|
||||
return VoronoiDiagramStatus::NO_ISSUE_DETECTED;
|
||||
}
|
||||
|
||||
inline static std::pair<std::unordered_map<Point, Point, PointHash>, double> try_to_fix_degenerated_voronoi_diagram_by_rotation(
|
||||
Geometry::VoronoiDiagram &voronoi_diagram,
|
||||
const Polygons &polys,
|
||||
Polygons &polys_rotated,
|
||||
std::vector<SkeletalTrapezoidation::Segment> &segments,
|
||||
const std::vector<double> &fix_angles)
|
||||
{
|
||||
const Polygons polys_rotated_original = polys_rotated;
|
||||
double fixed_by_angle = fix_angles.front();
|
||||
std::unordered_map<Point, Point, PointHash> vertex_mapping;
|
||||
|
||||
for (const double &fix_angle : fix_angles) {
|
||||
vertex_mapping.clear();
|
||||
polys_rotated = polys_rotated_original;
|
||||
fixed_by_angle = fix_angle;
|
||||
|
||||
for (Polygon &poly : polys_rotated)
|
||||
poly.rotate(fix_angle);
|
||||
|
||||
assert(polys_rotated.size() == polys.size());
|
||||
for (size_t poly_idx = 0; poly_idx < polys.size(); ++poly_idx) {
|
||||
assert(polys_rotated[poly_idx].size() == polys[poly_idx].size());
|
||||
for (size_t point_idx = 0; point_idx < polys[poly_idx].size(); ++point_idx)
|
||||
vertex_mapping.insert({polys_rotated[poly_idx][point_idx], polys[poly_idx][point_idx]});
|
||||
}
|
||||
|
||||
segments.clear();
|
||||
for (size_t poly_idx = 0; poly_idx < polys_rotated.size(); poly_idx++)
|
||||
for (size_t point_idx = 0; point_idx < polys_rotated[poly_idx].size(); point_idx++)
|
||||
segments.emplace_back(&polys_rotated, poly_idx, point_idx);
|
||||
|
||||
voronoi_diagram.clear();
|
||||
construct_voronoi(segments.begin(), segments.end(), &voronoi_diagram);
|
||||
|
||||
#ifdef ARACHNE_DEBUG_VORONOI
|
||||
{
|
||||
static int iRun = 0;
|
||||
dump_voronoi_to_svg(debug_out_path("arachne_voronoi-diagram-rotated-%d.svg", iRun++).c_str(), voronoi_diagram, to_points(polys), to_lines(polys));
|
||||
}
|
||||
#endif
|
||||
|
||||
if (detect_voronoi_diagram_known_issues(voronoi_diagram, segments) == VoronoiDiagramStatus::NO_ISSUE_DETECTED)
|
||||
break;
|
||||
}
|
||||
|
||||
assert(Geometry::VoronoiUtilsCgal::is_voronoi_diagram_planar_intersection(voronoi_diagram));
|
||||
|
||||
return {vertex_mapping, fixed_by_angle};
|
||||
}
|
||||
|
||||
void SkeletalTrapezoidation::constructFromPolygons(const Polygons& polys)
|
||||
{
|
||||
#ifdef ARACHNE_DEBUG
|
||||
@ -670,7 +682,8 @@ void SkeletalTrapezoidation::constructFromPolygons(const Polygons& polys)
|
||||
// When any Voronoi vertex is missing, the Voronoi diagram is not planar, or some voronoi edge is
|
||||
// intersecting input segment, rotate the input polygon and try again.
|
||||
VoronoiDiagramStatus status = detect_voronoi_diagram_known_issues(voronoi_diagram, segments);
|
||||
const double fix_angle = PI / 6;
|
||||
const std::vector<double> fix_angles = {PI / 6, PI / 5, PI / 7, PI / 11};
|
||||
double fixed_by_angle = fix_angles.front();
|
||||
|
||||
std::unordered_map<Point, Point, PointHash> vertex_mapping;
|
||||
// polys_copy is referenced through items stored in the std::vector segments.
|
||||
@ -683,16 +696,15 @@ void SkeletalTrapezoidation::constructFromPolygons(const Polygons& polys)
|
||||
else if (status == VoronoiDiagramStatus::VORONOI_EDGE_INTERSECTING_INPUT_SEGMENT)
|
||||
BOOST_LOG_TRIVIAL(warning) << "Detected Voronoi edge intersecting input segment, input polygons will be rotated back and forth.";
|
||||
|
||||
vertex_mapping = try_to_fix_degenerated_voronoi_diagram_by_rotation(voronoi_diagram, polys, polys_copy, segments, fix_angle);
|
||||
std::tie(vertex_mapping, fixed_by_angle) = try_to_fix_degenerated_voronoi_diagram_by_rotation(voronoi_diagram, polys, polys_copy, segments, fix_angles);
|
||||
|
||||
assert(!detect_missing_voronoi_vertex(voronoi_diagram, segments));
|
||||
assert(Geometry::VoronoiUtilsCgal::is_voronoi_diagram_planar_angle(voronoi_diagram, segments));
|
||||
assert(!detect_voronoi_edge_intersecting_input_segment(voronoi_diagram, segments));
|
||||
if (detect_missing_voronoi_vertex(voronoi_diagram, segments))
|
||||
VoronoiDiagramStatus status_after_fix = detect_voronoi_diagram_known_issues(voronoi_diagram, segments);
|
||||
assert(status_after_fix == VoronoiDiagramStatus::NO_ISSUE_DETECTED);
|
||||
if (status_after_fix == VoronoiDiagramStatus::MISSING_VORONOI_VERTEX)
|
||||
BOOST_LOG_TRIVIAL(error) << "Detected missing Voronoi vertex even after the rotation of input.";
|
||||
else if (!Geometry::VoronoiUtilsCgal::is_voronoi_diagram_planar_angle(voronoi_diagram, segments))
|
||||
else if (status_after_fix == VoronoiDiagramStatus::NON_PLANAR_VORONOI_DIAGRAM)
|
||||
BOOST_LOG_TRIVIAL(error) << "Detected non-planar Voronoi diagram even after the rotation of input.";
|
||||
else if (detect_voronoi_edge_intersecting_input_segment(voronoi_diagram, segments))
|
||||
else if (status_after_fix == VoronoiDiagramStatus::VORONOI_EDGE_INTERSECTING_INPUT_SEGMENT)
|
||||
BOOST_LOG_TRIVIAL(error) << "Detected Voronoi edge intersecting input segment even after the rotation of input.";
|
||||
}
|
||||
|
||||
@ -760,7 +772,7 @@ process_voronoi_diagram:
|
||||
if (status == VoronoiDiagramStatus::NO_ISSUE_DETECTED && has_missing_twin_edge(this->graph)) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "Detected degenerated Voronoi diagram, input polygons will be rotated back and forth.";
|
||||
status = VoronoiDiagramStatus::OTHER_TYPE_OF_VORONOI_DIAGRAM_DEGENERATION;
|
||||
vertex_mapping = try_to_fix_degenerated_voronoi_diagram_by_rotation(voronoi_diagram, polys, polys_copy, segments, fix_angle);
|
||||
std::tie(vertex_mapping, fixed_by_angle) = try_to_fix_degenerated_voronoi_diagram_by_rotation(voronoi_diagram, polys, polys_copy, segments, fix_angles);
|
||||
|
||||
assert(!detect_missing_voronoi_vertex(voronoi_diagram, segments));
|
||||
if (detect_missing_voronoi_vertex(voronoi_diagram, segments))
|
||||
@ -784,7 +796,7 @@ process_voronoi_diagram:
|
||||
}
|
||||
|
||||
if (status != VoronoiDiagramStatus::NO_ISSUE_DETECTED)
|
||||
rotate_back_skeletal_trapezoidation_graph_after_fix(this->graph, fix_angle, vertex_mapping);
|
||||
rotate_back_skeletal_trapezoidation_graph_after_fix(this->graph, fixed_by_angle, vertex_mapping);
|
||||
|
||||
#ifdef ARACHNE_DEBUG
|
||||
assert(Geometry::VoronoiUtilsCgal::is_voronoi_diagram_planar_intersection(voronoi_diagram));
|
||||
|
@ -113,8 +113,7 @@ void ExtrusionLine::simplify(const int64_t smallest_line_segment_squared, const
|
||||
//h^2 = (L / b)^2 [square it]
|
||||
//h^2 = L^2 / b^2 [factor the divisor]
|
||||
const auto height_2 = int64_t(double(area_removed_so_far) * double(area_removed_so_far) / double(base_length_2));
|
||||
coord_t weighted_average_width;
|
||||
const int64_t extrusion_area_error = calculateExtrusionAreaDeviationError(previous, current, next, weighted_average_width);
|
||||
const int64_t extrusion_area_error = calculateExtrusionAreaDeviationError(previous, current, next);
|
||||
if ((height_2 <= scaled<coord_t>(0.001) //Almost exactly colinear (barring rounding errors).
|
||||
&& Line::distance_to_infinite(current.p, previous.p, next.p) <= scaled<double>(0.001)) // Make sure that height_2 is not small because of cancellation of positive and negative areas
|
||||
// We shouldn't remove middle junctions of colinear segments if the area changed for the C-P segment is exceeding the maximum allowed
|
||||
@ -189,8 +188,7 @@ void ExtrusionLine::simplify(const int64_t smallest_line_segment_squared, const
|
||||
junctions = new_junctions;
|
||||
}
|
||||
|
||||
int64_t ExtrusionLine::calculateExtrusionAreaDeviationError(ExtrusionJunction A, ExtrusionJunction B, ExtrusionJunction C, coord_t& weighted_average_width)
|
||||
{
|
||||
int64_t ExtrusionLine::calculateExtrusionAreaDeviationError(ExtrusionJunction A, ExtrusionJunction B, ExtrusionJunction C) {
|
||||
/*
|
||||
* A B C A C
|
||||
* --------------- **************
|
||||
@ -208,27 +206,19 @@ int64_t ExtrusionLine::calculateExtrusionAreaDeviationError(ExtrusionJunction A,
|
||||
* weighted-average width for the entire extrusion line.
|
||||
*
|
||||
* */
|
||||
const int64_t ab_length = (B - A).cast<int64_t>().norm();
|
||||
const int64_t bc_length = (C - B).cast<int64_t>().norm();
|
||||
const coord_t width_diff = std::max(std::abs(B.w - A.w), std::abs(C.w - B.w));
|
||||
if (width_diff > 1)
|
||||
{
|
||||
const int64_t ab_length = (B.p - A.p).cast<int64_t>().norm();
|
||||
const int64_t bc_length = (C.p - B.p).cast<int64_t>().norm();
|
||||
if (const coord_t width_diff = std::max(std::abs(B.w - A.w), std::abs(C.w - B.w)); width_diff > 1) {
|
||||
// Adjust the width only if there is a difference, or else the rounding errors may produce the wrong
|
||||
// weighted average value.
|
||||
const int64_t ab_weight = (A.w + B.w) / 2;
|
||||
const int64_t bc_weight = (B.w + C.w) / 2;
|
||||
assert(((ab_length * ab_weight + bc_length * bc_weight) / (C - A).cast<int64_t>().norm()) <= std::numeric_limits<coord_t>::max());
|
||||
weighted_average_width = (ab_length * ab_weight + bc_length * bc_weight) / (C - A).cast<int64_t>().norm();
|
||||
assert((int64_t(std::abs(ab_weight - weighted_average_width)) * ab_length + int64_t(std::abs(bc_weight - weighted_average_width)) * bc_length) <= double(std::numeric_limits<int64_t>::max()));
|
||||
return std::abs(ab_weight - weighted_average_width) * ab_length + std::abs(bc_weight - weighted_average_width) * bc_length;
|
||||
}
|
||||
else
|
||||
{
|
||||
const int64_t weighted_average_width = (ab_length * ab_weight + bc_length * bc_weight) / (ab_length + bc_length);
|
||||
const int64_t ac_length = (C.p - A.p).cast<int64_t>().norm();
|
||||
return std::abs((ab_weight * ab_length + bc_weight * bc_length) - (weighted_average_width * ac_length));
|
||||
} else {
|
||||
// If the width difference is very small, then select the width of the segment that is longer
|
||||
weighted_average_width = ab_length > bc_length ? A.w : B.w;
|
||||
assert((int64_t(width_diff) * int64_t(bc_length)) <= std::numeric_limits<coord_t>::max());
|
||||
assert((int64_t(width_diff) * int64_t(ab_length)) <= std::numeric_limits<coord_t>::max());
|
||||
return ab_length > bc_length ? width_diff * bc_length : width_diff * ab_length;
|
||||
return ab_length > bc_length ? int64_t(width_diff) * bc_length : int64_t(width_diff) * ab_length;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -186,9 +186,8 @@ struct ExtrusionLine
|
||||
* \param A Start point of the 3-point-straight line
|
||||
* \param B Intermediate point of the 3-point-straight line
|
||||
* \param C End point of the 3-point-straight line
|
||||
* \param weighted_average_width The weighted average of the widths of the two colinear extrusion segments
|
||||
* */
|
||||
static int64_t calculateExtrusionAreaDeviationError(ExtrusionJunction A, ExtrusionJunction B, ExtrusionJunction C, coord_t& weighted_average_width);
|
||||
static int64_t calculateExtrusionAreaDeviationError(ExtrusionJunction A, ExtrusionJunction B, ExtrusionJunction C);
|
||||
|
||||
bool is_contour() const;
|
||||
|
||||
|
@ -583,8 +583,12 @@ static void process_arrangeable(const ArrangePolygon &arrpoly,
|
||||
outp.emplace_back(std::move(p));
|
||||
outp.back().rotation(rotation);
|
||||
outp.back().translation({offs.x(), offs.y()});
|
||||
outp.back().inflate(arrpoly.inflation);
|
||||
outp.back().binId(arrpoly.bed_idx);
|
||||
outp.back().priority(arrpoly.priority);
|
||||
outp.back().setOnPackedFn([&arrpoly](Item &itm){
|
||||
itm.inflate(-arrpoly.inflation);
|
||||
});
|
||||
}
|
||||
|
||||
template<class Fn> auto call_with_bed(const Points &bed, Fn &&fn)
|
||||
|
@ -55,7 +55,7 @@ void remove_bad(ExPolygons &expolygons);
|
||||
|
||||
// helpr for heal shape
|
||||
// Return true when erase otherwise false
|
||||
bool remove_same_neighbor(Points &points);
|
||||
bool remove_same_neighbor(Polygon &points);
|
||||
bool remove_same_neighbor(Polygons &polygons);
|
||||
bool remove_same_neighbor(ExPolygons &expolygons);
|
||||
|
||||
@ -276,14 +276,22 @@ void priv::remove_bad(ExPolygons &expolygons) {
|
||||
remove_bad(expolygon.holes);
|
||||
}
|
||||
|
||||
bool priv::remove_same_neighbor(Slic3r::Points &points)
|
||||
bool priv::remove_same_neighbor(Slic3r::Polygon &polygon)
|
||||
{
|
||||
Points &points = polygon.points;
|
||||
if (points.empty()) return false;
|
||||
auto last = std::unique(points.begin(), points.end());
|
||||
|
||||
// remove first and last neighbor duplication
|
||||
if (const Point& last_point = *(last - 1);
|
||||
last_point == points.front()) {
|
||||
--last;
|
||||
}
|
||||
|
||||
// no duplicits
|
||||
if (last == points.end()) return false;
|
||||
|
||||
points.erase(last, points.end());
|
||||
// clear points without area
|
||||
if (points.size() <= 2) points.clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -291,34 +299,30 @@ bool priv::remove_same_neighbor(Polygons &polygons) {
|
||||
if (polygons.empty()) return false;
|
||||
bool exist = false;
|
||||
for (Polygon& polygon : polygons)
|
||||
exist |= remove_same_neighbor(polygon.points);
|
||||
exist |= remove_same_neighbor(polygon);
|
||||
// remove empty polygons
|
||||
polygons.erase(
|
||||
std::remove_if(polygons.begin(), polygons.end(),
|
||||
[](const Polygon &p) { return p.empty(); }),
|
||||
[](const Polygon &p) { return p.points.size() <= 2; }),
|
||||
polygons.end());
|
||||
return exist;
|
||||
}
|
||||
|
||||
bool priv::remove_same_neighbor(ExPolygons &expolygons) {
|
||||
if(expolygons.empty()) return false;
|
||||
bool exist = false;
|
||||
bool remove_from_holes = false;
|
||||
bool remove_from_contour = false;
|
||||
for (ExPolygon &expoly : expolygons) {
|
||||
exist |= remove_same_neighbor(expoly.contour.points);
|
||||
Polygons &holes = expoly.holes;
|
||||
for (Polygon &hole : holes)
|
||||
exist |= remove_same_neighbor(hole.points);
|
||||
holes.erase(
|
||||
std::remove_if(holes.begin(), holes.end(),
|
||||
[](const Polygon &p) { return p.size() < 3; }),
|
||||
holes.end());
|
||||
remove_from_contour |= remove_same_neighbor(expoly.contour);
|
||||
remove_from_holes |= remove_same_neighbor(expoly.holes);
|
||||
}
|
||||
|
||||
// Removing of point could create polygon with less than 3 points
|
||||
if (exist)
|
||||
remove_bad(expolygons);
|
||||
|
||||
return exist;
|
||||
// Removing of expolygons without contour
|
||||
if (remove_from_contour)
|
||||
expolygons.erase(
|
||||
std::remove_if(expolygons.begin(), expolygons.end(),
|
||||
[](const ExPolygon &p) { return p.contour.points.size() <=2; }),
|
||||
expolygons.end());
|
||||
return remove_from_holes || remove_from_contour;
|
||||
}
|
||||
|
||||
Points priv::collect_close_points(const ExPolygons &expolygons, double distance) {
|
||||
@ -506,9 +510,9 @@ bool priv::remove_self_intersections(ExPolygons &shape, unsigned max_iteration)
|
||||
hole.translate(p);
|
||||
holes.push_back(hole);
|
||||
}
|
||||
// union overlapped holes
|
||||
if (holes.size() > 1)
|
||||
holes = Slic3r::union_(holes);
|
||||
// Union of overlapped holes is not neccessary
|
||||
// Clipper calculate winding number separately for each input parameter
|
||||
// if (holes.size() > 1) holes = Slic3r::union_(holes);
|
||||
shape = Slic3r::diff_ex(shape, holes, ApplySafetyOffset::Yes);
|
||||
|
||||
// TODO: find where diff ex could create same neighbor
|
||||
@ -634,7 +638,6 @@ bool priv::heal_dupl_inter(ExPolygons &shape, unsigned max_iteration)
|
||||
holes.push_back(hole);
|
||||
}
|
||||
|
||||
holes = Slic3r::union_(holes);
|
||||
shape = Slic3r::diff_ex(shape, holes, ApplySafetyOffset::Yes);
|
||||
|
||||
// prepare for next loop
|
||||
|
@ -37,6 +37,7 @@ std::pair<double, double> Extruder::extrude(double dE)
|
||||
value supplied will overwrite the previous one if any. */
|
||||
std::pair<double, double> Extruder::retract(double retract_length, double restart_extra)
|
||||
{
|
||||
assert(restart_extra >= 0);
|
||||
// in case of relative E distances we always reset to 0 before any output
|
||||
if (m_config->use_relative_e_distances)
|
||||
m_E = 0.;
|
||||
@ -64,6 +65,24 @@ std::pair<double, double> Extruder::unretract()
|
||||
return std::make_pair(dE, emitE);
|
||||
}
|
||||
|
||||
// Setting the retract state from the script.
|
||||
// Sets current retraction value & restart extra filament amount if retracted > 0.
|
||||
void Extruder::set_retracted(double retracted, double restart_extra)
|
||||
{
|
||||
if (retracted < - EPSILON)
|
||||
throw Slic3r::RuntimeError("Custom G-code reports negative z_retracted.");
|
||||
if (restart_extra < - EPSILON)
|
||||
throw Slic3r::RuntimeError("Custom G-code reports negative z_restart_extra.");
|
||||
|
||||
if (retracted > EPSILON) {
|
||||
m_retracted = retracted;
|
||||
m_restart_extra = restart_extra < EPSILON ? 0 : restart_extra;
|
||||
} else {
|
||||
m_retracted = 0;
|
||||
m_restart_extra = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Used filament volume in mm^3.
|
||||
double Extruder::extruded_volume() const
|
||||
{
|
||||
|
@ -37,6 +37,19 @@ public:
|
||||
// Used filament length in mm.
|
||||
double used_filament() const;
|
||||
|
||||
// Getters for the PlaceholderParser.
|
||||
// Get current extruder position. Only applicable with absolute extruder addressing.
|
||||
double position() const { return m_E; }
|
||||
// Get current retraction value. Only non-negative values.
|
||||
double retracted() const { return m_retracted; }
|
||||
// Get extra retraction planned after
|
||||
double restart_extra() const { return m_restart_extra; }
|
||||
// Setters for the PlaceholderParser.
|
||||
// Set current extruder position. Only applicable with absolute extruder addressing.
|
||||
void set_position(double e) { m_E = e; }
|
||||
// Sets current retraction value & restart extra filament amount if retracted > 0.
|
||||
void set_retracted(double retracted, double restart_extra);
|
||||
|
||||
double filament_diameter() const;
|
||||
double filament_crossection() const { return this->filament_diameter() * this->filament_diameter() * 0.25 * PI; }
|
||||
double filament_density() const;
|
||||
|
@ -1,10 +1,10 @@
|
||||
#include "ExtrusionRole.hpp"
|
||||
#include "I18N.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <cassert>
|
||||
|
||||
#define L(s) (s)
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
|
@ -6,9 +6,6 @@
|
||||
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
|
||||
// Mark string for localization and translate.
|
||||
#define L(s) Slic3r::I18N::translate(s)
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
FlowErrorNegativeSpacing::FlowErrorNegativeSpacing() :
|
||||
@ -58,7 +55,7 @@ static inline FlowRole opt_key_to_flow_role(const std::string &opt_key)
|
||||
|
||||
static inline void throw_on_missing_variable(const std::string &opt_key, const char *dependent_opt_key)
|
||||
{
|
||||
throw FlowErrorMissingVariable((boost::format(L("Cannot calculate extrusion width for %1%: Variable \"%2%\" not accessible.")) % opt_key % dependent_opt_key).str());
|
||||
throw FlowErrorMissingVariable((boost::format(_u8L("Cannot calculate extrusion width for %1%: Variable \"%2%\" not accessible.")) % opt_key % dependent_opt_key).str());
|
||||
}
|
||||
|
||||
// Used to provide hints to the user on default extrusion width values, and to provide reasonable values to the PlaceholderParser.
|
||||
|
@ -306,11 +306,6 @@ bool is_valid_object_type(const std::string& type)
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
//! macro used to mark string used at localization,
|
||||
//! return same string
|
||||
#define L(s) (s)
|
||||
#define _(s) Slic3r::I18N::translate(s)
|
||||
|
||||
// Base class with error messages management
|
||||
class _3MF_Base
|
||||
{
|
||||
@ -992,7 +987,7 @@ namespace Slic3r {
|
||||
}
|
||||
|
||||
if (res == 0) {
|
||||
add_error("Error while extracting model data from zip archive");
|
||||
add_error("Error while extracting model data from ZIP archive");
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1889,9 +1884,9 @@ namespace Slic3r {
|
||||
if (m_curr_metadata_name == SLIC3RPE_3MF_VERSION) {
|
||||
m_version = (unsigned int)atoi(m_curr_characters.c_str());
|
||||
if (m_check_version && (m_version > VERSION_3MF_COMPATIBLE)) {
|
||||
// std::string msg = _(L("The selected 3mf file has been saved with a newer version of " + std::string(SLIC3R_APP_NAME) + " and is not compatible."));
|
||||
// std::string msg = _u8L("The selected 3mf file has been saved with a newer version of " + std::string(SLIC3R_APP_NAME) + " and is not compatible.");
|
||||
// throw version_error(msg.c_str());
|
||||
const std::string msg = (boost::format(_(L("The selected 3mf file has been saved with a newer version of %1% and is not compatible."))) % std::string(SLIC3R_APP_NAME)).str();
|
||||
const std::string msg = (boost::format(_u8L("The selected 3mf file has been saved with a newer version of %1% and is not compatible.")) % std::string(SLIC3R_APP_NAME)).str();
|
||||
throw version_error(msg);
|
||||
}
|
||||
} else if (m_curr_metadata_name == "Application") {
|
||||
@ -1902,15 +1897,15 @@ namespace Slic3r {
|
||||
} else if (m_curr_metadata_name == SLIC3RPE_FDM_SUPPORTS_PAINTING_VERSION) {
|
||||
m_fdm_supports_painting_version = (unsigned int) atoi(m_curr_characters.c_str());
|
||||
check_painting_version(m_fdm_supports_painting_version, FDM_SUPPORTS_PAINTING_VERSION,
|
||||
_(L("The selected 3MF contains FDM supports painted object using a newer version of PrusaSlicer and is not compatible.")));
|
||||
_u8L("The selected 3MF contains FDM supports painted object using a newer version of PrusaSlicer and is not compatible."));
|
||||
} else if (m_curr_metadata_name == SLIC3RPE_SEAM_PAINTING_VERSION) {
|
||||
m_seam_painting_version = (unsigned int) atoi(m_curr_characters.c_str());
|
||||
check_painting_version(m_seam_painting_version, SEAM_PAINTING_VERSION,
|
||||
_(L("The selected 3MF contains seam painted object using a newer version of PrusaSlicer and is not compatible.")));
|
||||
_u8L("The selected 3MF contains seam painted object using a newer version of PrusaSlicer and is not compatible."));
|
||||
} else if (m_curr_metadata_name == SLIC3RPE_MM_PAINTING_VERSION) {
|
||||
m_mm_painting_version = (unsigned int) atoi(m_curr_characters.c_str());
|
||||
check_painting_version(m_mm_painting_version, MM_PAINTING_VERSION,
|
||||
_(L("The selected 3MF contains multi-material painted object using a newer version of PrusaSlicer and is not compatible.")));
|
||||
_u8L("The selected 3MF contains multi-material painted object using a newer version of PrusaSlicer and is not compatible."));
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -3002,6 +2997,8 @@ namespace Slic3r {
|
||||
|
||||
unsigned int object_cnt = 0;
|
||||
for (const ModelObject* object : model.objects) {
|
||||
if (!object->is_cut())
|
||||
continue;
|
||||
object_cnt++;
|
||||
pt::ptree& obj_tree = tree.add("objects.object", "");
|
||||
|
||||
|
@ -57,10 +57,6 @@ const char* SLIC3R_CONFIG_TYPE = "slic3rpe_config";
|
||||
namespace Slic3r
|
||||
{
|
||||
|
||||
//! macro used to mark string used at localization,
|
||||
//! return same string
|
||||
#define L(s) (s)
|
||||
#define _(s) Slic3r::I18N::translate(s)
|
||||
|
||||
struct AMFParserContext
|
||||
{
|
||||
@ -997,7 +993,7 @@ bool extract_model_from_archive(mz_zip_archive& archive, const mz_zip_archive_fi
|
||||
{
|
||||
// std::string msg = _(L("The selected amf file has been saved with a newer version of " + std::string(SLIC3R_APP_NAME) + " and is not compatible."));
|
||||
// throw Slic3r::FileIOError(msg.c_str());
|
||||
const std::string msg = (boost::format(_(L("The selected amf file has been saved with a newer version of %1% and is not compatible."))) % std::string(SLIC3R_APP_NAME)).str();
|
||||
const std::string msg = (boost::format(_u8L("The selected amf file has been saved with a newer version of %1% and is not compatible.")) % std::string(SLIC3R_APP_NAME)).str();
|
||||
throw Slic3r::FileIOError(msg);
|
||||
}
|
||||
|
||||
|
@ -1,13 +1,13 @@
|
||||
#include "SLAArchiveReader.hpp"
|
||||
#include "SL1.hpp"
|
||||
#include "SL1_SVG.hpp"
|
||||
#include "I18N.hpp"
|
||||
|
||||
#include "libslic3r/SlicesToTriangleMesh.hpp"
|
||||
|
||||
#include <boost/filesystem/path.hpp>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
constexpr const char * L(const char * str) { return str; }
|
||||
|
||||
#include <array>
|
||||
#include <map>
|
||||
@ -37,8 +37,8 @@ static const std::map<std::string, ArchiveEntry> REGISTERED_ARCHIVES {
|
||||
[] (const std::string &fname, SLAImportQuality quality, const ProgrFn &progr) { return std::make_unique<SL1Reader>(fname, quality, progr); } }
|
||||
},
|
||||
{
|
||||
"SL2",
|
||||
{ L("SL2 archive files"), {"sl2", "sl1_svg"/*, "zip"*/}, // also a zip but unnecessary hassle to implement single extension for multiple archives
|
||||
"SL1SVG",
|
||||
{ L("SL1SVG archive files"), {"sl1_svg"/*, "zip"*/}, // also a zip but unnecessary hassle to implement single extension for multiple archives
|
||||
[] (const std::string &fname, SLAImportQuality quality, const ProgrFn &progr) { return std::make_unique<SL1_SVGReader>(fname, quality, progr); }}
|
||||
},
|
||||
// TODO: pwmx and future others.
|
||||
|
@ -25,9 +25,13 @@ static const std::map<std::string, ArchiveEntry> REGISTERED_ARCHIVES {
|
||||
"SL1",
|
||||
{ "sl1", [] (const auto &cfg) { return std::make_unique<SL1Archive>(cfg); } }
|
||||
},
|
||||
{
|
||||
"SL1SVG",
|
||||
{ "sl1_svg", [] (const auto &cfg) { return std::make_unique<SL1_SVGArchive>(cfg); } }
|
||||
},
|
||||
{
|
||||
"SL2",
|
||||
{ "sl2", [] (const auto &cfg) { return std::make_unique<SL1_SVGArchive>(cfg); } }
|
||||
{ "sl1_svg", [] (const auto &cfg) { return std::make_unique<SL1_SVGArchive>(cfg); } }
|
||||
},
|
||||
{
|
||||
"pwmx",
|
||||
|
@ -71,11 +71,6 @@ using namespace std::literals::string_view_literals;
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
//! macro used to mark string used at localization,
|
||||
//! return same string
|
||||
#define L(s) (s)
|
||||
#define _(s) Slic3r::I18N::translate(s)
|
||||
|
||||
// Only add a newline in case the current G-code does not end with a newline.
|
||||
static inline void check_add_eol(std::string& gcode)
|
||||
{
|
||||
@ -124,10 +119,14 @@ namespace Slic3r {
|
||||
// we assume that heating is always slower than cooling, so no need to block
|
||||
gcode += gcodegen.writer().set_temperature
|
||||
(this->_get_temp(gcodegen) + gcodegen.config().standby_temperature_delta.value, false, extruder_id);
|
||||
gcode.pop_back();
|
||||
gcode += " ;cooldown\n"; // this is a marker for GCodeProcessor, so it can supress the commands when needed
|
||||
}
|
||||
} else {
|
||||
// Use the value from filament settings. That one is absolute, not delta.
|
||||
gcode += gcodegen.writer().set_temperature(filament_idle_temp.get_at(extruder_id), false, extruder_id);
|
||||
gcode.pop_back();
|
||||
gcode += " ;cooldown\n"; // this is a marker for GCodeProcessor, so it can supress the commands when needed
|
||||
}
|
||||
|
||||
return gcode;
|
||||
@ -424,7 +423,7 @@ namespace Slic3r {
|
||||
std::string WipeTowerIntegration::finalize(GCode& gcodegen)
|
||||
{
|
||||
std::string gcode;
|
||||
if (std::abs(gcodegen.writer().get_position()(2) - m_final_purge.print_z) > EPSILON)
|
||||
if (std::abs(gcodegen.writer().get_position().z() - m_final_purge.print_z) > EPSILON)
|
||||
gcode += gcodegen.change_layer(m_final_purge.print_z);
|
||||
gcode += append_tcr(gcodegen, m_final_purge, -1);
|
||||
return gcode;
|
||||
@ -434,6 +433,115 @@ namespace Slic3r {
|
||||
|
||||
#define EXTRUDER_CONFIG(OPT) m_config.OPT.get_at(m_writer.extruder()->id())
|
||||
|
||||
void GCode::PlaceholderParserIntegration::reset()
|
||||
{
|
||||
this->failed_templates.clear();
|
||||
this->output_config.clear();
|
||||
this->opt_position = nullptr;
|
||||
this->opt_zhop = nullptr;
|
||||
this->opt_e_position = nullptr;
|
||||
this->opt_e_retracted = nullptr;
|
||||
this->opt_e_restart_extra = nullptr;
|
||||
this->opt_extruded_volume = nullptr;
|
||||
this->opt_extruded_weight = nullptr;
|
||||
this->opt_extruded_volume_total = nullptr;
|
||||
this->opt_extruded_weight_total = nullptr;
|
||||
this->num_extruders = 0;
|
||||
this->position.clear();
|
||||
this->e_position.clear();
|
||||
this->e_retracted.clear();
|
||||
this->e_restart_extra.clear();
|
||||
}
|
||||
|
||||
void GCode::PlaceholderParserIntegration::init(const GCodeWriter &writer)
|
||||
{
|
||||
this->reset();
|
||||
const std::vector<Extruder> &extruders = writer.extruders();
|
||||
if (! extruders.empty()) {
|
||||
this->num_extruders = extruders.back().id() + 1;
|
||||
this->e_retracted.assign(num_extruders, 0);
|
||||
this->e_restart_extra.assign(num_extruders, 0);
|
||||
this->opt_e_retracted = new ConfigOptionFloats(e_retracted);
|
||||
this->opt_e_restart_extra = new ConfigOptionFloats(e_restart_extra);
|
||||
this->output_config.set_key_value("e_retracted", this->opt_e_retracted);
|
||||
this->output_config.set_key_value("e_restart_extra", this->opt_e_restart_extra);
|
||||
if (! writer.config.use_relative_e_distances) {
|
||||
e_position.assign(num_extruders, 0);
|
||||
opt_e_position = new ConfigOptionFloats(e_position);
|
||||
this->output_config.set_key_value("e_position", opt_e_position);
|
||||
}
|
||||
}
|
||||
this->opt_extruded_volume = new ConfigOptionFloats(this->num_extruders, 0.f);
|
||||
this->opt_extruded_weight = new ConfigOptionFloats(this->num_extruders, 0.f);
|
||||
this->opt_extruded_volume_total = new ConfigOptionFloat(0.f);
|
||||
this->opt_extruded_weight_total = new ConfigOptionFloat(0.f);
|
||||
this->parser.set("extruded_volume", this->opt_extruded_volume);
|
||||
this->parser.set("extruded_weight", this->opt_extruded_weight);
|
||||
this->parser.set("extruded_volume_total", this->opt_extruded_volume_total);
|
||||
this->parser.set("extruded_weight_total", this->opt_extruded_weight_total);
|
||||
|
||||
// Reserve buffer for current position.
|
||||
this->position.assign(3, 0);
|
||||
this->opt_position = new ConfigOptionFloats(this->position);
|
||||
this->output_config.set_key_value("position", this->opt_position);
|
||||
// Store zhop variable into the parser itself, it is a read-only variable to the script.
|
||||
this->opt_zhop = new ConfigOptionFloat(writer.get_zhop());
|
||||
this->parser.set("zhop", this->opt_zhop);
|
||||
}
|
||||
|
||||
void GCode::PlaceholderParserIntegration::update_from_gcodewriter(const GCodeWriter &writer)
|
||||
{
|
||||
memcpy(this->position.data(), writer.get_position().data(), sizeof(double) * 3);
|
||||
this->opt_position->values = this->position;
|
||||
this->opt_zhop->value = writer.get_zhop();
|
||||
|
||||
if (this->num_extruders > 0) {
|
||||
const std::vector<Extruder> &extruders = writer.extruders();
|
||||
assert(! extruders.empty() && num_extruders == extruders.back().id() + 1);
|
||||
this->e_retracted.assign(num_extruders, 0);
|
||||
this->e_restart_extra.assign(num_extruders, 0);
|
||||
this->opt_extruded_volume->values.assign(num_extruders, 0);
|
||||
this->opt_extruded_weight->values.assign(num_extruders, 0);
|
||||
double total_volume = 0.;
|
||||
double total_weight = 0.;
|
||||
for (const Extruder &e : extruders) {
|
||||
this->e_retracted[e.id()] = e.retracted();
|
||||
this->e_restart_extra[e.id()] = e.restart_extra();
|
||||
double v = e.extruded_volume();
|
||||
double w = v * e.filament_density() * 0.001;
|
||||
this->opt_extruded_volume->values[e.id()] = v;
|
||||
this->opt_extruded_weight->values[e.id()] = w;
|
||||
total_volume += v;
|
||||
total_weight += w;
|
||||
}
|
||||
opt_extruded_volume_total->value = total_volume;
|
||||
opt_extruded_weight_total->value = total_weight;
|
||||
opt_e_retracted->values = this->e_retracted;
|
||||
opt_e_restart_extra->values = this->e_restart_extra;
|
||||
if (! writer.config.use_relative_e_distances) {
|
||||
this->e_position.assign(num_extruders, 0);
|
||||
for (const Extruder &e : extruders)
|
||||
this->e_position[e.id()] = e.position();
|
||||
this->opt_e_position->values = this->e_position;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Throw if any of the output vector variables were resized by the script.
|
||||
void GCode::PlaceholderParserIntegration::validate_output_vector_variables()
|
||||
{
|
||||
if (this->opt_position->values.size() != 3)
|
||||
throw Slic3r::RuntimeError("\"position\" output variable must not be resized by the script.");
|
||||
if (this->num_extruders > 0) {
|
||||
if (this->opt_e_position && this->opt_e_position->values.size() != this->num_extruders)
|
||||
throw Slic3r::RuntimeError("\"e_position\" output variable must not be resized by the script.");
|
||||
if (this->opt_e_retracted->values.size() != this->num_extruders)
|
||||
throw Slic3r::RuntimeError("\"e_retracted\" output variable must not be resized by the script.");
|
||||
if (this->opt_e_restart_extra->values.size() != this->num_extruders)
|
||||
throw Slic3r::RuntimeError("\"e_restart_extra\" output variable must not be resized by the script.");
|
||||
}
|
||||
}
|
||||
|
||||
// Collect pairs of object_layer + support_layer sorted by print_z.
|
||||
// object_layer & support_layer are considered to be on the same print_z, if they are not further than EPSILON.
|
||||
GCode::ObjectsLayerToPrint GCode::collect_layers_to_print(const PrintObject& object)
|
||||
@ -487,8 +595,8 @@ GCode::ObjectsLayerToPrint GCode::collect_layers_to_print(const PrintObject& obj
|
||||
// first layer may result in skirt/brim in the air and maybe other issues.
|
||||
if (layers_to_print.size() == 1u) {
|
||||
if (!has_extrusions)
|
||||
throw Slic3r::SlicingError(_(L("There is an object with no extrusions in the first layer.")) + "\n" +
|
||||
_(L("Object name")) + ": " + object.model_object()->name);
|
||||
throw Slic3r::SlicingError(_u8L("There is an object with no extrusions in the first layer.") + "\n" +
|
||||
_u8L("Object name") + ": " + object.model_object()->name);
|
||||
}
|
||||
|
||||
// In case there are extrusions on this layer, check there is a layer to lay it on.
|
||||
@ -518,14 +626,14 @@ GCode::ObjectsLayerToPrint GCode::collect_layers_to_print(const PrintObject& obj
|
||||
std::string warning;
|
||||
size_t i = 0;
|
||||
for (i = 0; i < std::min(warning_ranges.size(), size_t(3)); ++i)
|
||||
warning += Slic3r::format(_(L("Empty layer between %1% and %2%.")),
|
||||
warning += Slic3r::format(_u8L("Empty layer between %1% and %2%."),
|
||||
warning_ranges[i].first, warning_ranges[i].second) + "\n";
|
||||
if (i < warning_ranges.size())
|
||||
warning += _(L("(Some lines not shown)")) + "\n";
|
||||
warning += _u8L("(Some lines not shown)") + "\n";
|
||||
warning += "\n";
|
||||
warning += Slic3r::format(_(L("Object name: %1%")), object.model_object()->name) + "\n\n"
|
||||
+ _(L("Make sure the object is printable. This is usually caused by negligibly small extrusions or by a faulty model. "
|
||||
"Try to repair the model or change its orientation on the bed."));
|
||||
warning += Slic3r::format(_u8L("Object name: %1%"), object.model_object()->name) + "\n\n"
|
||||
+ _u8L("Make sure the object is printable. This is usually caused by negligibly small extrusions or by a faulty model. "
|
||||
"Try to repair the model or change its orientation on the bed.");
|
||||
|
||||
const_cast<Print*>(object.print())->active_step_add_warning(
|
||||
PrintStateBase::WarningLevel::CRITICAL, warning);
|
||||
@ -655,25 +763,25 @@ namespace DoExport {
|
||||
};
|
||||
|
||||
const GCodeConfig& config = print.config();
|
||||
check(_(L("Start G-code")), config.start_gcode.value);
|
||||
if (ret.size() < MAX_TAGS_COUNT) check(_(L("End G-code")), config.end_gcode.value);
|
||||
if (ret.size() < MAX_TAGS_COUNT) check(_(L("Before layer change G-code")), config.before_layer_gcode.value);
|
||||
if (ret.size() < MAX_TAGS_COUNT) check(_(L("After layer change G-code")), config.layer_gcode.value);
|
||||
if (ret.size() < MAX_TAGS_COUNT) check(_(L("Tool change G-code")), config.toolchange_gcode.value);
|
||||
if (ret.size() < MAX_TAGS_COUNT) check(_(L("Between objects G-code (for sequential printing)")), config.between_objects_gcode.value);
|
||||
if (ret.size() < MAX_TAGS_COUNT) check(_(L("Color Change G-code")), config.color_change_gcode.value);
|
||||
if (ret.size() < MAX_TAGS_COUNT) check(_(L("Pause Print G-code")), config.pause_print_gcode.value);
|
||||
if (ret.size() < MAX_TAGS_COUNT) check(_(L("Template Custom G-code")), config.template_custom_gcode.value);
|
||||
check(_u8L("Start G-code"), config.start_gcode.value);
|
||||
if (ret.size() < MAX_TAGS_COUNT) check(_u8L("End G-code"), config.end_gcode.value);
|
||||
if (ret.size() < MAX_TAGS_COUNT) check(_u8L("Before layer change G-code"), config.before_layer_gcode.value);
|
||||
if (ret.size() < MAX_TAGS_COUNT) check(_u8L("After layer change G-code"), config.layer_gcode.value);
|
||||
if (ret.size() < MAX_TAGS_COUNT) check(_u8L("Tool change G-code"), config.toolchange_gcode.value);
|
||||
if (ret.size() < MAX_TAGS_COUNT) check(_u8L("Between objects G-code (for sequential printing)"), config.between_objects_gcode.value);
|
||||
if (ret.size() < MAX_TAGS_COUNT) check(_u8L("Color Change G-code"), config.color_change_gcode.value);
|
||||
if (ret.size() < MAX_TAGS_COUNT) check(_u8L("Pause Print G-code"), config.pause_print_gcode.value);
|
||||
if (ret.size() < MAX_TAGS_COUNT) check(_u8L("Template Custom G-code"), config.template_custom_gcode.value);
|
||||
if (ret.size() < MAX_TAGS_COUNT) {
|
||||
for (const std::string& value : config.start_filament_gcode.values) {
|
||||
check(_(L("Filament Start G-code")), value);
|
||||
check(_u8L("Filament Start G-code"), value);
|
||||
if (ret.size() == MAX_TAGS_COUNT)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ret.size() < MAX_TAGS_COUNT) {
|
||||
for (const std::string& value : config.end_filament_gcode.values) {
|
||||
check(_(L("Filament End G-code")), value);
|
||||
check(_u8L("Filament End G-code"), value);
|
||||
if (ret.size() == MAX_TAGS_COUNT)
|
||||
break;
|
||||
}
|
||||
@ -681,7 +789,7 @@ namespace DoExport {
|
||||
if (ret.size() < MAX_TAGS_COUNT) {
|
||||
const CustomGCode::Info& custom_gcode_per_print_z = print.model().custom_gcode_per_print_z;
|
||||
for (const auto& gcode : custom_gcode_per_print_z.gcodes) {
|
||||
check(_(L("Custom G-code")), gcode.extra);
|
||||
check(_u8L("Custom G-code"), gcode.extra);
|
||||
if (ret.size() == MAX_TAGS_COUNT)
|
||||
break;
|
||||
}
|
||||
@ -714,9 +822,9 @@ void GCode::do_export(Print* print, const char* path, GCodeProcessorResult* resu
|
||||
reports += source + ": \"" + keyword + "\"\n";
|
||||
}
|
||||
print->active_step_add_warning(PrintStateBase::WarningLevel::NON_CRITICAL,
|
||||
_(L("In the custom G-code were found reserved keywords:")) + "\n" +
|
||||
_u8L("In the custom G-code were found reserved keywords:") + "\n" +
|
||||
reports +
|
||||
_(L("This may cause problems in g-code visualization and printing time estimation.")));
|
||||
_u8L("This may cause problems in g-code visualization and printing time estimation."));
|
||||
}
|
||||
|
||||
BOOST_LOG_TRIVIAL(info) << "Exporting G-code..." << log_memory_info();
|
||||
@ -733,7 +841,6 @@ void GCode::do_export(Print* print, const char* path, GCodeProcessorResult* resu
|
||||
throw Slic3r::RuntimeError(std::string("G-code export to ") + path + " failed.\nCannot open the file for writing.\n");
|
||||
|
||||
try {
|
||||
m_placeholder_parser_failed_templates.clear();
|
||||
this->_do_export(*print, file, thumbnail_cb);
|
||||
file.flush();
|
||||
if (file.is_error()) {
|
||||
@ -750,11 +857,11 @@ void GCode::do_export(Print* print, const char* path, GCodeProcessorResult* resu
|
||||
}
|
||||
file.close();
|
||||
|
||||
if (! m_placeholder_parser_failed_templates.empty()) {
|
||||
if (! m_placeholder_parser_integration.failed_templates.empty()) {
|
||||
// G-code export proceeded, but some of the PlaceholderParser substitutions failed.
|
||||
//FIXME localize!
|
||||
std::string msg = std::string("G-code export to ") + path + " failed due to invalid custom G-code sections:\n\n";
|
||||
for (const auto &name_and_error : m_placeholder_parser_failed_templates)
|
||||
for (const auto &name_and_error : m_placeholder_parser_integration.failed_templates)
|
||||
msg += name_and_error.first + "\n" + name_and_error.second + "\n";
|
||||
msg += "\nPlease inspect the file ";
|
||||
msg += path_tmp + " for error messages enclosed between\n";
|
||||
@ -1083,12 +1190,12 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
|
||||
file.find_replace_enable();
|
||||
|
||||
// Prepare the helper object for replacing placeholders in custom G-code and output filename.
|
||||
m_placeholder_parser = print.placeholder_parser();
|
||||
m_placeholder_parser.update_timestamp();
|
||||
m_placeholder_parser_context.rng = std::mt19937(std::chrono::high_resolution_clock::now().time_since_epoch().count());
|
||||
m_placeholder_parser_integration.parser = print.placeholder_parser();
|
||||
m_placeholder_parser_integration.parser.update_timestamp();
|
||||
m_placeholder_parser_integration.context.rng = std::mt19937(std::chrono::high_resolution_clock::now().time_since_epoch().count());
|
||||
// Enable passing global variables between PlaceholderParser invocations.
|
||||
m_placeholder_parser_context.global_config = std::make_unique<DynamicConfig>();
|
||||
print.update_object_placeholders(m_placeholder_parser.config_writable(), ".gcode");
|
||||
m_placeholder_parser_integration.context.global_config = std::make_unique<DynamicConfig>();
|
||||
print.update_object_placeholders(m_placeholder_parser_integration.parser.config_writable(), ".gcode");
|
||||
|
||||
// Get optimal tool ordering to minimize tool switches of a multi-exruder print.
|
||||
// For a print by objects, find the 1st printing object.
|
||||
@ -1111,7 +1218,7 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
|
||||
}
|
||||
if (initial_extruder_id == static_cast<unsigned int>(-1))
|
||||
// No object to print was found, cancel the G-code export.
|
||||
throw Slic3r::SlicingError(_(L("No extrusions were generated for objects.")));
|
||||
throw Slic3r::SlicingError(_u8L("No extrusions were generated for objects."));
|
||||
// We don't allow switching of extruders per layer by Model::custom_gcode_per_print_z in sequential mode.
|
||||
// Use the extruder IDs collected from Regions.
|
||||
this->set_extruders(print.extruders());
|
||||
@ -1122,7 +1229,7 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
|
||||
tool_ordering.assign_custom_gcodes(print);
|
||||
if (tool_ordering.all_extruders().empty())
|
||||
// No object to print was found, cancel the G-code export.
|
||||
throw Slic3r::SlicingError(_(L("No extrusions were generated for objects.")));
|
||||
throw Slic3r::SlicingError(_u8L("No extrusions were generated for objects."));
|
||||
has_wipe_tower = print.has_wipe_tower() && tool_ordering.has_wipe_tower();
|
||||
initial_extruder_id = (has_wipe_tower && ! print.config().single_extruder_multi_material_priming) ?
|
||||
// The priming towers will be skipped.
|
||||
@ -1152,27 +1259,25 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
|
||||
// Emit machine envelope limits for the Marlin firmware.
|
||||
this->print_machine_envelope(file, print);
|
||||
|
||||
// Disable fan.
|
||||
if (! print.config().cooling.get_at(initial_extruder_id) || print.config().disable_fan_first_layers.get_at(initial_extruder_id))
|
||||
file.write(m_writer.set_fan(0));
|
||||
|
||||
// Update output variables after the extruders were initialized.
|
||||
m_placeholder_parser_integration.init(m_writer);
|
||||
// Let the start-up script prime the 1st printing tool.
|
||||
m_placeholder_parser.set("initial_tool", initial_extruder_id);
|
||||
m_placeholder_parser.set("initial_extruder", initial_extruder_id);
|
||||
m_placeholder_parser.set("current_extruder", initial_extruder_id);
|
||||
this->placeholder_parser().set("initial_tool", initial_extruder_id);
|
||||
this->placeholder_parser().set("initial_extruder", initial_extruder_id);
|
||||
this->placeholder_parser().set("current_extruder", initial_extruder_id);
|
||||
//Set variable for total layer count so it can be used in custom gcode.
|
||||
m_placeholder_parser.set("total_layer_count", m_layer_count);
|
||||
this->placeholder_parser().set("total_layer_count", m_layer_count);
|
||||
// Useful for sequential prints.
|
||||
m_placeholder_parser.set("current_object_idx", 0);
|
||||
this->placeholder_parser().set("current_object_idx", 0);
|
||||
// For the start / end G-code to do the priming and final filament pull in case there is no wipe tower provided.
|
||||
m_placeholder_parser.set("has_wipe_tower", has_wipe_tower);
|
||||
m_placeholder_parser.set("has_single_extruder_multi_material_priming", has_wipe_tower && print.config().single_extruder_multi_material_priming);
|
||||
m_placeholder_parser.set("total_toolchanges", std::max(0, print.wipe_tower_data().number_of_toolchanges)); // Check for negative toolchanges (single extruder mode) and set to 0 (no tool change).
|
||||
this->placeholder_parser().set("has_wipe_tower", has_wipe_tower);
|
||||
this->placeholder_parser().set("has_single_extruder_multi_material_priming", has_wipe_tower && print.config().single_extruder_multi_material_priming);
|
||||
this->placeholder_parser().set("total_toolchanges", std::max(0, print.wipe_tower_data().number_of_toolchanges)); // Check for negative toolchanges (single extruder mode) and set to 0 (no tool change).
|
||||
{
|
||||
BoundingBoxf bbox(print.config().bed_shape.values);
|
||||
m_placeholder_parser.set("print_bed_min", new ConfigOptionFloats({ bbox.min.x(), bbox.min.y() }));
|
||||
m_placeholder_parser.set("print_bed_max", new ConfigOptionFloats({ bbox.max.x(), bbox.max.y() }));
|
||||
m_placeholder_parser.set("print_bed_size", new ConfigOptionFloats({ bbox.size().x(), bbox.size().y() }));
|
||||
this->placeholder_parser().set("print_bed_min", new ConfigOptionFloats({ bbox.min.x(), bbox.min.y() }));
|
||||
this->placeholder_parser().set("print_bed_max", new ConfigOptionFloats({ bbox.max.x(), bbox.max.y() }));
|
||||
this->placeholder_parser().set("print_bed_size", new ConfigOptionFloats({ bbox.size().x(), bbox.size().y() }));
|
||||
}
|
||||
{
|
||||
// Convex hull of the 1st layer extrusions, for bed leveling and placing the initial purge line.
|
||||
@ -1185,15 +1290,15 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
|
||||
for (const Point &pt : print.first_layer_convex_hull().points)
|
||||
pts->values.emplace_back(unscale(pt));
|
||||
BoundingBoxf bbox(pts->values);
|
||||
m_placeholder_parser.set("first_layer_print_convex_hull", pts.release());
|
||||
m_placeholder_parser.set("first_layer_print_min", new ConfigOptionFloats({ bbox.min.x(), bbox.min.y() }));
|
||||
m_placeholder_parser.set("first_layer_print_max", new ConfigOptionFloats({ bbox.max.x(), bbox.max.y() }));
|
||||
m_placeholder_parser.set("first_layer_print_size", new ConfigOptionFloats({ bbox.size().x(), bbox.size().y() }));
|
||||
this->placeholder_parser().set("first_layer_print_convex_hull", pts.release());
|
||||
this->placeholder_parser().set("first_layer_print_min", new ConfigOptionFloats({ bbox.min.x(), bbox.min.y() }));
|
||||
this->placeholder_parser().set("first_layer_print_max", new ConfigOptionFloats({ bbox.max.x(), bbox.max.y() }));
|
||||
this->placeholder_parser().set("first_layer_print_size", new ConfigOptionFloats({ bbox.size().x(), bbox.size().y() }));
|
||||
|
||||
std::vector<unsigned char> is_extruder_used(print.config().nozzle_diameter.size(), 0);
|
||||
for (unsigned int extruder_id : tool_ordering.all_extruders())
|
||||
is_extruder_used[extruder_id] = true;
|
||||
m_placeholder_parser.set("is_extruder_used", new ConfigOptionBools(is_extruder_used));
|
||||
this->placeholder_parser().set("is_extruder_used", new ConfigOptionBools(is_extruder_used));
|
||||
}
|
||||
|
||||
// Enable ooze prevention if configured so.
|
||||
@ -1260,7 +1365,7 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
|
||||
// Ff we are printing the bottom layer of an object, and we have already finished
|
||||
// another one, set first layer temperatures. This happens before the Z move
|
||||
// is triggered, so machine has more time to reach such temperatures.
|
||||
m_placeholder_parser.set("current_object_idx", int(finished_objects));
|
||||
this->placeholder_parser().set("current_object_idx", int(finished_objects));
|
||||
std::string between_objects_gcode = this->placeholder_parser_process("between_objects_gcode", print.config().between_objects_gcode.value, initial_extruder_id);
|
||||
// Set first layer bed and extruder temperatures, don't wait for it to reach the temperature.
|
||||
this->_print_first_layer_bed_temperature(file, print, between_objects_gcode, initial_extruder_id, false);
|
||||
@ -1316,8 +1421,8 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
|
||||
// (See https://github.com/prusa3d/PrusaSlicer/issues/5441.)
|
||||
if (overlap) {
|
||||
print.active_step_add_warning(PrintStateBase::WarningLevel::CRITICAL,
|
||||
_(L("Your print is very close to the priming regions. "
|
||||
"Make sure there is no collision.")));
|
||||
_u8L("Your print is very close to the priming regions. "
|
||||
"Make sure there is no collision."));
|
||||
} else {
|
||||
// Just continue printing, no action necessary.
|
||||
}
|
||||
@ -1346,7 +1451,7 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
|
||||
{
|
||||
DynamicConfig config;
|
||||
config.set_key_value("layer_num", new ConfigOptionInt(m_layer_index));
|
||||
config.set_key_value("layer_z", new ConfigOptionFloat(m_writer.get_position()(2) - m_config.z_offset.value));
|
||||
config.set_key_value("layer_z", new ConfigOptionFloat(m_writer.get_position().z() - m_config.z_offset.value));
|
||||
config.set_key_value("max_layer_z", new ConfigOptionFloat(m_max_layer_z));
|
||||
if (print.config().single_extruder_multi_material) {
|
||||
// Process the end_filament_gcode for the active filament only.
|
||||
@ -1569,17 +1674,46 @@ void GCode::process_layers(
|
||||
output_stream.find_replace_enable();
|
||||
}
|
||||
|
||||
std::string GCode::placeholder_parser_process(const std::string &name, const std::string &templ, unsigned int current_extruder_id, const DynamicConfig *config_override)
|
||||
std::string GCode::placeholder_parser_process(
|
||||
const std::string &name,
|
||||
const std::string &templ,
|
||||
unsigned int current_extruder_id,
|
||||
const DynamicConfig *config_override)
|
||||
{
|
||||
PlaceholderParserIntegration &ppi = m_placeholder_parser_integration;
|
||||
try {
|
||||
return m_placeholder_parser.process(templ, current_extruder_id, config_override, &m_placeholder_parser_context);
|
||||
} catch (std::runtime_error &err) {
|
||||
ppi.update_from_gcodewriter(m_writer);
|
||||
std::string output = ppi.parser.process(templ, current_extruder_id, config_override, &ppi.output_config, &ppi.context);
|
||||
ppi.validate_output_vector_variables();
|
||||
|
||||
if (const std::vector<double> &pos = ppi.opt_position->values; ppi.position != pos) {
|
||||
// Update G-code writer.
|
||||
m_writer.update_position({ pos[0], pos[1], pos[2] });
|
||||
this->set_last_pos(this->gcode_to_point({ pos[0], pos[1] }));
|
||||
}
|
||||
|
||||
for (const Extruder &e : m_writer.extruders()) {
|
||||
unsigned int eid = e.id();
|
||||
assert(eid < ppi.num_extruders);
|
||||
if ( eid < ppi.num_extruders) {
|
||||
if (! m_writer.config.use_relative_e_distances && ! is_approx(ppi.e_position[eid], ppi.opt_e_position->values[eid]))
|
||||
const_cast<Extruder&>(e).set_position(ppi.opt_e_position->values[eid]);
|
||||
if (! is_approx(ppi.e_retracted[eid], ppi.opt_e_retracted->values[eid]) ||
|
||||
! is_approx(ppi.e_restart_extra[eid], ppi.opt_e_restart_extra->values[eid]))
|
||||
const_cast<Extruder&>(e).set_retracted(ppi.opt_e_retracted->values[eid], ppi.opt_e_restart_extra->values[eid]);
|
||||
}
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
catch (std::runtime_error &err)
|
||||
{
|
||||
// Collect the names of failed template substitutions for error reporting.
|
||||
auto it = m_placeholder_parser_failed_templates.find(name);
|
||||
if (it == m_placeholder_parser_failed_templates.end())
|
||||
auto it = ppi.failed_templates.find(name);
|
||||
if (it == ppi.failed_templates.end())
|
||||
// Only if there was no error reported for this template, store the first error message into the map to be reported.
|
||||
// We don't want to collect error message for each and every occurence of a single custom G-code section.
|
||||
m_placeholder_parser_failed_templates.insert(it, std::make_pair(name, std::string(err.what())));
|
||||
ppi.failed_templates.insert(it, std::make_pair(name, std::string(err.what())));
|
||||
// Insert the macro error message into the G-code.
|
||||
return
|
||||
std::string("\n!!!!! Failed to process the custom G-code template ") + name + "\n" +
|
||||
@ -1672,23 +1806,25 @@ void GCode::print_machine_envelope(GCodeOutputStream &file, Print &print)
|
||||
int(print.config().machine_max_feedrate_e.values.front() * factor + 0.5),
|
||||
factor == 60 ? "mm / min" : "mm / sec");
|
||||
|
||||
// Now M204 - acceleration. This one is quite hairy thanks to how Marlin guys care about
|
||||
// backwards compatibility: https://github.com/prusa3d/PrusaSlicer/issues/1089
|
||||
// Legacy Marlin should export travel acceleration the same as printing acceleration.
|
||||
// MarlinFirmware has the two separated.
|
||||
int travel_acc = flavor == gcfMarlinLegacy
|
||||
? int(print.config().machine_max_acceleration_extruding.values.front() + 0.5)
|
||||
: int(print.config().machine_max_acceleration_travel.values.front() + 0.5);
|
||||
// Retract acceleration not accepted in M204 in RRF
|
||||
// Now M204 - acceleration. This one is quite hairy...
|
||||
if (flavor == gcfRepRapFirmware)
|
||||
// Uses M204 P[print] T[travel]
|
||||
file.write_format("M204 P%d T%d ; sets acceleration (P, T), mm/sec^2\n",
|
||||
int(print.config().machine_max_acceleration_extruding.values.front() + 0.5),
|
||||
travel_acc);
|
||||
else
|
||||
int(print.config().machine_max_acceleration_travel.values.front() + 0.5));
|
||||
else if (flavor == gcfMarlinLegacy)
|
||||
// Legacy Marlin uses M204 S[print] T[retract]
|
||||
file.write_format("M204 S%d T%d ; sets acceleration (S) and retract acceleration (R), mm/sec^2\n",
|
||||
int(print.config().machine_max_acceleration_extruding.values.front() + 0.5),
|
||||
int(print.config().machine_max_acceleration_retracting.values.front() + 0.5));
|
||||
else if (flavor == gcfMarlinFirmware)
|
||||
// New Marlin uses M204 P[print] R[retract] T[travel]
|
||||
file.write_format("M204 P%d R%d T%d ; sets acceleration (P, T) and retract acceleration (R), mm/sec^2\n",
|
||||
int(print.config().machine_max_acceleration_extruding.values.front() + 0.5),
|
||||
int(print.config().machine_max_acceleration_retracting.values.front() + 0.5),
|
||||
travel_acc);
|
||||
int(print.config().machine_max_acceleration_travel.values.front() + 0.5));
|
||||
else
|
||||
assert(false);
|
||||
|
||||
assert(is_decimal_separator_point());
|
||||
file.write_format(flavor == gcfRepRapFirmware
|
||||
@ -1715,17 +1851,18 @@ void GCode::print_machine_envelope(GCodeOutputStream &file, Print &print)
|
||||
// M190 - Set Extruder Temperature and Wait
|
||||
void GCode::_print_first_layer_bed_temperature(GCodeOutputStream &file, Print &print, const std::string &gcode, unsigned int first_printing_extruder_id, bool wait)
|
||||
{
|
||||
bool autoemit = print.config().autoemit_temperature_commands;
|
||||
// Initial bed temperature based on the first extruder.
|
||||
int temp = print.config().first_layer_bed_temperature.get_at(first_printing_extruder_id);
|
||||
// Is the bed temperature set by the provided custom G-code?
|
||||
int temp_by_gcode = -1;
|
||||
bool temp_set_by_gcode = custom_gcode_sets_temperature(gcode, 140, 190, false, temp_by_gcode);
|
||||
if (temp_set_by_gcode && temp_by_gcode >= 0 && temp_by_gcode < 1000)
|
||||
if (autoemit && temp_set_by_gcode && temp_by_gcode >= 0 && temp_by_gcode < 1000)
|
||||
temp = temp_by_gcode;
|
||||
// Always call m_writer.set_bed_temperature() so it will set the internal "current" state of the bed temp as if
|
||||
// the custom start G-code emited these.
|
||||
std::string set_temp_gcode = m_writer.set_bed_temperature(temp, wait);
|
||||
if (! temp_set_by_gcode)
|
||||
if (autoemit && ! temp_set_by_gcode)
|
||||
file.write(set_temp_gcode);
|
||||
}
|
||||
|
||||
@ -1736,13 +1873,14 @@ void GCode::_print_first_layer_bed_temperature(GCodeOutputStream &file, Print &p
|
||||
// RepRapFirmware: G10 Sxx
|
||||
void GCode::_print_first_layer_extruder_temperatures(GCodeOutputStream &file, Print &print, const std::string &gcode, unsigned int first_printing_extruder_id, bool wait)
|
||||
{
|
||||
bool autoemit = print.config().autoemit_temperature_commands;
|
||||
// Is the bed temperature set by the provided custom G-code?
|
||||
int temp_by_gcode = -1;
|
||||
bool include_g10 = print.config().gcode_flavor == gcfRepRapFirmware;
|
||||
if (custom_gcode_sets_temperature(gcode, 104, 109, include_g10, temp_by_gcode)) {
|
||||
if (! autoemit || custom_gcode_sets_temperature(gcode, 104, 109, include_g10, temp_by_gcode)) {
|
||||
// Set the extruder temperature at m_writer, but throw away the generated G-code as it will be written with the custom G-code.
|
||||
int temp = print.config().first_layer_temperature.get_at(first_printing_extruder_id);
|
||||
if (temp_by_gcode >= 0 && temp_by_gcode < 1000)
|
||||
if (autoemit && temp_by_gcode >= 0 && temp_by_gcode < 1000)
|
||||
temp = temp_by_gcode;
|
||||
m_writer.set_temperature(temp, wait, first_printing_extruder_id);
|
||||
} else {
|
||||
@ -2552,7 +2690,7 @@ std::string GCode::extrude_loop(ExtrusionLoop loop, const std::string_view descr
|
||||
}
|
||||
|
||||
// reset acceleration
|
||||
gcode += m_writer.set_acceleration((unsigned int)(m_config.default_acceleration.value + 0.5));
|
||||
gcode += m_writer.set_print_acceleration((unsigned int)(m_config.default_acceleration.value + 0.5));
|
||||
|
||||
if (m_wipe.enable) {
|
||||
m_wipe.path = paths.front().polyline;
|
||||
@ -2638,7 +2776,7 @@ std::string GCode::extrude_multi_path(ExtrusionMultiPath multipath, const std::s
|
||||
}
|
||||
}
|
||||
// reset acceleration
|
||||
gcode += m_writer.set_acceleration((unsigned int)floor(m_config.default_acceleration.value + 0.5));
|
||||
gcode += m_writer.set_print_acceleration((unsigned int)floor(m_config.default_acceleration.value + 0.5));
|
||||
return gcode;
|
||||
}
|
||||
|
||||
@ -2664,7 +2802,7 @@ std::string GCode::extrude_path(ExtrusionPath path, std::string_view description
|
||||
m_wipe.path.reverse();
|
||||
}
|
||||
// reset acceleration
|
||||
gcode += m_writer.set_acceleration((unsigned int)floor(m_config.default_acceleration.value + 0.5));
|
||||
gcode += m_writer.set_print_acceleration((unsigned int)floor(m_config.default_acceleration.value + 0.5));
|
||||
return gcode;
|
||||
}
|
||||
|
||||
@ -2807,7 +2945,7 @@ std::string GCode::_extrude(const ExtrusionPath &path, const std::string_view de
|
||||
} else {
|
||||
acceleration = m_config.default_acceleration.value;
|
||||
}
|
||||
gcode += m_writer.set_acceleration((unsigned int)floor(acceleration + 0.5));
|
||||
gcode += m_writer.set_print_acceleration((unsigned int)floor(acceleration + 0.5));
|
||||
}
|
||||
|
||||
// calculate extrusion length per distance unit
|
||||
@ -3076,8 +3214,18 @@ std::string GCode::travel_to(const Point &point, ExtrusionRole role, std::string
|
||||
|
||||
// use G1 because we rely on paths being straight (G0 may make round paths)
|
||||
if (travel.size() >= 2) {
|
||||
|
||||
gcode += m_writer.set_travel_acceleration((unsigned int)(m_config.travel_acceleration.value + 0.5));
|
||||
|
||||
for (size_t i = 1; i < travel.size(); ++ i)
|
||||
gcode += m_writer.travel_to_xy(this->point_to_gcode(travel.points[i]), comment);
|
||||
|
||||
if (! GCodeWriter::supports_separate_travel_acceleration(config().gcode_flavor)) {
|
||||
// In case that this flavor does not support separate print and travel acceleration,
|
||||
// reset acceleration to default.
|
||||
gcode += m_writer.set_travel_acceleration((unsigned int)(m_config.travel_acceleration.value + 0.5));
|
||||
}
|
||||
|
||||
this->set_last_pos(travel.points.back());
|
||||
}
|
||||
return gcode;
|
||||
@ -3155,7 +3303,7 @@ std::string GCode::set_extruder(unsigned int extruder_id, double print_z)
|
||||
|
||||
// if we are running a single-extruder setup, just set the extruder and return nothing
|
||||
if (!m_writer.multiple_extruders) {
|
||||
m_placeholder_parser.set("current_extruder", extruder_id);
|
||||
this->placeholder_parser().set("current_extruder", extruder_id);
|
||||
|
||||
std::string gcode;
|
||||
// Append the filament start G-code.
|
||||
@ -3164,7 +3312,7 @@ std::string GCode::set_extruder(unsigned int extruder_id, double print_z)
|
||||
// Process the start_filament_gcode for the filament.
|
||||
DynamicConfig config;
|
||||
config.set_key_value("layer_num", new ConfigOptionInt(m_layer_index));
|
||||
config.set_key_value("layer_z", new ConfigOptionFloat(this->writer().get_position()(2) - m_config.z_offset.value));
|
||||
config.set_key_value("layer_z", new ConfigOptionFloat(this->writer().get_position().z() - m_config.z_offset.value));
|
||||
config.set_key_value("max_layer_z", new ConfigOptionFloat(m_max_layer_z));
|
||||
config.set_key_value("filament_extruder_id", new ConfigOptionInt(int(extruder_id)));
|
||||
gcode += this->placeholder_parser_process("start_filament_gcode", start_filament_gcode, extruder_id, &config);
|
||||
@ -3228,7 +3376,7 @@ std::string GCode::set_extruder(unsigned int extruder_id, double print_z)
|
||||
gcode += m_writer.set_temperature(temp, false);
|
||||
}
|
||||
|
||||
m_placeholder_parser.set("current_extruder", extruder_id);
|
||||
this->placeholder_parser().set("current_extruder", extruder_id);
|
||||
|
||||
// Append the filament start G-code.
|
||||
const std::string &start_filament_gcode = m_config.start_filament_gcode.get_at(extruder_id);
|
||||
@ -3236,7 +3384,7 @@ std::string GCode::set_extruder(unsigned int extruder_id, double print_z)
|
||||
// Process the start_filament_gcode for the new filament.
|
||||
DynamicConfig config;
|
||||
config.set_key_value("layer_num", new ConfigOptionInt(m_layer_index));
|
||||
config.set_key_value("layer_z", new ConfigOptionFloat(this->writer().get_position()(2) - m_config.z_offset.value));
|
||||
config.set_key_value("layer_z", new ConfigOptionFloat(this->writer().get_position().z() - m_config.z_offset.value));
|
||||
config.set_key_value("max_layer_z", new ConfigOptionFloat(m_max_layer_z));
|
||||
config.set_key_value("filament_extruder_id", new ConfigOptionInt(int(extruder_id)));
|
||||
gcode += this->placeholder_parser_process("start_filament_gcode", start_filament_gcode, extruder_id, &config);
|
||||
@ -3265,10 +3413,12 @@ Vec2d GCode::point_to_gcode_quantized(const Point &point) const
|
||||
// convert a model-space scaled point into G-code coordinates
|
||||
Point GCode::gcode_to_point(const Vec2d &point) const
|
||||
{
|
||||
Vec2d extruder_offset = EXTRUDER_CONFIG(extruder_offset);
|
||||
return Point(
|
||||
scale_(point(0) - m_origin(0) + extruder_offset(0)),
|
||||
scale_(point(1) - m_origin(1) + extruder_offset(1)));
|
||||
Vec2d pt = point - m_origin;
|
||||
if (const Extruder *extruder = m_writer.extruder(); extruder)
|
||||
// This function may be called at the very start from toolchange G-code when the extruder is not assigned yet.
|
||||
pt += m_config.extruder_offset.get_at(extruder->id());
|
||||
return scaled<coord_t>(pt);
|
||||
|
||||
}
|
||||
|
||||
} // namespace Slic3r
|
||||
|
@ -173,8 +173,8 @@ public:
|
||||
const Layer* layer() const { return m_layer; }
|
||||
GCodeWriter& writer() { return m_writer; }
|
||||
const GCodeWriter& writer() const { return m_writer; }
|
||||
PlaceholderParser& placeholder_parser() { return m_placeholder_parser; }
|
||||
const PlaceholderParser& placeholder_parser() const { return m_placeholder_parser; }
|
||||
PlaceholderParser& placeholder_parser() { return m_placeholder_parser_integration.parser; }
|
||||
const PlaceholderParser& placeholder_parser() const { return m_placeholder_parser_integration.parser; }
|
||||
// Process a template through the placeholder parser, collect error messages to be reported
|
||||
// inside the generated string and after the G-code export finishes.
|
||||
std::string placeholder_parser_process(const std::string &name, const std::string &templ, unsigned int current_extruder_id, const DynamicConfig *config_override = nullptr);
|
||||
@ -343,11 +343,37 @@ private:
|
||||
// scaled G-code resolution
|
||||
double m_scaled_resolution;
|
||||
GCodeWriter m_writer;
|
||||
PlaceholderParser m_placeholder_parser;
|
||||
|
||||
struct PlaceholderParserIntegration {
|
||||
void reset();
|
||||
void init(const GCodeWriter &config);
|
||||
void update_from_gcodewriter(const GCodeWriter &writer);
|
||||
void validate_output_vector_variables();
|
||||
|
||||
PlaceholderParser parser;
|
||||
// For random number generator etc.
|
||||
PlaceholderParser::ContextData m_placeholder_parser_context;
|
||||
PlaceholderParser::ContextData context;
|
||||
// Collection of templates, on which the placeholder substitution failed.
|
||||
std::map<std::string, std::string> m_placeholder_parser_failed_templates;
|
||||
std::map<std::string, std::string> failed_templates;
|
||||
// Input/output from/to custom G-code block, for returning position, retraction etc.
|
||||
DynamicConfig output_config;
|
||||
ConfigOptionFloats *opt_position { nullptr };
|
||||
ConfigOptionFloat *opt_zhop { nullptr };
|
||||
ConfigOptionFloats *opt_e_position { nullptr };
|
||||
ConfigOptionFloats *opt_e_retracted { nullptr };
|
||||
ConfigOptionFloats *opt_e_restart_extra { nullptr };
|
||||
ConfigOptionFloats *opt_extruded_volume { nullptr };
|
||||
ConfigOptionFloats *opt_extruded_weight { nullptr };
|
||||
ConfigOptionFloat *opt_extruded_volume_total { nullptr };
|
||||
ConfigOptionFloat *opt_extruded_weight_total { nullptr };
|
||||
// Caches of the data passed to the script.
|
||||
size_t num_extruders;
|
||||
std::vector<double> position;
|
||||
std::vector<double> e_position;
|
||||
std::vector<double> e_retracted;
|
||||
std::vector<double> e_restart_extra;
|
||||
} m_placeholder_parser_integration;
|
||||
|
||||
OozePrevention m_ooze_prevention;
|
||||
Wipe m_wipe;
|
||||
AvoidCrossingPerimeters m_avoid_crossing_perimeters;
|
||||
|
@ -3,6 +3,7 @@
|
||||
#include "libslic3r/Print.hpp"
|
||||
#include "libslic3r/LocalesUtils.hpp"
|
||||
#include "libslic3r/format.hpp"
|
||||
#include "libslic3r/GCodeWriter.hpp"
|
||||
#include "GCodeProcessor.hpp"
|
||||
|
||||
#include <boost/algorithm/string/case_conv.hpp>
|
||||
@ -440,6 +441,9 @@ void GCodeProcessorResult::reset() {
|
||||
max_print_height = 0.0f;
|
||||
settings_ids.reset();
|
||||
extruders_count = 0;
|
||||
#if ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
backtrace_enabled = false;
|
||||
#endif // ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
extruder_colors = std::vector<std::string>();
|
||||
filament_diameters = std::vector<float>(MIN_EXTRUDERS_COUNT, DEFAULT_FILAMENT_DIAMETER);
|
||||
filament_densities = std::vector<float>(MIN_EXTRUDERS_COUNT, DEFAULT_FILAMENT_DENSITY);
|
||||
@ -457,6 +461,9 @@ void GCodeProcessorResult::reset() {
|
||||
max_print_height = 0.0f;
|
||||
settings_ids.reset();
|
||||
extruders_count = 0;
|
||||
#if ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
backtrace_enabled = false;
|
||||
#endif // ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
extruder_colors = std::vector<std::string>();
|
||||
filament_diameters = std::vector<float>(MIN_EXTRUDERS_COUNT, DEFAULT_FILAMENT_DIAMETER);
|
||||
filament_densities = std::vector<float>(MIN_EXTRUDERS_COUNT, DEFAULT_FILAMENT_DENSITY);
|
||||
@ -550,6 +557,10 @@ void GCodeProcessor::apply_config(const PrintConfig& config)
|
||||
m_producer = EProducer::PrusaSlicer;
|
||||
m_flavor = config.gcode_flavor;
|
||||
|
||||
#if ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
m_result.backtrace_enabled = is_XL_printer(config);
|
||||
#endif // ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
|
||||
size_t extruders_count = config.nozzle_diameter.values.size();
|
||||
m_result.extruders_count = extruders_count;
|
||||
|
||||
@ -559,19 +570,25 @@ void GCodeProcessor::apply_config(const PrintConfig& config)
|
||||
m_result.filament_densities.resize(extruders_count);
|
||||
m_result.filament_cost.resize(extruders_count);
|
||||
m_extruder_temps.resize(extruders_count);
|
||||
m_extruder_temps_config.resize(extruders_count);
|
||||
m_extruder_temps_first_layer_config.resize(extruders_count);
|
||||
m_is_XL_printer = is_XL_printer(config);
|
||||
|
||||
for (size_t i = 0; i < extruders_count; ++ i) {
|
||||
m_extruder_offsets[i] = to_3d(config.extruder_offset.get_at(i).cast<float>().eval(), 0.f);
|
||||
m_extruder_colors[i] = static_cast<unsigned char>(i);
|
||||
m_extruder_temps_config[i] = static_cast<int>(config.temperature.get_at(i));
|
||||
m_extruder_temps_first_layer_config[i] = static_cast<int>(config.first_layer_temperature.get_at(i));
|
||||
m_result.filament_diameters[i] = static_cast<float>(config.filament_diameter.get_at(i));
|
||||
m_result.filament_densities[i] = static_cast<float>(config.filament_density.get_at(i));
|
||||
m_result.filament_cost[i] = static_cast<float>(config.filament_cost.get_at(i));
|
||||
}
|
||||
|
||||
if ((m_flavor == gcfMarlinLegacy || m_flavor == gcfMarlinFirmware || m_flavor == gcfRepRapFirmware) && config.machine_limits_usage.value != MachineLimitsUsage::Ignore) {
|
||||
if ((m_flavor == gcfMarlinLegacy || m_flavor == gcfMarlinFirmware || m_flavor == gcfRepRapFirmware || m_flavor == gcfKlipper)
|
||||
&& config.machine_limits_usage.value != MachineLimitsUsage::Ignore) {
|
||||
m_time_processor.machine_limits = reinterpret_cast<const MachineEnvelopeConfig&>(config);
|
||||
if (m_flavor == gcfMarlinLegacy) {
|
||||
// Legacy Marlin does not have separate travel acceleration, it uses the 'extruding' value instead.
|
||||
if (m_flavor == gcfMarlinLegacy || m_flavor == gcfKlipper) {
|
||||
// Legacy Marlin and Klipper don't have separate travel acceleration, they use the 'extruding' value instead.
|
||||
m_time_processor.machine_limits.machine_max_acceleration_travel = m_time_processor.machine_limits.machine_max_acceleration_extruding;
|
||||
}
|
||||
if (m_flavor == gcfRepRapFirmware) {
|
||||
@ -609,7 +626,12 @@ for (size_t i = 0; i < static_cast<size_t>(PrintEstimatedStatistics::ETimeMode::
|
||||
float max_retract_acceleration = get_option_value(m_time_processor.machine_limits.machine_max_acceleration_retracting, i);
|
||||
m_time_processor.machines[i].max_retract_acceleration = max_retract_acceleration;
|
||||
m_time_processor.machines[i].retract_acceleration = (max_retract_acceleration > 0.0f) ? max_retract_acceleration : DEFAULT_RETRACT_ACCELERATION;
|
||||
|
||||
float max_travel_acceleration = get_option_value(m_time_processor.machine_limits.machine_max_acceleration_travel, i);
|
||||
if ( ! GCodeWriter::supports_separate_travel_acceleration(config.gcode_flavor.value) || config.machine_limits_usage.value != MachineLimitsUsage::EmitToGCode) {
|
||||
// Only clamp travel acceleration when it is accessible in machine limits.
|
||||
max_travel_acceleration = 0;
|
||||
}
|
||||
m_time_processor.machines[i].max_travel_acceleration = max_travel_acceleration;
|
||||
m_time_processor.machines[i].travel_acceleration = (max_travel_acceleration > 0.0f) ? max_travel_acceleration : DEFAULT_TRAVEL_ACCELERATION;
|
||||
}
|
||||
@ -788,7 +810,7 @@ void GCodeProcessor::apply_config(const DynamicPrintConfig& config)
|
||||
if (machine_limits_usage != nullptr)
|
||||
use_machine_limits = machine_limits_usage->value != MachineLimitsUsage::Ignore;
|
||||
|
||||
if (use_machine_limits && (m_flavor == gcfMarlinLegacy || m_flavor == gcfMarlinFirmware || m_flavor == gcfRepRapFirmware)) {
|
||||
if (use_machine_limits && (m_flavor == gcfMarlinLegacy || m_flavor == gcfMarlinFirmware || m_flavor == gcfRepRapFirmware || m_flavor == gcfKlipper)) {
|
||||
const ConfigOptionFloats* machine_max_acceleration_x = config.option<ConfigOptionFloats>("machine_max_acceleration_x");
|
||||
if (machine_max_acceleration_x != nullptr)
|
||||
m_time_processor.machine_limits.machine_max_acceleration_x.values = machine_max_acceleration_x->values;
|
||||
@ -846,8 +868,8 @@ void GCodeProcessor::apply_config(const DynamicPrintConfig& config)
|
||||
m_time_processor.machine_limits.machine_max_acceleration_retracting.values = machine_max_acceleration_retracting->values;
|
||||
|
||||
|
||||
// Legacy Marlin does not have separate travel acceleration, it uses the 'extruding' value instead.
|
||||
const ConfigOptionFloats* machine_max_acceleration_travel = config.option<ConfigOptionFloats>(m_flavor == gcfMarlinLegacy
|
||||
// Legacy Marlin and Klipper don't have separate travel acceleration, they use the 'extruding' value instead.
|
||||
const ConfigOptionFloats* machine_max_acceleration_travel = config.option<ConfigOptionFloats>((m_flavor == gcfMarlinLegacy || m_flavor == gcfKlipper)
|
||||
? "machine_max_acceleration_extruding"
|
||||
: "machine_max_acceleration_travel");
|
||||
if (machine_max_acceleration_travel != nullptr)
|
||||
@ -885,7 +907,7 @@ void GCodeProcessor::apply_config(const DynamicPrintConfig& config)
|
||||
m_time_processor.machines[i].travel_acceleration = (max_travel_acceleration > 0.0f) ? max_travel_acceleration : DEFAULT_TRAVEL_ACCELERATION;
|
||||
}
|
||||
|
||||
if (m_flavor == gcfMarlinLegacy || m_flavor == gcfMarlinFirmware) {
|
||||
if (m_flavor == gcfMarlinLegacy || m_flavor == gcfMarlinFirmware) { // No Klipper here, it does not support silent mode.
|
||||
const ConfigOptionBool* silent_mode = config.option<ConfigOptionBool>("silent_mode");
|
||||
if (silent_mode != nullptr) {
|
||||
if (silent_mode->value && m_time_processor.machine_limits.machine_max_acceleration_x.values.size() > 1)
|
||||
@ -3244,7 +3266,7 @@ void GCodeProcessor::process_M205(const GCodeReader::GCodeLine& line)
|
||||
|
||||
void GCodeProcessor::process_M220(const GCodeReader::GCodeLine& line)
|
||||
{
|
||||
if (m_flavor != gcfMarlinLegacy && m_flavor != gcfMarlinFirmware)
|
||||
if (m_flavor != gcfMarlinLegacy && m_flavor != gcfMarlinFirmware && m_flavor != gcfKlipper)
|
||||
return;
|
||||
|
||||
if (line.has('B'))
|
||||
@ -3454,18 +3476,261 @@ void GCodeProcessor::post_process()
|
||||
last_exported_stop[i] = time_in_minutes(m_time_processor.machines[i].time);
|
||||
}
|
||||
|
||||
#if ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
// Helper class to modify and export gcode to file
|
||||
class ExportLines
|
||||
{
|
||||
public:
|
||||
struct Backtrace
|
||||
{
|
||||
float time{ 60.0f };
|
||||
unsigned int steps{ 10 };
|
||||
float time_step() const { return time / float(steps); }
|
||||
};
|
||||
|
||||
enum class EWriteType
|
||||
{
|
||||
BySize,
|
||||
ByTime
|
||||
};
|
||||
|
||||
private:
|
||||
struct LineData
|
||||
{
|
||||
std::string line;
|
||||
float time;
|
||||
};
|
||||
|
||||
#ifndef NDEBUG
|
||||
class Statistics
|
||||
{
|
||||
ExportLines& m_parent;
|
||||
size_t m_max_size{ 0 };
|
||||
size_t m_lines_count{ 0 };
|
||||
size_t m_max_lines_count{ 0 };
|
||||
|
||||
public:
|
||||
explicit Statistics(ExportLines& parent)
|
||||
: m_parent(parent)
|
||||
{}
|
||||
|
||||
void add_line(size_t line_size) {
|
||||
++m_lines_count;
|
||||
m_max_size = std::max(m_max_size, m_parent.get_size() + line_size);
|
||||
m_max_lines_count = std::max(m_max_lines_count, m_lines_count);
|
||||
}
|
||||
|
||||
void remove_line() { --m_lines_count; }
|
||||
void remove_all_lines() { m_lines_count = 0; }
|
||||
};
|
||||
|
||||
Statistics m_statistics;
|
||||
#endif // NDEBUG
|
||||
|
||||
EWriteType m_write_type{ EWriteType::BySize };
|
||||
// Time machine containing g1 times cache
|
||||
TimeMachine& m_machine;
|
||||
// Current time
|
||||
float m_time{ 0.0f };
|
||||
// Current size in bytes
|
||||
size_t m_size{ 0 };
|
||||
|
||||
// gcode lines cache
|
||||
std::deque<LineData> m_lines;
|
||||
size_t m_added_lines_counter{ 0 };
|
||||
// map of gcode line ids from original to final
|
||||
// used to update m_result.moves[].gcode_id
|
||||
std::vector<std::pair<size_t, size_t>> m_gcode_lines_map;
|
||||
|
||||
size_t m_curr_g1_id{ 0 };
|
||||
size_t m_out_file_pos{ 0 };
|
||||
|
||||
public:
|
||||
ExportLines(EWriteType type, TimeMachine& machine)
|
||||
#ifndef NDEBUG
|
||||
: m_statistics(*this), m_write_type(type), m_machine(machine) {}
|
||||
#else
|
||||
: m_write_type(type), m_machine(machine) {}
|
||||
#endif // NDEBUG
|
||||
|
||||
void update(size_t lines_counter, size_t g1_lines_counter) {
|
||||
m_gcode_lines_map.push_back({ lines_counter, 0 });
|
||||
|
||||
if (g1_lines_counter == 0)
|
||||
return;
|
||||
|
||||
auto init_it = m_machine.g1_times_cache.begin() + m_curr_g1_id;
|
||||
auto it = init_it;
|
||||
while (it != m_machine.g1_times_cache.end() && it->id < g1_lines_counter + 1) {
|
||||
++it;
|
||||
++m_curr_g1_id;
|
||||
}
|
||||
|
||||
if (it != init_it || m_curr_g1_id == 0)
|
||||
m_time = it->elapsed_time;
|
||||
}
|
||||
|
||||
// add the given gcode line to the cache
|
||||
void append_line(const std::string& line) {
|
||||
m_lines.push_back({ line, m_time });
|
||||
#ifndef NDEBUG
|
||||
m_statistics.add_line(line.length());
|
||||
#endif // NDEBUG
|
||||
m_size += line.length();
|
||||
++m_added_lines_counter;
|
||||
assert(!m_gcode_lines_map.empty());
|
||||
m_gcode_lines_map.back().second = m_added_lines_counter;
|
||||
}
|
||||
|
||||
// Insert the gcode lines required by the command cmd by backtracing into the cache
|
||||
void insert_lines(const Backtrace& backtrace, const std::string& cmd, std::function<std::string(unsigned int, float, float)> line_inserter,
|
||||
std::function<std::string(const std::string&)> line_replacer) {
|
||||
assert(!m_lines.empty());
|
||||
const float time_step = backtrace.time_step();
|
||||
size_t rev_it_dist = 0; // distance from the end of the cache of the starting point of the backtrace
|
||||
float last_time_insertion = 0.0f; // used to avoid inserting two lines at the same time
|
||||
for (unsigned int i = 0; i < backtrace.steps; ++i) {
|
||||
const float backtrace_time_i = (i + 1) * time_step;
|
||||
const float time_threshold_i = m_time - backtrace_time_i;
|
||||
auto rev_it = m_lines.rbegin() + rev_it_dist;
|
||||
auto start_rev_it = rev_it;
|
||||
|
||||
// backtrace into the cache to find the place where to insert the line
|
||||
while (rev_it != m_lines.rend() && rev_it->time > time_threshold_i && GCodeReader::GCodeLine::extract_cmd(rev_it->line) != cmd) {
|
||||
rev_it->line = line_replacer(rev_it->line);
|
||||
++rev_it;
|
||||
}
|
||||
|
||||
// we met the previous evenience of cmd. stop inserting lines
|
||||
if (rev_it != m_lines.rend() && GCodeReader::GCodeLine::extract_cmd(rev_it->line) == cmd)
|
||||
break;
|
||||
|
||||
// insert the line for the current step
|
||||
if (rev_it != m_lines.rend() && rev_it != start_rev_it && rev_it->time != last_time_insertion) {
|
||||
last_time_insertion = rev_it->time;
|
||||
const std::string out_line = line_inserter(i + 1, last_time_insertion, m_time - last_time_insertion);
|
||||
rev_it_dist = std::distance(m_lines.rbegin(), rev_it) + 1;
|
||||
const auto new_it = m_lines.insert(rev_it.base(), { out_line, rev_it->time });
|
||||
#ifndef NDEBUG
|
||||
m_statistics.add_line(out_line.length());
|
||||
#endif // NDEBUG
|
||||
m_size += out_line.length();
|
||||
// synchronize gcode lines map
|
||||
for (auto map_it = m_gcode_lines_map.rbegin(); map_it != m_gcode_lines_map.rbegin() + rev_it_dist - 1; ++map_it) {
|
||||
++map_it->second;
|
||||
}
|
||||
|
||||
++m_added_lines_counter;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// write to file:
|
||||
// m_write_type == EWriteType::ByTime - all lines older than m_time - backtrace_time
|
||||
// m_write_type == EWriteType::BySize - all lines if current size is greater than 65535 bytes
|
||||
void write(FilePtr& out, float backtrace_time, GCodeProcessorResult& result, const std::string& out_path) {
|
||||
if (m_lines.empty())
|
||||
return;
|
||||
|
||||
// collect lines to write into a single string
|
||||
std::string out_string;
|
||||
if (!m_lines.empty()) {
|
||||
if (m_write_type == EWriteType::ByTime) {
|
||||
while (m_lines.front().time < m_time - backtrace_time) {
|
||||
const LineData& data = m_lines.front();
|
||||
out_string += data.line;
|
||||
m_size -= data.line.length();
|
||||
m_lines.pop_front();
|
||||
#ifndef NDEBUG
|
||||
m_statistics.remove_line();
|
||||
#endif // NDEBUG
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (m_size > 65535) {
|
||||
while (!m_lines.empty()) {
|
||||
out_string += m_lines.front().line;
|
||||
m_lines.pop_front();
|
||||
}
|
||||
m_size = 0;
|
||||
#ifndef NDEBUG
|
||||
m_statistics.remove_all_lines();
|
||||
#endif // NDEBUG
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
write_to_file(out, out_string, result, out_path);
|
||||
}
|
||||
|
||||
// flush the current content of the cache to file
|
||||
void flush(FilePtr& out, GCodeProcessorResult& result, const std::string& out_path) {
|
||||
// collect lines to flush into a single string
|
||||
std::string out_string;
|
||||
while (!m_lines.empty()) {
|
||||
out_string += m_lines.front().line;
|
||||
m_lines.pop_front();
|
||||
}
|
||||
m_size = 0;
|
||||
#ifndef NDEBUG
|
||||
m_statistics.remove_all_lines();
|
||||
#endif // NDEBUG
|
||||
|
||||
write_to_file(out, out_string, result, out_path);
|
||||
}
|
||||
|
||||
void synchronize_moves(GCodeProcessorResult& result) const {
|
||||
auto it = m_gcode_lines_map.begin();
|
||||
for (GCodeProcessorResult::MoveVertex& move : result.moves) {
|
||||
while (it != m_gcode_lines_map.end() && it->first < move.gcode_id) {
|
||||
++it;
|
||||
}
|
||||
if (it != m_gcode_lines_map.end() && it->first == move.gcode_id)
|
||||
move.gcode_id = it->second;
|
||||
}
|
||||
}
|
||||
|
||||
size_t get_size() const { return m_size; }
|
||||
|
||||
private:
|
||||
void write_to_file(FilePtr& out, const std::string& out_string, GCodeProcessorResult& result, const std::string& out_path) {
|
||||
if (!out_string.empty()) {
|
||||
fwrite((const void*)out_string.c_str(), 1, out_string.length(), out.f);
|
||||
if (ferror(out.f)) {
|
||||
out.close();
|
||||
boost::nowide::remove(out_path.c_str());
|
||||
throw Slic3r::RuntimeError(std::string("GCode processor post process export failed.\nIs the disk full?\n"));
|
||||
}
|
||||
for (size_t i = 0; i < out_string.size(); ++i) {
|
||||
if (out_string[i] == '\n')
|
||||
result.lines_ends.emplace_back(m_out_file_pos + i + 1);
|
||||
}
|
||||
m_out_file_pos += out_string.size();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
ExportLines export_lines(m_result.backtrace_enabled ? ExportLines::EWriteType::ByTime : ExportLines::EWriteType::BySize, m_time_processor.machines[0]);
|
||||
#else
|
||||
// buffer line to export only when greater than 64K to reduce writing calls
|
||||
std::string export_line;
|
||||
#endif // ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
|
||||
// replace placeholder lines with the proper final value
|
||||
// gcode_line is in/out parameter, to reduce expensive memory allocation
|
||||
auto process_placeholders = [&](std::string& gcode_line) {
|
||||
#if ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
bool processed = false;
|
||||
#else
|
||||
unsigned int extra_lines_count = 0;
|
||||
#endif // ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
|
||||
// remove trailing '\n'
|
||||
auto line = std::string_view(gcode_line).substr(0, gcode_line.length() - 1);
|
||||
|
||||
#if !ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
std::string ret;
|
||||
#endif // !ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
if (line.length() > 1) {
|
||||
line = line.substr(1);
|
||||
if (m_time_processor.export_remaining_time_enabled &&
|
||||
@ -3474,17 +3739,29 @@ void GCodeProcessor::post_process()
|
||||
const TimeMachine& machine = m_time_processor.machines[i];
|
||||
if (machine.enabled) {
|
||||
// export pair <percent, remaining time>
|
||||
#if ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
export_lines.append_line(format_line_M73_main(machine.line_m73_main_mask.c_str(),
|
||||
(line == reserved_tag(ETags::First_Line_M73_Placeholder)) ? 0 : 100,
|
||||
(line == reserved_tag(ETags::First_Line_M73_Placeholder)) ? time_in_minutes(machine.time) : 0));
|
||||
processed = true;
|
||||
#else
|
||||
ret += format_line_M73_main(machine.line_m73_main_mask.c_str(),
|
||||
(line == reserved_tag(ETags::First_Line_M73_Placeholder)) ? 0 : 100,
|
||||
(line == reserved_tag(ETags::First_Line_M73_Placeholder)) ? time_in_minutes(machine.time) : 0);
|
||||
++extra_lines_count;
|
||||
#endif // ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
|
||||
// export remaining time to next printer stop
|
||||
if (line == reserved_tag(ETags::First_Line_M73_Placeholder) && !machine.stop_times.empty()) {
|
||||
int to_export_stop = time_in_minutes(machine.stop_times.front().elapsed_time);
|
||||
const int to_export_stop = time_in_minutes(machine.stop_times.front().elapsed_time);
|
||||
#if ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
export_lines.append_line(format_line_M73_stop_int(machine.line_m73_stop_mask.c_str(), to_export_stop));
|
||||
last_exported_stop[i] = to_export_stop;
|
||||
#else
|
||||
ret += format_line_M73_stop_int(machine.line_m73_stop_mask.c_str(), to_export_stop);
|
||||
last_exported_stop[i] = to_export_stop;
|
||||
++extra_lines_count;
|
||||
#endif // ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3498,16 +3775,41 @@ void GCodeProcessor::post_process()
|
||||
sprintf(buf, "; estimated printing time (%s mode) = %s\n",
|
||||
(mode == PrintEstimatedStatistics::ETimeMode::Normal) ? "normal" : "silent",
|
||||
get_time_dhms(machine.time).c_str());
|
||||
#if ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
export_lines.append_line(buf);
|
||||
processed = true;
|
||||
#else
|
||||
ret += buf;
|
||||
#endif // ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
}
|
||||
}
|
||||
for (size_t i = 0; i < static_cast<size_t>(PrintEstimatedStatistics::ETimeMode::Count); ++i) {
|
||||
const TimeMachine& machine = m_time_processor.machines[i];
|
||||
PrintEstimatedStatistics::ETimeMode mode = static_cast<PrintEstimatedStatistics::ETimeMode>(i);
|
||||
if (mode == PrintEstimatedStatistics::ETimeMode::Normal || machine.enabled) {
|
||||
char buf[128];
|
||||
sprintf(buf, "; estimated first layer printing time (%s mode) = %s\n",
|
||||
(mode == PrintEstimatedStatistics::ETimeMode::Normal) ? "normal" : "silent",
|
||||
get_time_dhms(machine.layers_time.empty() ? 0.f : machine.layers_time.front()).c_str());
|
||||
#if ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
export_lines.append_line(buf);
|
||||
processed = true;
|
||||
#else
|
||||
ret += buf;
|
||||
#endif // ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
return processed;
|
||||
#else
|
||||
if (!ret.empty())
|
||||
// Not moving the move operator on purpose, so that the gcode_line allocation will grow and it will not be reallocated after handful of lines are processed.
|
||||
gcode_line = ret;
|
||||
return std::tuple(!ret.empty(), (extra_lines_count == 0) ? extra_lines_count : extra_lines_count - 1);
|
||||
#endif // ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
};
|
||||
|
||||
std::vector<double> filament_mm(m_result.extruders_count, 0.0);
|
||||
@ -3581,10 +3883,16 @@ void GCodeProcessor::post_process()
|
||||
time_in_minutes, format_time_float, format_line_M73_main, format_line_M73_stop_int, format_line_M73_stop_float, time_in_last_minute,
|
||||
// Caches, to be modified
|
||||
&g1_times_cache_it, &last_exported_main, &last_exported_stop,
|
||||
#if ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
&export_lines]
|
||||
#else
|
||||
// String output
|
||||
&export_line]
|
||||
#endif // ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
(const size_t g1_lines_counter) {
|
||||
#if !ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
unsigned int exported_lines_count = 0;
|
||||
#endif // !ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
if (m_time_processor.export_remaining_time_enabled) {
|
||||
for (size_t i = 0; i < static_cast<size_t>(PrintEstimatedStatistics::ETimeMode::Count); ++i) {
|
||||
const TimeMachine& machine = m_time_processor.machines[i];
|
||||
@ -3598,10 +3906,17 @@ void GCodeProcessor::post_process()
|
||||
std::pair<int, int> to_export_main = { int(100.0f * it->elapsed_time / machine.time),
|
||||
time_in_minutes(machine.time - it->elapsed_time) };
|
||||
if (last_exported_main[i] != to_export_main) {
|
||||
#if ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
export_lines.append_line(format_line_M73_main(machine.line_m73_main_mask.c_str(),
|
||||
to_export_main.first, to_export_main.second));
|
||||
#else
|
||||
export_line += format_line_M73_main(machine.line_m73_main_mask.c_str(),
|
||||
to_export_main.first, to_export_main.second);
|
||||
#endif // ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
last_exported_main[i] = to_export_main;
|
||||
#if !ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
++exported_lines_count;
|
||||
#endif // !ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
}
|
||||
// export remaining time to next printer stop
|
||||
auto it_stop = std::upper_bound(machine.stop_times.begin(), machine.stop_times.end(), it->elapsed_time,
|
||||
@ -3611,9 +3926,15 @@ void GCodeProcessor::post_process()
|
||||
if (last_exported_stop[i] != to_export_stop) {
|
||||
if (to_export_stop > 0) {
|
||||
if (last_exported_stop[i] != to_export_stop) {
|
||||
#if ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
export_lines.append_line(format_line_M73_stop_int(machine.line_m73_stop_mask.c_str(), to_export_stop));
|
||||
#else
|
||||
export_line += format_line_M73_stop_int(machine.line_m73_stop_mask.c_str(), to_export_stop);
|
||||
#endif // ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
last_exported_stop[i] = to_export_stop;
|
||||
#if !ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
++exported_lines_count;
|
||||
#endif // !ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
}
|
||||
}
|
||||
else {
|
||||
@ -3632,13 +3953,22 @@ void GCodeProcessor::post_process()
|
||||
}
|
||||
|
||||
if (is_last) {
|
||||
#if ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
if (std::distance(machine.stop_times.begin(), it_stop) == static_cast<ptrdiff_t>(machine.stop_times.size() - 1))
|
||||
export_lines.append_line(format_line_M73_stop_int(machine.line_m73_stop_mask.c_str(), to_export_stop));
|
||||
else
|
||||
export_lines.append_line(format_line_M73_stop_float(machine.line_m73_stop_mask.c_str(), time_in_last_minute(it_stop->elapsed_time - it->elapsed_time)));
|
||||
#else
|
||||
if (std::distance(machine.stop_times.begin(), it_stop) == static_cast<ptrdiff_t>(machine.stop_times.size() - 1))
|
||||
export_line += format_line_M73_stop_int(machine.line_m73_stop_mask.c_str(), to_export_stop);
|
||||
else
|
||||
export_line += format_line_M73_stop_float(machine.line_m73_stop_mask.c_str(), time_in_last_minute(it_stop->elapsed_time - it->elapsed_time));
|
||||
#endif // ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
|
||||
last_exported_stop[i] = to_export_stop;
|
||||
#if !ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
++exported_lines_count;
|
||||
#endif // !ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3647,12 +3977,50 @@ void GCodeProcessor::post_process()
|
||||
}
|
||||
}
|
||||
}
|
||||
#if !ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
return exported_lines_count;
|
||||
#endif // !ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
};
|
||||
|
||||
#if ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
// add lines XXX to exported gcode
|
||||
auto process_line_T = [this, &export_lines](const std::string& gcode_line, const size_t g1_lines_counter, const ExportLines::Backtrace& backtrace) {
|
||||
const std::string cmd = GCodeReader::GCodeLine::extract_cmd(gcode_line);
|
||||
if (cmd.size() >= 2) {
|
||||
std::stringstream ss(cmd.substr(1));
|
||||
int tool_number = -1;
|
||||
ss >> tool_number;
|
||||
if (tool_number != -1)
|
||||
export_lines.insert_lines(backtrace, cmd,
|
||||
// line inserter
|
||||
[tool_number, this](unsigned int id, float time, float time_diff) {
|
||||
int temperature = int( m_layer_id != 1 ? m_extruder_temps_config[tool_number] : m_extruder_temps_first_layer_config[tool_number]);
|
||||
const std::string out = "M104 T" + std::to_string(tool_number) + " P" + std::to_string(int(std::round(time_diff))) + " S" + std::to_string(temperature) + "\n";
|
||||
return out;
|
||||
},
|
||||
// line replacer
|
||||
[this, tool_number](const std::string& line) {
|
||||
if (GCodeReader::GCodeLine::cmd_is(line, "M104")) {
|
||||
GCodeReader::GCodeLine gline;
|
||||
GCodeReader reader;
|
||||
reader.parse_line(line, [&gline](GCodeReader& reader, const GCodeReader::GCodeLine& l) { gline = l; });
|
||||
|
||||
float val;
|
||||
if (gline.has_value('T', val) && gline.raw().find("cooldown") != std::string::npos && m_is_XL_printer) {
|
||||
if (static_cast<int>(val) == tool_number)
|
||||
return std::string("; removed M104\n");
|
||||
}
|
||||
}
|
||||
return line;
|
||||
});
|
||||
}
|
||||
};
|
||||
#endif // ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
|
||||
m_result.lines_ends.clear();
|
||||
#if !ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
// helper function to write to disk
|
||||
size_t out_file_pos = 0;
|
||||
m_result.lines_ends.clear();
|
||||
auto write_string = [this, &export_line, &out, &out_path, &out_file_pos](const std::string& str) {
|
||||
fwrite((const void*)export_line.c_str(), 1, export_line.length(), out.f);
|
||||
if (ferror(out.f)) {
|
||||
@ -3666,9 +4034,18 @@ void GCodeProcessor::post_process()
|
||||
out_file_pos += export_line.size();
|
||||
export_line.clear();
|
||||
};
|
||||
#endif // !ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
|
||||
unsigned int line_id = 0;
|
||||
#if ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
// Backtrace data for Tx gcode lines
|
||||
static const ExportLines::Backtrace backtrace_T = { 120.0f, 10 };
|
||||
// In case there are multiple sources of backtracing, keeps track of the longest backtrack time needed
|
||||
// to flush the backtrace cache accordingly
|
||||
float max_backtrace_time = 120.0f;
|
||||
#else
|
||||
std::vector<std::pair<unsigned int, unsigned int>> offsets;
|
||||
#endif // ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
|
||||
{
|
||||
// Read the input stream 64kB at a time, extract lines and process them.
|
||||
@ -3692,14 +4069,39 @@ void GCodeProcessor::post_process()
|
||||
gcode_line.insert(gcode_line.end(), it, it_end);
|
||||
if (eol) {
|
||||
++line_id;
|
||||
#if ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
export_lines.update(line_id, g1_lines_counter);
|
||||
#endif // ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
|
||||
gcode_line += "\n";
|
||||
// replace placeholder lines
|
||||
#if ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
bool processed = process_placeholders(gcode_line);
|
||||
if (processed)
|
||||
gcode_line.clear();
|
||||
#else
|
||||
auto [processed, lines_added_count] = process_placeholders(gcode_line);
|
||||
if (processed && lines_added_count > 0)
|
||||
offsets.push_back({ line_id, lines_added_count });
|
||||
#endif // ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
if (!processed)
|
||||
processed = process_used_filament(gcode_line);
|
||||
#if ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
if (!processed && !is_temporary_decoration(gcode_line)) {
|
||||
if (GCodeReader::GCodeLine::cmd_is(gcode_line, "G1"))
|
||||
// add lines M73 where needed
|
||||
process_line_G1(g1_lines_counter++);
|
||||
else if (m_result.backtrace_enabled && GCodeReader::GCodeLine::cmd_starts_with(gcode_line, "T")) {
|
||||
// add lines XXX where needed
|
||||
process_line_T(gcode_line, g1_lines_counter, backtrace_T);
|
||||
max_backtrace_time = std::max(max_backtrace_time, backtrace_T.time);
|
||||
}
|
||||
}
|
||||
|
||||
if (!gcode_line.empty())
|
||||
export_lines.append_line(gcode_line);
|
||||
export_lines.write(out, 1.1f * max_backtrace_time, m_result, out_path);
|
||||
#else
|
||||
if (!processed && !is_temporary_decoration(gcode_line) && GCodeReader::GCodeLine::cmd_is(gcode_line, "G1")) {
|
||||
// remove temporary lines, add lines M73 where needed
|
||||
unsigned int extra_lines_count = process_line_G1(g1_lines_counter++);
|
||||
@ -3710,6 +4112,7 @@ void GCodeProcessor::post_process()
|
||||
export_line += gcode_line;
|
||||
if (export_line.length() > 65535)
|
||||
write_string(export_line);
|
||||
#endif // ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
gcode_line.clear();
|
||||
}
|
||||
// Skip EOL.
|
||||
@ -3724,12 +4127,19 @@ void GCodeProcessor::post_process()
|
||||
}
|
||||
}
|
||||
|
||||
#if ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
export_lines.flush(out, m_result, out_path);
|
||||
#else
|
||||
if (!export_line.empty())
|
||||
write_string(export_line);
|
||||
#endif // ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
|
||||
out.close();
|
||||
in.close();
|
||||
|
||||
#if ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
export_lines.synchronize_moves(m_result);
|
||||
#else
|
||||
// updates moves' gcode ids which have been modified by the insertion of the M73 lines
|
||||
unsigned int curr_offset_id = 0;
|
||||
unsigned int total_offset = 0;
|
||||
@ -3740,6 +4150,7 @@ void GCodeProcessor::post_process()
|
||||
}
|
||||
move.gcode_id += total_offset;
|
||||
}
|
||||
#endif // ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
|
||||
if (rename_file(out_path, m_result.filename))
|
||||
throw Slic3r::RuntimeError(std::string("Failed to rename the output G-code file from ") + out_path + " to " + m_result.filename + '\n' +
|
||||
@ -3890,6 +4301,8 @@ void GCodeProcessor::set_travel_acceleration(PrintEstimatedStatistics::ETimeMode
|
||||
|
||||
float GCodeProcessor::get_filament_load_time(size_t extruder_id)
|
||||
{
|
||||
if (m_is_XL_printer)
|
||||
return 4.5f; // FIXME
|
||||
return (m_time_processor.filament_load_times.empty() || m_time_processor.extruder_unloaded) ?
|
||||
0.0f :
|
||||
((extruder_id < m_time_processor.filament_load_times.size()) ?
|
||||
@ -3898,6 +4311,8 @@ float GCodeProcessor::get_filament_load_time(size_t extruder_id)
|
||||
|
||||
float GCodeProcessor::get_filament_unload_time(size_t extruder_id)
|
||||
{
|
||||
if (m_is_XL_printer)
|
||||
return 0.f; // FIXME
|
||||
return (m_time_processor.filament_unload_times.empty() || m_time_processor.extruder_unloaded) ?
|
||||
0.0f :
|
||||
((extruder_id < m_time_processor.filament_unload_times.size()) ?
|
||||
|
@ -125,6 +125,9 @@ namespace Slic3r {
|
||||
float max_print_height;
|
||||
SettingsIds settings_ids;
|
||||
size_t extruders_count;
|
||||
#if ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
bool backtrace_enabled;
|
||||
#endif // ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
std::vector<std::string> extruder_colors;
|
||||
std::vector<float> filament_diameters;
|
||||
std::vector<float> filament_densities;
|
||||
@ -543,6 +546,9 @@ namespace Slic3r {
|
||||
unsigned char m_extruder_id;
|
||||
ExtruderColors m_extruder_colors;
|
||||
ExtruderTemps m_extruder_temps;
|
||||
ExtruderTemps m_extruder_temps_config;
|
||||
ExtruderTemps m_extruder_temps_first_layer_config;
|
||||
bool m_is_XL_printer = false;
|
||||
float m_parking_position;
|
||||
float m_extra_loading_move;
|
||||
float m_extruded_last_z;
|
||||
|
@ -185,11 +185,6 @@ static int run_script(const std::string &script, const std::string &gcode, std::
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
//! macro used to mark string used at localization,
|
||||
//! return same string
|
||||
#define L(s) (s)
|
||||
#define _(s) Slic3r::I18N::translate(s)
|
||||
|
||||
// Run post processing script / scripts if defined.
|
||||
// Returns true if a post-processing script was executed.
|
||||
// Returns false if no post-processing script was defined.
|
||||
@ -285,10 +280,10 @@ bool run_post_process_scripts(std::string &src_path, bool make_copy, const std::
|
||||
throw Slic3r::RuntimeError(msg);
|
||||
}
|
||||
if (! boost::filesystem::exists(gcode_file)) {
|
||||
const std::string msg = (boost::format(_(L(
|
||||
const std::string msg = (boost::format(_u8L(
|
||||
"Post-processing script %1% failed.\n\n"
|
||||
"The post-processing script is expected to change the G-code file %2% in place, but the G-code file was deleted and likely saved under a new name.\n"
|
||||
"Please adjust the post-processing script to change the G-code in place and consult the manual on how to optionally rename the post-processed G-code file.\n")))
|
||||
"Please adjust the post-processing script to change the G-code in place and consult the manual on how to optionally rename the post-processed G-code file.\n"))
|
||||
% script % path).str();
|
||||
BOOST_LOG_TRIVIAL(error) << msg;
|
||||
throw Slic3r::RuntimeError(msg);
|
||||
|
@ -4,12 +4,17 @@
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <numeric>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
|
||||
#include "ClipperUtils.hpp"
|
||||
#include "GCodeProcessor.hpp"
|
||||
#include "BoundingBox.hpp"
|
||||
#include "LocalesUtils.hpp"
|
||||
#include "Geometry.hpp"
|
||||
#include "Surface.hpp"
|
||||
#include "Fill/FillRectilinear.hpp"
|
||||
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
|
||||
@ -88,9 +93,12 @@ public:
|
||||
}
|
||||
|
||||
WipeTowerWriter& disable_linear_advance() {
|
||||
m_gcode += (m_gcode_flavor == gcfRepRapSprinter || m_gcode_flavor == gcfRepRapFirmware
|
||||
? (std::string("M572 D") + std::to_string(m_current_tool) + " S0\n")
|
||||
: std::string("M900 K0\n"));
|
||||
if (m_gcode_flavor == gcfRepRapSprinter || m_gcode_flavor == gcfRepRapFirmware)
|
||||
m_gcode += (std::string("M572 D") + std::to_string(m_current_tool) + " S0\n");
|
||||
else if (m_gcode_flavor == gcfKlipper)
|
||||
m_gcode += "SET_PRESSURE_ADVANCE ADVANCE=0\n";
|
||||
else
|
||||
m_gcode += "M900 K0\n";
|
||||
return *this;
|
||||
}
|
||||
|
||||
@ -358,6 +366,8 @@ public:
|
||||
// Set digital trimpot motor
|
||||
WipeTowerWriter& set_extruder_trimpot(int current)
|
||||
{
|
||||
if (m_gcode_flavor == gcfKlipper)
|
||||
return *this;
|
||||
if (m_gcode_flavor == gcfRepRapSprinter || m_gcode_flavor == gcfRepRapFirmware)
|
||||
m_gcode += "M906 E";
|
||||
else
|
||||
@ -512,6 +522,8 @@ WipeTower::WipeTower(const PrintConfig& config, const std::vector<std::vector<fl
|
||||
m_wipe_tower_width(float(config.wipe_tower_width)),
|
||||
m_wipe_tower_rotation_angle(float(config.wipe_tower_rotation_angle)),
|
||||
m_wipe_tower_brim_width(float(config.wipe_tower_brim_width)),
|
||||
m_wipe_tower_cone_angle(float(config.wipe_tower_cone_angle)),
|
||||
m_extra_spacing(float(config.wipe_tower_extra_spacing/100.)),
|
||||
m_y_shift(0.f),
|
||||
m_z_pos(0.f),
|
||||
m_bridging(float(config.wipe_tower_bridging)),
|
||||
@ -1169,45 +1181,201 @@ WipeTower::ToolChangeResult WipeTower::finish_layer()
|
||||
";------------------\n\n\n\n\n\n\n");
|
||||
}
|
||||
|
||||
// outer perimeter (always):
|
||||
writer.rectangle(wt_box, feedrate);
|
||||
const float spacing = m_perimeter_width - m_layer_height*float(1.-M_PI_4);
|
||||
|
||||
// This block creates the stabilization cone.
|
||||
// First define a lambda to draw the rectangle with stabilization.
|
||||
auto supported_rectangle = [this, &writer, spacing](const box_coordinates& wt_box, double feedrate, bool infill_cone) -> Polygon {
|
||||
const auto [R, support_scale] = get_wipe_tower_cone_base(m_wipe_tower_width, m_wipe_tower_height, m_wipe_tower_depth, m_wipe_tower_cone_angle);
|
||||
|
||||
double z = m_no_sparse_layers ? (m_current_height + m_layer_info->height) : m_layer_info->z; // the former should actually work in both cases, but let's stay on the safe side (the 2.6.0 is close)
|
||||
|
||||
double r = std::tan(Geometry::deg2rad(m_wipe_tower_cone_angle/2.f)) * (m_wipe_tower_height - z);
|
||||
Vec2f center = (wt_box.lu + wt_box.rd) / 2.;
|
||||
double w = wt_box.lu.y() - wt_box.ld.y();
|
||||
enum Type {
|
||||
Arc,
|
||||
Corner,
|
||||
ArcStart,
|
||||
ArcEnd
|
||||
};
|
||||
|
||||
// First generate vector of annotated point which form the boundary.
|
||||
std::vector<std::pair<Vec2f, Type>> pts = {{wt_box.ru, Corner}};
|
||||
if (double alpha_start = std::asin((0.5*w)/r); ! std::isnan(alpha_start) && r > 0.5*w+0.01) {
|
||||
for (double alpha = alpha_start; alpha < M_PI-alpha_start+0.001; alpha+=(M_PI-2*alpha_start) / 20.)
|
||||
pts.emplace_back(Vec2f(center.x() + r*std::cos(alpha)/support_scale, center.y() + r*std::sin(alpha)), alpha == alpha_start ? ArcStart : Arc);
|
||||
pts.back().second = ArcEnd;
|
||||
}
|
||||
pts.emplace_back(wt_box.lu, Corner);
|
||||
pts.emplace_back(wt_box.ld, Corner);
|
||||
for (int i=int(pts.size())-3; i>0; --i)
|
||||
pts.emplace_back(Vec2f(pts[i].first.x(), 2*center.y()-pts[i].first.y()), i == int(pts.size())-3 ? ArcStart : i == 1 ? ArcEnd : Arc);
|
||||
pts.emplace_back(wt_box.rd, Corner);
|
||||
|
||||
// Create a Polygon from the points.
|
||||
Polygon poly;
|
||||
for (const auto& [pt, tag] : pts)
|
||||
poly.points.push_back(Point::new_scale(pt));
|
||||
|
||||
// Prepare polygons to be filled by infill.
|
||||
Polylines polylines;
|
||||
if (infill_cone && m_wipe_tower_width > 2*spacing && m_wipe_tower_depth > 2*spacing) {
|
||||
ExPolygons infill_areas;
|
||||
ExPolygon wt_contour(poly);
|
||||
Polygon wt_rectangle(Points{Point::new_scale(wt_box.ld), Point::new_scale(wt_box.rd), Point::new_scale(wt_box.ru), Point::new_scale(wt_box.lu)});
|
||||
wt_rectangle = offset(wt_rectangle, scale_(-spacing/2.)).front();
|
||||
wt_contour = offset_ex(wt_contour, scale_(-spacing/2.)).front();
|
||||
infill_areas = diff_ex(wt_contour, wt_rectangle);
|
||||
if (infill_areas.size() == 2) {
|
||||
ExPolygon& bottom_expoly = infill_areas.front().contour.points.front().y() < infill_areas.back().contour.points.front().y() ? infill_areas[0] : infill_areas[1];
|
||||
std::unique_ptr<Fill> filler(Fill::new_from_type(ipMonotonicLines));
|
||||
filler->angle = Geometry::deg2rad(45.f);
|
||||
filler->spacing = spacing;
|
||||
FillParams params;
|
||||
params.density = 1.f;
|
||||
Surface surface(stBottom, bottom_expoly);
|
||||
filler->bounding_box = get_extents(bottom_expoly);
|
||||
polylines = filler->fill_surface(&surface, params);
|
||||
if (! polylines.empty()) {
|
||||
if (polylines.front().points.front().x() > polylines.back().points.back().x()) {
|
||||
std::reverse(polylines.begin(), polylines.end());
|
||||
for (Polyline& p : polylines)
|
||||
p.reverse();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Find the closest corner and travel to it.
|
||||
int start_i = 0;
|
||||
double min_dist = std::numeric_limits<double>::max();
|
||||
for (int i=0; i<int(pts.size()); ++i) {
|
||||
if (pts[i].second == Corner) {
|
||||
double dist = (pts[i].first - Vec2f(writer.x(), writer.y())).squaredNorm();
|
||||
if (dist < min_dist) {
|
||||
min_dist = dist;
|
||||
start_i = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
writer.travel(pts[start_i].first);
|
||||
|
||||
// Now actually extrude the boundary (and possibly infill):
|
||||
int i = start_i+1 == int(pts.size()) ? 0 : start_i + 1;
|
||||
while (i != start_i) {
|
||||
writer.extrude(pts[i].first, feedrate);
|
||||
if (pts[i].second == ArcEnd) {
|
||||
// Extrude the infill.
|
||||
if (! polylines.empty()) {
|
||||
// Extrude the infill and travel back to where we were.
|
||||
bool mirror = ((pts[i].first.y() - center.y()) * (unscale(polylines.front().points.front()).y() - center.y())) < 0.;
|
||||
for (const Polyline& line : polylines) {
|
||||
writer.travel(center - (mirror ? 1.f : -1.f) * (unscale(line.points.front()).cast<float>() - center));
|
||||
for (size_t i=0; i<line.points.size(); ++i)
|
||||
writer.extrude(center - (mirror ? 1.f : -1.f) * (unscale(line.points[i]).cast<float>() - center));
|
||||
}
|
||||
writer.travel(pts[i].first);
|
||||
}
|
||||
}
|
||||
if (++i == int(pts.size()))
|
||||
i = 0;
|
||||
}
|
||||
writer.extrude(pts[start_i].first, feedrate);
|
||||
return poly;
|
||||
};
|
||||
|
||||
// outer contour (always)
|
||||
bool infill_cone = first_layer && m_wipe_tower_width > 2*spacing && m_wipe_tower_depth > 2*spacing;
|
||||
Polygon poly = supported_rectangle(wt_box, feedrate, infill_cone);
|
||||
|
||||
|
||||
// brim (first layer only)
|
||||
if (first_layer) {
|
||||
box_coordinates box = wt_box;
|
||||
float spacing = m_perimeter_width - m_layer_height*float(1.-M_PI_4);
|
||||
// How many perimeters shall the brim have?
|
||||
size_t loops_num = (m_wipe_tower_brim_width + spacing/2.f) / spacing;
|
||||
|
||||
for (size_t i = 0; i < loops_num; ++ i) {
|
||||
box.expand(spacing);
|
||||
writer.rectangle(box);
|
||||
poly = offset(poly, scale_(spacing)).front();
|
||||
int cp = poly.closest_point_index(Point::new_scale(writer.x(), writer.y()));
|
||||
writer.travel(unscale(poly.points[cp]).cast<float>());
|
||||
for (int i=cp+1; true; ++i ) {
|
||||
if (i==int(poly.points.size()))
|
||||
i = 0;
|
||||
writer.extrude(unscale(poly.points[i]).cast<float>());
|
||||
if (i == cp)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Save actual brim width to be later passed to the Print object, which will use it
|
||||
// for skirt calculation and pass it to GLCanvas for precise preview box
|
||||
m_wipe_tower_brim_width_real = wt_box.ld.x() - box.ld.x() + spacing/2.f;
|
||||
wt_box = box;
|
||||
m_wipe_tower_brim_width_real = loops_num * spacing;
|
||||
}
|
||||
|
||||
// Now prepare future wipe. box contains rectangle that was extruded last (ccw).
|
||||
Vec2f target = (writer.pos() == wt_box.ld ? wt_box.rd :
|
||||
(writer.pos() == wt_box.rd ? wt_box.ru :
|
||||
(writer.pos() == wt_box.ru ? wt_box.lu :
|
||||
wt_box.ld)));
|
||||
writer.add_wipe_point(writer.pos())
|
||||
.add_wipe_point(target);
|
||||
|
||||
// Now prepare future wipe.
|
||||
int i = poly.closest_point_index(Point::new_scale(writer.x(), writer.y()));
|
||||
writer.add_wipe_point(writer.pos());
|
||||
writer.add_wipe_point(unscale(poly.points[i==0 ? int(poly.points.size())-1 : i-1]).cast<float>());
|
||||
|
||||
// Ask our writer about how much material was consumed.
|
||||
// Skip this in case the layer is sparse and config option to not print sparse layers is enabled.
|
||||
if (! m_no_sparse_layers || toolchanges_on_layer || first_layer)
|
||||
if (! m_no_sparse_layers || toolchanges_on_layer || first_layer) {
|
||||
if (m_current_tool < m_used_filament_length.size())
|
||||
m_used_filament_length[m_current_tool] += writer.get_and_reset_used_filament_length();
|
||||
m_current_height += m_layer_info->height;
|
||||
}
|
||||
|
||||
return construct_tcr(writer, false, old_tool);
|
||||
}
|
||||
|
||||
// Static method to get the radius and x-scaling of the stabilizing cone base.
|
||||
std::pair<double, double> WipeTower::get_wipe_tower_cone_base(double width, double height, double depth, double angle_deg)
|
||||
{
|
||||
double R = std::tan(Geometry::deg2rad(angle_deg/2.)) * height;
|
||||
double fake_width = 0.66 * width;
|
||||
double diag = std::hypot(fake_width / 2., depth / 2.);
|
||||
double support_scale = 1.;
|
||||
if (R > diag) {
|
||||
double w = fake_width;
|
||||
double sin = 0.5 * depth / diag;
|
||||
double tan = depth / w;
|
||||
double t = (R - diag) * sin;
|
||||
support_scale = (w / 2. + t / tan + t * tan) / (w / 2.);
|
||||
}
|
||||
return std::make_pair(R, support_scale);
|
||||
}
|
||||
|
||||
// Static method to extract wipe_volumes[from][to] from the configuration.
|
||||
std::vector<std::vector<float>> WipeTower::extract_wipe_volumes(const PrintConfig& config)
|
||||
{
|
||||
// Get wiping matrix to get number of extruders and convert vector<double> to vector<float>:
|
||||
std::vector<float> wiping_matrix(cast<float>(config.wiping_volumes_matrix.values));
|
||||
|
||||
// The values shall only be used when SEMM is enabled. The purging for other printers
|
||||
// is determined by filament_minimal_purge_on_wipe_tower.
|
||||
if (! config.single_extruder_multi_material.value)
|
||||
std::fill(wiping_matrix.begin(), wiping_matrix.end(), 0.f);
|
||||
|
||||
// Extract purging volumes for each extruder pair:
|
||||
std::vector<std::vector<float>> wipe_volumes;
|
||||
const unsigned int number_of_extruders = (unsigned int)(sqrt(wiping_matrix.size())+EPSILON);
|
||||
for (unsigned int i = 0; i<number_of_extruders; ++i)
|
||||
wipe_volumes.push_back(std::vector<float>(wiping_matrix.begin()+i*number_of_extruders, wiping_matrix.begin()+(i+1)*number_of_extruders));
|
||||
|
||||
// Also include filament_minimal_purge_on_wipe_tower. This is needed for the preview.
|
||||
for (unsigned int i = 0; i<number_of_extruders; ++i) {
|
||||
for (unsigned int j = 0; j<number_of_extruders; ++j) {
|
||||
float w = wipe_volumes[i][j];
|
||||
|
||||
if (wipe_volumes[i][j] < config.filament_minimal_purge_on_wipe_tower.get_at(j))
|
||||
wipe_volumes[i][j] = config.filament_minimal_purge_on_wipe_tower.get_at(j);
|
||||
}
|
||||
}
|
||||
|
||||
return wipe_volumes;
|
||||
}
|
||||
|
||||
// Appends a toolchange into m_plan and calculates neccessary depth of the corresponding box
|
||||
void WipeTower::plan_toolchange(float z_par, float layer_height_par, unsigned int old_tool,
|
||||
unsigned int new_tool, float wipe_volume)
|
||||
@ -1250,6 +1418,8 @@ void WipeTower::plan_tower()
|
||||
m_wipe_tower_depth = 0.f;
|
||||
for (auto& layer : m_plan)
|
||||
layer.depth = 0.f;
|
||||
m_wipe_tower_height = m_plan.empty() ? 0.f : m_plan.back().z;
|
||||
m_current_height = 0.f;
|
||||
|
||||
for (int layer_index = int(m_plan.size()) - 1; layer_index >= 0; --layer_index)
|
||||
{
|
||||
@ -1334,8 +1504,6 @@ void WipeTower::generate(std::vector<std::vector<WipeTower::ToolChangeResult>> &
|
||||
if (m_plan.empty())
|
||||
return;
|
||||
|
||||
m_extra_spacing = 1.f;
|
||||
|
||||
plan_tower();
|
||||
for (int i=0;i<5;++i) {
|
||||
save_on_last_wipe();
|
||||
@ -1343,6 +1511,7 @@ void WipeTower::generate(std::vector<std::vector<WipeTower::ToolChangeResult>> &
|
||||
}
|
||||
|
||||
m_layer_info = m_plan.begin();
|
||||
m_current_height = 0.f;
|
||||
|
||||
// we don't know which extruder to start with - we'll set it according to the first toolchange
|
||||
for (const auto& layer : m_plan) {
|
||||
@ -1358,7 +1527,7 @@ void WipeTower::generate(std::vector<std::vector<WipeTower::ToolChangeResult>> &
|
||||
m_old_temperature = -1; // reset last temperature written in the gcode
|
||||
|
||||
std::vector<WipeTower::ToolChangeResult> layer_result;
|
||||
for (auto layer : m_plan)
|
||||
for (const WipeTower::WipeTowerInfo& layer : m_plan)
|
||||
{
|
||||
set_layer(layer.z, layer.height, 0, false/*layer.z == m_plan.front().z*/, layer.z == m_plan.back().z);
|
||||
m_internal_rotation += 180.f;
|
||||
|
@ -22,6 +22,8 @@ class WipeTower
|
||||
{
|
||||
public:
|
||||
static const std::string never_skip_tag() { return "_GCODE_WIPE_TOWER_NEVER_SKIP_TAG"; }
|
||||
static std::pair<double, double> get_wipe_tower_cone_base(double width, double height, double depth, double angle_deg);
|
||||
static std::vector<std::vector<float>> extract_wipe_volumes(const PrintConfig& config);
|
||||
|
||||
struct Extrusion
|
||||
{
|
||||
@ -142,6 +144,7 @@ public:
|
||||
|
||||
float get_depth() const { return m_wipe_tower_depth; }
|
||||
float get_brim_width() const { return m_wipe_tower_brim_width_real; }
|
||||
float get_wipe_tower_height() const { return m_wipe_tower_height; }
|
||||
|
||||
|
||||
|
||||
@ -253,6 +256,8 @@ private:
|
||||
Vec2f m_wipe_tower_pos; // Left front corner of the wipe tower in mm.
|
||||
float m_wipe_tower_width; // Width of the wipe tower.
|
||||
float m_wipe_tower_depth = 0.f; // Depth of the wipe tower
|
||||
float m_wipe_tower_height = 0.f;
|
||||
float m_wipe_tower_cone_angle = 0.f;
|
||||
float m_wipe_tower_brim_width = 0.f; // Width of brim (mm) from config
|
||||
float m_wipe_tower_brim_width_real = 0.f; // Width of brim (mm) after generation
|
||||
float m_wipe_tower_rotation_angle = 0.f; // Wipe tower rotation angle in degrees (with respect to x axis)
|
||||
@ -359,6 +364,10 @@ private:
|
||||
std::vector<WipeTowerInfo> m_plan; // Stores information about all layers and toolchanges for the future wipe tower (filled by plan_toolchange(...))
|
||||
std::vector<WipeTowerInfo>::iterator m_layer_info = m_plan.end();
|
||||
|
||||
// This sums height of all extruded layers, not counting the layers which
|
||||
// will be later removed when the "no_sparse_layers" is used.
|
||||
float m_current_height = 0.f;
|
||||
|
||||
// Stores information about used filament length per extruder:
|
||||
std::vector<float> m_used_filament_length;
|
||||
|
||||
|
@ -71,6 +71,19 @@ public:
|
||||
return strncmp(cmd, cmd_test, len) == 0 && GCodeReader::is_end_of_word(cmd[len]);
|
||||
}
|
||||
|
||||
#if ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
static bool cmd_starts_with(const std::string& gcode_line, const char* cmd_test) {
|
||||
return strncmp(GCodeReader::skip_whitespaces(gcode_line.c_str()), cmd_test, strlen(cmd_test)) == 0;
|
||||
}
|
||||
|
||||
static std::string extract_cmd(const std::string& gcode_line) {
|
||||
GCodeLine temp;
|
||||
temp.m_raw = gcode_line;
|
||||
const std::string_view cmd = temp.cmd();
|
||||
return { cmd.begin(), cmd.end() };
|
||||
}
|
||||
#endif // ENABLE_GCODE_POSTPROCESS_BACKTRACE
|
||||
|
||||
private:
|
||||
std::string m_raw;
|
||||
float m_axis[NUM_AXES];
|
||||
|
@ -15,6 +15,12 @@
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
// static
|
||||
bool GCodeWriter::supports_separate_travel_acceleration(GCodeFlavor flavor)
|
||||
{
|
||||
return (flavor == gcfRepetier || flavor == gcfMarlinFirmware || flavor == gcfRepRapFirmware);
|
||||
}
|
||||
|
||||
void GCodeWriter::apply_print_config(const PrintConfig &print_config)
|
||||
{
|
||||
this->config.apply(print_config, true);
|
||||
@ -25,6 +31,8 @@ void GCodeWriter::apply_print_config(const PrintConfig &print_config)
|
||||
|| print_config.gcode_flavor.value == gcfRepRapFirmware;
|
||||
m_max_acceleration = static_cast<unsigned int>(std::round((use_mach_limits && print_config.machine_limits_usage.value == MachineLimitsUsage::EmitToGCode) ?
|
||||
print_config.machine_max_acceleration_extruding.values.front() : 0));
|
||||
m_max_travel_acceleration = static_cast<unsigned int>(std::round((use_mach_limits && print_config.machine_limits_usage.value == MachineLimitsUsage::EmitToGCode && supports_separate_travel_acceleration(print_config.gcode_flavor.value)) ?
|
||||
print_config.machine_max_acceleration_travel.values.front() : 0));
|
||||
}
|
||||
|
||||
void GCodeWriter::set_extruders(std::vector<unsigned int> extruder_ids)
|
||||
@ -53,6 +61,7 @@ std::string GCodeWriter::preamble()
|
||||
FLAVOR_IS(gcfRepRapFirmware) ||
|
||||
FLAVOR_IS(gcfMarlinLegacy) ||
|
||||
FLAVOR_IS(gcfMarlinFirmware) ||
|
||||
FLAVOR_IS(gcfKlipper) ||
|
||||
FLAVOR_IS(gcfTeacup) ||
|
||||
FLAVOR_IS(gcfRepetier) ||
|
||||
FLAVOR_IS(gcfSmoothie))
|
||||
@ -154,36 +163,31 @@ std::string GCodeWriter::set_bed_temperature(unsigned int temperature, bool wait
|
||||
return gcode.str();
|
||||
}
|
||||
|
||||
std::string GCodeWriter::set_acceleration(unsigned int acceleration)
|
||||
std::string GCodeWriter::set_acceleration_internal(Acceleration type, unsigned int acceleration)
|
||||
{
|
||||
// Clamp the acceleration to the allowed maximum.
|
||||
if (m_max_acceleration > 0 && acceleration > m_max_acceleration)
|
||||
if (type == Acceleration::Print && m_max_acceleration > 0 && acceleration > m_max_acceleration)
|
||||
acceleration = m_max_acceleration;
|
||||
if (type == Acceleration::Travel && m_max_travel_acceleration > 0 && acceleration > m_max_travel_acceleration)
|
||||
acceleration = m_max_travel_acceleration;
|
||||
|
||||
if (acceleration == 0 || acceleration == m_last_acceleration)
|
||||
// Are we setting travel acceleration for a flavour that supports separate travel and print acc?
|
||||
bool separate_travel = (type == Acceleration::Travel && supports_separate_travel_acceleration(this->config.gcode_flavor));
|
||||
|
||||
auto& last_value = separate_travel ? m_last_travel_acceleration : m_last_acceleration ;
|
||||
if (acceleration == 0 || acceleration == last_value)
|
||||
return std::string();
|
||||
|
||||
m_last_acceleration = acceleration;
|
||||
last_value = acceleration;
|
||||
|
||||
std::ostringstream gcode;
|
||||
if (FLAVOR_IS(gcfRepetier)) {
|
||||
// M201: Set max printing acceleration
|
||||
gcode << "M201 X" << acceleration << " Y" << acceleration;
|
||||
if (this->config.gcode_comments) gcode << " ; adjust acceleration";
|
||||
gcode << "\n";
|
||||
// M202: Set max travel acceleration
|
||||
gcode << "M202 X" << acceleration << " Y" << acceleration;
|
||||
} else if (FLAVOR_IS(gcfRepRapFirmware)) {
|
||||
// M204: Set default acceleration
|
||||
gcode << "M204 P" << acceleration;
|
||||
} else if (FLAVOR_IS(gcfMarlinFirmware)) {
|
||||
// This is new MarlinFirmware with separated print/retraction/travel acceleration.
|
||||
// Use M204 P, we don't want to override travel acc by M204 S (which is deprecated anyway).
|
||||
gcode << "M204 P" << acceleration;
|
||||
} else {
|
||||
// M204: Set default acceleration
|
||||
if (FLAVOR_IS(gcfRepetier))
|
||||
gcode << (separate_travel ? "M202 X" : "M201 X") << acceleration << " Y" << acceleration;
|
||||
else if (FLAVOR_IS(gcfRepRapFirmware) || FLAVOR_IS(gcfMarlinFirmware))
|
||||
gcode << (separate_travel ? "M204 T" : "M204 P") << acceleration;
|
||||
else
|
||||
gcode << "M204 S" << acceleration;
|
||||
}
|
||||
|
||||
if (this->config.gcode_comments) gcode << " ; adjust acceleration";
|
||||
gcode << "\n";
|
||||
|
||||
@ -482,6 +486,20 @@ std::string GCodeWriter::unlift()
|
||||
return gcode;
|
||||
}
|
||||
|
||||
void GCodeWriter::update_position(const Vec3d &new_pos)
|
||||
{
|
||||
assert(this->m_lifted >= 0);
|
||||
const double nominal_z = m_pos.z() - m_lifted;
|
||||
m_lifted = new_pos.z() - nominal_z;
|
||||
if (m_lifted < - EPSILON)
|
||||
throw Slic3r::RuntimeError("Custom G-code reports negative Z-hop. Final Z position is below the print_z height.");
|
||||
// In case that retract_lift == layer_height we could end up with almost zero in_m_lifted
|
||||
// and a retract could be skipped (https://github.com/prusa3d/PrusaSlicer/issues/2154
|
||||
if (m_lifted < EPSILON)
|
||||
m_lifted = 0.;
|
||||
m_pos = new_pos;
|
||||
}
|
||||
|
||||
std::string GCodeWriter::set_fan(const GCodeFlavor gcode_flavor, bool gcode_comments, unsigned int speed)
|
||||
{
|
||||
std::ostringstream gcode;
|
||||
|
@ -43,7 +43,8 @@ public:
|
||||
std::string postamble() const;
|
||||
std::string set_temperature(unsigned int temperature, bool wait = false, int tool = -1) const;
|
||||
std::string set_bed_temperature(unsigned int temperature, bool wait = false);
|
||||
std::string set_acceleration(unsigned int acceleration);
|
||||
std::string set_print_acceleration(unsigned int acceleration) { return set_acceleration_internal(Acceleration::Print, acceleration); }
|
||||
std::string set_travel_acceleration(unsigned int acceleration) { return set_acceleration_internal(Acceleration::Travel, acceleration); }
|
||||
std::string reset_e(bool force = false);
|
||||
std::string update_progress(unsigned int num, unsigned int tot, bool allow_100 = false) const;
|
||||
// return false if this extruder was already selected
|
||||
@ -67,7 +68,21 @@ public:
|
||||
std::string unretract();
|
||||
std::string lift();
|
||||
std::string unlift();
|
||||
|
||||
// Current position of the printer, in G-code coordinates.
|
||||
// Z coordinate of current position contains zhop. If zhop is applied (this->zhop() > 0),
|
||||
// then the print_z = this->get_position().z() - this->zhop().
|
||||
Vec3d get_position() const { return m_pos; }
|
||||
// Current Z hop value.
|
||||
double get_zhop() const { return m_lifted; }
|
||||
// Update position of the print head based on the final position returned by a custom G-code block.
|
||||
// The new position Z coordinate contains the Z-hop.
|
||||
// GCodeWriter expects the custom script to NOT change print_z, only Z-hop, thus the print_z is maintained
|
||||
// by this function while the current Z-hop accumulator is updated.
|
||||
void update_position(const Vec3d &new_pos);
|
||||
|
||||
// Returns whether this flavor supports separate print and travel acceleration.
|
||||
static bool supports_separate_travel_acceleration(GCodeFlavor flavor);
|
||||
|
||||
// To be called by the CoolingBuffer from another thread.
|
||||
static std::string set_fan(const GCodeFlavor gcode_flavor, bool gcode_comments, unsigned int speed);
|
||||
@ -81,17 +96,26 @@ private:
|
||||
std::string m_extrusion_axis;
|
||||
bool m_single_extruder_multi_material;
|
||||
Extruder* m_extruder;
|
||||
unsigned int m_last_acceleration;
|
||||
unsigned int m_last_acceleration = (unsigned int)(-1);
|
||||
unsigned int m_last_travel_acceleration = (unsigned int)(-1); // only used for flavors supporting separate print/travel acc
|
||||
// Limit for setting the acceleration, to respect the machine limits set for the Marlin firmware.
|
||||
// If set to zero, the limit is not in action.
|
||||
unsigned int m_max_acceleration;
|
||||
unsigned int m_max_travel_acceleration;
|
||||
|
||||
unsigned int m_last_bed_temperature;
|
||||
bool m_last_bed_temperature_reached;
|
||||
double m_lifted;
|
||||
Vec3d m_pos = Vec3d::Zero();
|
||||
|
||||
enum class Acceleration {
|
||||
Travel,
|
||||
Print
|
||||
};
|
||||
|
||||
std::string _travel_to_z(double z, const std::string &comment);
|
||||
std::string _retract(double length, double restart_extra, const std::string &comment);
|
||||
std::string set_acceleration_internal(Acceleration type, unsigned int acceleration);
|
||||
};
|
||||
|
||||
class GCodeFormatter {
|
||||
|
@ -395,7 +395,6 @@ Vec3d extract_rotation(const Transform3d& transform)
|
||||
return extract_rotation(m);
|
||||
}
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
Transform3d Transformation::get_offset_matrix() const
|
||||
{
|
||||
return translation_transform(get_offset());
|
||||
@ -461,57 +460,12 @@ Transform3d Transformation::get_rotation_matrix() const
|
||||
{
|
||||
return extract_rotation_matrix(m_matrix);
|
||||
}
|
||||
#else
|
||||
bool Transformation::Flags::needs_update(bool dont_translate, bool dont_rotate, bool dont_scale, bool dont_mirror) const
|
||||
{
|
||||
return (this->dont_translate != dont_translate) || (this->dont_rotate != dont_rotate) || (this->dont_scale != dont_scale) || (this->dont_mirror != dont_mirror);
|
||||
}
|
||||
|
||||
void Transformation::Flags::set(bool dont_translate, bool dont_rotate, bool dont_scale, bool dont_mirror)
|
||||
{
|
||||
this->dont_translate = dont_translate;
|
||||
this->dont_rotate = dont_rotate;
|
||||
this->dont_scale = dont_scale;
|
||||
this->dont_mirror = dont_mirror;
|
||||
}
|
||||
|
||||
Transformation::Transformation()
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
Transformation::Transformation(const Transform3d& transform)
|
||||
{
|
||||
set_from_transform(transform);
|
||||
}
|
||||
|
||||
void Transformation::set_offset(const Vec3d& offset)
|
||||
{
|
||||
set_offset(X, offset.x());
|
||||
set_offset(Y, offset.y());
|
||||
set_offset(Z, offset.z());
|
||||
}
|
||||
|
||||
void Transformation::set_offset(Axis axis, double offset)
|
||||
{
|
||||
if (m_offset(axis) != offset) {
|
||||
m_offset(axis) = offset;
|
||||
m_dirty = true;
|
||||
}
|
||||
}
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
void Transformation::set_rotation(const Vec3d& rotation)
|
||||
{
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
const Vec3d offset = get_offset();
|
||||
m_matrix = rotation_transform(rotation) * extract_scale(m_matrix);
|
||||
m_matrix.translation() = offset;
|
||||
#else
|
||||
set_rotation(X, rotation.x());
|
||||
set_rotation(Y, rotation.y());
|
||||
set_rotation(Z, rotation.z());
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
}
|
||||
|
||||
void Transformation::set_rotation(Axis axis, double rotation)
|
||||
@ -520,7 +474,6 @@ void Transformation::set_rotation(Axis axis, double rotation)
|
||||
if (is_approx(std::abs(rotation), 2.0 * double(PI)))
|
||||
rotation = 0.0;
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
auto [curr_rotation, scale] = extract_rotation_scale(m_matrix);
|
||||
Vec3d angles = extract_rotation(curr_rotation);
|
||||
angles[axis] = rotation;
|
||||
@ -528,15 +481,8 @@ void Transformation::set_rotation(Axis axis, double rotation)
|
||||
const Vec3d offset = get_offset();
|
||||
m_matrix = rotation_transform(angles) * scale;
|
||||
m_matrix.translation() = offset;
|
||||
#else
|
||||
if (m_rotation(axis) != rotation) {
|
||||
m_rotation(axis) = rotation;
|
||||
m_dirty = true;
|
||||
}
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
}
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
Vec3d Transformation::get_scaling_factor() const
|
||||
{
|
||||
const Transform3d scale = extract_scale(m_matrix);
|
||||
@ -551,26 +497,18 @@ Transform3d Transformation::get_scaling_factor_matrix() const
|
||||
scale(2, 2) = std::abs(scale(2, 2));
|
||||
return scale;
|
||||
}
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
void Transformation::set_scaling_factor(const Vec3d& scaling_factor)
|
||||
{
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
assert(scaling_factor.x() > 0.0 && scaling_factor.y() > 0.0 && scaling_factor.z() > 0.0);
|
||||
|
||||
const Vec3d offset = get_offset();
|
||||
m_matrix = extract_rotation_matrix(m_matrix) * scale_transform(scaling_factor);
|
||||
m_matrix.translation() = offset;
|
||||
#else
|
||||
set_scaling_factor(X, scaling_factor.x());
|
||||
set_scaling_factor(Y, scaling_factor.y());
|
||||
set_scaling_factor(Z, scaling_factor.z());
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
}
|
||||
|
||||
void Transformation::set_scaling_factor(Axis axis, double scaling_factor)
|
||||
{
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
assert(scaling_factor > 0.0);
|
||||
|
||||
auto [rotation, scale] = extract_rotation_scale(m_matrix);
|
||||
@ -579,15 +517,8 @@ void Transformation::set_scaling_factor(Axis axis, double scaling_factor)
|
||||
const Vec3d offset = get_offset();
|
||||
m_matrix = rotation * scale;
|
||||
m_matrix.translation() = offset;
|
||||
#else
|
||||
if (m_scaling_factor(axis) != std::abs(scaling_factor)) {
|
||||
m_scaling_factor(axis) = std::abs(scaling_factor);
|
||||
m_dirty = true;
|
||||
}
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
}
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
Vec3d Transformation::get_mirror() const
|
||||
{
|
||||
const Transform3d scale = extract_scale(m_matrix);
|
||||
@ -602,11 +533,9 @@ Transform3d Transformation::get_mirror_matrix() const
|
||||
scale(2, 2) = scale(2, 2) / std::abs(scale(2, 2));
|
||||
return scale;
|
||||
}
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
void Transformation::set_mirror(const Vec3d& mirror)
|
||||
{
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
Vec3d copy(mirror);
|
||||
const Vec3d abs_mirror = copy.cwiseAbs();
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
@ -627,11 +556,6 @@ void Transformation::set_mirror(const Vec3d& mirror)
|
||||
const Vec3d offset = get_offset();
|
||||
m_matrix = rotation * scale;
|
||||
m_matrix.translation() = offset;
|
||||
#else
|
||||
set_mirror(X, mirror.x());
|
||||
set_mirror(Y, mirror.y());
|
||||
set_mirror(Z, mirror.z());
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
}
|
||||
|
||||
void Transformation::set_mirror(Axis axis, double mirror)
|
||||
@ -642,7 +566,6 @@ void Transformation::set_mirror(Axis axis, double mirror)
|
||||
else if (abs_mirror != 1.0)
|
||||
mirror /= abs_mirror;
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
auto [rotation, scale] = extract_rotation_scale(m_matrix);
|
||||
const double curr_scale = scale(axis, axis);
|
||||
const double sign = curr_scale * mirror;
|
||||
@ -652,74 +575,18 @@ void Transformation::set_mirror(Axis axis, double mirror)
|
||||
const Vec3d offset = get_offset();
|
||||
m_matrix = rotation * scale;
|
||||
m_matrix.translation() = offset;
|
||||
#else
|
||||
if (m_mirror(axis) != mirror) {
|
||||
m_mirror(axis) = mirror;
|
||||
m_dirty = true;
|
||||
}
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
}
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
bool Transformation::has_skew() const
|
||||
{
|
||||
return contains_skew(m_matrix);
|
||||
}
|
||||
#else
|
||||
void Transformation::set_from_transform(const Transform3d& transform)
|
||||
{
|
||||
// offset
|
||||
set_offset(transform.matrix().block(0, 3, 3, 1));
|
||||
|
||||
Eigen::Matrix<double, 3, 3, Eigen::DontAlign> m3x3 = transform.matrix().block(0, 0, 3, 3);
|
||||
|
||||
// mirror
|
||||
// it is impossible to reconstruct the original mirroring factors from a matrix,
|
||||
// we can only detect if the matrix contains a left handed reference system
|
||||
// in which case we reorient it back to right handed by mirroring the x axis
|
||||
Vec3d mirror = Vec3d::Ones();
|
||||
if (m3x3.col(0).dot(m3x3.col(1).cross(m3x3.col(2))) < 0.0) {
|
||||
mirror.x() = -1.0;
|
||||
// remove mirror
|
||||
m3x3.col(0) *= -1.0;
|
||||
}
|
||||
set_mirror(mirror);
|
||||
|
||||
// scale
|
||||
set_scaling_factor(Vec3d(m3x3.col(0).norm(), m3x3.col(1).norm(), m3x3.col(2).norm()));
|
||||
|
||||
// remove scale
|
||||
m3x3.col(0).normalize();
|
||||
m3x3.col(1).normalize();
|
||||
m3x3.col(2).normalize();
|
||||
|
||||
// rotation
|
||||
set_rotation(extract_rotation(m3x3));
|
||||
|
||||
// forces matrix recalculation matrix
|
||||
m_matrix = get_matrix();
|
||||
|
||||
// // debug check
|
||||
// if (!m_matrix.isApprox(transform))
|
||||
// std::cout << "something went wrong in extracting data from matrix" << std::endl;
|
||||
}
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
void Transformation::reset()
|
||||
{
|
||||
#if !ENABLE_WORLD_COORDINATE
|
||||
m_offset = Vec3d::Zero();
|
||||
m_rotation = Vec3d::Zero();
|
||||
m_scaling_factor = Vec3d::Ones();
|
||||
m_mirror = Vec3d::Ones();
|
||||
#endif // !ENABLE_WORLD_COORDINATE
|
||||
m_matrix = Transform3d::Identity();
|
||||
#if !ENABLE_WORLD_COORDINATE
|
||||
m_dirty = false;
|
||||
#endif // !ENABLE_WORLD_COORDINATE
|
||||
}
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
void Transformation::reset_rotation()
|
||||
{
|
||||
const Geometry::TransformationSVD svd(*this);
|
||||
@ -755,88 +622,12 @@ Transform3d Transformation::get_matrix_no_scaling_factor() const
|
||||
copy.reset_scaling_factor();
|
||||
return copy.get_matrix();
|
||||
}
|
||||
#else
|
||||
const Transform3d& Transformation::get_matrix(bool dont_translate, bool dont_rotate, bool dont_scale, bool dont_mirror) const
|
||||
{
|
||||
if (m_dirty || m_flags.needs_update(dont_translate, dont_rotate, dont_scale, dont_mirror)) {
|
||||
m_matrix = Geometry::assemble_transform(
|
||||
dont_translate ? Vec3d::Zero() : m_offset,
|
||||
dont_rotate ? Vec3d::Zero() : m_rotation,
|
||||
dont_scale ? Vec3d::Ones() : m_scaling_factor,
|
||||
dont_mirror ? Vec3d::Ones() : m_mirror
|
||||
);
|
||||
|
||||
m_flags.set(dont_translate, dont_rotate, dont_scale, dont_mirror);
|
||||
m_dirty = false;
|
||||
}
|
||||
|
||||
return m_matrix;
|
||||
}
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
Transformation Transformation::operator * (const Transformation& other) const
|
||||
{
|
||||
return Transformation(get_matrix() * other.get_matrix());
|
||||
}
|
||||
|
||||
#if !ENABLE_WORLD_COORDINATE
|
||||
Transformation Transformation::volume_to_bed_transformation(const Transformation& instance_transformation, const BoundingBoxf3& bbox)
|
||||
{
|
||||
Transformation out;
|
||||
|
||||
if (instance_transformation.is_scaling_uniform()) {
|
||||
// No need to run the non-linear least squares fitting for uniform scaling.
|
||||
// Just set the inverse.
|
||||
out.set_from_transform(instance_transformation.get_matrix(true).inverse());
|
||||
}
|
||||
else if (is_rotation_ninety_degrees(instance_transformation.get_rotation())) {
|
||||
// Anisotropic scaling, rotation by multiples of ninety degrees.
|
||||
Eigen::Matrix3d instance_rotation_trafo =
|
||||
(Eigen::AngleAxisd(instance_transformation.get_rotation().z(), Vec3d::UnitZ()) *
|
||||
Eigen::AngleAxisd(instance_transformation.get_rotation().y(), Vec3d::UnitY()) *
|
||||
Eigen::AngleAxisd(instance_transformation.get_rotation().x(), Vec3d::UnitX())).toRotationMatrix();
|
||||
Eigen::Matrix3d volume_rotation_trafo =
|
||||
(Eigen::AngleAxisd(-instance_transformation.get_rotation().x(), Vec3d::UnitX()) *
|
||||
Eigen::AngleAxisd(-instance_transformation.get_rotation().y(), Vec3d::UnitY()) *
|
||||
Eigen::AngleAxisd(-instance_transformation.get_rotation().z(), Vec3d::UnitZ())).toRotationMatrix();
|
||||
|
||||
// 8 corners of the bounding box.
|
||||
auto pts = Eigen::MatrixXd(8, 3);
|
||||
pts(0, 0) = bbox.min.x(); pts(0, 1) = bbox.min.y(); pts(0, 2) = bbox.min.z();
|
||||
pts(1, 0) = bbox.min.x(); pts(1, 1) = bbox.min.y(); pts(1, 2) = bbox.max.z();
|
||||
pts(2, 0) = bbox.min.x(); pts(2, 1) = bbox.max.y(); pts(2, 2) = bbox.min.z();
|
||||
pts(3, 0) = bbox.min.x(); pts(3, 1) = bbox.max.y(); pts(3, 2) = bbox.max.z();
|
||||
pts(4, 0) = bbox.max.x(); pts(4, 1) = bbox.min.y(); pts(4, 2) = bbox.min.z();
|
||||
pts(5, 0) = bbox.max.x(); pts(5, 1) = bbox.min.y(); pts(5, 2) = bbox.max.z();
|
||||
pts(6, 0) = bbox.max.x(); pts(6, 1) = bbox.max.y(); pts(6, 2) = bbox.min.z();
|
||||
pts(7, 0) = bbox.max.x(); pts(7, 1) = bbox.max.y(); pts(7, 2) = bbox.max.z();
|
||||
|
||||
// Corners of the bounding box transformed into the modifier mesh coordinate space, with inverse rotation applied to the modifier.
|
||||
auto qs = pts *
|
||||
(instance_rotation_trafo *
|
||||
Eigen::Scaling(instance_transformation.get_scaling_factor().cwiseProduct(instance_transformation.get_mirror())) *
|
||||
volume_rotation_trafo).inverse().transpose();
|
||||
// Fill in scaling based on least squares fitting of the bounding box corners.
|
||||
Vec3d scale;
|
||||
for (int i = 0; i < 3; ++i)
|
||||
scale(i) = pts.col(i).dot(qs.col(i)) / pts.col(i).dot(pts.col(i));
|
||||
|
||||
out.set_rotation(Geometry::extract_rotation(volume_rotation_trafo));
|
||||
out.set_scaling_factor(Vec3d(std::abs(scale.x()), std::abs(scale.y()), std::abs(scale.z())));
|
||||
out.set_mirror(Vec3d(scale.x() > 0 ? 1. : -1, scale.y() > 0 ? 1. : -1, scale.z() > 0 ? 1. : -1));
|
||||
}
|
||||
else {
|
||||
// General anisotropic scaling, general rotation.
|
||||
// Keep the modifier mesh in the instance coordinate system, so the modifier mesh will not be aligned with the world.
|
||||
// Scale it to get the required size.
|
||||
out.set_scaling_factor(instance_transformation.get_scaling_factor().cwiseInverse());
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
#endif // !ENABLE_WORLD_COORDINATE
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
TransformationSVD::TransformationSVD(const Transform3d& trafo)
|
||||
{
|
||||
const auto &m0 = trafo.matrix().block<3, 3>(0, 0);
|
||||
@ -883,7 +674,6 @@ TransformationSVD::TransformationSVD(const Transform3d& trafo)
|
||||
} else
|
||||
skew = false;
|
||||
}
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
// For parsing a transformation matrix from 3MF / AMF.
|
||||
Transform3d transform3d_from_string(const std::string& transform_str)
|
||||
|
@ -389,32 +389,9 @@ Vec3d extract_rotation(const Transform3d& transform);
|
||||
|
||||
class Transformation
|
||||
{
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
Transform3d m_matrix{ Transform3d::Identity() };
|
||||
#else
|
||||
struct Flags
|
||||
{
|
||||
bool dont_translate{ true };
|
||||
bool dont_rotate{ true };
|
||||
bool dont_scale{ true };
|
||||
bool dont_mirror{ true };
|
||||
|
||||
bool needs_update(bool dont_translate, bool dont_rotate, bool dont_scale, bool dont_mirror) const;
|
||||
void set(bool dont_translate, bool dont_rotate, bool dont_scale, bool dont_mirror);
|
||||
};
|
||||
|
||||
Vec3d m_offset{ Vec3d::Zero() }; // In unscaled coordinates
|
||||
Vec3d m_rotation{ Vec3d::Zero() }; // Rotation around the three axes, in radians around mesh center point
|
||||
Vec3d m_scaling_factor{ Vec3d::Ones() }; // Scaling factors along the three axes
|
||||
Vec3d m_mirror{ Vec3d::Ones() }; // Mirroring along the three axes
|
||||
|
||||
mutable Transform3d m_matrix{ Transform3d::Identity() };
|
||||
mutable Flags m_flags;
|
||||
mutable bool m_dirty{ false };
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
public:
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
Transformation() = default;
|
||||
explicit Transformation(const Transform3d& transform) : m_matrix(transform) {}
|
||||
|
||||
@ -430,26 +407,10 @@ public:
|
||||
double get_rotation(Axis axis) const { return get_rotation()[axis]; }
|
||||
|
||||
Transform3d get_rotation_matrix() const;
|
||||
#else
|
||||
Transformation();
|
||||
explicit Transformation(const Transform3d& transform);
|
||||
|
||||
const Vec3d& get_offset() const { return m_offset; }
|
||||
double get_offset(Axis axis) const { return m_offset(axis); }
|
||||
|
||||
void set_offset(const Vec3d& offset);
|
||||
void set_offset(Axis axis, double offset);
|
||||
|
||||
const Vec3d& get_rotation() const { return m_rotation; }
|
||||
double get_rotation(Axis axis) const { return m_rotation(axis); }
|
||||
|
||||
Transform3d get_rotation_matrix() const { return rotation_transform(get_rotation()); }
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
void set_rotation(const Vec3d& rotation);
|
||||
void set_rotation(Axis axis, double rotation);
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
Vec3d get_scaling_factor() const;
|
||||
double get_scaling_factor(Axis axis) const { return get_scaling_factor()[axis]; }
|
||||
|
||||
@ -459,17 +420,10 @@ public:
|
||||
const Vec3d scale = get_scaling_factor();
|
||||
return std::abs(scale.x() - scale.y()) < 1e-8 && std::abs(scale.x() - scale.z()) < 1e-8;
|
||||
}
|
||||
#else
|
||||
const Vec3d& get_scaling_factor() const { return m_scaling_factor; }
|
||||
double get_scaling_factor(Axis axis) const { return m_scaling_factor(axis); }
|
||||
|
||||
Transform3d get_scaling_factor_matrix() const { return scale_transform(get_scaling_factor()); }
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
void set_scaling_factor(const Vec3d& scaling_factor);
|
||||
void set_scaling_factor(Axis axis, double scaling_factor);
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
Vec3d get_mirror() const;
|
||||
double get_mirror(Axis axis) const { return get_mirror()[axis]; }
|
||||
|
||||
@ -478,25 +432,13 @@ public:
|
||||
bool is_left_handed() const {
|
||||
return m_matrix.linear().determinant() < 0;
|
||||
}
|
||||
#else
|
||||
bool is_scaling_uniform() const { return std::abs(m_scaling_factor.x() - m_scaling_factor.y()) < 1e-8 && std::abs(m_scaling_factor.x() - m_scaling_factor.z()) < 1e-8; }
|
||||
|
||||
const Vec3d& get_mirror() const { return m_mirror; }
|
||||
double get_mirror(Axis axis) const { return m_mirror(axis); }
|
||||
bool is_left_handed() const { return m_mirror.x() * m_mirror.y() * m_mirror.z() < 0.; }
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
void set_mirror(const Vec3d& mirror);
|
||||
void set_mirror(Axis axis, double mirror);
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
bool has_skew() const;
|
||||
#else
|
||||
void set_from_transform(const Transform3d& transform);
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
void reset();
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
void reset_offset() { set_offset(Vec3d::Zero()); }
|
||||
void reset_rotation();
|
||||
void reset_scaling_factor();
|
||||
@ -508,22 +450,11 @@ public:
|
||||
Transform3d get_matrix_no_scaling_factor() const;
|
||||
|
||||
void set_matrix(const Transform3d& transform) { m_matrix = transform; }
|
||||
#else
|
||||
const Transform3d& get_matrix(bool dont_translate = false, bool dont_rotate = false, bool dont_scale = false, bool dont_mirror = false) const;
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
Transformation operator * (const Transformation& other) const;
|
||||
|
||||
#if !ENABLE_WORLD_COORDINATE
|
||||
// Find volume transformation, so that the chained (instance_trafo * volume_trafo) will be as close to identity
|
||||
// as possible in least squares norm in regard to the 8 corners of bbox.
|
||||
// Bounding box is expected to be centered around zero in all axes.
|
||||
static Transformation volume_to_bed_transformation(const Transformation& instance_transformation, const BoundingBoxf3& bbox);
|
||||
#endif // !ENABLE_WORLD_COORDINATE
|
||||
|
||||
private:
|
||||
friend class cereal::access;
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
template<class Archive> void serialize(Archive& ar) { ar(m_matrix); }
|
||||
explicit Transformation(int) {}
|
||||
template <class Archive> static void load_and_construct(Archive& ar, cereal::construct<Transformation>& construct)
|
||||
@ -532,24 +463,13 @@ private:
|
||||
construct(1);
|
||||
ar(construct.ptr()->m_matrix);
|
||||
}
|
||||
#else
|
||||
template<class Archive> void serialize(Archive& ar) { ar(m_offset, m_rotation, m_scaling_factor, m_mirror); }
|
||||
explicit Transformation(int) : m_dirty(true) {}
|
||||
template <class Archive> static void load_and_construct(Archive& ar, cereal::construct<Transformation>& construct)
|
||||
{
|
||||
// Calling a private constructor with special "int" parameter to indicate that no construction is necessary.
|
||||
construct(1);
|
||||
ar(construct.ptr()->m_offset, construct.ptr()->m_rotation, construct.ptr()->m_scaling_factor, construct.ptr()->m_mirror);
|
||||
}
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
};
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
struct TransformationSVD
|
||||
{
|
||||
Matrix3d u = Matrix3d::Identity();
|
||||
Matrix3d s = Matrix3d::Identity();
|
||||
Matrix3d v = Matrix3d::Identity();
|
||||
Matrix3d u{ Matrix3d::Identity() };
|
||||
Matrix3d s{ Matrix3d::Identity() };
|
||||
Matrix3d v{ Matrix3d::Identity() };
|
||||
|
||||
bool mirror{ false };
|
||||
bool scale{ false };
|
||||
@ -563,7 +483,6 @@ struct TransformationSVD
|
||||
|
||||
Eigen::DiagonalMatrix<double, 3, 3> mirror_matrix() const { return Eigen::DiagonalMatrix<double, 3, 3>(this->mirror ? -1. : 1., 1., 1.); }
|
||||
};
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
// For parsing a transformation matrix from 3MF / AMF.
|
||||
extern Transform3d transform3d_from_string(const std::string& transform_str);
|
||||
|
@ -128,7 +128,7 @@ inline static Linef make_linef(const VD::edge_type &edge)
|
||||
return {Vec2d(v0->x(), v0->y()), Vec2d(v1->x(), v1->y())};
|
||||
}
|
||||
|
||||
inline static bool is_equal(const VD::vertex_type &first, const VD::vertex_type &second) { return first.x() == second.x() && first.y() == second.y(); }
|
||||
[[maybe_unused]] inline static bool is_equal(const VD::vertex_type &first, const VD::vertex_type &second) { return first.x() == second.x() && first.y() == second.y(); }
|
||||
|
||||
// FIXME Lukas H.: Also includes parabolic segments.
|
||||
bool VoronoiUtilsCgal::is_voronoi_diagram_planar_intersection(const VD &voronoi_diagram)
|
||||
|
@ -3,6 +3,12 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
#ifdef SLIC3R_CURRENTLY_COMPILING_GUI_MODULE
|
||||
#ifndef SLIC3R_ALLOW_LIBSLIC3R_I18N_IN_SLIC3R
|
||||
#error You included libslic3r/I18N.hpp into a file belonging to slic3r module.
|
||||
#endif
|
||||
#endif
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
namespace I18N {
|
||||
@ -15,4 +21,17 @@ namespace I18N {
|
||||
|
||||
} // namespace Slic3r
|
||||
|
||||
// When this is included from slic3r, better do not define the translation functions.
|
||||
// Macros from slic3r/GUI/I18N.hpp should be used there.
|
||||
#ifndef SLIC3R_CURRENTLY_COMPILING_GUI_MODULE
|
||||
#ifdef L
|
||||
#error L macro is defined where it shouldn't be. Didn't you include slic3r/GUI/I18N.hpp in libslic3r by mistake?
|
||||
#endif
|
||||
namespace {
|
||||
[[maybe_unused]] const char* L(const char* s) { return s; }
|
||||
[[maybe_unused]] const char* L_CONTEXT(const char* s, const char* context) { return s; }
|
||||
[[maybe_unused]] std::string _u8L(const char* s) { return Slic3r::I18N::translate(s); }
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* slic3r_I18N_hpp_ */
|
||||
|
@ -727,7 +727,7 @@ void LayerRegion::prepare_fill_surfaces()
|
||||
if (! spiral_vase && this->region().config().top_solid_layers == 0) {
|
||||
for (Surface &surface : m_fill_surfaces)
|
||||
if (surface.is_top())
|
||||
surface.surface_type = this->layer()->object()->config().infill_only_where_needed && this->region().config().fill_pattern != ipLightning ? stInternalVoid : stInternal;
|
||||
surface.surface_type = /*this->layer()->object()->config().infill_only_where_needed && this->region().config().fill_pattern != ipLightning ? stInternalVoid :*/ stInternal;
|
||||
}
|
||||
if (this->region().config().bottom_solid_layers == 0) {
|
||||
for (Surface &surface : m_fill_surfaces)
|
||||
|
@ -1030,11 +1030,7 @@ const BoundingBoxf3& ModelObject::raw_bounding_box() const
|
||||
if (this->instances.empty())
|
||||
throw Slic3r::InvalidArgument("Can't call raw_bounding_box() with no instances");
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
const Transform3d inst_matrix = this->instances.front()->get_transformation().get_matrix_no_offset();
|
||||
#else
|
||||
const Transform3d& inst_matrix = this->instances.front()->get_transformation().get_matrix(true);
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
for (const ModelVolume *v : this->volumes)
|
||||
if (v->is_model_part())
|
||||
m_raw_bounding_box.merge(v->mesh().transformed_bounding_box(inst_matrix * v->get_matrix()));
|
||||
@ -1046,14 +1042,10 @@ const BoundingBoxf3& ModelObject::raw_bounding_box() const
|
||||
BoundingBoxf3 ModelObject::instance_bounding_box(size_t instance_idx, bool dont_translate) const
|
||||
{
|
||||
BoundingBoxf3 bb;
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
const Transform3d inst_matrix = dont_translate ?
|
||||
this->instances[instance_idx]->get_transformation().get_matrix_no_offset() :
|
||||
this->instances[instance_idx]->get_transformation().get_matrix();
|
||||
|
||||
#else
|
||||
const Transform3d& inst_matrix = this->instances[instance_idx]->get_transformation().get_matrix(dont_translate);
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
for (ModelVolume *v : this->volumes) {
|
||||
if (v->is_model_part())
|
||||
bb.merge(v->mesh().transformed_bounding_box(inst_matrix * v->get_matrix()));
|
||||
@ -1688,17 +1680,7 @@ ModelObjectPtrs ModelObject::cut(size_t instance, const Transform3d& cut_matrix,
|
||||
// in the transformation matrix and not applied to the mesh transform.
|
||||
|
||||
// const auto instance_matrix = instances[instance]->get_matrix(true);
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
const auto instance_matrix = instances[instance]->get_transformation().get_matrix_no_offset();
|
||||
#else
|
||||
const auto instance_matrix = assemble_transform(
|
||||
Vec3d::Zero(), // don't apply offset
|
||||
instances[instance]->get_rotation(),
|
||||
instances[instance]->get_scaling_factor(),
|
||||
instances[instance]->get_mirror()
|
||||
);
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
const Transformation cut_transformation = Transformation(cut_matrix);
|
||||
const Transform3d inverse_cut_matrix = cut_transformation.get_rotation_matrix().inverse() * translation_transform(-1. * cut_transformation.get_offset());
|
||||
|
||||
@ -1840,11 +1822,7 @@ void ModelObject::split(ModelObjectPtrs* new_objects)
|
||||
new_vol->config.set_key_value("extruder", new ConfigOptionInt(0));
|
||||
|
||||
for (ModelInstance* model_instance : new_object->instances) {
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
Vec3d shift = model_instance->get_transformation().get_matrix_no_offset() * new_vol->get_offset();
|
||||
#else
|
||||
Vec3d shift = model_instance->get_transformation().get_matrix(true) * new_vol->get_offset();
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
const Vec3d shift = model_instance->get_transformation().get_matrix_no_offset() * new_vol->get_offset();
|
||||
model_instance->set_offset(model_instance->get_offset() + shift);
|
||||
}
|
||||
|
||||
@ -1886,12 +1864,6 @@ void ModelObject::bake_xy_rotation_into_meshes(size_t instance_idx)
|
||||
assert(instance_idx < this->instances.size());
|
||||
|
||||
const Geometry::Transformation reference_trafo = this->instances[instance_idx]->get_transformation();
|
||||
#if !ENABLE_WORLD_COORDINATE
|
||||
if (Geometry::is_rotation_ninety_degrees(reference_trafo.get_rotation()))
|
||||
// nothing to do, scaling in the world coordinate space is possible in the representation of Geometry::Transformation.
|
||||
return;
|
||||
#endif // !ENABLE_WORLD_COORDINATE
|
||||
|
||||
bool left_handed = reference_trafo.is_left_handed();
|
||||
bool has_mirrorring = ! reference_trafo.get_mirror().isApprox(Vec3d(1., 1., 1.));
|
||||
bool uniform_scaling = std::abs(reference_trafo.get_scaling_factor().x() - reference_trafo.get_scaling_factor().y()) < EPSILON &&
|
||||
@ -1908,7 +1880,6 @@ void ModelObject::bake_xy_rotation_into_meshes(size_t instance_idx)
|
||||
|
||||
// Adjust the meshes.
|
||||
// Transformation to be applied to the meshes.
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
Geometry::Transformation reference_trafo_mod = reference_trafo;
|
||||
reference_trafo_mod.reset_offset();
|
||||
if (uniform_scaling)
|
||||
@ -1916,9 +1887,6 @@ void ModelObject::bake_xy_rotation_into_meshes(size_t instance_idx)
|
||||
if (!has_mirrorring)
|
||||
reference_trafo_mod.reset_mirror();
|
||||
Eigen::Matrix3d mesh_trafo_3x3 = reference_trafo_mod.get_matrix().matrix().block<3, 3>(0, 0);
|
||||
#else
|
||||
Eigen::Matrix3d mesh_trafo_3x3 = reference_trafo.get_matrix(true, false, uniform_scaling, ! has_mirrorring).matrix().block<3, 3>(0, 0);
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
Transform3d volume_offset_correction = this->instances[instance_idx]->get_transformation().get_matrix().inverse() * reference_trafo.get_matrix();
|
||||
for (ModelVolume *model_volume : this->volumes) {
|
||||
const Geometry::Transformation volume_trafo = model_volume->get_transformation();
|
||||
@ -1928,7 +1896,6 @@ void ModelObject::bake_xy_rotation_into_meshes(size_t instance_idx)
|
||||
std::abs(volume_trafo.get_scaling_factor().x() - volume_trafo.get_scaling_factor().z()) < EPSILON;
|
||||
double volume_new_scaling_factor = volume_uniform_scaling ? volume_trafo.get_scaling_factor().x() : 1.;
|
||||
// Transform the mesh.
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
Geometry::Transformation volume_trafo_mod = volume_trafo;
|
||||
volume_trafo_mod.reset_offset();
|
||||
if (volume_uniform_scaling)
|
||||
@ -1936,9 +1903,6 @@ void ModelObject::bake_xy_rotation_into_meshes(size_t instance_idx)
|
||||
if (!volume_has_mirrorring)
|
||||
volume_trafo_mod.reset_mirror();
|
||||
Eigen::Matrix3d volume_trafo_3x3 = volume_trafo_mod.get_matrix().matrix().block<3, 3>(0, 0);
|
||||
#else
|
||||
Matrix3d volume_trafo_3x3 = volume_trafo.get_matrix(true, false, volume_uniform_scaling, !volume_has_mirrorring).matrix().block<3, 3>(0, 0);
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
// Following method creates a new shared_ptr<TriangleMesh>
|
||||
model_volume->transform_this_mesh(mesh_trafo_3x3 * volume_trafo_3x3, left_handed != volume_left_handed);
|
||||
// Reset the rotation, scaling and mirroring.
|
||||
@ -1959,11 +1923,7 @@ double ModelObject::get_instance_min_z(size_t instance_idx) const
|
||||
double min_z = DBL_MAX;
|
||||
|
||||
const ModelInstance* inst = instances[instance_idx];
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
const Transform3d mi = inst->get_matrix_no_offset();
|
||||
#else
|
||||
const Transform3d& mi = inst->get_matrix(true);
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
for (const ModelVolume* v : volumes) {
|
||||
if (!v->is_model_part())
|
||||
@ -1984,11 +1944,7 @@ double ModelObject::get_instance_max_z(size_t instance_idx) const
|
||||
double max_z = -DBL_MAX;
|
||||
|
||||
const ModelInstance* inst = instances[instance_idx];
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
const Transform3d mi = inst->get_matrix_no_offset();
|
||||
#else
|
||||
const Transform3d& mi = inst->get_matrix(true);
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
for (const ModelVolume* v : volumes) {
|
||||
if (!v->is_model_part())
|
||||
@ -2428,29 +2384,17 @@ void ModelVolume::convert_from_meters()
|
||||
|
||||
void ModelInstance::transform_mesh(TriangleMesh* mesh, bool dont_translate) const
|
||||
{
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
mesh->transform(dont_translate ? get_matrix_no_offset() : get_matrix());
|
||||
#else
|
||||
mesh->transform(get_matrix(dont_translate));
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
}
|
||||
|
||||
BoundingBoxf3 ModelInstance::transform_bounding_box(const BoundingBoxf3 &bbox, bool dont_translate) const
|
||||
{
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
return bbox.transformed(dont_translate ? get_matrix_no_offset() : get_matrix());
|
||||
#else
|
||||
return bbox.transformed(get_matrix(dont_translate));
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
}
|
||||
|
||||
Vec3d ModelInstance::transform_vector(const Vec3d& v, bool dont_translate) const
|
||||
{
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
return dont_translate ? get_matrix_no_offset() * v : get_matrix() * v;
|
||||
#else
|
||||
return get_matrix(dont_translate) * v;
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
}
|
||||
|
||||
void ModelInstance::transform_polygon(Polygon* polygon) const
|
||||
|
@ -886,26 +886,16 @@ public:
|
||||
|
||||
const Geometry::Transformation& get_transformation() const { return m_transformation; }
|
||||
void set_transformation(const Geometry::Transformation& transformation) { m_transformation = transformation; }
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
void set_transformation(const Transform3d& trafo) { m_transformation.set_matrix(trafo); }
|
||||
|
||||
Vec3d get_offset() const { return m_transformation.get_offset(); }
|
||||
#else
|
||||
void set_transformation(const Transform3d &trafo) { m_transformation.set_from_transform(trafo); }
|
||||
|
||||
const Vec3d& get_offset() const { return m_transformation.get_offset(); }
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
double get_offset(Axis axis) const { return m_transformation.get_offset(axis); }
|
||||
|
||||
void set_offset(const Vec3d& offset) { m_transformation.set_offset(offset); }
|
||||
void set_offset(Axis axis, double offset) { m_transformation.set_offset(axis, offset); }
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
Vec3d get_rotation() const { return m_transformation.get_rotation(); }
|
||||
#else
|
||||
const Vec3d& get_rotation() const { return m_transformation.get_rotation(); }
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
double get_rotation(Axis axis) const { return m_transformation.get_rotation(axis); }
|
||||
|
||||
void set_rotation(const Vec3d& rotation) { m_transformation.set_rotation(rotation); }
|
||||
@ -917,11 +907,7 @@ public:
|
||||
void set_scaling_factor(const Vec3d& scaling_factor) { m_transformation.set_scaling_factor(scaling_factor); }
|
||||
void set_scaling_factor(Axis axis, double scaling_factor) { m_transformation.set_scaling_factor(axis, scaling_factor); }
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
Vec3d get_mirror() const { return m_transformation.get_mirror(); }
|
||||
#else
|
||||
const Vec3d& get_mirror() const { return m_transformation.get_mirror(); }
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
double get_mirror(Axis axis) const { return m_transformation.get_mirror(axis); }
|
||||
bool is_left_handed() const { return m_transformation.is_left_handed(); }
|
||||
|
||||
@ -930,12 +916,8 @@ public:
|
||||
void convert_from_imperial_units();
|
||||
void convert_from_meters();
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
const Transform3d& get_matrix() const { return m_transformation.get_matrix(); }
|
||||
Transform3d get_matrix_no_offset() const { return m_transformation.get_matrix_no_offset(); }
|
||||
#else
|
||||
const Transform3d& get_matrix(bool dont_translate = false, bool dont_rotate = false, bool dont_scale = false, bool dont_mirror = false) const { return m_transformation.get_matrix(dont_translate, dont_rotate, dont_scale, dont_mirror); }
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
void set_new_unique_id() {
|
||||
ObjectBase::set_new_unique_id();
|
||||
@ -1147,41 +1129,25 @@ public:
|
||||
const Geometry::Transformation& get_transformation() const { return m_transformation; }
|
||||
void set_transformation(const Geometry::Transformation& transformation) { m_transformation = transformation; }
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
Vec3d get_offset() const { return m_transformation.get_offset(); }
|
||||
#else
|
||||
const Vec3d& get_offset() const { return m_transformation.get_offset(); }
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
double get_offset(Axis axis) const { return m_transformation.get_offset(axis); }
|
||||
|
||||
void set_offset(const Vec3d& offset) { m_transformation.set_offset(offset); }
|
||||
void set_offset(Axis axis, double offset) { m_transformation.set_offset(axis, offset); }
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
Vec3d get_rotation() const { return m_transformation.get_rotation(); }
|
||||
#else
|
||||
const Vec3d& get_rotation() const { return m_transformation.get_rotation(); }
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
double get_rotation(Axis axis) const { return m_transformation.get_rotation(axis); }
|
||||
|
||||
void set_rotation(const Vec3d& rotation) { m_transformation.set_rotation(rotation); }
|
||||
void set_rotation(Axis axis, double rotation) { m_transformation.set_rotation(axis, rotation); }
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
Vec3d get_scaling_factor() const { return m_transformation.get_scaling_factor(); }
|
||||
#else
|
||||
const Vec3d& get_scaling_factor() const { return m_transformation.get_scaling_factor(); }
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
double get_scaling_factor(Axis axis) const { return m_transformation.get_scaling_factor(axis); }
|
||||
|
||||
void set_scaling_factor(const Vec3d& scaling_factor) { m_transformation.set_scaling_factor(scaling_factor); }
|
||||
void set_scaling_factor(Axis axis, double scaling_factor) { m_transformation.set_scaling_factor(axis, scaling_factor); }
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
Vec3d get_mirror() const { return m_transformation.get_mirror(); }
|
||||
#else
|
||||
const Vec3d& get_mirror() const { return m_transformation.get_mirror(); }
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
double get_mirror(Axis axis) const { return m_transformation.get_mirror(axis); }
|
||||
bool is_left_handed() const { return m_transformation.is_left_handed(); }
|
||||
|
||||
@ -1197,12 +1163,8 @@ public:
|
||||
// To be called on an external polygon. It does not translate the polygon, only rotates and scales.
|
||||
void transform_polygon(Polygon* polygon) const;
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
const Transform3d& get_matrix() const { return m_transformation.get_matrix(); }
|
||||
Transform3d get_matrix_no_offset() const { return m_transformation.get_matrix_no_offset(); }
|
||||
#else
|
||||
const Transform3d& get_matrix(bool dont_translate = false, bool dont_rotate = false, bool dont_scale = false, bool dont_mirror = false) const { return m_transformation.get_matrix(dont_translate, dont_rotate, dont_scale, dont_mirror); }
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
bool is_printable() const { return object->printable && printable && (print_volume_state == ModelInstancePVS_Inside); }
|
||||
|
||||
|
@ -1,17 +1,9 @@
|
||||
#include "NSVGUtils.hpp"
|
||||
#include "ClipperUtils.hpp"
|
||||
|
||||
using namespace Slic3r;
|
||||
|
||||
namespace Slic3r {
|
||||
// inspired by nanosvgrast.h function nsvgRasterize -> nsvg__flattenShape -> nsvg__flattenCubicBez
|
||||
// https://github.com/memononen/nanosvg/blob/f0a3e1034dd22e2e87e5db22401e44998383124e/src/nanosvgrast.h#L335
|
||||
void NSVGUtils::flatten_cubic_bez(Polygon &polygon,
|
||||
float tessTol,
|
||||
Vec2f p1,
|
||||
Vec2f p2,
|
||||
Vec2f p3,
|
||||
Vec2f p4,
|
||||
int level)
|
||||
void flatten_cubic_bez(Polygon &polygon, float tessTol, Vec2f p1, Vec2f p2, Vec2f p3, Vec2f p4, int level)
|
||||
{
|
||||
Vec2f p12 = (p1 + p2) * 0.5f;
|
||||
Vec2f p23 = (p2 + p3) * 0.5f;
|
||||
@ -31,38 +23,37 @@ void NSVGUtils::flatten_cubic_bez(Polygon &polygon,
|
||||
}
|
||||
|
||||
--level;
|
||||
if (level == 0) return;
|
||||
if (level == 0)
|
||||
return;
|
||||
Vec2f p234 = (p23 + p34) * 0.5f;
|
||||
Vec2f p1234 = (p123 + p234) * 0.5f;
|
||||
flatten_cubic_bez(polygon, tessTol, p1, p12, p123, p1234, level);
|
||||
flatten_cubic_bez(polygon, tessTol, p1234, p234, p34, p4, level);
|
||||
}
|
||||
|
||||
Polygons NSVGUtils::to_polygons(NSVGimage *image, float tessTol, int max_level)
|
||||
Polygons to_polygons(NSVGimage *image, float tessTol, int max_level, bool is_y_negative)
|
||||
{
|
||||
const float y_sign = is_y_negative ? -1.f : 1.f;
|
||||
Polygons polygons;
|
||||
for (NSVGshape *shape = image->shapes; shape != NULL;
|
||||
shape = shape->next) {
|
||||
if (!(shape->flags & NSVG_FLAGS_VISIBLE)) continue;
|
||||
Slic3r::Polygon polygon;
|
||||
if (shape->fill.type != NSVG_PAINT_NONE) {
|
||||
for (NSVGpath *path = shape->paths; path != NULL;
|
||||
path = path->next) {
|
||||
for (NSVGshape *shape = image->shapes; shape != NULL; shape = shape->next) {
|
||||
if (!(shape->flags & NSVG_FLAGS_VISIBLE))
|
||||
continue;
|
||||
if (shape->fill.type == NSVG_PAINT_NONE)
|
||||
continue;
|
||||
|
||||
Polygon polygon;
|
||||
for (NSVGpath *path = shape->paths; path != NULL; path = path->next) {
|
||||
// Flatten path
|
||||
polygon.points.emplace_back(path->pts[0], path->pts[1]);
|
||||
size_t path_size = (path->npts > 1) ?
|
||||
static_cast<size_t>(path->npts - 1) : 0;
|
||||
polygon.points.emplace_back(path->pts[0], y_sign * path->pts[1]);
|
||||
size_t path_size = (path->npts > 1) ? static_cast<size_t>(path->npts - 1) : 0;
|
||||
for (size_t i = 0; i < path_size; i += 3) {
|
||||
float *p = &path->pts[i * 2];
|
||||
Vec2f p1(p[0], p[1]), p2(p[2], p[3]), p3(p[4], p[5]),
|
||||
p4(p[6], p[7]);
|
||||
flatten_cubic_bez(polygon, tessTol, p1, p2, p3, p4,
|
||||
max_level);
|
||||
const float *p = &path->pts[i * 2];
|
||||
Vec2f p1(p[0], p[1]), p2(p[2], p[3]), p3(p[4], p[5]), p4(p[6], p[7]);
|
||||
flatten_cubic_bez(polygon, tessTol, p1, p2, p3, p4, max_level);
|
||||
}
|
||||
if (path->closed && !polygon.empty()) {
|
||||
polygons.push_back(polygon);
|
||||
polygon = Slic3r::Polygon();
|
||||
}
|
||||
polygon = Polygon();
|
||||
}
|
||||
}
|
||||
if (!polygon.empty())
|
||||
@ -71,15 +62,9 @@ Polygons NSVGUtils::to_polygons(NSVGimage *image, float tessTol, int max_level)
|
||||
return polygons;
|
||||
}
|
||||
|
||||
ExPolygons NSVGUtils::to_ExPolygons(NSVGimage *image,
|
||||
float tessTol,
|
||||
int max_level)
|
||||
ExPolygons to_expolygons(NSVGimage *image, float tessTol, int max_level, bool is_y_negative)
|
||||
{
|
||||
Polygons polygons = to_polygons(image, tessTol, max_level);
|
||||
|
||||
// Fix Y axis
|
||||
for (Polygon &polygon : polygons)
|
||||
for (Point &p : polygon.points) p.y() *= -1;
|
||||
|
||||
return Slic3r::union_ex(polygons);
|
||||
return union_ex(to_polygons(image, tessTol, max_level, is_y_negative));
|
||||
}
|
||||
|
||||
} // namespace Slic3r
|
@ -5,30 +5,32 @@
|
||||
#include "ExPolygon.hpp"
|
||||
#include "nanosvg/nanosvg.h" // load SVG file
|
||||
|
||||
// Helper function to work with nano svg
|
||||
namespace Slic3r {
|
||||
|
||||
// Helper function to work with nano svg
|
||||
class NSVGUtils
|
||||
{
|
||||
public:
|
||||
NSVGUtils() = delete;
|
||||
/// <summary>
|
||||
/// Convert cubic curve to lines
|
||||
/// Inspired by nanosvgrast.h function nsvgRasterize->nsvg__flattenShape
|
||||
/// </summary>
|
||||
/// <param name="polygon">Result points</param>
|
||||
/// <param name="tessTol">Tesselation tolerance</param>
|
||||
/// <param name="p1">Curve point</param>
|
||||
/// <param name="p2">Curve point</param>
|
||||
/// <param name="p3">Curve point</param>
|
||||
/// <param name="p4">Curve point</param>
|
||||
/// <param name="level"></param>
|
||||
void flatten_cubic_bez(Polygon &polygon, float tessTol, Vec2f p1, Vec2f p2, Vec2f p3, Vec2f p4, int level);
|
||||
|
||||
/// <summary>
|
||||
/// Convert .svg opened by nanoSvg to Polygons
|
||||
/// </summary>
|
||||
/// <param name="image">Opened file</param>
|
||||
/// <param name="tessTol">Tesselation tolerance</param>
|
||||
/// <param name="max_level">Maximal depth</param>
|
||||
/// <param name="is_y_negative">Flag is y negative, when true than y coor is multiplied by -1</param>
|
||||
/// <returns>Polygons extracted from svg</returns>
|
||||
Polygons to_polygons(NSVGimage *image, float tessTol = 10., int max_level = 10, bool is_y_negative = true);
|
||||
ExPolygons to_expolygons(NSVGimage *image, float tessTol = 10., int max_level = 10, bool is_y_negative = true);
|
||||
|
||||
// inspired by nanosvgrast.h function nsvgRasterize->nsvg__flattenShape
|
||||
static void flatten_cubic_bez(Polygon &polygon,
|
||||
float tessTol,
|
||||
Vec2f p1,
|
||||
Vec2f p2,
|
||||
Vec2f p3,
|
||||
Vec2f p4,
|
||||
int level);
|
||||
// convert svg image to ExPolygons
|
||||
static ExPolygons to_ExPolygons(NSVGimage *image,
|
||||
float tessTol = 10.,
|
||||
int max_level = 10);
|
||||
// convert svg paths to Polygons
|
||||
static Polygons to_polygons(NSVGimage *image,
|
||||
float tessTol = 10.,
|
||||
int max_level = 10);
|
||||
};
|
||||
} // namespace Slic3r
|
||||
#endif // slic3r_NSVGUtils_hpp_
|
||||
|
@ -1019,11 +1019,33 @@ std::tuple<std::vector<ExtrusionPaths>, Polygons> generate_extra_perimeters_over
|
||||
overhang_region.end());
|
||||
|
||||
if (!overhang_region.empty()) {
|
||||
// there is a special case, where the first (or last) generated overhang perimeter eats all anchor space.
|
||||
// When this happens, the first overhang perimeter is also a closed loop, and needs special check
|
||||
// instead of the following simple is_anchored lambda, which checks only the first and last point (not very useful on closed
|
||||
// polyline)
|
||||
bool first_overhang_is_closed_and_anchored =
|
||||
(overhang_region.front().first_point() == overhang_region.front().last_point() &&
|
||||
!intersection_pl(overhang_region.front().polyline, optimized_lower_slices).empty());
|
||||
|
||||
auto is_anchored = [&lower_layer_aabb_tree](const ExtrusionPath &path) {
|
||||
return lower_layer_aabb_tree.distance_from_lines<true>(path.first_point()) <= 0 ||
|
||||
lower_layer_aabb_tree.distance_from_lines<true>(path.last_point()) <= 0;
|
||||
};
|
||||
if (!first_overhang_is_closed_and_anchored) {
|
||||
std::reverse(overhang_region.begin(), overhang_region.end());
|
||||
} else {
|
||||
size_t min_dist_idx = 0;
|
||||
double min_dist = std::numeric_limits<double>::max();
|
||||
for (size_t i = 0; i < overhang_region.front().polyline.size(); i++) {
|
||||
Point p = overhang_region.front().polyline[i];
|
||||
if (double d = lower_layer_aabb_tree.distance_from_lines<true>(p) < min_dist) {
|
||||
min_dist = d;
|
||||
min_dist_idx = i;
|
||||
}
|
||||
}
|
||||
std::rotate(overhang_region.front().polyline.begin(), overhang_region.front().polyline.begin() + min_dist_idx,
|
||||
overhang_region.front().polyline.end());
|
||||
}
|
||||
auto first_unanchored = std::stable_partition(overhang_region.begin(), overhang_region.end(), is_anchored);
|
||||
int index_of_first_unanchored = first_unanchored - overhang_region.begin();
|
||||
overhang_region = sort_extra_perimeters(overhang_region, index_of_first_unanchored, overhang_flow.scaled_spacing());
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -3,6 +3,7 @@
|
||||
#include "Exception.hpp"
|
||||
#include "Preset.hpp"
|
||||
#include "AppConfig.hpp"
|
||||
#include "I18N.hpp"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
@ -10,15 +11,6 @@
|
||||
#include <Windows.h>
|
||||
#endif /* _MSC_VER */
|
||||
|
||||
// instead of #include "slic3r/GUI/I18N.hpp" :
|
||||
#ifndef L
|
||||
// !!! If you needed to translate some string,
|
||||
// !!! please use _L(string)
|
||||
// !!! _() - is a standard wxWidgets macro to translate
|
||||
// !!! L() is used only for marking localizable string
|
||||
// !!! It will be used in "xgettext" to create a Locating Message Catalog.
|
||||
#define L(s) s
|
||||
#endif /* L */
|
||||
|
||||
#include <algorithm>
|
||||
#include <fstream>
|
||||
@ -433,7 +425,7 @@ static std::vector<std::string> s_Preset_print_options {
|
||||
"top_solid_layers", "top_solid_min_thickness", "bottom_solid_layers", "bottom_solid_min_thickness",
|
||||
"extra_perimeters", "extra_perimeters_on_overhangs", "avoid_crossing_curled_overhangs", "avoid_crossing_perimeters", "thin_walls", "overhangs",
|
||||
"seam_position","staggered_inner_seams", "external_perimeters_first", "fill_density", "fill_pattern", "top_fill_pattern", "bottom_fill_pattern",
|
||||
"infill_every_layers", "infill_only_where_needed", "solid_infill_every_layers", "fill_angle", "bridge_angle",
|
||||
"infill_every_layers", /*"infill_only_where_needed",*/ "solid_infill_every_layers", "fill_angle", "bridge_angle",
|
||||
"solid_infill_below_area", "only_retract_when_crossing_perimeters", "infill_first",
|
||||
"ironing", "ironing_type", "ironing_flowrate", "ironing_speed", "ironing_spacing",
|
||||
"max_print_speed", "max_volumetric_speed", "avoid_crossing_perimeters_max_detour",
|
||||
@ -443,7 +435,7 @@ static std::vector<std::string> s_Preset_print_options {
|
||||
"enable_dynamic_overhang_speeds", "overhang_speed_0", "overhang_speed_1", "overhang_speed_2", "overhang_speed_3",
|
||||
"top_solid_infill_speed", "support_material_speed", "support_material_xy_spacing", "support_material_interface_speed",
|
||||
"bridge_speed", "gap_fill_speed", "gap_fill_enabled", "travel_speed", "travel_speed_z", "first_layer_speed", "first_layer_speed_over_raft", "perimeter_acceleration", "infill_acceleration",
|
||||
"external_perimeter_acceleration", "top_solid_infill_acceleration", "solid_infill_acceleration",
|
||||
"external_perimeter_acceleration", "top_solid_infill_acceleration", "solid_infill_acceleration", "travel_acceleration",
|
||||
"bridge_acceleration", "first_layer_acceleration", "first_layer_acceleration_over_raft", "default_acceleration", "skirts", "skirt_distance", "skirt_height", "draft_shield",
|
||||
"min_skirt_length", "brim_width", "brim_separation", "brim_type", "support_material", "support_material_auto", "support_material_threshold", "support_material_enforce_layers",
|
||||
"raft_layers", "raft_first_layer_density", "raft_first_layer_expansion", "raft_contact_distance", "raft_expansion",
|
||||
@ -460,8 +452,8 @@ static std::vector<std::string> s_Preset_print_options {
|
||||
"perimeter_extrusion_width", "external_perimeter_extrusion_width", "infill_extrusion_width", "solid_infill_extrusion_width",
|
||||
"top_infill_extrusion_width", "support_material_extrusion_width", "infill_overlap", "infill_anchor", "infill_anchor_max", "bridge_flow_ratio",
|
||||
"elefant_foot_compensation", "xy_size_compensation", "threads", "resolution", "gcode_resolution", "wipe_tower", "wipe_tower_x", "wipe_tower_y",
|
||||
"wipe_tower_width", "wipe_tower_rotation_angle", "wipe_tower_brim_width", "wipe_tower_bridging", "single_extruder_multi_material_priming", "mmu_segmented_region_max_width",
|
||||
"wipe_tower_no_sparse_layers", "compatible_printers", "compatible_printers_condition", "inherits",
|
||||
"wipe_tower_width", "wipe_tower_cone_angle", "wipe_tower_rotation_angle", "wipe_tower_brim_width", "wipe_tower_bridging", "single_extruder_multi_material_priming", "mmu_segmented_region_max_width",
|
||||
"wipe_tower_no_sparse_layers", "wipe_tower_extra_spacing", "compatible_printers", "compatible_printers_condition", "inherits",
|
||||
"perimeter_generator", "wall_transition_length", "wall_transition_filter_deviation", "wall_transition_angle",
|
||||
"wall_distribution_count", "min_feature_size", "min_bead_width"
|
||||
};
|
||||
@ -491,7 +483,7 @@ static std::vector<std::string> s_Preset_machine_limits_options {
|
||||
};
|
||||
|
||||
static std::vector<std::string> s_Preset_printer_options {
|
||||
"printer_technology",
|
||||
"printer_technology", "autoemit_temperature_commands",
|
||||
"bed_shape", "bed_custom_texture", "bed_custom_model", "z_offset", "gcode_flavor", "use_relative_e_distances",
|
||||
"use_firmware_retraction", "use_volumetric_e", "variable_layer_height",
|
||||
//FIXME the print host keys are left here just for conversion from the Printer preset to Physical Printer preset.
|
||||
|
@ -27,8 +27,6 @@
|
||||
#include <boost/log/trivial.hpp>
|
||||
#include <boost/regex.hpp>
|
||||
|
||||
// Mark string for localization and translate.
|
||||
#define L(s) Slic3r::I18N::translate(s)
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
@ -60,6 +58,7 @@ bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* n
|
||||
// Cache the plenty of parameters, which influence the G-code generator only,
|
||||
// or they are only notes not influencing the generated G-code.
|
||||
static std::unordered_set<std::string> steps_gcode = {
|
||||
"autoemit_temperature_commands",
|
||||
"avoid_crossing_perimeters",
|
||||
"avoid_crossing_perimeters_max_detour",
|
||||
"bed_shape",
|
||||
@ -139,6 +138,7 @@ bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* n
|
||||
"start_filament_gcode",
|
||||
"toolchange_gcode",
|
||||
"top_solid_infill_acceleration",
|
||||
"travel_acceleration",
|
||||
"thumbnails",
|
||||
"thumbnails_format",
|
||||
"use_firmware_retraction",
|
||||
@ -205,7 +205,9 @@ bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* n
|
||||
|| opt_key == "wipe_tower"
|
||||
|| opt_key == "wipe_tower_width"
|
||||
|| opt_key == "wipe_tower_brim_width"
|
||||
|| opt_key == "wipe_tower_cone_angle"
|
||||
|| opt_key == "wipe_tower_bridging"
|
||||
|| opt_key == "wipe_tower_extra_spacing"
|
||||
|| opt_key == "wipe_tower_no_sparse_layers"
|
||||
|| opt_key == "wiping_volumes_matrix"
|
||||
|| opt_key == "parking_pos_retraction"
|
||||
@ -394,7 +396,6 @@ bool Print::sequential_print_horizontal_clearance_valid(const Print& print, Poly
|
||||
// FIXME: Arrangement has different parameters for offsetting (jtMiter, limit 2)
|
||||
// which causes that the warning will be showed after arrangement with the
|
||||
// appropriate object distance. Even if I set this to jtMiter the warning still shows up.
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
Geometry::Transformation trafo = model_instance0->get_transformation();
|
||||
trafo.set_offset({ 0.0, 0.0, model_instance0->get_offset().z() });
|
||||
it_convex_hull = map_model_object_to_convex_hull.emplace_hint(it_convex_hull, model_object_id,
|
||||
@ -403,15 +404,6 @@ bool Print::sequential_print_horizontal_clearance_valid(const Print& print, Poly
|
||||
// exactly by satisfying the extruder_clearance_radius, this test will not trigger collision.
|
||||
float(scale_(0.5 * print.config().extruder_clearance_radius.value - BuildVolume::BedEpsilon)),
|
||||
jtRound, scale_(0.1)).front());
|
||||
#else
|
||||
it_convex_hull = map_model_object_to_convex_hull.emplace_hint(it_convex_hull, model_object_id,
|
||||
offset(print_object->model_object()->convex_hull_2d(
|
||||
Geometry::assemble_transform({ 0.0, 0.0, model_instance0->get_offset().z() }, model_instance0->get_rotation(), model_instance0->get_scaling_factor(), model_instance0->get_mirror())),
|
||||
// Shrink the extruder_clearance_radius a tiny bit, so that if the object arrangement algorithm placed the objects
|
||||
// exactly by satisfying the extruder_clearance_radius, this test will not trigger collision.
|
||||
float(scale_(0.5 * print.config().extruder_clearance_radius.value - BuildVolume::BedEpsilon)),
|
||||
jtRound, scale_(0.1)).front());
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
}
|
||||
// Make a copy, so it may be rotated for instances.
|
||||
Polygon convex_hull0 = it_convex_hull->second;
|
||||
@ -472,20 +464,20 @@ std::string Print::validate(std::string* warning) const
|
||||
std::vector<unsigned int> extruders = this->extruders();
|
||||
|
||||
if (m_objects.empty())
|
||||
return L("All objects are outside of the print volume.");
|
||||
return _u8L("All objects are outside of the print volume.");
|
||||
|
||||
if (extruders.empty())
|
||||
return L("The supplied settings will cause an empty print.");
|
||||
return _u8L("The supplied settings will cause an empty print.");
|
||||
|
||||
if (m_config.complete_objects) {
|
||||
if (! sequential_print_horizontal_clearance_valid(*this))
|
||||
return L("Some objects are too close; your extruder will collide with them.");
|
||||
return _u8L("Some objects are too close; your extruder will collide with them.");
|
||||
if (! sequential_print_vertical_clearance_valid(*this))
|
||||
return L("Some objects are too tall and cannot be printed without extruder collisions.");
|
||||
return _u8L("Some objects are too tall and cannot be printed without extruder collisions.");
|
||||
}
|
||||
|
||||
if (m_config.avoid_crossing_perimeters && m_config.avoid_crossing_curled_overhangs) {
|
||||
return L("Avoid crossing perimeters option and avoid crossing curled overhangs option cannot be both enabled together.");
|
||||
return _u8L("Avoid crossing perimeters option and avoid crossing curled overhangs option cannot be both enabled together.");
|
||||
}
|
||||
|
||||
if (m_config.spiral_vase) {
|
||||
@ -494,13 +486,17 @@ std::string Print::validate(std::string* warning) const
|
||||
total_copies_count += object->instances().size();
|
||||
// #4043
|
||||
if (total_copies_count > 1 && ! m_config.complete_objects.value)
|
||||
return L("Only a single object may be printed at a time in Spiral Vase mode. "
|
||||
return _u8L("Only a single object may be printed at a time in Spiral Vase mode. "
|
||||
"Either remove all but the last object, or enable sequential mode by \"complete_objects\".");
|
||||
assert(m_objects.size() == 1);
|
||||
if (m_objects.front()->all_regions().size() > 1)
|
||||
return L("The Spiral Vase option can only be used when printing single material objects.");
|
||||
return _u8L("The Spiral Vase option can only be used when printing single material objects.");
|
||||
}
|
||||
|
||||
if (m_config.machine_limits_usage == MachineLimitsUsage::EmitToGCode && m_config.gcode_flavor == gcfKlipper)
|
||||
return L("Machine limits cannot be emitted to G-Code when Klipper firmware flavor is used. "
|
||||
"Change the value of machine_limits_usage.");
|
||||
|
||||
// Cache of layer height profiles for checking:
|
||||
// 1) Whether all layers are synchronized if printing with wipe tower and / or unsynchronized supports.
|
||||
// 2) Whether layer height is constant for Organic supports.
|
||||
@ -522,7 +518,7 @@ std::string Print::validate(std::string* warning) const
|
||||
//FIXME It is quite expensive to generate object layers just to get the print height!
|
||||
if (auto layers = generate_object_layers(print_object.slicing_parameters(), layer_height_profile(print_object_idx));
|
||||
! layers.empty() && layers.back() > this->config().max_print_height + EPSILON) {
|
||||
return L("The print is taller than the maximum allowed height. You might want to reduce the size of your model"
|
||||
return _u8L("The print is taller than the maximum allowed height. You might want to reduce the size of your model"
|
||||
" or change current print settings and retry.");
|
||||
}
|
||||
}
|
||||
@ -539,7 +535,7 @@ std::string Print::validate(std::string* warning) const
|
||||
print_object.model_object()->has_custom_layering()) {
|
||||
if (const std::vector<coordf_t> &layers = layer_height_profile(print_object_idx); ! layers.empty())
|
||||
if (! check_object_layers_fixed(print_object.slicing_parameters(), layers))
|
||||
return L("Variable layer height is not supported with Organic supports.");
|
||||
return _u8L("Variable layer height is not supported with Organic supports.");
|
||||
}
|
||||
|
||||
if (this->has_wipe_tower() && ! m_objects.empty()) {
|
||||
@ -552,21 +548,22 @@ std::string Print::validate(std::string* warning) const
|
||||
double filament_diam = m_config.filament_diameter.get_at(extruder_idx);
|
||||
if (nozzle_diam - EPSILON > first_nozzle_diam || nozzle_diam + EPSILON < first_nozzle_diam
|
||||
|| std::abs((filament_diam-first_filament_diam)/first_filament_diam) > 0.1)
|
||||
return L("The wipe tower is only supported if all extruders have the same nozzle diameter "
|
||||
return _u8L("The wipe tower is only supported if all extruders have the same nozzle diameter "
|
||||
"and use filaments of the same diameter.");
|
||||
}
|
||||
|
||||
if (m_config.gcode_flavor != gcfRepRapSprinter && m_config.gcode_flavor != gcfRepRapFirmware &&
|
||||
m_config.gcode_flavor != gcfRepetier && m_config.gcode_flavor != gcfMarlinLegacy && m_config.gcode_flavor != gcfMarlinFirmware)
|
||||
return L("The Wipe Tower is currently only supported for the Marlin, RepRap/Sprinter, RepRapFirmware and Repetier G-code flavors.");
|
||||
m_config.gcode_flavor != gcfRepetier && m_config.gcode_flavor != gcfMarlinLegacy &&
|
||||
m_config.gcode_flavor != gcfMarlinFirmware && m_config.gcode_flavor != gcfKlipper)
|
||||
return _u8L("The Wipe Tower is currently only supported for the Marlin, Klipper, RepRap/Sprinter, RepRapFirmware and Repetier G-code flavors.");
|
||||
if (! m_config.use_relative_e_distances)
|
||||
return L("The Wipe Tower is currently only supported with the relative extruder addressing (use_relative_e_distances=1).");
|
||||
return _u8L("The Wipe Tower is currently only supported with the relative extruder addressing (use_relative_e_distances=1).");
|
||||
if (m_config.ooze_prevention && m_config.single_extruder_multi_material)
|
||||
return L("Ooze prevention is only supported with the wipe tower when 'single_extruder_multi_material' is off.");
|
||||
return _u8L("Ooze prevention is only supported with the wipe tower when 'single_extruder_multi_material' is off.");
|
||||
if (m_config.use_volumetric_e)
|
||||
return L("The Wipe Tower currently does not support volumetric E (use_volumetric_e=0).");
|
||||
return _u8L("The Wipe Tower currently does not support volumetric E (use_volumetric_e=0).");
|
||||
if (m_config.complete_objects && extruders.size() > 1)
|
||||
return L("The Wipe Tower is currently not supported for multimaterial sequential prints.");
|
||||
return _u8L("The Wipe Tower is currently not supported for multimaterial sequential prints.");
|
||||
|
||||
if (m_objects.size() > 1) {
|
||||
const SlicingParameters &slicing_params0 = m_objects.front()->slicing_parameters();
|
||||
@ -576,14 +573,14 @@ std::string Print::validate(std::string* warning) const
|
||||
const SlicingParameters &slicing_params = object->slicing_parameters();
|
||||
if (std::abs(slicing_params.first_print_layer_height - slicing_params0.first_print_layer_height) > EPSILON ||
|
||||
std::abs(slicing_params.layer_height - slicing_params0.layer_height ) > EPSILON)
|
||||
return L("The Wipe Tower is only supported for multiple objects if they have equal layer heights");
|
||||
return _u8L("The Wipe Tower is only supported for multiple objects if they have equal layer heights");
|
||||
if (slicing_params.raft_layers() != slicing_params0.raft_layers())
|
||||
return L("The Wipe Tower is only supported for multiple objects if they are printed over an equal number of raft layers");
|
||||
return _u8L("The Wipe Tower is only supported for multiple objects if they are printed over an equal number of raft layers");
|
||||
if (slicing_params0.gap_object_support != slicing_params.gap_object_support ||
|
||||
slicing_params0.gap_support_object != slicing_params.gap_support_object)
|
||||
return L("The Wipe Tower is only supported for multiple objects if they are printed with the same support_material_contact_distance");
|
||||
return _u8L("The Wipe Tower is only supported for multiple objects if they are printed with the same support_material_contact_distance");
|
||||
if (! equal_layering(slicing_params, slicing_params0))
|
||||
return L("The Wipe Tower is only supported for multiple objects if they are sliced equally.");
|
||||
return _u8L("The Wipe Tower is only supported for multiple objects if they are sliced equally.");
|
||||
if (has_custom_layering) {
|
||||
auto &lh = layer_height_profile(i);
|
||||
auto &lh_tallest = layer_height_profile(tallest_object_idx);
|
||||
@ -608,7 +605,7 @@ std::string Print::validate(std::string* warning) const
|
||||
if (i%2 == 0 && layer_height_profiles[tallest_object_idx][i] > layer_height_profiles[idx_object][layer_height_profiles[idx_object].size() - 2 ])
|
||||
break;
|
||||
if (std::abs(layer_height_profiles[idx_object][i] - layer_height_profiles[tallest_object_idx][i]) > eps)
|
||||
return L("The Wipe tower is only supported if all objects have the same variable layer height");
|
||||
return _u8L("The Wipe tower is only supported if all objects have the same variable layer height");
|
||||
++i;
|
||||
}
|
||||
}
|
||||
@ -632,7 +629,7 @@ std::string Print::validate(std::string* warning) const
|
||||
unsigned int total_extruders_count = m_config.nozzle_diameter.size();
|
||||
for (const auto& extruder_idx : extruders)
|
||||
if ( extruder_idx >= total_extruders_count )
|
||||
return L("One or more object were assigned an extruder that the printer does not have.");
|
||||
return _u8L("One or more object were assigned an extruder that the printer does not have.");
|
||||
#endif
|
||||
|
||||
auto validate_extrusion_width = [/*min_nozzle_diameter,*/ max_nozzle_diameter](const ConfigBase &config, const char *opt_key, double layer_height, std::string &err_msg) -> bool {
|
||||
@ -645,10 +642,10 @@ std::string Print::validate(std::string* warning) const
|
||||
if (extrusion_width_min == 0) {
|
||||
// Default "auto-generated" extrusion width is always valid.
|
||||
} else if (extrusion_width_min <= layer_height) {
|
||||
err_msg = (boost::format(L("%1%=%2% mm is too low to be printable at a layer height %3% mm")) % opt_key % extrusion_width_min % layer_height).str();
|
||||
err_msg = (boost::format(_u8L("%1%=%2% mm is too low to be printable at a layer height %3% mm")) % opt_key % extrusion_width_min % layer_height).str();
|
||||
return false;
|
||||
} else if (extrusion_width_max >= max_nozzle_diameter * 3.) {
|
||||
err_msg = (boost::format(L("Excessive %1%=%2% mm to be printable with a nozzle diameter %3% mm")) % opt_key % extrusion_width_max % max_nozzle_diameter).str();
|
||||
err_msg = (boost::format(_u8L("Excessive %1%=%2% mm to be printable with a nozzle diameter %3% mm")) % opt_key % extrusion_width_max % max_nozzle_diameter).str();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@ -659,7 +656,7 @@ std::string Print::validate(std::string* warning) const
|
||||
// The object has some form of support and either support_material_extruder or support_material_interface_extruder
|
||||
// will be printed with the current tool without a forced tool change. Play safe, assert that all object nozzles
|
||||
// are of the same diameter.
|
||||
return L("Printing with multiple extruders of differing nozzle diameters. "
|
||||
return _u8L("Printing with multiple extruders of differing nozzle diameters. "
|
||||
"If support is to be printed with the current extruder (support_material_extruder == 0 or support_material_interface_extruder == 0), "
|
||||
"all nozzles have to be of the same diameter.");
|
||||
}
|
||||
@ -667,11 +664,11 @@ std::string Print::validate(std::string* warning) const
|
||||
if (object->config().support_material_contact_distance == 0) {
|
||||
// Soluble interface
|
||||
if (! object->config().support_material_synchronize_layers)
|
||||
return L("For the Wipe Tower to work with the soluble supports, the support layers need to be synchronized with the object layers.");
|
||||
return _u8L("For the Wipe Tower to work with the soluble supports, the support layers need to be synchronized with the object layers.");
|
||||
} else {
|
||||
// Non-soluble interface
|
||||
if (object->config().support_material_extruder != 0 || object->config().support_material_interface_extruder != 0)
|
||||
return L("The Wipe Tower currently supports the non-soluble supports only if they are printed with the current extruder without triggering a tool change. "
|
||||
return _u8L("The Wipe Tower currently supports the non-soluble supports only if they are printed with the current extruder without triggering a tool change. "
|
||||
"(both support_material_extruder and support_material_interface_extruder need to be set to 0).");
|
||||
}
|
||||
}
|
||||
@ -707,12 +704,12 @@ std::string Print::validate(std::string* warning) const
|
||||
first_layer_min_nozzle_diameter = min_nozzle_diameter;
|
||||
}
|
||||
if (first_layer_height > first_layer_min_nozzle_diameter)
|
||||
return L("First layer height can't be greater than nozzle diameter");
|
||||
return _u8L("First layer height can't be greater than nozzle diameter");
|
||||
|
||||
// validate layer_height
|
||||
double layer_height = object->config().layer_height.value;
|
||||
if (layer_height > min_nozzle_diameter)
|
||||
return L("Layer height can't be greater than nozzle diameter");
|
||||
return _u8L("Layer height can't be greater than nozzle diameter");
|
||||
|
||||
// Validate extrusion widths.
|
||||
std::string err_msg;
|
||||
@ -733,11 +730,11 @@ std::string Print::validate(std::string* warning) const
|
||||
// See GH issues #6336 #5073
|
||||
if ((m_config.gcode_flavor == gcfMarlinLegacy || m_config.gcode_flavor == gcfMarlinFirmware) &&
|
||||
! before_layer_gcode_resets_extruder && ! layer_gcode_resets_extruder)
|
||||
return L("Relative extruder addressing requires resetting the extruder position at each layer to prevent loss of floating point accuracy. Add \"G92 E0\" to layer_gcode.");
|
||||
return _u8L("Relative extruder addressing requires resetting the extruder position at each layer to prevent loss of floating point accuracy. Add \"G92 E0\" to layer_gcode.");
|
||||
} else if (before_layer_gcode_resets_extruder)
|
||||
return L("\"G92 E0\" was found in before_layer_gcode, which is incompatible with absolute extruder addressing.");
|
||||
return _u8L("\"G92 E0\" was found in before_layer_gcode, which is incompatible with absolute extruder addressing.");
|
||||
else if (layer_gcode_resets_extruder)
|
||||
return L("\"G92 E0\" was found in layer_gcode, which is incompatible with absolute extruder addressing.");
|
||||
return _u8L("\"G92 E0\" was found in layer_gcode, which is incompatible with absolute extruder addressing.");
|
||||
}
|
||||
|
||||
return std::string();
|
||||
@ -879,7 +876,7 @@ void Print::process()
|
||||
BOOST_LOG_TRIVIAL(info) << "Starting the slicing process." << log_memory_info();
|
||||
for (PrintObject *obj : m_objects)
|
||||
obj->make_perimeters();
|
||||
this->set_status(70, L("Infilling layers"));
|
||||
this->set_status(70, _u8L("Infilling layers"));
|
||||
for (PrintObject *obj : m_objects)
|
||||
obj->infill();
|
||||
for (PrintObject *obj : m_objects)
|
||||
@ -896,7 +893,7 @@ void Print::process()
|
||||
m_wipe_tower_data.clear();
|
||||
m_tool_ordering.clear();
|
||||
if (this->has_wipe_tower()) {
|
||||
//this->set_status(95, L("Generating wipe tower"));
|
||||
//this->set_status(95, _u8L("Generating wipe tower"));
|
||||
this->_make_wipe_tower();
|
||||
} else if (! this->config().complete_objects.value) {
|
||||
// Initialize the tool ordering, so it could be used by the G-code preview slider for planning tool changes and filament switches.
|
||||
@ -907,7 +904,7 @@ void Print::process()
|
||||
this->set_done(psWipeTower);
|
||||
}
|
||||
if (this->set_started(psSkirtBrim)) {
|
||||
this->set_status(88, L("Generating skirt and brim"));
|
||||
this->set_status(88, _u8L("Generating skirt and brim"));
|
||||
|
||||
m_skirt.clear();
|
||||
m_skirt_convex_hull.clear();
|
||||
@ -955,11 +952,11 @@ std::string Print::export_gcode(const std::string& path_template, GCodeProcessor
|
||||
std::string message;
|
||||
if (!path.empty() && result == nullptr) {
|
||||
// Only show the path if preview_data is not set -> running from command line.
|
||||
message = L("Exporting G-code");
|
||||
message = _u8L("Exporting G-code");
|
||||
message += " to ";
|
||||
message += path;
|
||||
} else
|
||||
message = L("Generating G-code");
|
||||
message = _u8L("Generating G-code");
|
||||
this->set_status(90, message);
|
||||
|
||||
// Create GCode on heap, it has quite a lot of data.
|
||||
@ -1133,23 +1130,34 @@ Polygons Print::first_layer_islands() const
|
||||
|
||||
std::vector<Point> Print::first_layer_wipe_tower_corners() const
|
||||
{
|
||||
std::vector<Point> corners;
|
||||
std::vector<Point> pts_scaled;
|
||||
|
||||
if (has_wipe_tower() && ! m_wipe_tower_data.tool_changes.empty()) {
|
||||
double width = m_config.wipe_tower_width + 2*m_wipe_tower_data.brim_width;
|
||||
double depth = m_wipe_tower_data.depth + 2*m_wipe_tower_data.brim_width;
|
||||
Vec2d pt0(-m_wipe_tower_data.brim_width, -m_wipe_tower_data.brim_width);
|
||||
for (Vec2d pt : {
|
||||
pt0,
|
||||
Vec2d(pt0.x()+width, pt0.y() ),
|
||||
|
||||
// First the corners.
|
||||
std::vector<Vec2d> pts = { pt0,
|
||||
Vec2d(pt0.x()+width, pt0.y()),
|
||||
Vec2d(pt0.x()+width, pt0.y()+depth),
|
||||
Vec2d(pt0.x(), pt0.y()+depth)
|
||||
}) {
|
||||
Vec2d(pt0.x(),pt0.y()+depth)
|
||||
};
|
||||
|
||||
// Now the stabilization cone.
|
||||
Vec2d center = (pts[0] + pts[2])/2.;
|
||||
const auto [cone_R, cone_x_scale] = WipeTower::get_wipe_tower_cone_base(m_config.wipe_tower_width, m_wipe_tower_data.height, m_wipe_tower_data.depth, m_config.wipe_tower_cone_angle);
|
||||
double r = cone_R + m_wipe_tower_data.brim_width;
|
||||
for (double alpha = 0.; alpha<2*M_PI; alpha += M_PI/20.)
|
||||
pts.emplace_back(center + r*Vec2d(std::cos(alpha)/cone_x_scale, std::sin(alpha)));
|
||||
|
||||
for (Vec2d& pt : pts) {
|
||||
pt = Eigen::Rotation2Dd(Geometry::deg2rad(m_config.wipe_tower_rotation_angle.value)) * pt;
|
||||
pt += Vec2d(m_config.wipe_tower_x.value, m_config.wipe_tower_y.value);
|
||||
corners.emplace_back(Point(scale_(pt.x()), scale_(pt.y())));
|
||||
pts_scaled.emplace_back(Point(scale_(pt.x()), scale_(pt.y())));
|
||||
}
|
||||
}
|
||||
return corners;
|
||||
return pts_scaled;
|
||||
}
|
||||
|
||||
void Print::finalize_first_layer_convex_hull()
|
||||
@ -1168,30 +1176,30 @@ void Print::alert_when_supports_needed()
|
||||
{
|
||||
if (this->set_started(psAlertWhenSupportsNeeded)) {
|
||||
BOOST_LOG_TRIVIAL(debug) << "psAlertWhenSupportsNeeded - start";
|
||||
set_status(69, L("Alert if supports needed"));
|
||||
set_status(69, _u8L("Alert if supports needed"));
|
||||
|
||||
auto issue_to_alert_message = [](SupportSpotsGenerator::SupportPointCause cause, bool critical) {
|
||||
std::string message;
|
||||
switch (cause) {
|
||||
//TRN Alert when support is needed. Describes that the model has long bridging extrusions which may print badly
|
||||
case SupportSpotsGenerator::SupportPointCause::LongBridge: message = L("Long bridging extrusions"); break;
|
||||
case SupportSpotsGenerator::SupportPointCause::LongBridge: message = _u8L("Long bridging extrusions"); break;
|
||||
//TRN Alert when support is needed. Describes bridge anchors/turns in the air, which will definitely print badly
|
||||
case SupportSpotsGenerator::SupportPointCause::FloatingBridgeAnchor: message = L("Floating bridge anchors"); break;
|
||||
case SupportSpotsGenerator::SupportPointCause::FloatingBridgeAnchor: message = _u8L("Floating bridge anchors"); break;
|
||||
case SupportSpotsGenerator::SupportPointCause::FloatingExtrusion:
|
||||
if (critical) {
|
||||
//TRN Alert when support is needed. Describes that the print has large overhang area which will print badly or not print at all.
|
||||
message = L("Collapsing overhang");
|
||||
message = _u8L("Collapsing overhang");
|
||||
} else {
|
||||
//TRN Alert when support is needed. Describes extrusions that are not supported enough and come out curled or loose.
|
||||
message = L("Loose extrusions");
|
||||
message = _u8L("Loose extrusions");
|
||||
}
|
||||
break;
|
||||
//TRN Alert when support is needed. Describes that the print has low bed adhesion and may became loose.
|
||||
case SupportSpotsGenerator::SupportPointCause::SeparationFromBed: message = L("Low bed adhesion"); break;
|
||||
case SupportSpotsGenerator::SupportPointCause::SeparationFromBed: message = _u8L("Low bed adhesion"); break;
|
||||
//TRN Alert when support is needed. Describes that the object has part that is not connected to the bed and will not print at all without supports.
|
||||
case SupportSpotsGenerator::SupportPointCause::UnstableFloatingPart: message = L("Floating object part"); break;
|
||||
case SupportSpotsGenerator::SupportPointCause::UnstableFloatingPart: message = _u8L("Floating object part"); break;
|
||||
//TRN Alert when support is needed. Describes that the object has thin part that may brake during printing
|
||||
case SupportSpotsGenerator::SupportPointCause::WeakObjectPart: message = L("Thin fragile part"); break;
|
||||
case SupportSpotsGenerator::SupportPointCause::WeakObjectPart: message = _u8L("Thin fragile part"); break;
|
||||
}
|
||||
|
||||
return message;
|
||||
@ -1299,13 +1307,13 @@ void Print::alert_when_supports_needed()
|
||||
}
|
||||
|
||||
lines.push_back("");
|
||||
lines.push_back(L("Consider enabling supports."));
|
||||
lines.push_back(_u8L("Consider enabling supports."));
|
||||
if (recommend_brim) {
|
||||
lines.push_back(L("Also consider enabling brim."));
|
||||
lines.push_back(_u8L("Also consider enabling brim."));
|
||||
}
|
||||
|
||||
// TRN Alert message for detected print issues. first argument is a list of detected issues.
|
||||
auto message = Slic3r::format(L("Detected print stability issues:\n%1%"), elements_to_translated_list(lines, multiline_list_rule));
|
||||
auto message = Slic3r::format(_u8L("Detected print stability issues:\n%1%"), elements_to_translated_list(lines, multiline_list_rule));
|
||||
|
||||
if (objects_isssues.size() > 0) {
|
||||
this->active_step_add_warning(PrintStateBase::WarningLevel::NON_CRITICAL, message);
|
||||
@ -1329,11 +1337,23 @@ const WipeTowerData& Print::wipe_tower_data(size_t extruders_cnt) const
|
||||
{
|
||||
// If the wipe tower wasn't created yet, make sure the depth and brim_width members are set to default.
|
||||
if (! is_step_done(psWipeTower) && extruders_cnt !=0) {
|
||||
const_cast<Print*>(this)->m_wipe_tower_data.brim_width = m_config.wipe_tower_brim_width;
|
||||
|
||||
// Calculating depth should take into account currently set wiping volumes.
|
||||
// For a long time, the initial preview would just use 900/width per toolchange (15mm on a 60mm wide tower)
|
||||
// and it worked well enough. Let's try to do slightly better by accounting for the purging volumes.
|
||||
std::vector<std::vector<float>> wipe_volumes = WipeTower::extract_wipe_volumes(m_config);
|
||||
std::vector<float> max_wipe_volumes;
|
||||
for (const std::vector<float>& v : wipe_volumes)
|
||||
max_wipe_volumes.emplace_back(*std::max_element(v.begin(), v.end()));
|
||||
float maximum = std::accumulate(max_wipe_volumes.begin(), max_wipe_volumes.end(), 0.f);
|
||||
maximum = maximum * extruders_cnt / max_wipe_volumes.size();
|
||||
|
||||
float width = float(m_config.wipe_tower_width);
|
||||
float layer_height = 0.2f; // just assume fixed value, it will still be better than before.
|
||||
|
||||
const_cast<Print*>(this)->m_wipe_tower_data.depth = (900.f/width) * float(extruders_cnt - 1);
|
||||
const_cast<Print*>(this)->m_wipe_tower_data.brim_width = m_config.wipe_tower_brim_width;
|
||||
const_cast<Print*>(this)->m_wipe_tower_data.depth = (maximum/layer_height)/width;
|
||||
const_cast<Print*>(this)->m_wipe_tower_data.height = -1.f; // unknown yet
|
||||
}
|
||||
|
||||
return m_wipe_tower_data;
|
||||
@ -1345,13 +1365,7 @@ void Print::_make_wipe_tower()
|
||||
if (! this->has_wipe_tower())
|
||||
return;
|
||||
|
||||
// Get wiping matrix to get number of extruders and convert vector<double> to vector<float>:
|
||||
std::vector<float> wiping_matrix(cast<float>(m_config.wiping_volumes_matrix.values));
|
||||
// Extract purging volumes for each extruder pair:
|
||||
std::vector<std::vector<float>> wipe_volumes;
|
||||
const unsigned int number_of_extruders = (unsigned int)(sqrt(wiping_matrix.size())+EPSILON);
|
||||
for (unsigned int i = 0; i<number_of_extruders; ++i)
|
||||
wipe_volumes.push_back(std::vector<float>(wiping_matrix.begin()+i*number_of_extruders, wiping_matrix.begin()+(i+1)*number_of_extruders));
|
||||
std::vector<std::vector<float>> wipe_volumes = WipeTower::extract_wipe_volumes(m_config);
|
||||
|
||||
// Let the ToolOrdering class know there will be initial priming extrusions at the start of the print.
|
||||
m_wipe_tower_data.tool_ordering = ToolOrdering(*this, (unsigned int)-1, true);
|
||||
@ -1404,7 +1418,7 @@ void Print::_make_wipe_tower()
|
||||
//wipe_tower.set_zhop();
|
||||
|
||||
// Set the extruder & material properties at the wipe tower object.
|
||||
for (size_t i = 0; i < number_of_extruders; ++ i)
|
||||
for (size_t i = 0; i < m_config.nozzle_diameter.size(); ++ i)
|
||||
wipe_tower.set_extruder(i, m_config);
|
||||
|
||||
m_wipe_tower_data.priming = Slic3r::make_unique<std::vector<WipeTower::ToolChangeResult>>(
|
||||
@ -1447,6 +1461,7 @@ void Print::_make_wipe_tower()
|
||||
wipe_tower.generate(m_wipe_tower_data.tool_changes);
|
||||
m_wipe_tower_data.depth = wipe_tower.get_depth();
|
||||
m_wipe_tower_data.brim_width = wipe_tower.get_brim_width();
|
||||
m_wipe_tower_data.height = wipe_tower.get_wipe_tower_height();
|
||||
|
||||
// Unload the current filament over the purge tower.
|
||||
coordf_t layer_height = m_objects.front()->config().layer_height.value;
|
||||
|
@ -434,6 +434,7 @@ struct WipeTowerData
|
||||
// Depth of the wipe tower to pass to GLCanvas3D for exact bounding box:
|
||||
float depth;
|
||||
float brim_width;
|
||||
float height;
|
||||
|
||||
void clear() {
|
||||
priming.reset(nullptr);
|
||||
@ -565,6 +566,11 @@ public:
|
||||
SpanOfConstPtrs<PrintObject> objects() const { return SpanOfConstPtrs<PrintObject>(const_cast<const PrintObject* const* const>(m_objects.data()), m_objects.size()); }
|
||||
PrintObject* get_object(size_t idx) { return const_cast<PrintObject*>(m_objects[idx]); }
|
||||
const PrintObject* get_object(size_t idx) const { return m_objects[idx]; }
|
||||
const PrintObject* get_print_object_by_model_object_id(ObjectID object_id) const {
|
||||
auto it = std::find_if(m_objects.begin(), m_objects.end(),
|
||||
[object_id](const PrintObject* obj) { return obj->model_object()->id() == object_id; });
|
||||
return (it == m_objects.end()) ? nullptr : *it;
|
||||
}
|
||||
// PrintObject by its ObjectID, to be used to uniquely bind slicing warnings to their source PrintObjects
|
||||
// in the notification center.
|
||||
const PrintObject* get_object(ObjectID object_id) const {
|
||||
|
@ -791,13 +791,8 @@ void update_volume_bboxes(
|
||||
if (it != volumes_old.end() && it->volume_id == model_volume->id())
|
||||
layer_range.volumes.emplace_back(*it);
|
||||
} else
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
layer_range.volumes.push_back({ model_volume->id(),
|
||||
transformed_its_bbox2d(model_volume->mesh().its, trafo_for_bbox(object_trafo, model_volume->get_matrix()), offset) });
|
||||
#else
|
||||
layer_range.volumes.push_back({ model_volume->id(),
|
||||
transformed_its_bbox2d(model_volume->mesh().its, trafo_for_bbox(object_trafo, model_volume->get_matrix(false)), offset) });
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
}
|
||||
} else {
|
||||
std::vector<std::vector<PrintObjectRegions::VolumeExtents>> volumes_old;
|
||||
@ -829,11 +824,7 @@ void update_volume_bboxes(
|
||||
layer_range.volumes.emplace_back(*it);
|
||||
}
|
||||
} else {
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
transformed_its_bboxes_in_z_ranges(model_volume->mesh().its, trafo_for_bbox(object_trafo, model_volume->get_matrix()), ranges, bboxes, offset);
|
||||
#else
|
||||
transformed_its_bboxes_in_z_ranges(model_volume->mesh().its, trafo_for_bbox(object_trafo, model_volume->get_matrix(false)), ranges, bboxes, offset);
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
for (PrintObjectRegions::LayerRangeRegions &layer_range : layer_ranges)
|
||||
if (auto &bbox = bboxes[&layer_range - layer_ranges.data()]; bbox.second)
|
||||
layer_range.volumes.push_back({ model_volume->id(), bbox.first });
|
||||
|
@ -6,10 +6,6 @@
|
||||
|
||||
#include "I18N.hpp"
|
||||
|
||||
//! macro used to mark string used at localization,
|
||||
//! return same string
|
||||
#define L(s) Slic3r::I18N::translate(s)
|
||||
|
||||
namespace Slic3r
|
||||
{
|
||||
|
||||
@ -81,7 +77,7 @@ std::string PrintBase::output_filename(const std::string &format, const std::str
|
||||
filename = boost::filesystem::change_extension(filename, default_ext);
|
||||
return filename.string();
|
||||
} catch (std::runtime_error &err) {
|
||||
throw Slic3r::PlaceholderParserError(L("Failed processing of the output_filename_format template.") + "\n" + err.what());
|
||||
throw Slic3r::PlaceholderParserError(_u8L("Failed processing of the output_filename_format template.") + "\n" + err.what());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -16,11 +16,6 @@
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
//! macro used to mark string used at localization,
|
||||
//! return same string
|
||||
#define L(s) (s)
|
||||
#define _(s) Slic3r::I18N::translate(s)
|
||||
|
||||
static t_config_enum_names enum_names_from_keys_map(const t_config_enum_values &enum_keys_map)
|
||||
{
|
||||
t_config_enum_names names;
|
||||
@ -53,6 +48,7 @@ static const t_config_enum_values s_keys_map_GCodeFlavor {
|
||||
{ "makerware", gcfMakerWare },
|
||||
{ "marlin", gcfMarlinLegacy },
|
||||
{ "marlin2", gcfMarlinFirmware },
|
||||
{ "klipper", gcfKlipper },
|
||||
{ "sailfish", gcfSailfish },
|
||||
{ "smoothie", gcfSmoothie },
|
||||
{ "mach3", gcfMach3 },
|
||||
@ -72,6 +68,7 @@ static const t_config_enum_values s_keys_map_PrintHostType {
|
||||
{ "prusalink", htPrusaLink },
|
||||
{ "prusaconnect", htPrusaConnect },
|
||||
{ "octoprint", htOctoPrint },
|
||||
{ "mainsail", htMainSail },
|
||||
{ "duet", htDuet },
|
||||
{ "flashair", htFlashAir },
|
||||
{ "astrobox", htAstroBox },
|
||||
@ -404,6 +401,7 @@ void PrintConfigDef::init_fff_params()
|
||||
const int max_temp = 1500;
|
||||
def = this->add("avoid_crossing_curled_overhangs", coBool);
|
||||
def->label = L("Avoid crossing curled overhangs (Experimental)");
|
||||
// TRN PrintSettings: "Avoid crossing curled overhangs (Experimental)"
|
||||
def->tooltip = L("Plan travel moves such that the extruder avoids areas where the filament may be curled up. "
|
||||
"This is mostly happening on steeper rounded overhangs and may cause a crash with the nozzle. "
|
||||
"This feature slows down both the print and the G-code generation.");
|
||||
@ -461,8 +459,8 @@ void PrintConfigDef::init_fff_params()
|
||||
def->set_default_value(new ConfigOptionString(""));
|
||||
|
||||
def = this->add("bottom_solid_layers", coInt);
|
||||
//TRN To be shown in Print Settings "Bottom solid layers"
|
||||
def->label = L("Bottom");
|
||||
//TRN Print Settings: "Bottom solid layers"
|
||||
def->label = L_CONTEXT("Bottom", "Layers");
|
||||
def->category = L("Layers and Perimeters");
|
||||
def->tooltip = L("Number of solid layers to generate on bottom surfaces.");
|
||||
def->full_label = L("Bottom solid layers");
|
||||
@ -470,8 +468,7 @@ void PrintConfigDef::init_fff_params()
|
||||
def->set_default_value(new ConfigOptionInt(3));
|
||||
|
||||
def = this->add("bottom_solid_min_thickness", coFloat);
|
||||
//TRN To be shown in Print Settings "Top solid layers"
|
||||
def->label = L("Bottom");
|
||||
def->label = L_CONTEXT("Bottom", "Layers");
|
||||
def->category = L("Layers and Perimeters");
|
||||
def->tooltip = L("The number of bottom solid layers is increased above bottom_solid_layers if necessary to satisfy "
|
||||
"minimum thickness of bottom shell.");
|
||||
@ -538,6 +535,7 @@ void PrintConfigDef::init_fff_params()
|
||||
def->mode = comExpert;
|
||||
def->set_default_value(new ConfigOptionBool(false));
|
||||
|
||||
// TRN PrintSettings : "Dynamic overhang speed"
|
||||
auto overhang_speed_setting_description = L("Overhang size is expressed as a percentage of overlap of the extrusion with the previous layer: "
|
||||
"100% would be full overlap (no overhang), while 0% represents full overhang (floating extrusion, bridge). "
|
||||
"Speeds for overhang sizes in between are calculated via linear interpolation. "
|
||||
@ -585,10 +583,10 @@ void PrintConfigDef::init_fff_params()
|
||||
def->mode = comExpert;
|
||||
def->set_default_value(new ConfigOptionBools{false});
|
||||
|
||||
auto fan_speed_setting_description = L(
|
||||
"Overhang size is expressed as a percentage of overlap of the extrusion with the previous layer: "
|
||||
// TRN FilamentSettings : "Dynamic fan speeds"
|
||||
auto fan_speed_setting_description = L("Overhang size is expressed as a percentage of overlap of the extrusion with the previous layer: "
|
||||
"100% would be full overlap (no overhang), while 0% represents full overhang (floating extrusion, bridge). "
|
||||
"Fan speeds for overhang sizes in between are calculated via linear interpolation. ");
|
||||
"Fan speeds for overhang sizes in between are calculated via linear interpolation.");
|
||||
|
||||
def = this->add("overhang_fan_speed_0", coInts);
|
||||
def->label = L("speed for 0% overlap (bridge)");
|
||||
@ -1409,6 +1407,7 @@ void PrintConfigDef::init_fff_params()
|
||||
{ "makerware", "MakerWare (MakerBot)" },
|
||||
{ "marlin", "Marlin (legacy)" },
|
||||
{ "marlin2", "Marlin 2" },
|
||||
{ "klipper", "Klipper" },
|
||||
{ "sailfish", "Sailfish (MakerBot)" },
|
||||
{ "mach3", "Mach3/LinuxCNC" },
|
||||
{ "machinekit", "Machinekit" },
|
||||
@ -1467,6 +1466,14 @@ void PrintConfigDef::init_fff_params()
|
||||
def->mode = comExpert;
|
||||
def->set_default_value(new ConfigOptionFloat(0));
|
||||
|
||||
def = this->add("travel_acceleration", coFloat);
|
||||
def->label = L("Travel");
|
||||
def->tooltip = L("This is the acceleration your printer will use for travel moves. Set zero to disable "
|
||||
"acceleration control for travel.");
|
||||
def->sidetext = L("mm/s²");
|
||||
def->min = 0;
|
||||
def->mode = comExpert;
|
||||
def->set_default_value(new ConfigOptionFloat(0));
|
||||
|
||||
def = this->add("infill_every_layers", coInt);
|
||||
def->label = L("Combine infill every");
|
||||
@ -1552,14 +1559,14 @@ void PrintConfigDef::init_fff_params()
|
||||
def->mode = comExpert;
|
||||
def->set_default_value(new ConfigOptionBool(false));
|
||||
|
||||
def = this->add("infill_only_where_needed", coBool);
|
||||
def->label = L("Only infill where needed");
|
||||
def->category = L("Infill");
|
||||
def->tooltip = L("This option will limit infill to the areas actually needed for supporting ceilings "
|
||||
"(it will act as internal support material). If enabled, slows down the G-code generation "
|
||||
"due to the multiple checks involved.");
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionBool(false));
|
||||
// def = this->add("infill_only_where_needed", coBool);
|
||||
// def->label = L("Only infill where needed");
|
||||
// def->category = L("Infill");
|
||||
// def->tooltip = L("This option will limit infill to the areas actually needed for supporting ceilings "
|
||||
// "(it will act as internal support material). If enabled, slows down the G-code generation "
|
||||
// "due to the multiple checks involved.");
|
||||
// def->mode = comAdvanced;
|
||||
// def->set_default_value(new ConfigOptionBool(false));
|
||||
|
||||
def = this->add("infill_overlap", coFloatOrPercent);
|
||||
def->label = L("Infill/perimeters overlap");
|
||||
@ -1795,9 +1802,7 @@ void PrintConfigDef::init_fff_params()
|
||||
def = this->add("machine_max_acceleration_extruding", coFloats);
|
||||
def->full_label = L("Maximum acceleration when extruding");
|
||||
def->category = L("Machine limits");
|
||||
def->tooltip = L("Maximum acceleration when extruding (M204 P)\n\n"
|
||||
"Marlin (legacy) firmware flavor will use this also "
|
||||
"as travel acceleration (M204 T).");
|
||||
def->tooltip = L("Maximum acceleration when extruding");
|
||||
def->sidetext = L("mm/s²");
|
||||
def->min = 0;
|
||||
def->mode = comAdvanced;
|
||||
@ -1808,7 +1813,8 @@ void PrintConfigDef::init_fff_params()
|
||||
def = this->add("machine_max_acceleration_retracting", coFloats);
|
||||
def->full_label = L("Maximum acceleration when retracting");
|
||||
def->category = L("Machine limits");
|
||||
def->tooltip = L("Maximum acceleration when retracting (M204 R)");
|
||||
def->tooltip = L("Maximum acceleration when retracting.\n\n"
|
||||
"Not used for RepRapFirmware, which does not support it.");
|
||||
def->sidetext = L("mm/s²");
|
||||
def->min = 0;
|
||||
def->mode = comAdvanced;
|
||||
@ -1818,7 +1824,7 @@ void PrintConfigDef::init_fff_params()
|
||||
def = this->add("machine_max_acceleration_travel", coFloats);
|
||||
def->full_label = L("Maximum acceleration for travel moves");
|
||||
def->category = L("Machine limits");
|
||||
def->tooltip = L("Maximum acceleration for travel moves (M204 T)");
|
||||
def->tooltip = L("Maximum acceleration for travel moves.");
|
||||
def->sidetext = L("mm/s²");
|
||||
def->min = 0;
|
||||
def->mode = comAdvanced;
|
||||
@ -1947,6 +1953,7 @@ void PrintConfigDef::init_fff_params()
|
||||
{ "prusalink", "PrusaLink" },
|
||||
{ "prusaconnect", "PrusaConnect" },
|
||||
{ "octoprint", "OctoPrint" },
|
||||
{ "mainsail", "Mainsail/Fluidd" },
|
||||
{ "duet", "Duet" },
|
||||
{ "flashair", "FlashAir" },
|
||||
{ "astrobox", "AstroBox" },
|
||||
@ -1966,7 +1973,8 @@ void PrintConfigDef::init_fff_params()
|
||||
|
||||
def = this->add("ooze_prevention", coBool);
|
||||
def->label = L("Enable");
|
||||
def->tooltip = L("This option will drop the temperature of the inactive extruders to prevent oozing. ");
|
||||
// TRN PrintSettings: Enable ooze prevention
|
||||
def->tooltip = L("This option will drop the temperature of the inactive extruders to prevent oozing.");
|
||||
def->mode = comExpert;
|
||||
def->set_default_value(new ConfigOptionBool(false));
|
||||
|
||||
@ -2304,6 +2312,7 @@ void PrintConfigDef::init_fff_params()
|
||||
|
||||
def = this->add("staggered_inner_seams", coBool);
|
||||
def->label = L("Staggered inner seams");
|
||||
// TRN PrintSettings: "Staggered inner seams"
|
||||
def->tooltip = L("This option causes the inner seams to be shifted backwards based on their depth, forming a zigzag pattern.");
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionBool(false));
|
||||
@ -2469,6 +2478,7 @@ void PrintConfigDef::init_fff_params()
|
||||
|
||||
def = this->add("standby_temperature_delta", coInt);
|
||||
def->label = L("Temperature variation");
|
||||
// TRN PrintSettings : "Ooze prevention" > "Temperature variation"
|
||||
def->tooltip = L("Temperature difference to be applied when an extruder is not active. "
|
||||
"The value is not used when 'idle_temperature' in filament settings "
|
||||
"is defined.");
|
||||
@ -2478,15 +2488,25 @@ void PrintConfigDef::init_fff_params()
|
||||
def->mode = comExpert;
|
||||
def->set_default_value(new ConfigOptionInt(-5));
|
||||
|
||||
def = this->add("start_gcode", coString);
|
||||
def->label = L("Start G-code");
|
||||
def->tooltip = L("This start procedure is inserted at the beginning, after bed has reached "
|
||||
"the target temperature and extruder just started heating, and before extruder "
|
||||
"has finished heating. If PrusaSlicer detects M104 or M190 in your custom codes, "
|
||||
"such commands will not be prepended automatically so you're free to customize "
|
||||
def = this->add("autoemit_temperature_commands", coBool);
|
||||
def->label = L("Emit temperature commands automatically");
|
||||
def->tooltip = L("When enabled, PrusaSlicer will check whether your Custom Start G-Code contains M104 or M190. "
|
||||
"If so, the temperatures will not be emitted automatically so you're free to customize "
|
||||
"the order of heating commands and other custom actions. Note that you can use "
|
||||
"placeholder variables for all PrusaSlicer settings, so you can put "
|
||||
"a \"M109 S[first_layer_temperature]\" command wherever you want.");
|
||||
"a \"M109 S[first_layer_temperature]\" command wherever you want.\n"
|
||||
"If your Custom Start G-Code does NOT contain M104 or M190, "
|
||||
"PrusaSlicer will execute the Start G-Code after bed reached its target temperature "
|
||||
"and extruder just started heating.\n\n"
|
||||
"When disabled, PrusaSlicer will NOT emit commands to heat up extruder and bed, "
|
||||
"leaving both to Custom Start G-Code.");
|
||||
def->mode = comExpert;
|
||||
def->set_default_value(new ConfigOptionBool(true));
|
||||
|
||||
def = this->add("start_gcode", coString);
|
||||
def->label = L("Start G-code");
|
||||
def->tooltip = L("This start procedure is inserted at the beginning, possibly prepended by "
|
||||
"temperature-changing commands. See 'autoemit_temperature_commands'.");
|
||||
def->multiline = true;
|
||||
def->full_width = true;
|
||||
def->height = 12;
|
||||
@ -2646,8 +2666,8 @@ void PrintConfigDef::init_fff_params()
|
||||
"If set to zero, support_material_contact_distance will be used for both top and bottom contact Z distances.");
|
||||
def->sidetext = L("mm");
|
||||
// def->min = 0;
|
||||
//TRN To be shown in Print Settings "Bottom contact Z distance". Have to be as short as possible
|
||||
def->set_enum_values(ConfigOptionDef::GUIType::f_enum_open, {
|
||||
//TRN Print Settings: "Bottom contact Z distance". Have to be as short as possible
|
||||
{ "0", L("Same as top") },
|
||||
{ "0.1", "0.1" },
|
||||
{ "0.2", "0.2" }
|
||||
@ -2705,7 +2725,7 @@ void PrintConfigDef::init_fff_params()
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionInt(1));
|
||||
|
||||
auto support_material_interface_layers = def = this->add("support_material_interface_layers", coInt);
|
||||
def = this->add("support_material_interface_layers", coInt);
|
||||
def->label = L("Top interface layers");
|
||||
def->category = L("Support material");
|
||||
def->tooltip = L("Number of interface layers to insert between the object(s) and support material.");
|
||||
@ -2727,8 +2747,8 @@ void PrintConfigDef::init_fff_params()
|
||||
"Set to -1 to use support_material_interface_layers");
|
||||
def->sidetext = L("layers");
|
||||
def->min = -1;
|
||||
//TRN To be shown in Print Settings "Bottom interface layers". Have to be as short as possible
|
||||
def->set_enum_values(ConfigOptionDef::GUIType::i_enum_open, {
|
||||
//TRN Print Settings: "Bottom interface layers". Have to be as short as possible
|
||||
{ "-1", L("Same as top") },
|
||||
{ "0", L("0 (off)") },
|
||||
{ "1", L("1 (light)") },
|
||||
@ -2829,6 +2849,7 @@ void PrintConfigDef::init_fff_params()
|
||||
def = this->add("support_material_synchronize_layers", coBool);
|
||||
def->label = L("Synchronize with object layers");
|
||||
def->category = L("Support material");
|
||||
// TRN PrintSettings : "Synchronize with object layers"
|
||||
def->tooltip = L("Synchronize support layers with the object print layers. This is useful "
|
||||
"with multi-material printers, where the extruder switch is expensive. "
|
||||
"This option is only available when top contact Z distance is set to zero.");
|
||||
@ -2860,6 +2881,7 @@ void PrintConfigDef::init_fff_params()
|
||||
def = this->add("support_tree_angle", coFloat);
|
||||
def->label = L("Maximum Branch Angle");
|
||||
def->category = L("Support material");
|
||||
// TRN PrintSettings: "Organic supports" > "Maximum Branch Angle"
|
||||
def->tooltip = L("The maximum angle of the branches, when the branches have to avoid the model. "
|
||||
"Use a lower angle to make them more vertical and more stable. Use a higher angle to be able to have more reach.");
|
||||
def->sidetext = L("°");
|
||||
@ -2871,6 +2893,7 @@ void PrintConfigDef::init_fff_params()
|
||||
def = this->add("support_tree_angle_slow", coFloat);
|
||||
def->label = L("Preferred Branch Angle");
|
||||
def->category = L("Support material");
|
||||
// TRN PrintSettings: "Organic supports" > "Preferred Branch Angle"
|
||||
def->tooltip = L("The preferred angle of the branches, when they do not have to avoid the model. "
|
||||
"Use a lower angle to make them more vertical and more stable. Use a higher angle for branches to merge faster.");
|
||||
def->sidetext = L("°");
|
||||
@ -2882,7 +2905,8 @@ void PrintConfigDef::init_fff_params()
|
||||
def = this->add("support_tree_tip_diameter", coFloat);
|
||||
def->label = L("Tip Diameter");
|
||||
def->category = L("Support material");
|
||||
def->tooltip = L("The diameter of the top of the tip of the branches of organic support.");
|
||||
// TRN PrintSettings: "Organic supports" > "Tip Diameter"
|
||||
def->tooltip = L("Branch tip diameter for organic supports.");
|
||||
def->sidetext = L("mm");
|
||||
def->min = 0;
|
||||
def->mode = comAdvanced;
|
||||
@ -2891,6 +2915,7 @@ void PrintConfigDef::init_fff_params()
|
||||
def = this->add("support_tree_branch_diameter", coFloat);
|
||||
def->label = L("Branch Diameter");
|
||||
def->category = L("Support material");
|
||||
// TRN PrintSettings: "Organic supports" > "Branch Diameter"
|
||||
def->tooltip = L("The diameter of the thinnest branches of organic support. Thicker branches are more sturdy. "
|
||||
"Branches towards the base will be thicker than this.");
|
||||
def->sidetext = L("mm");
|
||||
@ -2899,8 +2924,10 @@ void PrintConfigDef::init_fff_params()
|
||||
def->set_default_value(new ConfigOptionFloat(2));
|
||||
|
||||
def = this->add("support_tree_branch_diameter_angle", coFloat);
|
||||
// TRN PrintSettings: #lmFIXME
|
||||
def->label = L("Branch Diameter Angle");
|
||||
def->category = L("Support material");
|
||||
// TRN PrintSettings: "Organic supports" > "Branch Diameter Angle"
|
||||
def->tooltip = L("The angle of the branches' diameter as they gradually become thicker towards the bottom. "
|
||||
"An angle of 0 will cause the branches to have uniform thickness over their length. "
|
||||
"A bit of an angle can increase stability of the organic support.");
|
||||
@ -2914,8 +2941,10 @@ void PrintConfigDef::init_fff_params()
|
||||
// How far apart the branches need to be when they touch the model. Making this distance small will cause
|
||||
// the tree support to touch the model at more points, causing better overhang but making support harder to remove.
|
||||
def = this->add("support_tree_branch_distance", coFloat);
|
||||
// TRN PrintSettings: #lmFIXME
|
||||
def->label = L("Branch Distance");
|
||||
def->category = L("Support material");
|
||||
// TRN PrintSettings: "Organic supports" > "Branch Distance"
|
||||
def->tooltip = L("How far apart the branches need to be when they touch the model. "
|
||||
"Making this distance small will cause the tree support to touch the model at more points, "
|
||||
"causing better overhang but making support harder to remove.");
|
||||
@ -2925,6 +2954,7 @@ void PrintConfigDef::init_fff_params()
|
||||
def = this->add("support_tree_top_rate", coPercent);
|
||||
def->label = L("Branch Density");
|
||||
def->category = L("Support material");
|
||||
// TRN PrintSettings: "Organic supports" > "Branch Density"
|
||||
def->tooltip = L("Adjusts the density of the support structure used to generate the tips of the branches. "
|
||||
"A higher value results in better overhangs but the supports are harder to remove, "
|
||||
"thus it is recommended to enable top support interfaces instead of a high branch density value "
|
||||
@ -3013,8 +3043,8 @@ void PrintConfigDef::init_fff_params()
|
||||
def->set_default_value(new ConfigOptionFloatOrPercent(15, false));
|
||||
|
||||
def = this->add("top_solid_layers", coInt);
|
||||
//TRN To be shown in Print Settings "Top solid layers"
|
||||
def->label = L("Top");
|
||||
//TRN Print Settings: "Top solid layers"
|
||||
def->label = L_CONTEXT("Top", "Layers");
|
||||
def->category = L("Layers and Perimeters");
|
||||
def->tooltip = L("Number of solid layers to generate on top surfaces.");
|
||||
def->full_label = L("Top solid layers");
|
||||
@ -3022,8 +3052,7 @@ void PrintConfigDef::init_fff_params()
|
||||
def->set_default_value(new ConfigOptionInt(3));
|
||||
|
||||
def = this->add("top_solid_min_thickness", coFloat);
|
||||
//TRN To be shown in Print Settings "Top solid layers"
|
||||
def->label = L("Top");
|
||||
def->label = L_CONTEXT("Top", "Layers");
|
||||
def->category = L("Layers and Perimeters");
|
||||
def->tooltip = L("The number of top solid layers is increased above top_solid_layers if necessary to satisfy "
|
||||
"minimum thickness of top shell."
|
||||
@ -3150,6 +3179,25 @@ void PrintConfigDef::init_fff_params()
|
||||
def->min = 0.;
|
||||
def->set_default_value(new ConfigOptionFloat(2.));
|
||||
|
||||
def = this->add("wipe_tower_cone_angle", coFloat);
|
||||
def->label = L("Stabilization cone apex angle");
|
||||
def->tooltip = L("Angle at the apex of the cone that is used to stabilize the wipe tower. "
|
||||
"Larger angle means wider base.");
|
||||
def->sidetext = L("°");
|
||||
def->mode = comAdvanced;
|
||||
def->min = 0.;
|
||||
def->max = 90.;
|
||||
def->set_default_value(new ConfigOptionFloat(0.));
|
||||
|
||||
def = this->add("wipe_tower_extra_spacing", coPercent);
|
||||
def->label = L("Wipe tower purge lines spacing");
|
||||
def->tooltip = L("Spacing of purge lines on the wipe tower.");
|
||||
def->sidetext = L("%");
|
||||
def->mode = comExpert;
|
||||
def->min = 100.;
|
||||
def->max = 300.;
|
||||
def->set_default_value(new ConfigOptionPercent(100.));
|
||||
|
||||
def = this->add("wipe_into_infill", coBool);
|
||||
def->category = L("Wipe options");
|
||||
def->label = L("Wipe into this object's infill");
|
||||
@ -3860,7 +3908,9 @@ void PrintConfigDef::init_sla_params()
|
||||
def->tooltip = L("Support tree building strategy");
|
||||
def->set_enum<sla::SupportTreeType>(
|
||||
ConfigOptionEnum<sla::SupportTreeType>::get_enum_names(),
|
||||
{ L("Default"), L("Branching (experimental)") });
|
||||
{ L("Default"),
|
||||
// TRN One of the "Support tree type"s on SLAPrintSettings : Supports
|
||||
L("Branching (experimental)") });
|
||||
// TODO: def->enum_def->labels[2] = L("Organic");
|
||||
def->mode = comSimple;
|
||||
def->set_default_value(new ConfigOptionEnum(sla::SupportTreeType::Default));
|
||||
@ -4103,6 +4153,8 @@ static std::set<std::string> PrintConfigDef_ignore = {
|
||||
"wall_add_middle_threshold", "wall_split_middle_threshold",
|
||||
// Replaced by new concentric ensuring in 2.6.0-alpha5
|
||||
"ensure_vertical_shell_thickness",
|
||||
// Disabled in 2.6.0-alpha6, this option is problematic
|
||||
"infill_only_where_needed",
|
||||
};
|
||||
|
||||
void PrintConfigDef::handle_legacy(t_config_option_key &opt_key, std::string &value)
|
||||
@ -4383,8 +4435,9 @@ std::string validate(const FullPrintConfig &cfg)
|
||||
cfg.gcode_flavor.value != gcfMarlinLegacy &&
|
||||
cfg.gcode_flavor.value != gcfMarlinFirmware &&
|
||||
cfg.gcode_flavor.value != gcfMachinekit &&
|
||||
cfg.gcode_flavor.value != gcfRepetier)
|
||||
return "--use-firmware-retraction is only supported by Marlin, Smoothie, RepRapFirmware, Repetier and Machinekit firmware";
|
||||
cfg.gcode_flavor.value != gcfRepetier &&
|
||||
cfg.gcode_flavor.value != gcfKlipper)
|
||||
return "--use-firmware-retraction is only supported by Marlin, Klipper, Smoothie, RepRapFirmware, Repetier and Machinekit firmware";
|
||||
|
||||
if (cfg.use_firmware_retraction.value)
|
||||
for (unsigned char wipe : cfg.wipe.values)
|
||||
@ -4500,12 +4553,19 @@ std::string validate(const FullPrintConfig &cfg)
|
||||
}
|
||||
case coFloats:
|
||||
case coPercents:
|
||||
for (double v : static_cast<const ConfigOptionVector<double>*>(opt)->values)
|
||||
{
|
||||
const auto* vec = static_cast<const ConfigOptionVector<double>*>(opt);
|
||||
for (size_t i = 0; i < vec->size(); ++i) {
|
||||
if (vec->is_nil(i))
|
||||
continue;
|
||||
double v = vec->values[i];
|
||||
if (v < optdef->min || v > optdef->max) {
|
||||
out_of_range = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case coInt:
|
||||
{
|
||||
auto *iopt = static_cast<const ConfigOptionInt*>(opt);
|
||||
@ -4513,12 +4573,19 @@ std::string validate(const FullPrintConfig &cfg)
|
||||
break;
|
||||
}
|
||||
case coInts:
|
||||
for (int v : static_cast<const ConfigOptionVector<int>*>(opt)->values)
|
||||
{
|
||||
const auto* vec = static_cast<const ConfigOptionVector<int>*>(opt);
|
||||
for (size_t i = 0; i < vec->size(); ++i) {
|
||||
if (vec->is_nil(i))
|
||||
continue;
|
||||
int v = vec->values[i];
|
||||
if (v < optdef->min || v > optdef->max) {
|
||||
out_of_range = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:;
|
||||
}
|
||||
if (out_of_range)
|
||||
@ -4598,7 +4665,7 @@ CLIActionsConfigDef::CLIActionsConfigDef()
|
||||
#if ENABLE_GL_CORE_PROFILE
|
||||
def = this->add("opengl-version", coString);
|
||||
def->label = L("OpenGL version");
|
||||
def->tooltip = L("Select the specified OpenGL version");
|
||||
def->tooltip = L("Select a specific version of OpenGL");
|
||||
def->cli = "opengl-version";
|
||||
def->set_default_value(new ConfigOptionString());
|
||||
|
||||
@ -4867,18 +4934,21 @@ std::string get_sla_suptree_prefix(const DynamicPrintConfig &config)
|
||||
return slatree;
|
||||
}
|
||||
|
||||
bool is_XL_printer(const DynamicPrintConfig &cfg)
|
||||
static bool is_XL_printer(const std::string& printer_model)
|
||||
{
|
||||
static constexpr const char *ALIGN_ONLY_FOR = "XL";
|
||||
return boost::algorithm::contains(printer_model, ALIGN_ONLY_FOR);
|
||||
}
|
||||
|
||||
bool ret = false;
|
||||
|
||||
bool is_XL_printer(const DynamicPrintConfig &cfg)
|
||||
{
|
||||
auto *printer_model = cfg.opt<ConfigOptionString>("printer_model");
|
||||
return printer_model && is_XL_printer(printer_model->value);
|
||||
}
|
||||
|
||||
if (printer_model)
|
||||
ret = boost::algorithm::contains(printer_model->value, ALIGN_ONLY_FOR);
|
||||
|
||||
return ret;
|
||||
bool is_XL_printer(const PrintConfig &cfg)
|
||||
{
|
||||
return is_XL_printer(cfg.printer_model.value);
|
||||
}
|
||||
|
||||
} // namespace Slic3r
|
||||
|
@ -32,7 +32,7 @@
|
||||
namespace Slic3r {
|
||||
|
||||
enum GCodeFlavor : unsigned char {
|
||||
gcfRepRapSprinter, gcfRepRapFirmware, gcfRepetier, gcfTeacup, gcfMakerWare, gcfMarlinLegacy, gcfMarlinFirmware, gcfSailfish, gcfMach3, gcfMachinekit,
|
||||
gcfRepRapSprinter, gcfRepRapFirmware, gcfRepetier, gcfTeacup, gcfMakerWare, gcfMarlinLegacy, gcfMarlinFirmware, gcfKlipper, gcfSailfish, gcfMach3, gcfMachinekit,
|
||||
gcfSmoothie, gcfNoExtrusion,
|
||||
};
|
||||
|
||||
@ -44,7 +44,7 @@ enum class MachineLimitsUsage {
|
||||
};
|
||||
|
||||
enum PrintHostType {
|
||||
htPrusaLink, htPrusaConnect, htOctoPrint, htDuet, htFlashAir, htAstroBox, htRepetier, htMKS
|
||||
htPrusaLink, htPrusaConnect, htOctoPrint, htDuet, htFlashAir, htAstroBox, htRepetier, htMKS, htMainSail
|
||||
};
|
||||
|
||||
enum AuthorizationType {
|
||||
@ -495,7 +495,7 @@ PRINT_CONFIG_CLASS_DEFINE(
|
||||
((ConfigOptionFloatOrPercent, extrusion_width))
|
||||
((ConfigOptionFloat, first_layer_acceleration_over_raft))
|
||||
((ConfigOptionFloatOrPercent, first_layer_speed_over_raft))
|
||||
((ConfigOptionBool, infill_only_where_needed))
|
||||
// ((ConfigOptionBool, infill_only_where_needed))
|
||||
// Force the generation of solid shells between adjacent materials/volumes.
|
||||
((ConfigOptionBool, interface_shells))
|
||||
((ConfigOptionFloat, layer_height))
|
||||
@ -661,6 +661,7 @@ PRINT_CONFIG_CLASS_DEFINE(
|
||||
PRINT_CONFIG_CLASS_DEFINE(
|
||||
GCodeConfig,
|
||||
|
||||
((ConfigOptionBool, autoemit_temperature_commands))
|
||||
((ConfigOptionString, before_layer_gcode))
|
||||
((ConfigOptionString, between_objects_gcode))
|
||||
((ConfigOptionFloats, deretract_speed))
|
||||
@ -815,6 +816,7 @@ PRINT_CONFIG_CLASS_DERIVED_DEFINE(
|
||||
((ConfigOptionPoints, thumbnails))
|
||||
((ConfigOptionEnum<GCodeThumbnailsFormat>, thumbnails_format))
|
||||
((ConfigOptionFloat, top_solid_infill_acceleration))
|
||||
((ConfigOptionFloat, travel_acceleration))
|
||||
((ConfigOptionBools, wipe))
|
||||
((ConfigOptionBool, wipe_tower))
|
||||
((ConfigOptionFloat, wipe_tower_x))
|
||||
@ -823,6 +825,8 @@ PRINT_CONFIG_CLASS_DERIVED_DEFINE(
|
||||
((ConfigOptionFloat, wipe_tower_per_color_wipe))
|
||||
((ConfigOptionFloat, wipe_tower_rotation_angle))
|
||||
((ConfigOptionFloat, wipe_tower_brim_width))
|
||||
((ConfigOptionFloat, wipe_tower_cone_angle))
|
||||
((ConfigOptionPercent, wipe_tower_extra_spacing))
|
||||
((ConfigOptionFloat, wipe_tower_bridging))
|
||||
((ConfigOptionFloats, wiping_volumes_matrix))
|
||||
((ConfigOptionFloats, wiping_volumes_extruders))
|
||||
@ -1188,6 +1192,7 @@ private:
|
||||
};
|
||||
|
||||
bool is_XL_printer(const DynamicPrintConfig &cfg);
|
||||
bool is_XL_printer(const PrintConfig &cfg);
|
||||
|
||||
Points get_bed_shape(const DynamicPrintConfig &cfg);
|
||||
Points get_bed_shape(const PrintConfig &cfg);
|
||||
|
@ -56,10 +56,6 @@
|
||||
|
||||
using namespace std::literals;
|
||||
|
||||
//! macro used to mark string used at localization,
|
||||
//! return same string
|
||||
#define L(s) Slic3r::I18N::translate(s)
|
||||
|
||||
#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
|
||||
#define SLIC3R_DEBUG
|
||||
#endif
|
||||
@ -153,7 +149,7 @@ void PrintObject::make_perimeters()
|
||||
if (! this->set_started(posPerimeters))
|
||||
return;
|
||||
|
||||
m_print->set_status(20, L("Generating perimeters"));
|
||||
m_print->set_status(20, _u8L("Generating perimeters"));
|
||||
BOOST_LOG_TRIVIAL(info) << "Generating perimeters..." << log_memory_info();
|
||||
|
||||
// Revert the typed slices into untyped slices.
|
||||
@ -258,7 +254,7 @@ void PrintObject::prepare_infill()
|
||||
if (! this->set_started(posPrepareInfill))
|
||||
return;
|
||||
|
||||
m_print->set_status(30, L("Preparing infill"));
|
||||
m_print->set_status(30, _u8L("Preparing infill"));
|
||||
|
||||
if (m_typed_slices) {
|
||||
// To improve robustness of detect_surfaces_type() when reslicing (working with typed slices), see GH issue #7442.
|
||||
@ -352,8 +348,8 @@ void PrintObject::prepare_infill()
|
||||
//FIXME The surfaces are supported by a sparse infill, but the sparse infill is only as large as the area to support.
|
||||
// Likely the sparse infill will not be anchored correctly, so it will not work as intended.
|
||||
// Also one wishes the perimeters to be supported by a full infill.
|
||||
this->clip_fill_surfaces();
|
||||
m_print->throw_if_canceled();
|
||||
// this->clip_fill_surfaces();
|
||||
// m_print->throw_if_canceled();
|
||||
|
||||
#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
|
||||
for (size_t region_id = 0; region_id < this->num_printing_regions(); ++ region_id) {
|
||||
@ -403,7 +399,8 @@ void PrintObject::infill()
|
||||
this->prepare_infill();
|
||||
|
||||
if (this->set_started(posInfill)) {
|
||||
m_print->set_status(45, L("making infill"));
|
||||
// TRN Status for the Print calculation
|
||||
m_print->set_status(45, _u8L("Making infill"));
|
||||
const auto& adaptive_fill_octree = this->m_adaptive_fill_octrees.first;
|
||||
const auto& support_fill_octree = this->m_adaptive_fill_octrees.second;
|
||||
|
||||
@ -450,7 +447,7 @@ void PrintObject::generate_support_spots()
|
||||
{
|
||||
if (this->set_started(posSupportSpotsSearch)) {
|
||||
BOOST_LOG_TRIVIAL(debug) << "Searching support spots - start";
|
||||
m_print->set_status(65, L("Searching support spots"));
|
||||
m_print->set_status(65, _u8L("Searching support spots"));
|
||||
if (!this->shared_regions()->generated_support_points.has_value()) {
|
||||
PrintTryCancel cancel_func = m_print->make_try_cancel();
|
||||
SupportSpotsGenerator::Params params{this->print()->m_config.filament_type.values,
|
||||
@ -475,7 +472,7 @@ void PrintObject::generate_support_material()
|
||||
if (this->set_started(posSupportMaterial)) {
|
||||
this->clear_support_layers();
|
||||
if ((this->has_support() && m_layers.size() > 1) || (this->has_raft() && ! m_layers.empty())) {
|
||||
m_print->set_status(70, L("Generating support material"));
|
||||
m_print->set_status(70, _u8L("Generating support material"));
|
||||
this->_generate_support_material();
|
||||
m_print->throw_if_canceled();
|
||||
} else {
|
||||
@ -496,7 +493,7 @@ void PrintObject::estimate_curled_extrusions()
|
||||
if (this->set_started(posEstimateCurledExtrusions)) {
|
||||
if (this->print()->config().avoid_crossing_curled_overhangs) {
|
||||
BOOST_LOG_TRIVIAL(debug) << "Estimating areas with curled extrusions - start";
|
||||
m_print->set_status(88, L("Estimating curled extrusions"));
|
||||
m_print->set_status(88, _u8L("Estimating curled extrusions"));
|
||||
|
||||
// Estimate curling of support material and add it to the malformaition lines of each layer
|
||||
float support_flow_width = support_material_flow(this, this->config().layer_height).width();
|
||||
@ -1376,43 +1373,56 @@ void PrintObject::discover_vertical_shells()
|
||||
}
|
||||
#endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
|
||||
polygons_append(holes, cache_top_botom_regions[idx_layer].holes);
|
||||
if (int n_top_layers = region_config.top_solid_layers.value; n_top_layers > 0) {
|
||||
// Gather top regions projected to this layer.
|
||||
coordf_t print_z = layer->print_z;
|
||||
for (int i = int(idx_layer) + 1;
|
||||
i < int(cache_top_botom_regions.size()) &&
|
||||
(i < int(idx_layer) + n_top_layers ||
|
||||
m_layers[i]->print_z - print_z < region_config.top_solid_min_thickness - EPSILON);
|
||||
++ i) {
|
||||
const DiscoverVerticalShellsCacheEntry &cache = cache_top_botom_regions[i];
|
||||
if (! holes.empty())
|
||||
holes = intersection(holes, cache.holes);
|
||||
if (! cache.top_surfaces.empty()) {
|
||||
polygons_append(shell, cache.top_surfaces);
|
||||
auto combine_holes = [&holes](const Polygons &holes2) {
|
||||
if (holes.empty() || holes2.empty())
|
||||
holes.clear();
|
||||
else
|
||||
holes = intersection(holes, holes2);
|
||||
};
|
||||
auto combine_shells = [&shell](const Polygons &shells2) {
|
||||
if (shell.empty())
|
||||
shell = std::move(shells2);
|
||||
else if (! shells2.empty()) {
|
||||
polygons_append(shell, shells2);
|
||||
// Running the union_ using the Clipper library piece by piece is cheaper
|
||||
// than running the union_ all at once.
|
||||
shell = union_(shell);
|
||||
}
|
||||
};
|
||||
static constexpr const bool one_more_layer_below_top_bottom_surfaces = false;
|
||||
if (int n_top_layers = region_config.top_solid_layers.value; n_top_layers > 0) {
|
||||
// Gather top regions projected to this layer.
|
||||
coordf_t print_z = layer->print_z;
|
||||
int i = int(idx_layer) + 1;
|
||||
int itop = int(idx_layer) + n_top_layers;
|
||||
for (; i < int(cache_top_botom_regions.size()) &&
|
||||
(i < itop || m_layers[i]->print_z - print_z < region_config.top_solid_min_thickness - EPSILON);
|
||||
++ i) {
|
||||
const DiscoverVerticalShellsCacheEntry &cache = cache_top_botom_regions[i];
|
||||
combine_holes(cache.holes);
|
||||
combine_shells(cache.top_surfaces);
|
||||
}
|
||||
if (one_more_layer_below_top_bottom_surfaces)
|
||||
if (i < int(cache_top_botom_regions.size()) &&
|
||||
(i <= itop || m_layers[i]->bottom_z() - print_z < region_config.top_solid_min_thickness - EPSILON))
|
||||
combine_holes(cache_top_botom_regions[i].holes);
|
||||
}
|
||||
if (int n_bottom_layers = region_config.bottom_solid_layers.value; n_bottom_layers > 0) {
|
||||
// Gather bottom regions projected to this layer.
|
||||
coordf_t bottom_z = layer->bottom_z();
|
||||
for (int i = int(idx_layer) - 1;
|
||||
i >= 0 &&
|
||||
(i > int(idx_layer) - n_bottom_layers ||
|
||||
bottom_z - m_layers[i]->bottom_z() < region_config.bottom_solid_min_thickness - EPSILON);
|
||||
int i = int(idx_layer) - 1;
|
||||
int ibottom = int(idx_layer) - n_bottom_layers;
|
||||
for (; i >= 0 &&
|
||||
(i > ibottom || bottom_z - m_layers[i]->bottom_z() < region_config.bottom_solid_min_thickness - EPSILON);
|
||||
-- i) {
|
||||
const DiscoverVerticalShellsCacheEntry &cache = cache_top_botom_regions[i];
|
||||
if (! holes.empty())
|
||||
holes = intersection(holes, cache.holes);
|
||||
if (! cache.bottom_surfaces.empty()) {
|
||||
polygons_append(shell, cache.bottom_surfaces);
|
||||
// Running the union_ using the Clipper library piece by piece is cheaper
|
||||
// than running the union_ all at once.
|
||||
shell = union_(shell);
|
||||
}
|
||||
combine_holes(cache.holes);
|
||||
combine_shells(cache.bottom_surfaces);
|
||||
}
|
||||
if (one_more_layer_below_top_bottom_surfaces)
|
||||
if (i >= 0 &&
|
||||
(i > ibottom || bottom_z - m_layers[i]->print_z < region_config.bottom_solid_min_thickness - EPSILON))
|
||||
combine_holes(cache_top_botom_regions[i].holes);
|
||||
}
|
||||
#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
|
||||
{
|
||||
@ -1641,7 +1651,8 @@ void PrintObject::bridge_over_infill()
|
||||
unsupported_area = closing(unsupported_area, SCALED_EPSILON);
|
||||
// By expanding the lower layer solids, we avoid making bridges from the tiny internal overhangs that are (very likely) supported by previous layer solids
|
||||
// NOTE that we cannot filter out polygons worth bridging by their area, because sometimes there is a very small internal island that will grow into large hole
|
||||
lower_layer_solids = expand(lower_layer_solids, 3 * spacing);
|
||||
lower_layer_solids = shrink(lower_layer_solids, 1 * spacing); // first remove thin regions that will not support anything
|
||||
lower_layer_solids = expand(lower_layer_solids, (1 + 3) * spacing); // then expand back (opening), and further for parts supported by internal solids
|
||||
// By shrinking the unsupported area, we avoid making bridges from narrow ensuring region along perimeters.
|
||||
unsupported_area = shrink(unsupported_area, 3 * spacing);
|
||||
unsupported_area = diff(unsupported_area, lower_layer_solids);
|
||||
@ -1815,13 +1826,17 @@ void PrintObject::bridge_over_infill()
|
||||
|
||||
std::map<double, int> counted_directions;
|
||||
for (const Polygon &p : bridged_area) {
|
||||
double acc_distance = 0;
|
||||
for (int point_idx = 0; point_idx < int(p.points.size()) - 1; ++point_idx) {
|
||||
Vec2d start = p.points[point_idx].cast<double>();
|
||||
Vec2d next = p.points[point_idx + 1].cast<double>();
|
||||
Vec2d v = next - start; // vector from next to current
|
||||
double dist_to_next = v.norm();
|
||||
acc_distance += dist_to_next;
|
||||
if (acc_distance > scaled(2.0)) {
|
||||
acc_distance = 0.0;
|
||||
v.normalize();
|
||||
int lines_count = int(std::ceil(dist_to_next / scaled(3.0)));
|
||||
int lines_count = int(std::ceil(dist_to_next / scaled(2.0)));
|
||||
float step_size = dist_to_next / lines_count;
|
||||
for (int i = 0; i < lines_count; ++i) {
|
||||
Point a = (start + v * (i * step_size)).cast<coord_t>();
|
||||
@ -1835,6 +1850,7 @@ void PrintObject::bridge_over_infill()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::pair<double, int> best_dir{0, 0};
|
||||
// sliding window accumulation
|
||||
@ -2073,14 +2089,27 @@ void PrintObject::bridge_over_infill()
|
||||
};
|
||||
return a.min.x() < b.min.x();
|
||||
});
|
||||
if (surfaces_by_layer[lidx].size() > 2) {
|
||||
Vec2d origin = get_extents(surfaces_by_layer[lidx].front().new_polys).max.cast<double>();
|
||||
std::stable_sort(surfaces_by_layer[lidx].begin() + 1, surfaces_by_layer[lidx].end(),
|
||||
[origin](const CandidateSurface &left, const CandidateSurface &right) {
|
||||
auto a = get_extents(left.new_polys);
|
||||
auto b = get_extents(right.new_polys);
|
||||
|
||||
return (origin - a.min.cast<double>()).squaredNorm() <
|
||||
(origin - b.min.cast<double>()).squaredNorm();
|
||||
});
|
||||
}
|
||||
|
||||
// Gather deep infill areas, where thick bridges fit
|
||||
coordf_t spacing = surfaces_by_layer[lidx].front().region->flow(frSolidInfill, true).scaled_spacing();
|
||||
coordf_t target_flow_height = surfaces_by_layer[lidx].front().region->flow(frSolidInfill, true).height() * target_flow_height_factor;
|
||||
Polygons deep_infill_area = gather_areas_w_depth(po, lidx, target_flow_height);
|
||||
|
||||
{
|
||||
// Now also remove area that has been already filled on lower layers by bridging expansion - For this
|
||||
// reason we did the clustering of layers per thread.
|
||||
Polygons filled_polyons_on_lower_layers;
|
||||
double bottom_z = layer->print_z - target_flow_height - EPSILON;
|
||||
if (job_idx > 0) {
|
||||
for (int lower_job_idx = job_idx - 1; lower_job_idx >= 0; lower_job_idx--) {
|
||||
@ -2088,13 +2117,16 @@ void PrintObject::bridge_over_infill()
|
||||
const Layer *lower_layer = po->get_layer(lower_layer_idx);
|
||||
if (lower_layer->print_z >= bottom_z) {
|
||||
for (const auto &c : surfaces_by_layer[lower_layer_idx]) {
|
||||
deep_infill_area = diff(deep_infill_area, c.new_polys);
|
||||
filled_polyons_on_lower_layers.insert(filled_polyons_on_lower_layers.end(), c.new_polys.begin(),
|
||||
c.new_polys.end());
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
deep_infill_area = diff(deep_infill_area, filled_polyons_on_lower_layers);
|
||||
}
|
||||
|
||||
deep_infill_area = expand(deep_infill_area, spacing * 1.5);
|
||||
|
||||
@ -2110,11 +2142,10 @@ void PrintObject::bridge_over_infill()
|
||||
total_fill_area = closing(total_fill_area, SCALED_EPSILON);
|
||||
expansion_area = closing(expansion_area, SCALED_EPSILON);
|
||||
expansion_area = intersection(expansion_area, deep_infill_area);
|
||||
Polylines anchors = intersection_pl(infill_lines[lidx - 1], expansion_area);
|
||||
Polylines anchors = intersection_pl(infill_lines[lidx - 1], shrink(expansion_area, spacing));
|
||||
|
||||
#ifdef DEBUG_BRIDGE_OVER_INFILL
|
||||
debug_draw(std::to_string(lidx) + "_" + std::to_string(cluster_idx) + "_" + std::to_string(job_idx) + "_" +
|
||||
"_total_area",
|
||||
debug_draw(std::to_string(lidx) + "_" + std::to_string(cluster_idx) + "_" + std::to_string(job_idx) + "_" + "_total_area",
|
||||
to_lines(total_fill_area), to_lines(expansion_area), to_lines(deep_infill_area), to_lines(anchors));
|
||||
#endif
|
||||
|
||||
@ -2176,6 +2207,7 @@ void PrintObject::bridge_over_infill()
|
||||
}
|
||||
|
||||
bridging_area = opening(bridging_area, flow.scaled_spacing());
|
||||
bridging_area = closing(bridging_area, flow.scaled_spacing());
|
||||
bridging_area = intersection(bridging_area, limiting_area);
|
||||
bridging_area = intersection(bridging_area, total_fill_area);
|
||||
expansion_area = diff(expansion_area, bridging_area);
|
||||
@ -2210,35 +2242,33 @@ void PrintObject::bridge_over_infill()
|
||||
for (LayerRegion *region : layer->regions()) {
|
||||
Surfaces new_surfaces;
|
||||
|
||||
SurfacesPtr internal_infills = region->m_fill_surfaces.filter_by_type(stInternal);
|
||||
ExPolygons new_internal_infills = diff_ex(internal_infills, cut_from_infill);
|
||||
for (const ExPolygon &ep : new_internal_infills) {
|
||||
new_surfaces.emplace_back(*internal_infills.front(), ep);
|
||||
}
|
||||
|
||||
SurfacesPtr internal_solids = region->m_fill_surfaces.filter_by_type(stInternalSolid);
|
||||
for (const CandidateSurface &cs : surfaces_by_layer.at(lidx)) {
|
||||
for (Surface &surface : region->m_fill_surfaces.surfaces) {
|
||||
if (cs.original_surface == &surface) {
|
||||
Surface tmp(surface, {});
|
||||
for (const ExPolygon &expoly : diff_ex(surface.expolygon, cs.new_polys)) {
|
||||
if (expoly.area() > region->flow(frSolidInfill).scaled_width() * scale_(4.0)) {
|
||||
new_surfaces.emplace_back(tmp, expoly);
|
||||
}
|
||||
}
|
||||
for (const Surface *surface : internal_solids) {
|
||||
if (cs.original_surface == surface) {
|
||||
Surface tmp{*surface, {}};
|
||||
tmp.surface_type = stInternalBridge;
|
||||
tmp.bridge_angle = cs.bridge_angle;
|
||||
for (const ExPolygon &expoly : union_ex(cs.new_polys)) {
|
||||
new_surfaces.emplace_back(tmp, expoly);
|
||||
for (const ExPolygon &ep : union_ex(cs.new_polys)) {
|
||||
new_surfaces.emplace_back(tmp, ep);
|
||||
}
|
||||
surface.clear();
|
||||
} else if (surface.surface_type == stInternal) {
|
||||
Surface tmp(surface, {});
|
||||
for (const ExPolygon &expoly : diff_ex(surface.expolygon, cut_from_infill)) {
|
||||
new_surfaces.emplace_back(tmp, expoly);
|
||||
}
|
||||
surface.clear();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
region->m_fill_surfaces.surfaces.insert(region->m_fill_surfaces.surfaces.end(), new_surfaces.begin(), new_surfaces.end());
|
||||
region->m_fill_surfaces.surfaces.erase(std::remove_if(region->m_fill_surfaces.surfaces.begin(),
|
||||
region->m_fill_surfaces.surfaces.end(),
|
||||
[](const Surface &s) { return s.empty(); }),
|
||||
region->m_fill_surfaces.surfaces.end());
|
||||
ExPolygons new_internal_solids = diff_ex(internal_solids, cut_from_infill);
|
||||
for (const ExPolygon &ep : new_internal_solids) {
|
||||
new_surfaces.emplace_back(*internal_solids.front(), ep);
|
||||
}
|
||||
|
||||
region->m_fill_surfaces.remove_types({stInternalSolid, stInternal});
|
||||
region->m_fill_surfaces.append(new_surfaces);
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -2422,98 +2452,98 @@ bool PrintObject::update_layer_height_profile(const ModelObject &model_object, c
|
||||
// Also one wishes the perimeters to be supported by a full infill.
|
||||
// Idempotence of this method is guaranteed by the fact that we don't remove things from
|
||||
// fill_surfaces but we only turn them into VOID surfaces, thus preserving the boundaries.
|
||||
void PrintObject::clip_fill_surfaces()
|
||||
{
|
||||
bool has_lightning_infill = false;
|
||||
for (size_t region_id = 0; region_id < this->num_printing_regions(); ++region_id)
|
||||
if (const PrintRegionConfig &config = this->printing_region(region_id).config(); config.fill_density > 0 && config.fill_pattern == ipLightning)
|
||||
has_lightning_infill = true;
|
||||
// void PrintObject::clip_fill_surfaces()
|
||||
// {
|
||||
// bool has_lightning_infill = false;
|
||||
// for (size_t region_id = 0; region_id < this->num_printing_regions(); ++region_id)
|
||||
// if (const PrintRegionConfig &config = this->printing_region(region_id).config(); config.fill_density > 0 && config.fill_pattern == ipLightning)
|
||||
// has_lightning_infill = true;
|
||||
|
||||
// For Lightning infill, infill_only_where_needed is ignored because both
|
||||
// do a similar thing, and their combination doesn't make much sense.
|
||||
if (! m_config.infill_only_where_needed.value || has_lightning_infill)
|
||||
return;
|
||||
bool has_infill = false;
|
||||
for (size_t i = 0; i < this->num_printing_regions(); ++ i)
|
||||
if (this->printing_region(i).config().fill_density > 0) {
|
||||
has_infill = true;
|
||||
break;
|
||||
}
|
||||
if (! has_infill)
|
||||
return;
|
||||
// // For Lightning infill, infill_only_where_needed is ignored because both
|
||||
// // do a similar thing, and their combination doesn't make much sense.
|
||||
// if (! m_config.infill_only_where_needed.value || has_lightning_infill)
|
||||
// return;
|
||||
// bool has_infill = false;
|
||||
// for (size_t i = 0; i < this->num_printing_regions(); ++ i)
|
||||
// if (this->printing_region(i).config().fill_density > 0) {
|
||||
// has_infill = true;
|
||||
// break;
|
||||
// }
|
||||
// if (! has_infill)
|
||||
// return;
|
||||
|
||||
// We only want infill under ceilings; this is almost like an
|
||||
// internal support material.
|
||||
// Proceed top-down, skipping the bottom layer.
|
||||
Polygons upper_internal;
|
||||
for (int layer_id = int(m_layers.size()) - 1; layer_id > 0; -- layer_id) {
|
||||
Layer *layer = m_layers[layer_id];
|
||||
Layer *lower_layer = m_layers[layer_id - 1];
|
||||
// Detect things that we need to support.
|
||||
// Cummulative fill surfaces.
|
||||
Polygons fill_surfaces;
|
||||
// Solid surfaces to be supported.
|
||||
Polygons overhangs;
|
||||
for (const LayerRegion *layerm : layer->m_regions)
|
||||
for (const Surface &surface : layerm->fill_surfaces()) {
|
||||
Polygons polygons = to_polygons(surface.expolygon);
|
||||
if (surface.is_solid())
|
||||
polygons_append(overhangs, polygons);
|
||||
polygons_append(fill_surfaces, std::move(polygons));
|
||||
}
|
||||
Polygons lower_layer_fill_surfaces;
|
||||
Polygons lower_layer_internal_surfaces;
|
||||
for (const LayerRegion *layerm : lower_layer->m_regions)
|
||||
for (const Surface &surface : layerm->fill_surfaces()) {
|
||||
Polygons polygons = to_polygons(surface.expolygon);
|
||||
if (surface.surface_type == stInternal || surface.surface_type == stInternalVoid)
|
||||
polygons_append(lower_layer_internal_surfaces, polygons);
|
||||
polygons_append(lower_layer_fill_surfaces, std::move(polygons));
|
||||
}
|
||||
// We also need to support perimeters when there's at least one full unsupported loop
|
||||
{
|
||||
// Get perimeters area as the difference between slices and fill_surfaces
|
||||
// Only consider the area that is not supported by lower perimeters
|
||||
Polygons perimeters = intersection(diff(layer->lslices, fill_surfaces), lower_layer_fill_surfaces);
|
||||
// Only consider perimeter areas that are at least one extrusion width thick.
|
||||
//FIXME Offset2 eats out from both sides, while the perimeters are create outside in.
|
||||
//Should the pw not be half of the current value?
|
||||
float pw = FLT_MAX;
|
||||
for (const LayerRegion *layerm : layer->m_regions)
|
||||
pw = std::min(pw, (float)layerm->flow(frPerimeter).scaled_width());
|
||||
// Append such thick perimeters to the areas that need support
|
||||
polygons_append(overhangs, opening(perimeters, pw));
|
||||
}
|
||||
// Merge the new overhangs, find new internal infill.
|
||||
polygons_append(upper_internal, std::move(overhangs));
|
||||
static constexpr const auto closing_radius = scaled<float>(2.f);
|
||||
upper_internal = intersection(
|
||||
// Regularize the overhang regions, so that the infill areas will not become excessively jagged.
|
||||
smooth_outward(
|
||||
closing(upper_internal, closing_radius, ClipperLib::jtSquare, 0.),
|
||||
scaled<coord_t>(0.1)),
|
||||
lower_layer_internal_surfaces);
|
||||
// Apply new internal infill to regions.
|
||||
for (LayerRegion *layerm : lower_layer->m_regions) {
|
||||
if (layerm->region().config().fill_density.value == 0)
|
||||
continue;
|
||||
Polygons internal;
|
||||
for (Surface &surface : layerm->m_fill_surfaces.surfaces)
|
||||
if (surface.surface_type == stInternal || surface.surface_type == stInternalVoid)
|
||||
polygons_append(internal, std::move(surface.expolygon));
|
||||
layerm->m_fill_surfaces.remove_types({ stInternal, stInternalVoid });
|
||||
layerm->m_fill_surfaces.append(intersection_ex(internal, upper_internal, ApplySafetyOffset::Yes), stInternal);
|
||||
layerm->m_fill_surfaces.append(diff_ex (internal, upper_internal, ApplySafetyOffset::Yes), stInternalVoid);
|
||||
// If there are voids it means that our internal infill is not adjacent to
|
||||
// perimeters. In this case it would be nice to add a loop around infill to
|
||||
// make it more robust and nicer. TODO.
|
||||
#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
|
||||
layerm->export_region_fill_surfaces_to_svg_debug("6_clip_fill_surfaces");
|
||||
#endif
|
||||
}
|
||||
m_print->throw_if_canceled();
|
||||
}
|
||||
} // void PrintObject::clip_fill_surfaces()
|
||||
// // We only want infill under ceilings; this is almost like an
|
||||
// // internal support material.
|
||||
// // Proceed top-down, skipping the bottom layer.
|
||||
// Polygons upper_internal;
|
||||
// for (int layer_id = int(m_layers.size()) - 1; layer_id > 0; -- layer_id) {
|
||||
// Layer *layer = m_layers[layer_id];
|
||||
// Layer *lower_layer = m_layers[layer_id - 1];
|
||||
// // Detect things that we need to support.
|
||||
// // Cummulative fill surfaces.
|
||||
// Polygons fill_surfaces;
|
||||
// // Solid surfaces to be supported.
|
||||
// Polygons overhangs;
|
||||
// for (const LayerRegion *layerm : layer->m_regions)
|
||||
// for (const Surface &surface : layerm->fill_surfaces()) {
|
||||
// Polygons polygons = to_polygons(surface.expolygon);
|
||||
// if (surface.is_solid())
|
||||
// polygons_append(overhangs, polygons);
|
||||
// polygons_append(fill_surfaces, std::move(polygons));
|
||||
// }
|
||||
// Polygons lower_layer_fill_surfaces;
|
||||
// Polygons lower_layer_internal_surfaces;
|
||||
// for (const LayerRegion *layerm : lower_layer->m_regions)
|
||||
// for (const Surface &surface : layerm->fill_surfaces()) {
|
||||
// Polygons polygons = to_polygons(surface.expolygon);
|
||||
// if (surface.surface_type == stInternal || surface.surface_type == stInternalVoid)
|
||||
// polygons_append(lower_layer_internal_surfaces, polygons);
|
||||
// polygons_append(lower_layer_fill_surfaces, std::move(polygons));
|
||||
// }
|
||||
// // We also need to support perimeters when there's at least one full unsupported loop
|
||||
// {
|
||||
// // Get perimeters area as the difference between slices and fill_surfaces
|
||||
// // Only consider the area that is not supported by lower perimeters
|
||||
// Polygons perimeters = intersection(diff(layer->lslices, fill_surfaces), lower_layer_fill_surfaces);
|
||||
// // Only consider perimeter areas that are at least one extrusion width thick.
|
||||
// //FIXME Offset2 eats out from both sides, while the perimeters are create outside in.
|
||||
// //Should the pw not be half of the current value?
|
||||
// float pw = FLT_MAX;
|
||||
// for (const LayerRegion *layerm : layer->m_regions)
|
||||
// pw = std::min(pw, (float)layerm->flow(frPerimeter).scaled_width());
|
||||
// // Append such thick perimeters to the areas that need support
|
||||
// polygons_append(overhangs, opening(perimeters, pw));
|
||||
// }
|
||||
// // Merge the new overhangs, find new internal infill.
|
||||
// polygons_append(upper_internal, std::move(overhangs));
|
||||
// static constexpr const auto closing_radius = scaled<float>(2.f);
|
||||
// upper_internal = intersection(
|
||||
// // Regularize the overhang regions, so that the infill areas will not become excessively jagged.
|
||||
// smooth_outward(
|
||||
// closing(upper_internal, closing_radius, ClipperLib::jtSquare, 0.),
|
||||
// scaled<coord_t>(0.1)),
|
||||
// lower_layer_internal_surfaces);
|
||||
// // Apply new internal infill to regions.
|
||||
// for (LayerRegion *layerm : lower_layer->m_regions) {
|
||||
// if (layerm->region().config().fill_density.value == 0)
|
||||
// continue;
|
||||
// Polygons internal;
|
||||
// for (Surface &surface : layerm->m_fill_surfaces.surfaces)
|
||||
// if (surface.surface_type == stInternal || surface.surface_type == stInternalVoid)
|
||||
// polygons_append(internal, std::move(surface.expolygon));
|
||||
// layerm->m_fill_surfaces.remove_types({ stInternal, stInternalVoid });
|
||||
// layerm->m_fill_surfaces.append(intersection_ex(internal, upper_internal, ApplySafetyOffset::Yes), stInternal);
|
||||
// layerm->m_fill_surfaces.append(diff_ex (internal, upper_internal, ApplySafetyOffset::Yes), stInternalVoid);
|
||||
// // If there are voids it means that our internal infill is not adjacent to
|
||||
// // perimeters. In this case it would be nice to add a loop around infill to
|
||||
// // make it more robust and nicer. TODO.
|
||||
// #ifdef SLIC3R_DEBUG_SLICE_PROCESSING
|
||||
// layerm->export_region_fill_surfaces_to_svg_debug("6_clip_fill_surfaces");
|
||||
// #endif
|
||||
// }
|
||||
// m_print->throw_if_canceled();
|
||||
// }
|
||||
// } // void PrintObject::clip_fill_surfaces()
|
||||
|
||||
void PrintObject::discover_horizontal_shells()
|
||||
{
|
||||
|
@ -10,8 +10,6 @@
|
||||
|
||||
#include <tbb/parallel_for.h>
|
||||
|
||||
//! macro used to mark string used at localization, return same string
|
||||
#define L(s) Slic3r::I18N::translate(s)
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
@ -499,7 +497,7 @@ void PrintObject::slice()
|
||||
{
|
||||
if (! this->set_started(posSlice))
|
||||
return;
|
||||
m_print->set_status(10, L("Processing triangulated mesh"));
|
||||
m_print->set_status(10, _u8L("Processing triangulated mesh"));
|
||||
std::vector<coordf_t> layer_height_profile;
|
||||
this->update_layer_height_profile(*this->model_object(), m_slicing_params, layer_height_profile);
|
||||
m_print->throw_if_canceled();
|
||||
@ -733,9 +731,9 @@ void PrintObject::slice_volumes()
|
||||
if (m_config.xy_size_compensation.value != 0.f) {
|
||||
this->active_step_add_warning(
|
||||
PrintStateBase::WarningLevel::CRITICAL,
|
||||
L("An object has enabled XY Size compensation which will not be used because it is also multi-material painted.\nXY Size "
|
||||
_u8L("An object has enabled XY Size compensation which will not be used because it is also multi-material painted.\nXY Size "
|
||||
"compensation cannot be combined with multi-material painting.") +
|
||||
"\n" + (L("Object name")) + ": " + this->model_object()->name);
|
||||
"\n" + (_u8L("Object name")) + ": " + this->model_object()->name);
|
||||
}
|
||||
|
||||
BOOST_LOG_TRIVIAL(debug) << "Slicing volumes - MMU segmentation";
|
||||
|
@ -23,10 +23,6 @@
|
||||
#include <libslic3r/MTUtils.hpp>
|
||||
#include <libslic3r/I18N.hpp>
|
||||
|
||||
//! macro used to mark string used at localization,
|
||||
//! return same string
|
||||
#define L(s) Slic3r::I18N::translate(s)
|
||||
|
||||
namespace Slic3r {
|
||||
namespace sla {
|
||||
|
||||
@ -83,12 +79,12 @@ InteriorPtr generate_interior(const VoxelGrid &vgrid,
|
||||
auto narrowb = 1.f; // voxel units (voxel count)
|
||||
|
||||
if (ctl.stopcondition()) return {};
|
||||
else ctl.statuscb(0, L("Hollowing"));
|
||||
else ctl.statuscb(0, _u8L("Hollowing"));
|
||||
|
||||
auto gridptr = dilate_grid(vgrid, out_range, in_range);
|
||||
|
||||
if (ctl.stopcondition()) return {};
|
||||
else ctl.statuscb(30, L("Hollowing"));
|
||||
else ctl.statuscb(30, _u8L("Hollowing"));
|
||||
|
||||
double iso_surface = D;
|
||||
if (D > EPSILON) {
|
||||
@ -103,7 +99,7 @@ InteriorPtr generate_interior(const VoxelGrid &vgrid,
|
||||
}
|
||||
|
||||
if (ctl.stopcondition()) return {};
|
||||
else ctl.statuscb(70, L("Hollowing"));
|
||||
else ctl.statuscb(70, _u8L("Hollowing"));
|
||||
|
||||
double adaptivity = 0.;
|
||||
InteriorPtr interior = InteriorPtr{new Interior{}};
|
||||
@ -112,7 +108,7 @@ InteriorPtr generate_interior(const VoxelGrid &vgrid,
|
||||
interior->gridptr = std::move(gridptr);
|
||||
|
||||
if (ctl.stopcondition()) return {};
|
||||
else ctl.statuscb(100, L("Hollowing"));
|
||||
else ctl.statuscb(100, _u8L("Hollowing"));
|
||||
|
||||
interior->iso_surface = iso_surface;
|
||||
interior->thickness = offset;
|
||||
|
@ -21,9 +21,6 @@
|
||||
#include "I18N.hpp"
|
||||
#include <boost/log/trivial.hpp>
|
||||
|
||||
//! macro used to mark string used at localization,
|
||||
//! return same string
|
||||
#define L(s) Slic3r::I18N::translate(s)
|
||||
|
||||
namespace Slic3r { namespace sla {
|
||||
|
||||
@ -530,7 +527,7 @@ std::string PadConfig::validate() const
|
||||
if (brim_size_mm < MIN_BRIM_SIZE_MM ||
|
||||
bottom_offset() > brim_size_mm + wing_distance() ||
|
||||
get_waffle_offset(*this) <= MIN_BRIM_SIZE_MM)
|
||||
return L("Pad brim size is too small for the current configuration.");
|
||||
return _u8L("Pad brim size is too small for the current configuration.");
|
||||
|
||||
return "";
|
||||
}
|
||||
|
@ -300,18 +300,8 @@ struct RotfinderBoilerplate {
|
||||
TriangleMesh mesh = mo.raw_mesh();
|
||||
|
||||
ModelInstance *mi = mo.instances[0];
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
const Geometry::Transformation trafo = mi->get_transformation();
|
||||
Transform3d trafo_instance = trafo.get_scaling_factor_matrix() * trafo.get_mirror_matrix();
|
||||
#else
|
||||
auto rotation = Vec3d::Zero();
|
||||
auto offset = Vec3d::Zero();
|
||||
Transform3d trafo_instance =
|
||||
Geometry::assemble_transform(offset, rotation,
|
||||
mi->get_scaling_factor(),
|
||||
mi->get_mirror());
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
mesh.transform(trafo_instance);
|
||||
|
||||
return mesh;
|
||||
|
@ -16,13 +16,9 @@
|
||||
#include <libslic3r/TriangleMeshSlicer.hpp>
|
||||
|
||||
#include <boost/log/trivial.hpp>
|
||||
#include <libslic3r/I18N.hpp>
|
||||
|
||||
#include <libnest2d/tools/benchmark.h>
|
||||
|
||||
//! macro used to mark string used at localization,
|
||||
//! return same string
|
||||
#define L(s) Slic3r::I18N::translate(s)
|
||||
|
||||
namespace Slic3r { namespace sla {
|
||||
|
||||
|
@ -2,6 +2,7 @@
|
||||
#include "SLAPrintSteps.hpp"
|
||||
#include "CSGMesh/CSGMeshCopy.hpp"
|
||||
#include "CSGMesh/PerformCSGMeshBooleans.hpp"
|
||||
#include "format.hpp"
|
||||
|
||||
#include "Geometry.hpp"
|
||||
#include "Thread.hpp"
|
||||
@ -23,7 +24,7 @@
|
||||
|
||||
//! macro used to mark string used at localization,
|
||||
//! return same string
|
||||
#define L(s) Slic3r::I18N::translate(s)
|
||||
#define _u8L(s) Slic3r::I18N::translate(s)
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
@ -543,7 +544,7 @@ std::string SLAPrint::validate(std::string*) const
|
||||
if(supports_en &&
|
||||
mo->sla_points_status == sla::PointsStatus::UserModified &&
|
||||
mo->sla_support_points.empty())
|
||||
return L("Cannot proceed without support points! "
|
||||
return _u8L("Cannot proceed without support points! "
|
||||
"Add support points or disable support generation.");
|
||||
|
||||
sla::SupportTreeConfig cfg = make_support_cfg(po->config());
|
||||
@ -554,13 +555,13 @@ std::string SLAPrint::validate(std::string*) const
|
||||
sla::PadConfig::EmbedObject &builtinpad = padcfg.embed_object;
|
||||
|
||||
if(supports_en && !builtinpad.enabled && elv < cfg.head_fullwidth())
|
||||
return L(
|
||||
return _u8L(
|
||||
"Elevation is too low for object. Use the \"Pad around "
|
||||
"object\" feature to print the object without elevation.");
|
||||
|
||||
if(supports_en && builtinpad.enabled &&
|
||||
cfg.pillar_base_safety_distance_mm < builtinpad.object_gap_mm) {
|
||||
return L(
|
||||
return _u8L(
|
||||
"The endings of the support pillars will be deployed on the "
|
||||
"gap between the object and the pad. 'Support base safety "
|
||||
"distance' has to be greater than the 'Pad object gap' "
|
||||
@ -576,18 +577,27 @@ std::string SLAPrint::validate(std::string*) const
|
||||
double expt_cur = m_material_config.exposure_time.getFloat();
|
||||
|
||||
if (expt_cur < expt_min || expt_cur > expt_max)
|
||||
return L("Exposition time is out of printer profile bounds.");
|
||||
return _u8L("Exposition time is out of printer profile bounds.");
|
||||
|
||||
double iexpt_max = m_printer_config.max_initial_exposure_time.getFloat();
|
||||
double iexpt_min = m_printer_config.min_initial_exposure_time.getFloat();
|
||||
double iexpt_cur = m_material_config.initial_exposure_time.getFloat();
|
||||
|
||||
if (iexpt_cur < iexpt_min || iexpt_cur > iexpt_max)
|
||||
return L("Initial exposition time is out of printer profile bounds.");
|
||||
return _u8L("Initial exposition time is out of printer profile bounds.");
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
void SLAPrint::export_print(const std::string &fname, const ThumbnailsList &thumbnails, const std::string &projectname)
|
||||
{
|
||||
if (m_archiver)
|
||||
m_archiver->export_print(fname, *this, thumbnails, projectname);
|
||||
else {
|
||||
throw ExportError(format(_u8L("Unknown archive format: %s"), m_printer_config.sla_archive_format.value));
|
||||
}
|
||||
}
|
||||
|
||||
bool SLAPrint::invalidate_step(SLAPrintStep step)
|
||||
{
|
||||
bool invalidated = Inherited::invalidate_step(step);
|
||||
@ -690,7 +700,7 @@ void SLAPrint::process()
|
||||
}
|
||||
|
||||
// If everything vent well
|
||||
m_report_status(*this, 100, L("Slicing done"));
|
||||
m_report_status(*this, 100, _u8L("Slicing done"));
|
||||
|
||||
#ifdef SLAPRINT_DO_BENCHMARK
|
||||
std::string csvbenchstr;
|
||||
|
@ -546,10 +546,7 @@ public:
|
||||
|
||||
void export_print(const std::string &fname,
|
||||
const ThumbnailsList &thumbnails,
|
||||
const std::string &projectname = "")
|
||||
{
|
||||
m_archiver->export_print(fname, *this, thumbnails, projectname);
|
||||
}
|
||||
const std::string &projectname = "");
|
||||
|
||||
private:
|
||||
|
||||
|
@ -31,10 +31,7 @@
|
||||
#include "I18N.hpp"
|
||||
|
||||
#include <libnest2d/tools/benchmark.h>
|
||||
|
||||
//! macro used to mark string used at localization,
|
||||
//! return same string
|
||||
#define L(s) Slic3r::I18N::translate(s)
|
||||
#include "format.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
@ -54,14 +51,15 @@ const std::array<unsigned, slaposCount> OBJ_STEP_LEVELS = {
|
||||
std::string OBJ_STEP_LABELS(size_t idx)
|
||||
{
|
||||
switch (idx) {
|
||||
case slaposAssembly: return L("Assembling model from parts");
|
||||
case slaposHollowing: return L("Hollowing model");
|
||||
case slaposDrillHoles: return L("Drilling holes into model.");
|
||||
case slaposObjectSlice: return L("Slicing model");
|
||||
case slaposSupportPoints: return L("Generating support points");
|
||||
case slaposSupportTree: return L("Generating support tree");
|
||||
case slaposPad: return L("Generating pad");
|
||||
case slaposSliceSupports: return L("Slicing supports");
|
||||
// TRN Status of the SLA print calculation
|
||||
case slaposAssembly: return _u8L("Assembling model from parts");
|
||||
case slaposHollowing: return _u8L("Hollowing model");
|
||||
case slaposDrillHoles: return _u8L("Drilling holes into model.");
|
||||
case slaposObjectSlice: return _u8L("Slicing model");
|
||||
case slaposSupportPoints: return _u8L("Generating support points");
|
||||
case slaposSupportTree: return _u8L("Generating support tree");
|
||||
case slaposPad: return _u8L("Generating pad");
|
||||
case slaposSliceSupports: return _u8L("Slicing supports");
|
||||
default:;
|
||||
}
|
||||
assert(false);
|
||||
@ -76,8 +74,8 @@ const std::array<unsigned, slapsCount> PRINT_STEP_LEVELS = {
|
||||
std::string PRINT_STEP_LABELS(size_t idx)
|
||||
{
|
||||
switch (idx) {
|
||||
case slapsMergeSlicesAndEval: return L("Merging slices and calculating statistics");
|
||||
case slapsRasterize: return L("Rasterizing layers");
|
||||
case slapsMergeSlicesAndEval: return _u8L("Merging slices and calculating statistics");
|
||||
case slapsRasterize: return _u8L("Rasterizing layers");
|
||||
default:;
|
||||
}
|
||||
assert(false); return "Out of bounds!";
|
||||
@ -201,7 +199,13 @@ void SLAPrint::Steps::generate_preview(SLAPrintObject &po, SLAPrintObjectStep st
|
||||
m = csgmesh_merge_positive_parts(r);
|
||||
handled = true;
|
||||
} else if (csg::check_csgmesh_booleans(r) == r.end()) {
|
||||
auto cgalmeshptr = csg::perform_csgmesh_booleans(r);
|
||||
MeshBoolean::cgal::CGALMeshPtr cgalmeshptr;
|
||||
try {
|
||||
cgalmeshptr = csg::perform_csgmesh_booleans(r);
|
||||
} catch (...) {
|
||||
// leaves cgalmeshptr as nullptr
|
||||
}
|
||||
|
||||
if (cgalmeshptr) {
|
||||
m = MeshBoolean::cgal::cgal_to_indexed_triangle_set(*cgalmeshptr);
|
||||
handled = true;
|
||||
@ -252,14 +256,14 @@ void SLAPrint::Steps::generate_preview(SLAPrintObject &po, SLAPrintObjectStep st
|
||||
if (ret & static_cast<int>(sla::HollowMeshResult::FaultyMesh)) {
|
||||
po.active_step_add_warning(
|
||||
PrintStateBase::WarningLevel::NON_CRITICAL,
|
||||
L("Mesh to be hollowed is not suitable for hollowing (does not "
|
||||
_u8L("Mesh to be hollowed is not suitable for hollowing (does not "
|
||||
"bound a volume)."));
|
||||
}
|
||||
|
||||
if (ret & static_cast<int>(sla::HollowMeshResult::FaultyHoles)) {
|
||||
po.active_step_add_warning(
|
||||
PrintStateBase::WarningLevel::NON_CRITICAL,
|
||||
L("Unable to drill the current configuration of holes into the "
|
||||
_u8L("Unable to drill the current configuration of holes into the "
|
||||
"model."));
|
||||
}
|
||||
|
||||
@ -267,7 +271,7 @@ void SLAPrint::Steps::generate_preview(SLAPrintObject &po, SLAPrintObjectStep st
|
||||
|
||||
if (ret & static_cast<int>(sla::HollowMeshResult::DrillingFailed)) {
|
||||
po.active_step_add_warning(
|
||||
PrintStateBase::WarningLevel::NON_CRITICAL, L(
|
||||
PrintStateBase::WarningLevel::NON_CRITICAL, _u8L(
|
||||
"Drilling holes into the mesh failed. "
|
||||
"This is usually caused by broken model. Try to fix it first."));
|
||||
|
||||
@ -276,7 +280,7 @@ void SLAPrint::Steps::generate_preview(SLAPrintObject &po, SLAPrintObjectStep st
|
||||
|
||||
if (hole_fail) {
|
||||
po.active_step_add_warning(PrintStateBase::WarningLevel::NON_CRITICAL,
|
||||
L("Failed to drill some holes into the model"));
|
||||
_u8L("Failed to drill some holes into the model"));
|
||||
|
||||
handled = false;
|
||||
}
|
||||
@ -286,8 +290,7 @@ void SLAPrint::Steps::generate_preview(SLAPrintObject &po, SLAPrintObjectStep st
|
||||
|
||||
if (!handled) { // Last resort to voxelization.
|
||||
po.active_step_add_warning(PrintStateBase::WarningLevel::NON_CRITICAL,
|
||||
L("Can't perform full mesh booleans! "
|
||||
"Some parts of the print will be previewed with approximated meshes. "
|
||||
_u8L("Some parts of the print will be previewed with approximated meshes. "
|
||||
"This does not affect the quality of slices or the physical print in any way."));
|
||||
m = generate_preview_vdb(po, step);
|
||||
}
|
||||
@ -506,9 +509,7 @@ void SLAPrint::Steps::slice_model(SLAPrintObject &po)
|
||||
|
||||
if(slindex_it == po.m_slice_index.end())
|
||||
//TRN To be shown at the status bar on SLA slicing error.
|
||||
throw Slic3r::RuntimeError(
|
||||
L("Slicing had to be stopped due to an internal error: "
|
||||
"Inconsistent slice index."));
|
||||
throw Slic3r::RuntimeError(format("Model named: %s can not be sliced. Please check if the model is sane.", po.model_object()->name));
|
||||
|
||||
po.m_model_height_levels.clear();
|
||||
po.m_model_height_levels.reserve(po.m_slice_index.size());
|
||||
@ -688,7 +689,7 @@ void SLAPrint::Steps::support_points(SLAPrintObject &po)
|
||||
|
||||
// Using RELOAD_SLA_SUPPORT_POINTS to tell the Plater to pass
|
||||
// the update status to GLGizmoSlaSupports
|
||||
report_status(-1, L("Generating support points"),
|
||||
report_status(-1, _u8L("Generating support points"),
|
||||
SlicingStatus::RELOAD_SLA_SUPPORT_POINTS);
|
||||
} else {
|
||||
// There are either some points on the front-end, or the user
|
||||
@ -737,7 +738,7 @@ void SLAPrint::Steps::support_tree(SLAPrintObject &po)
|
||||
auto rc = SlicingStatus::RELOAD_SCENE;
|
||||
|
||||
// This is to prevent "Done." being displayed during merged_mesh()
|
||||
report_status(-1, L("Visualizing supports"));
|
||||
report_status(-1, _u8L("Visualizing supports"));
|
||||
|
||||
BOOST_LOG_TRIVIAL(debug) << "Processed support point count "
|
||||
<< po.m_supportdata->input.pts.size();
|
||||
@ -746,7 +747,7 @@ void SLAPrint::Steps::support_tree(SLAPrintObject &po)
|
||||
if(po.support_mesh().empty())
|
||||
BOOST_LOG_TRIVIAL(warning) << "Support mesh is empty";
|
||||
|
||||
report_status(-1, L("Visualizing supports"), rc);
|
||||
report_status(-1, _u8L("Visualizing supports"), rc);
|
||||
}
|
||||
|
||||
void SLAPrint::Steps::generate_pad(SLAPrintObject &po) {
|
||||
@ -776,7 +777,7 @@ void SLAPrint::Steps::generate_pad(SLAPrintObject &po) {
|
||||
|
||||
if (!validate_pad(po.m_supportdata->pad_mesh.its, pcfg))
|
||||
throw Slic3r::SlicingError(
|
||||
L("No pad can be generated for this model with the "
|
||||
_u8L("No pad can be generated for this model with the "
|
||||
"current configuration"));
|
||||
|
||||
} else if(po.m_supportdata) {
|
||||
@ -784,7 +785,7 @@ void SLAPrint::Steps::generate_pad(SLAPrintObject &po) {
|
||||
}
|
||||
|
||||
throw_if_canceled();
|
||||
report_status(-1, L("Visualizing supports"), SlicingStatus::RELOAD_SCENE);
|
||||
report_status(-1, _u8L("Visualizing supports"), SlicingStatus::RELOAD_SCENE);
|
||||
}
|
||||
|
||||
// Slicing the support geometries similarly to the model slicing procedure.
|
||||
@ -905,7 +906,7 @@ void SLAPrint::Steps::initialize_printer_input()
|
||||
for(const SliceRecord& slicerecord : o->get_slice_index()) {
|
||||
if (!slicerecord.is_valid())
|
||||
throw Slic3r::SlicingError(
|
||||
L("There are unprintable objects. Try to "
|
||||
_u8L("There are unprintable objects. Try to "
|
||||
"adjust support settings to make the "
|
||||
"objects printable."));
|
||||
|
||||
|
@ -32,6 +32,10 @@
|
||||
#define ENABLE_RAYCAST_PICKING_DEBUG 0
|
||||
// Shows an imgui dialog with GLModel statistics data
|
||||
#define ENABLE_GLMODEL_STATISTICS 0
|
||||
// Shows an imgui dialog containing the matrices of the selected volumes
|
||||
#define ENABLE_MATRICES_DEBUG 0
|
||||
// Shows an imgui dialog containing data from class ObjectManipulation
|
||||
#define ENABLE_OBJECT_MANIPULATION_DEBUG 0
|
||||
|
||||
|
||||
// Enable rendering of objects using environment map
|
||||
@ -39,24 +43,23 @@
|
||||
// Enable smoothing of objects normals
|
||||
#define ENABLE_SMOOTH_NORMALS 0
|
||||
|
||||
|
||||
//====================
|
||||
// 2.6.0.alpha1 techs
|
||||
//====================
|
||||
#define ENABLE_2_6_0_ALPHA1 1
|
||||
|
||||
// Enable OpenGL ES
|
||||
#define ENABLE_OPENGL_ES 0
|
||||
// Enable OpenGL core profile context (tested against Mesa 20.1.8 on Windows)
|
||||
#define ENABLE_GL_CORE_PROFILE (1 && !ENABLE_OPENGL_ES)
|
||||
// Enable OpenGL debug messages using debug context
|
||||
#define ENABLE_OPENGL_DEBUG_OPTION (1 && ENABLE_GL_CORE_PROFILE)
|
||||
// Enable editing volumes transformation in world coordinates and instances in local coordinates
|
||||
#define ENABLE_WORLD_COORDINATE (1 && ENABLE_2_6_0_ALPHA1)
|
||||
// Shows an imgui dialog containing the matrices of the selected volumes
|
||||
#define ENABLE_WORLD_COORDINATE_DEBUG (0 && ENABLE_WORLD_COORDINATE)
|
||||
|
||||
|
||||
//====================
|
||||
// 2.6.0.alpha1 techs
|
||||
//====================
|
||||
#define ENABLE_2_6_0_ALPHA1 1
|
||||
|
||||
// Enable alternative version of file_wildcards()
|
||||
#define ENABLE_ALTERNATIVE_FILE_WILDCARDS_GENERATOR (1 && ENABLE_2_6_0_ALPHA1)
|
||||
// Enable gcode postprocess modified to allow for backward insertion of new lines
|
||||
#define ENABLE_GCODE_POSTPROCESS_BACKTRACE (1 && ENABLE_2_6_0_ALPHA1)
|
||||
|
||||
|
||||
#endif // _prusaslicer_technologies_h_
|
||||
|
@ -6,10 +6,6 @@
|
||||
#include <boost/log/trivial.hpp>
|
||||
#include "I18N.hpp"
|
||||
|
||||
//! macro used to mark string used at localization,
|
||||
//! return same string
|
||||
#define L(s) Slic3r::I18N::translate(s)
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER <= 1800 || __cplusplus < 201103L
|
||||
#define SLIC3R_NORETURN
|
||||
#elif __cplusplus >= 201103L
|
||||
@ -24,7 +20,7 @@ public:
|
||||
|
||||
std::string formatted_errorstr() const
|
||||
{
|
||||
return L("Error with zip archive") + " " + m_zipname + ": " +
|
||||
return _u8L("Error with ZIP archive") + " " + m_zipname + ": " +
|
||||
get_errorstr();
|
||||
}
|
||||
|
||||
|
@ -6,11 +6,7 @@
|
||||
#include "boost/nowide/cstdio.hpp"
|
||||
#endif
|
||||
|
||||
#include "I18N.hpp"
|
||||
|
||||
//! macro used to mark string used at localization,
|
||||
//! return same string
|
||||
#define L(s) Slic3r::I18N::translate(s)
|
||||
#include "libslic3r/I18N.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
@ -88,67 +84,67 @@ std::string MZ_Archive::get_errorstr(mz_zip_error mz_err)
|
||||
case MZ_ZIP_NO_ERROR:
|
||||
return "no error";
|
||||
case MZ_ZIP_UNDEFINED_ERROR:
|
||||
return L("undefined error");
|
||||
return _u8L("undefined error");
|
||||
case MZ_ZIP_TOO_MANY_FILES:
|
||||
return L("too many files");
|
||||
return _u8L("too many files");
|
||||
case MZ_ZIP_FILE_TOO_LARGE:
|
||||
return L("file too large");
|
||||
return _u8L("file too large");
|
||||
case MZ_ZIP_UNSUPPORTED_METHOD:
|
||||
return L("unsupported method");
|
||||
return _u8L("unsupported method");
|
||||
case MZ_ZIP_UNSUPPORTED_ENCRYPTION:
|
||||
return L("unsupported encryption");
|
||||
return _u8L("unsupported encryption");
|
||||
case MZ_ZIP_UNSUPPORTED_FEATURE:
|
||||
return L("unsupported feature");
|
||||
return _u8L("unsupported feature");
|
||||
case MZ_ZIP_FAILED_FINDING_CENTRAL_DIR:
|
||||
return L("failed finding central directory");
|
||||
return _u8L("failed finding central directory");
|
||||
case MZ_ZIP_NOT_AN_ARCHIVE:
|
||||
return L("not a ZIP archive");
|
||||
return _u8L("not a ZIP archive");
|
||||
case MZ_ZIP_INVALID_HEADER_OR_CORRUPTED:
|
||||
return L("invalid header or archive is corrupted");
|
||||
return _u8L("invalid header or archive is corrupted");
|
||||
case MZ_ZIP_UNSUPPORTED_MULTIDISK:
|
||||
return L("unsupported multidisk archive");
|
||||
return _u8L("unsupported multidisk archive");
|
||||
case MZ_ZIP_DECOMPRESSION_FAILED:
|
||||
return L("decompression failed or archive is corrupted");
|
||||
return _u8L("decompression failed or archive is corrupted");
|
||||
case MZ_ZIP_COMPRESSION_FAILED:
|
||||
return L("compression failed");
|
||||
return _u8L("compression failed");
|
||||
case MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE:
|
||||
return L("unexpected decompressed size");
|
||||
return _u8L("unexpected decompressed size");
|
||||
case MZ_ZIP_CRC_CHECK_FAILED:
|
||||
return L("CRC-32 check failed");
|
||||
return _u8L("CRC-32 check failed");
|
||||
case MZ_ZIP_UNSUPPORTED_CDIR_SIZE:
|
||||
return L("unsupported central directory size");
|
||||
return _u8L("unsupported central directory size");
|
||||
case MZ_ZIP_ALLOC_FAILED:
|
||||
return L("allocation failed");
|
||||
return _u8L("allocation failed");
|
||||
case MZ_ZIP_FILE_OPEN_FAILED:
|
||||
return L("file open failed");
|
||||
return _u8L("file open failed");
|
||||
case MZ_ZIP_FILE_CREATE_FAILED:
|
||||
return L("file create failed");
|
||||
return _u8L("file create failed");
|
||||
case MZ_ZIP_FILE_WRITE_FAILED:
|
||||
return L("file write failed");
|
||||
return _u8L("file write failed");
|
||||
case MZ_ZIP_FILE_READ_FAILED:
|
||||
return L("file read failed");
|
||||
return _u8L("file read failed");
|
||||
case MZ_ZIP_FILE_CLOSE_FAILED:
|
||||
return L("file close failed");
|
||||
return _u8L("file close failed");
|
||||
case MZ_ZIP_FILE_SEEK_FAILED:
|
||||
return L("file seek failed");
|
||||
return _u8L("file seek failed");
|
||||
case MZ_ZIP_FILE_STAT_FAILED:
|
||||
return L("file stat failed");
|
||||
return _u8L("file stat failed");
|
||||
case MZ_ZIP_INVALID_PARAMETER:
|
||||
return L("invalid parameter");
|
||||
return _u8L("invalid parameter");
|
||||
case MZ_ZIP_INVALID_FILENAME:
|
||||
return L("invalid filename");
|
||||
return _u8L("invalid filename");
|
||||
case MZ_ZIP_BUF_TOO_SMALL:
|
||||
return L("buffer too small");
|
||||
return _u8L("buffer too small");
|
||||
case MZ_ZIP_INTERNAL_ERROR:
|
||||
return L("internal error");
|
||||
return _u8L("internal error");
|
||||
case MZ_ZIP_FILE_NOT_FOUND:
|
||||
return L("file not found");
|
||||
return _u8L("file not found");
|
||||
case MZ_ZIP_ARCHIVE_TOO_LARGE:
|
||||
return L("archive is too large");
|
||||
return _u8L("archive is too large");
|
||||
case MZ_ZIP_VALIDATION_FAILED:
|
||||
return L("validation failed");
|
||||
return _u8L("validation failed");
|
||||
case MZ_ZIP_WRITE_CALLBACK_FAILED:
|
||||
return L("write calledback failed");
|
||||
return _u8L("write calledback failed");
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -344,3 +344,6 @@ if (UNIX AND NOT APPLE)
|
||||
target_include_directories(libslic3r_gui PRIVATE ${GTK${SLIC3R_GTK}_INCLUDE_DIRS})
|
||||
target_link_libraries(libslic3r_gui ${GTK${SLIC3R_GTK}_LIBRARIES} fontconfig)
|
||||
endif ()
|
||||
|
||||
# Add a definition so that we can tell we are compiling slic3r.
|
||||
target_compile_definitions(libslic3r_gui PRIVATE SLIC3R_CURRENTLY_COMPILING_GUI_MODULE)
|
||||
|
@ -29,54 +29,6 @@ static const Slic3r::ColorRGBA DEFAULT_TRANSPARENT_GRID_COLOR = { 0.9f, 0.9f, 0
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
||||
#if !ENABLE_WORLD_COORDINATE
|
||||
const float Bed3D::Axes::DefaultStemRadius = 0.5f;
|
||||
const float Bed3D::Axes::DefaultStemLength = 25.0f;
|
||||
const float Bed3D::Axes::DefaultTipRadius = 2.5f * Bed3D::Axes::DefaultStemRadius;
|
||||
const float Bed3D::Axes::DefaultTipLength = 5.0f;
|
||||
|
||||
void Bed3D::Axes::render()
|
||||
{
|
||||
auto render_axis = [this](GLShaderProgram* shader, const Transform3d& transform) {
|
||||
const Camera& camera = wxGetApp().plater()->get_camera();
|
||||
const Transform3d& view_matrix = camera.get_view_matrix();
|
||||
shader->set_uniform("view_model_matrix", view_matrix * transform);
|
||||
shader->set_uniform("projection_matrix", camera.get_projection_matrix());
|
||||
const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * transform.matrix().block(0, 0, 3, 3).inverse().transpose();
|
||||
shader->set_uniform("view_normal_matrix", view_normal_matrix);
|
||||
m_arrow.render();
|
||||
};
|
||||
|
||||
if (!m_arrow.is_initialized())
|
||||
m_arrow.init_from(stilized_arrow(16, DefaultTipRadius, DefaultTipLength, DefaultStemRadius, m_stem_length));
|
||||
|
||||
GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light");
|
||||
if (shader == nullptr)
|
||||
return;
|
||||
|
||||
glsafe(::glEnable(GL_DEPTH_TEST));
|
||||
|
||||
shader->start_using();
|
||||
shader->set_uniform("emission_factor", 0.0f);
|
||||
|
||||
// x axis
|
||||
m_arrow.set_color(ColorRGBA::X());
|
||||
render_axis(shader, Geometry::assemble_transform(m_origin, { 0.0, 0.5 * M_PI, 0.0 }));
|
||||
|
||||
// y axis
|
||||
m_arrow.set_color(ColorRGBA::Y());
|
||||
render_axis(shader, Geometry::assemble_transform(m_origin, { -0.5 * M_PI, 0.0, 0.0 }));
|
||||
|
||||
// z axis
|
||||
m_arrow.set_color(ColorRGBA::Z());
|
||||
render_axis(shader, Geometry::assemble_transform(m_origin));
|
||||
|
||||
shader->stop_using();
|
||||
|
||||
glsafe(::glDisable(GL_DEPTH_TEST));
|
||||
}
|
||||
#endif // !ENABLE_WORLD_COORDINATE
|
||||
|
||||
bool Bed3D::set_shape(const Pointfs& bed_shape, const double max_print_height, const std::string& custom_texture, const std::string& custom_model, bool force_as_custom)
|
||||
{
|
||||
auto check_texture = [](const std::string& texture) {
|
||||
@ -201,11 +153,7 @@ BoundingBoxf3 Bed3D::calc_extended_bounding_box() const
|
||||
out.merge(m_axes.get_origin());
|
||||
// extend to contain axes
|
||||
out.merge(m_axes.get_origin() + m_axes.get_total_length() * Vec3d::Ones());
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
out.merge(out.min + Vec3d(-m_axes.get_tip_radius(), -m_axes.get_tip_radius(), out.max.z()));
|
||||
#else
|
||||
out.merge(out.min + Vec3d(-Axes::DefaultTipRadius, -Axes::DefaultTipRadius, out.max.z()));
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
// extend to contain model, if any
|
||||
BoundingBoxf3 model_bb = m_model.model.get_bounding_box();
|
||||
if (model_bb.defined) {
|
||||
@ -364,11 +312,7 @@ std::tuple<Bed3D::Type, std::string, std::string> Bed3D::detect_type(const Point
|
||||
void Bed3D::render_axes()
|
||||
{
|
||||
if (m_build_volume.valid())
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
m_axes.render(Transform3d::Identity(), 0.25f);
|
||||
#else
|
||||
m_axes.render();
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
}
|
||||
|
||||
void Bed3D::render_system(GLCanvas3D& canvas, const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom, bool show_texture)
|
||||
|
@ -3,11 +3,7 @@
|
||||
|
||||
#include "GLTexture.hpp"
|
||||
#include "3DScene.hpp"
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
#include "CoordAxes.hpp"
|
||||
#else
|
||||
#include "GLModel.hpp"
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
#include "MeshUtils.hpp"
|
||||
|
||||
#include "libslic3r/BuildVolume.hpp"
|
||||
@ -23,32 +19,6 @@ class GLCanvas3D;
|
||||
|
||||
class Bed3D
|
||||
{
|
||||
#if !ENABLE_WORLD_COORDINATE
|
||||
class Axes
|
||||
{
|
||||
public:
|
||||
static const float DefaultStemRadius;
|
||||
static const float DefaultStemLength;
|
||||
static const float DefaultTipRadius;
|
||||
static const float DefaultTipLength;
|
||||
|
||||
private:
|
||||
Vec3d m_origin{ Vec3d::Zero() };
|
||||
float m_stem_length{ DefaultStemLength };
|
||||
GLModel m_arrow;
|
||||
|
||||
public:
|
||||
const Vec3d& get_origin() const { return m_origin; }
|
||||
void set_origin(const Vec3d& origin) { m_origin = origin; }
|
||||
void set_stem_length(float length) {
|
||||
m_stem_length = length;
|
||||
m_arrow.reset();
|
||||
}
|
||||
float get_total_length() const { return m_stem_length + DefaultTipLength; }
|
||||
void render();
|
||||
};
|
||||
#endif // !ENABLE_WORLD_COORDINATE
|
||||
|
||||
public:
|
||||
enum class Type : unsigned char
|
||||
{
|
||||
@ -77,11 +47,7 @@ private:
|
||||
GLTexture m_temp_texture;
|
||||
PickingModel m_model;
|
||||
Vec3d m_model_offset{ Vec3d::Zero() };
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
CoordAxes m_axes;
|
||||
#else
|
||||
Axes m_axes;
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
float m_scale_factor{ 1.0f };
|
||||
|
||||
|
@ -480,21 +480,19 @@ int GLVolumeCollection::load_object_volume(
|
||||
|
||||
#if ENABLE_OPENGL_ES
|
||||
int GLVolumeCollection::load_wipe_tower_preview(
|
||||
float pos_x, float pos_y, float width, float depth, float height,
|
||||
float pos_x, float pos_y, float width, float depth, float height, float cone_angle,
|
||||
float rotation_angle, bool size_unknown, float brim_width, TriangleMesh* out_mesh)
|
||||
#else
|
||||
int GLVolumeCollection::load_wipe_tower_preview(
|
||||
float pos_x, float pos_y, float width, float depth, float height,
|
||||
float pos_x, float pos_y, float width, float depth, float height, float cone_angle,
|
||||
float rotation_angle, bool size_unknown, float brim_width)
|
||||
#endif // ENABLE_OPENGL_ES
|
||||
{
|
||||
if (depth < 0.01f)
|
||||
return int(this->volumes.size() - 1);
|
||||
if (height == 0.0f)
|
||||
height = 0.1f;
|
||||
|
||||
static const float brim_height = 0.2f;
|
||||
const float scaled_brim_height = brim_height / height;
|
||||
// const float scaled_brim_height = brim_height / height;
|
||||
|
||||
TriangleMesh mesh;
|
||||
ColorRGBA color = ColorRGBA::DARK_YELLOW();
|
||||
@ -544,6 +542,21 @@ int GLVolumeCollection::load_wipe_tower_preview(
|
||||
brim_mesh.translate(-brim_width, -brim_width, 0.f);
|
||||
mesh.merge(brim_mesh);
|
||||
|
||||
// Now the stabilization cone and its base.
|
||||
const auto [R, scale_x] = WipeTower::get_wipe_tower_cone_base(width, height, depth, cone_angle);
|
||||
if (R > 0.) {
|
||||
TriangleMesh cone_mesh(its_make_cone(R, height));
|
||||
cone_mesh.scale(Vec3f(1.f/scale_x, 1.f, 1.f));
|
||||
|
||||
TriangleMesh disk_mesh(its_make_cylinder(R, brim_height));
|
||||
disk_mesh.scale(Vec3f(1. / scale_x, 1., 1.)); // Now it matches the base, which may be elliptic.
|
||||
disk_mesh.scale(Vec3f(1.f + scale_x*brim_width/R, 1.f + brim_width/R, 1.f)); // Scale so the brim is not deformed.
|
||||
cone_mesh.merge(disk_mesh);
|
||||
cone_mesh.translate(width / 2., depth / 2., 0.);
|
||||
mesh.merge(cone_mesh);
|
||||
}
|
||||
|
||||
|
||||
volumes.emplace_back(new GLVolume(color));
|
||||
GLVolume& v = *volumes.back();
|
||||
#if ENABLE_OPENGL_ES
|
||||
@ -564,6 +577,71 @@ int GLVolumeCollection::load_wipe_tower_preview(
|
||||
return int(volumes.size() - 1);
|
||||
}
|
||||
|
||||
// Load SLA auxiliary GLVolumes (for support trees or pad).
|
||||
// This function produces volumes for multiple instances in a single shot,
|
||||
// as some object specific mesh conversions may be expensive.
|
||||
void GLVolumeCollection::load_object_auxiliary(
|
||||
const SLAPrintObject* print_object,
|
||||
int obj_idx,
|
||||
// pairs of <instance_idx, print_instance_idx>
|
||||
const std::vector<std::pair<size_t, size_t>>& instances,
|
||||
SLAPrintObjectStep milestone,
|
||||
// Timestamp of the last change of the milestone
|
||||
size_t timestamp)
|
||||
{
|
||||
if (print_object->get_mesh_to_print() == nullptr)
|
||||
return;
|
||||
const Transform3d mesh_trafo_inv = print_object->trafo().inverse();
|
||||
|
||||
auto add_volume = [this, &instances, timestamp](int obj_idx, int inst_idx, const ModelInstance& model_instance, SLAPrintObjectStep step,
|
||||
const TriangleMesh& mesh, const ColorRGBA& color, std::optional<const TriangleMesh> convex_hull = std::nullopt) {
|
||||
if (mesh.empty())
|
||||
return;
|
||||
|
||||
GLVolume& v = *this->volumes.emplace_back(new GLVolume(color));
|
||||
#if ENABLE_SMOOTH_NORMALS
|
||||
v.model.init_from(mesh, true);
|
||||
#else
|
||||
v.model.init_from(mesh);
|
||||
v.model.set_color(color);
|
||||
v.mesh_raycaster = std::make_unique<GUI::MeshRaycaster>(std::make_shared<const TriangleMesh>(mesh));
|
||||
#endif // ENABLE_SMOOTH_NORMALS
|
||||
v.composite_id = GLVolume::CompositeID(obj_idx, -int(step), inst_idx);
|
||||
v.geometry_id = std::pair<size_t, size_t>(timestamp, model_instance.id().id);
|
||||
if (convex_hull.has_value())
|
||||
v.set_convex_hull(*convex_hull);
|
||||
v.is_modifier = false;
|
||||
v.shader_outside_printer_detection_enabled = (step == slaposSupportTree);
|
||||
v.set_instance_transformation(model_instance.get_transformation());
|
||||
};
|
||||
|
||||
// Get the support mesh.
|
||||
if (milestone == SLAPrintObjectStep::slaposSupportTree) {
|
||||
TriangleMesh supports_mesh = print_object->support_mesh();
|
||||
if (!supports_mesh.empty()) {
|
||||
supports_mesh.transform(mesh_trafo_inv);
|
||||
TriangleMesh convex_hull = supports_mesh.convex_hull_3d();
|
||||
for (const std::pair<size_t, size_t>& instance_idx : instances) {
|
||||
const ModelInstance& model_instance = *print_object->model_object()->instances[instance_idx.first];
|
||||
add_volume(obj_idx, (int)instance_idx.first, model_instance, slaposSupportTree, supports_mesh, GLVolume::SLA_SUPPORT_COLOR, convex_hull);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get the pad mesh.
|
||||
if (milestone == SLAPrintObjectStep::slaposPad) {
|
||||
TriangleMesh pad_mesh = print_object->pad_mesh();
|
||||
if (!pad_mesh.empty()) {
|
||||
pad_mesh.transform(mesh_trafo_inv);
|
||||
TriangleMesh convex_hull = pad_mesh.convex_hull_3d();
|
||||
for (const std::pair<size_t, size_t>& instance_idx : instances) {
|
||||
const ModelInstance& model_instance = *print_object->model_object()->instances[instance_idx.first];
|
||||
add_volume(obj_idx, (int)instance_idx.first, model_instance, slaposPad, pad_mesh, GLVolume::SLA_PAD_COLOR, convex_hull);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GLVolume* GLVolumeCollection::new_toolpath_volume(const ColorRGBA& rgba)
|
||||
{
|
||||
GLVolume* out = new_nontoolpath_volume(rgba);
|
||||
|
@ -212,23 +212,15 @@ public:
|
||||
|
||||
const Geometry::Transformation& get_instance_transformation() const { return m_instance_transformation; }
|
||||
void set_instance_transformation(const Geometry::Transformation& transformation) { m_instance_transformation = transformation; set_bounding_boxes_as_dirty(); }
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
void set_instance_transformation(const Transform3d& transform) { m_instance_transformation.set_matrix(transform); set_bounding_boxes_as_dirty(); }
|
||||
|
||||
Vec3d get_instance_offset() const { return m_instance_transformation.get_offset(); }
|
||||
#else
|
||||
const Vec3d& get_instance_offset() const { return m_instance_transformation.get_offset(); }
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
double get_instance_offset(Axis axis) const { return m_instance_transformation.get_offset(axis); }
|
||||
|
||||
void set_instance_offset(const Vec3d& offset) { m_instance_transformation.set_offset(offset); set_bounding_boxes_as_dirty(); }
|
||||
void set_instance_offset(Axis axis, double offset) { m_instance_transformation.set_offset(axis, offset); set_bounding_boxes_as_dirty(); }
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
Vec3d get_instance_rotation() const { return m_instance_transformation.get_rotation(); }
|
||||
#else
|
||||
const Vec3d& get_instance_rotation() const { return m_instance_transformation.get_rotation(); }
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
double get_instance_rotation(Axis axis) const { return m_instance_transformation.get_rotation(axis); }
|
||||
|
||||
void set_instance_rotation(const Vec3d& rotation) { m_instance_transformation.set_rotation(rotation); set_bounding_boxes_as_dirty(); }
|
||||
@ -240,11 +232,7 @@ public:
|
||||
void set_instance_scaling_factor(const Vec3d& scaling_factor) { m_instance_transformation.set_scaling_factor(scaling_factor); set_bounding_boxes_as_dirty(); }
|
||||
void set_instance_scaling_factor(Axis axis, double scaling_factor) { m_instance_transformation.set_scaling_factor(axis, scaling_factor); set_bounding_boxes_as_dirty(); }
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
Vec3d get_instance_mirror() const { return m_instance_transformation.get_mirror(); }
|
||||
#else
|
||||
const Vec3d& get_instance_mirror() const { return m_instance_transformation.get_mirror(); }
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
double get_instance_mirror(Axis axis) const { return m_instance_transformation.get_mirror(axis); }
|
||||
|
||||
void set_instance_mirror(const Vec3d& mirror) { m_instance_transformation.set_mirror(mirror); set_bounding_boxes_as_dirty(); }
|
||||
@ -252,43 +240,27 @@ public:
|
||||
|
||||
const Geometry::Transformation& get_volume_transformation() const { return m_volume_transformation; }
|
||||
void set_volume_transformation(const Geometry::Transformation& transformation) { m_volume_transformation = transformation; set_bounding_boxes_as_dirty(); }
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
void set_volume_transformation(const Transform3d& transform) { m_volume_transformation.set_matrix(transform); set_bounding_boxes_as_dirty(); }
|
||||
|
||||
Vec3d get_volume_offset() const { return m_volume_transformation.get_offset(); }
|
||||
#else
|
||||
const Vec3d& get_volume_offset() const { return m_volume_transformation.get_offset(); }
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
double get_volume_offset(Axis axis) const { return m_volume_transformation.get_offset(axis); }
|
||||
|
||||
void set_volume_offset(const Vec3d& offset) { m_volume_transformation.set_offset(offset); set_bounding_boxes_as_dirty(); }
|
||||
void set_volume_offset(Axis axis, double offset) { m_volume_transformation.set_offset(axis, offset); set_bounding_boxes_as_dirty(); }
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
Vec3d get_volume_rotation() const { return m_volume_transformation.get_rotation(); }
|
||||
#else
|
||||
const Vec3d& get_volume_rotation() const { return m_volume_transformation.get_rotation(); }
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
double get_volume_rotation(Axis axis) const { return m_volume_transformation.get_rotation(axis); }
|
||||
|
||||
void set_volume_rotation(const Vec3d& rotation) { m_volume_transformation.set_rotation(rotation); set_bounding_boxes_as_dirty(); }
|
||||
void set_volume_rotation(Axis axis, double rotation) { m_volume_transformation.set_rotation(axis, rotation); set_bounding_boxes_as_dirty(); }
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
Vec3d get_volume_scaling_factor() const { return m_volume_transformation.get_scaling_factor(); }
|
||||
#else
|
||||
const Vec3d& get_volume_scaling_factor() const { return m_volume_transformation.get_scaling_factor(); }
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
double get_volume_scaling_factor(Axis axis) const { return m_volume_transformation.get_scaling_factor(axis); }
|
||||
|
||||
void set_volume_scaling_factor(const Vec3d& scaling_factor) { m_volume_transformation.set_scaling_factor(scaling_factor); set_bounding_boxes_as_dirty(); }
|
||||
void set_volume_scaling_factor(Axis axis, double scaling_factor) { m_volume_transformation.set_scaling_factor(axis, scaling_factor); set_bounding_boxes_as_dirty(); }
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
Vec3d get_volume_mirror() const { return m_volume_transformation.get_mirror(); }
|
||||
#else
|
||||
const Vec3d& get_volume_mirror() const { return m_volume_transformation.get_mirror(); }
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
double get_volume_mirror(Axis axis) const { return m_volume_transformation.get_mirror(axis); }
|
||||
|
||||
void set_volume_mirror(const Vec3d& mirror) { m_volume_transformation.set_mirror(mirror); set_bounding_boxes_as_dirty(); }
|
||||
@ -424,12 +396,22 @@ public:
|
||||
|
||||
#if ENABLE_OPENGL_ES
|
||||
int load_wipe_tower_preview(
|
||||
float pos_x, float pos_y, float width, float depth, float height, float rotation_angle, bool size_unknown, float brim_width, TriangleMesh* out_mesh = nullptr);
|
||||
float pos_x, float pos_y, float width, float depth, float height, float cone_angle, float rotation_angle, bool size_unknown, float brim_width, TriangleMesh* out_mesh = nullptr);
|
||||
#else
|
||||
int load_wipe_tower_preview(
|
||||
float pos_x, float pos_y, float width, float depth, float height, float rotation_angle, bool size_unknown, float brim_width);
|
||||
float pos_x, float pos_y, float width, float depth, float height, float cone_angle, float rotation_angle, bool size_unknown, float brim_width);
|
||||
#endif // ENABLE_OPENGL_ES
|
||||
|
||||
// Load SLA auxiliary GLVolumes (for support trees or pad).
|
||||
void load_object_auxiliary(
|
||||
const SLAPrintObject* print_object,
|
||||
int obj_idx,
|
||||
// pairs of <instance_idx, print_instance_idx>
|
||||
const std::vector<std::pair<size_t, size_t>>& instances,
|
||||
SLAPrintObjectStep milestone,
|
||||
// Timestamp of the last change of the milestone
|
||||
size_t timestamp);
|
||||
|
||||
GLVolume* new_toolpath_volume(const ColorRGBA& rgba);
|
||||
GLVolume* new_nontoolpath_volume(const ColorRGBA& rgba);
|
||||
// Render the volumes by OpenGL.
|
||||
|
@ -41,9 +41,9 @@ void AboutDialogLogo::onRepaint(wxEvent &event)
|
||||
// CopyrightsDialog
|
||||
// -----------------------------------------
|
||||
CopyrightsDialog::CopyrightsDialog()
|
||||
: DPIDialog(static_cast<wxWindow*>(wxGetApp().mainframe), wxID_ANY, from_u8((boost::format("%1% - %2%")
|
||||
% (wxGetApp().is_editor() ? SLIC3R_APP_NAME : GCODEVIEWER_APP_NAME)
|
||||
% _utf8(L("Portions copyright"))).str()),
|
||||
: DPIDialog(static_cast<wxWindow*>(wxGetApp().mainframe), wxID_ANY, format_wxstr("%1% - %2%"
|
||||
, wxGetApp().is_editor() ? SLIC3R_APP_NAME : GCODEVIEWER_APP_NAME
|
||||
, _L("Portions copyright")),
|
||||
wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
|
||||
{
|
||||
this->SetFont(wxGetApp().normal_font());
|
||||
@ -141,7 +141,6 @@ wxString CopyrightsDialog::get_html_text()
|
||||
const auto bgr_clr_str = encode_color(ColorRGB(bgr_clr.Red(), bgr_clr.Green(), bgr_clr.Blue()));
|
||||
|
||||
const wxString copyright_str = _L("Copyright") + "© ";
|
||||
// TRN "Slic3r _is licensed under the_ License"
|
||||
const wxString header_str = _L("License agreements of all following programs (libraries) are part of application license agreement");
|
||||
|
||||
wxString text = wxString::Format(
|
||||
@ -211,7 +210,7 @@ void CopyrightsDialog::onCloseDialog(wxEvent &)
|
||||
}
|
||||
|
||||
AboutDialog::AboutDialog()
|
||||
: DPIDialog(static_cast<wxWindow*>(wxGetApp().mainframe), wxID_ANY, from_u8((boost::format(_utf8(L("About %s"))) % (wxGetApp().is_editor() ? SLIC3R_APP_NAME : GCODEVIEWER_APP_NAME)).str()), wxDefaultPosition,
|
||||
: DPIDialog(static_cast<wxWindow*>(wxGetApp().mainframe), wxID_ANY, format_wxstr(_L("About %s"), wxGetApp().is_editor() ? SLIC3R_APP_NAME : GCODEVIEWER_APP_NAME), wxDefaultPosition,
|
||||
wxDefaultSize, /*wxCAPTION*/wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
|
||||
{
|
||||
SetFont(wxGetApp().normal_font());
|
||||
@ -267,14 +266,13 @@ AboutDialog::AboutDialog()
|
||||
int size[] = {fs,fs,fs,fs,fs,fs,fs};
|
||||
m_html->SetFonts(font.GetFaceName(), font.GetFaceName(), size);
|
||||
m_html->SetBorders(2);
|
||||
const std::string copyright_str = _utf8(L("Copyright"));
|
||||
// TRN "Slic3r _is licensed under the_ License"
|
||||
const std::string is_lecensed_str = _utf8(L("is licensed under the"));
|
||||
const std::string license_str = _utf8(L("GNU Affero General Public License, version 3"));
|
||||
const std::string based_on_str = _utf8(L("PrusaSlicer is based on Slic3r by Alessandro Ranellucci and the RepRap community."));
|
||||
const std::string contributors_str = _utf8(L("Contributions by Henrik Brix Andersen, Nicolas Dandrimont, Mark Hindess, Petr Ledvina, Joseph Lenox, Y. Sapir, Mike Sheldrake, Vojtech Bubnik and numerous others."));
|
||||
const auto text = from_u8(
|
||||
(boost::format(
|
||||
const wxString copyright_str = _L("Copyright");
|
||||
// TRN AboutDialog: "Slic3r %1% GNU Affero General Public License"
|
||||
const wxString is_lecensed_str = _L("is licensed under the");
|
||||
const wxString license_str = _L("GNU Affero General Public License, version 3");
|
||||
const wxString based_on_str = _L("PrusaSlicer is based on Slic3r by Alessandro Ranellucci and the RepRap community.");
|
||||
const wxString contributors_str = _L("Contributions by Henrik Brix Andersen, Nicolas Dandrimont, Mark Hindess, Petr Ledvina, Joseph Lenox, Y. Sapir, Mike Sheldrake, Vojtech Bubnik and numerous others.");
|
||||
const auto text = format_wxstr(
|
||||
"<html>"
|
||||
"<body bgcolor= %1% link= %2%>"
|
||||
"<font color=%3%>"
|
||||
@ -288,12 +286,12 @@ AboutDialog::AboutDialog()
|
||||
"%9%"
|
||||
"</font>"
|
||||
"</body>"
|
||||
"</html>") % bgr_clr_str % text_clr_str % text_clr_str
|
||||
% copyright_str % copyright_str
|
||||
% is_lecensed_str
|
||||
% license_str
|
||||
% based_on_str
|
||||
% contributors_str).str());
|
||||
"</html>", bgr_clr_str, text_clr_str, text_clr_str
|
||||
, copyright_str, copyright_str
|
||||
, is_lecensed_str
|
||||
, license_str
|
||||
, based_on_str
|
||||
, contributors_str);
|
||||
m_html->SetPage(text);
|
||||
vsizer->Add(m_html, 1, wxEXPAND | wxBOTTOM, 10);
|
||||
m_html->Bind(wxEVT_HTML_LINK_CLICKED, &AboutDialog::onLinkClicked, this);
|
||||
|
@ -76,10 +76,10 @@ std::pair<std::string, bool> SlicingProcessCompletedEvent::format_error_message(
|
||||
try {
|
||||
this->rethrow_exception();
|
||||
} catch (const std::bad_alloc &ex) {
|
||||
wxString errmsg = GUI::from_u8((boost::format(_utf8(L("%s has encountered an error. It was likely caused by running out of memory. "
|
||||
error = GUI::format(_L("%s has encountered an error. It was likely caused by running out of memory. "
|
||||
"If you are sure you have enough RAM on your system, this may also be a bug and we would "
|
||||
"be glad if you reported it."))) % SLIC3R_APP_NAME).str());
|
||||
error = std::string(errmsg.ToUTF8()) + "\n\n" + std::string(ex.what());
|
||||
"be glad if you reported it."), SLIC3R_APP_NAME);
|
||||
error += "\n\n" + std::string(ex.what());
|
||||
} catch (const HardCrash &ex) {
|
||||
error = GUI::format(_L("PrusaSlicer has encountered a fatal error: \"%1%\""), ex.what()) + "\n\n" +
|
||||
_u8L("Please save your project and restart PrusaSlicer. "
|
||||
@ -159,7 +159,7 @@ void BackgroundSlicingProcess::process_fff()
|
||||
wxQueueEvent(GUI::wxGetApp().mainframe->m_plater, new wxCommandEvent(m_event_export_began_id));
|
||||
prepare_upload();
|
||||
} else {
|
||||
m_print->set_status(100, _utf8(L("Slicing complete")));
|
||||
m_print->set_status(100, _u8L("Slicing complete"));
|
||||
}
|
||||
this->set_step_done(bspsGCodeFinalize);
|
||||
}
|
||||
@ -180,12 +180,12 @@ void BackgroundSlicingProcess::process_sla()
|
||||
|
||||
m_sla_print->export_print(export_path, thumbnails);
|
||||
|
||||
m_print->set_status(100, (boost::format(_utf8(L("Masked SLA file exported to %1%"))) % export_path).str());
|
||||
m_print->set_status(100, GUI::format(_L("Masked SLA file exported to %1%"), export_path));
|
||||
} else if (! m_upload_job.empty()) {
|
||||
wxQueueEvent(GUI::wxGetApp().mainframe->m_plater, new wxCommandEvent(m_event_export_began_id));
|
||||
prepare_upload();
|
||||
} else {
|
||||
m_print->set_status(100, _utf8(L("Slicing complete")));
|
||||
m_print->set_status(100, _u8L("Slicing complete"));
|
||||
}
|
||||
this->set_step_done(bspsGCodeFinalize);
|
||||
}
|
||||
@ -649,7 +649,7 @@ bool BackgroundSlicingProcess::invalidate_all_steps()
|
||||
// Copy the final G-code to target location (possibly a SD card, if it is a removable media, then verify that the file was written without an error).
|
||||
void BackgroundSlicingProcess::finalize_gcode()
|
||||
{
|
||||
m_print->set_status(95, _utf8(L("Running post-processing scripts")));
|
||||
m_print->set_status(95, _u8L("Running post-processing scripts"));
|
||||
|
||||
// Perform the final post-processing of the export path by applying the print statistics over the file name.
|
||||
std::string export_path = m_fff_print->print_statistics().finalize_output_path(m_export_path);
|
||||
@ -680,32 +680,32 @@ void BackgroundSlicingProcess::finalize_gcode()
|
||||
catch (...)
|
||||
{
|
||||
remove_post_processed_temp_file();
|
||||
throw Slic3r::ExportError(_utf8(L("Unknown error occured during exporting G-code.")));
|
||||
throw Slic3r::ExportError(_u8L("Unknown error occured during exporting G-code."));
|
||||
}
|
||||
switch (copy_ret_val) {
|
||||
case CopyFileResult::SUCCESS: break; // no error
|
||||
case CopyFileResult::FAIL_COPY_FILE:
|
||||
throw Slic3r::ExportError((boost::format(_utf8(L("Copying of the temporary G-code to the output G-code failed. Maybe the SD card is write locked?\nError message: %1%"))) % error_message).str());
|
||||
throw Slic3r::ExportError(GUI::format(_L("Copying of the temporary G-code to the output G-code failed. Maybe the SD card is write locked?\nError message: %1%"), error_message));
|
||||
break;
|
||||
case CopyFileResult::FAIL_FILES_DIFFERENT:
|
||||
throw Slic3r::ExportError((boost::format(_utf8(L("Copying of the temporary G-code to the output G-code failed. There might be problem with target device, please try exporting again or using different device. The corrupted output G-code is at %1%.tmp."))) % export_path).str());
|
||||
throw Slic3r::ExportError(GUI::format(_L("Copying of the temporary G-code to the output G-code failed. There might be problem with target device, please try exporting again or using different device. The corrupted output G-code is at %1%.tmp."), export_path));
|
||||
break;
|
||||
case CopyFileResult::FAIL_RENAMING:
|
||||
throw Slic3r::ExportError((boost::format(_utf8(L("Renaming of the G-code after copying to the selected destination folder has failed. Current path is %1%.tmp. Please try exporting again."))) % export_path).str());
|
||||
throw Slic3r::ExportError(GUI::format(_L("Renaming of the G-code after copying to the selected destination folder has failed. Current path is %1%.tmp. Please try exporting again."), export_path));
|
||||
break;
|
||||
case CopyFileResult::FAIL_CHECK_ORIGIN_NOT_OPENED:
|
||||
throw Slic3r::ExportError((boost::format(_utf8(L("Copying of the temporary G-code has finished but the original code at %1% couldn't be opened during copy check. The output G-code is at %2%.tmp."))) % output_path % export_path).str());
|
||||
throw Slic3r::ExportError(GUI::format(_L("Copying of the temporary G-code has finished but the original code at %1% couldn't be opened during copy check. The output G-code is at %2%.tmp."), output_path, export_path));
|
||||
break;
|
||||
case CopyFileResult::FAIL_CHECK_TARGET_NOT_OPENED:
|
||||
throw Slic3r::ExportError((boost::format(_utf8(L("Copying of the temporary G-code has finished but the exported code couldn't be opened during copy check. The output G-code is at %1%.tmp."))) % export_path).str());
|
||||
throw Slic3r::ExportError(GUI::format(_L("Copying of the temporary G-code has finished but the exported code couldn't be opened during copy check. The output G-code is at %1%.tmp."), export_path));
|
||||
break;
|
||||
default:
|
||||
throw Slic3r::ExportError(_utf8(L("Unknown error occured during exporting G-code.")));
|
||||
throw Slic3r::ExportError(_u8L("Unknown error occured during exporting G-code."));
|
||||
BOOST_LOG_TRIVIAL(error) << "Unexpected fail code(" << (int)copy_ret_val << ") durring copy_file() to " << export_path << ".";
|
||||
break;
|
||||
}
|
||||
|
||||
m_print->set_status(100, (boost::format(_utf8(L("G-code file exported to %1%"))) % export_path).str());
|
||||
m_print->set_status(100, GUI::format(_L("G-code file exported to %1%"), export_path));
|
||||
}
|
||||
|
||||
// A print host upload job has been scheduled, enqueue it to the printhost job queue
|
||||
@ -716,10 +716,10 @@ void BackgroundSlicingProcess::prepare_upload()
|
||||
/ boost::filesystem::unique_path("." SLIC3R_APP_KEY ".upload.%%%%-%%%%-%%%%-%%%%");
|
||||
|
||||
if (m_print == m_fff_print) {
|
||||
m_print->set_status(95, _utf8(L("Running post-processing scripts")));
|
||||
m_print->set_status(95, _u8L("Running post-processing scripts"));
|
||||
std::string error_message;
|
||||
if (copy_file(m_temp_output_path, source_path.string(), error_message) != SUCCESS)
|
||||
throw Slic3r::RuntimeError(_utf8(L("Copying of the temporary G-code to the output G-code failed")));
|
||||
throw Slic3r::RuntimeError("Copying of the temporary G-code to the output G-code failed");
|
||||
m_upload_job.upload_data.upload_path = m_fff_print->print_statistics().finalize_output_path(m_upload_job.upload_data.upload_path.string());
|
||||
// Make a copy of the source path, as run_post_process_scripts() is allowed to change it when making a copy of the source file
|
||||
// (not here, but when the final target is a file).
|
||||
@ -735,7 +735,7 @@ void BackgroundSlicingProcess::prepare_upload()
|
||||
m_sla_print->export_print(source_path.string(),thumbnails, m_upload_job.upload_data.upload_path.filename().string());
|
||||
}
|
||||
|
||||
m_print->set_status(100, (boost::format(_utf8(L("Scheduling upload to `%1%`. See Window -> Print Host Upload Queue"))) % m_upload_job.printhost->get_host()).str());
|
||||
m_print->set_status(100, GUI::format(_L("Scheduling upload to `%1%`. See Window -> Print Host Upload Queue"), m_upload_job.printhost->get_host()));
|
||||
|
||||
m_upload_job.upload_data.source_path = std::move(source_path);
|
||||
|
||||
|
@ -128,6 +128,9 @@ void BedShape::apply_optgroup_values(ConfigOptionsGroupShp optgroup)
|
||||
}
|
||||
}
|
||||
|
||||
BedShapeDialog::BedShapeDialog(wxWindow* parent) : DPIDialog(parent, wxID_ANY, _(L("Bed Shape")),
|
||||
wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER) {}
|
||||
|
||||
void BedShapeDialog::build_dialog(const ConfigOptionPoints& default_pt, const ConfigOptionString& custom_texture, const ConfigOptionString& custom_model)
|
||||
{
|
||||
SetFont(wxGetApp().normal_font());
|
||||
|
@ -5,7 +5,6 @@
|
||||
|
||||
#include "GUI_Utils.hpp"
|
||||
#include "2DBed.hpp"
|
||||
#include "I18N.hpp"
|
||||
|
||||
#include <libslic3r/BuildVolume.hpp>
|
||||
|
||||
@ -93,8 +92,7 @@ class BedShapeDialog : public DPIDialog
|
||||
{
|
||||
BedShapePanel* m_panel;
|
||||
public:
|
||||
BedShapeDialog(wxWindow* parent) : DPIDialog(parent, wxID_ANY, _(L("Bed Shape")),
|
||||
wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER) {}
|
||||
BedShapeDialog(wxWindow* parent);
|
||||
|
||||
void build_dialog(const ConfigOptionPoints& default_pt, const ConfigOptionString& custom_texture, const ConfigOptionString& custom_model);
|
||||
|
||||
|
@ -224,14 +224,14 @@ void BonjourDialog::on_timer(wxTimerEvent &)
|
||||
// explicitly (wxTimerEvent should not be created by user code).
|
||||
void BonjourDialog::on_timer_process()
|
||||
{
|
||||
const auto search_str = _utf8(L("Searching for devices"));
|
||||
const auto search_str = _L("Searching for devices");
|
||||
|
||||
if (timer_state > 0) {
|
||||
const std::string dots(timer_state, '.');
|
||||
label->SetLabel(GUI::from_u8((boost::format("%1% %2%") % search_str % dots).str()));
|
||||
label->SetLabel(search_str + dots);
|
||||
timer_state = (timer_state) % 3 + 1;
|
||||
} else {
|
||||
label->SetLabel(GUI::from_u8((boost::format("%1%: %2%") % search_str % (_utf8(L("Finished"))+".")).str()));
|
||||
label->SetLabel(search_str + ": " + _L("Finished") + ".");
|
||||
timer->Stop();
|
||||
}
|
||||
}
|
||||
|
@ -160,7 +160,7 @@ void FillSizerWithModeColorDescriptions(
|
||||
wxFlexGridSizer* grid_sizer = new wxFlexGridSizer(9, 5, 5);
|
||||
sizer->Add(grid_sizer, 0, wxEXPAND);
|
||||
|
||||
const std::vector<wxString> names = { _L("Simple"), _CTX(L_CONTEXT("Advanced", "Mode"), "Mode"), _L("Expert") };
|
||||
const std::vector<wxString> names = { _L("Simple"), _CTX("Advanced", "Mode"), _L("Expert") };
|
||||
|
||||
for (size_t mode = 0; mode < names.size(); ++mode) {
|
||||
wxColour& color = mode_palette[mode];
|
||||
|
@ -256,7 +256,7 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig* config)
|
||||
|
||||
bool have_default_acceleration = config->opt_float("default_acceleration") > 0;
|
||||
for (auto el : { "perimeter_acceleration", "infill_acceleration", "top_solid_infill_acceleration",
|
||||
"solid_infill_acceleration", "external_perimeter_acceleration"
|
||||
"solid_infill_acceleration", "external_perimeter_acceleration",
|
||||
"bridge_acceleration", "first_layer_acceleration" })
|
||||
toggle_field(el, have_default_acceleration);
|
||||
|
||||
@ -319,8 +319,8 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig* config)
|
||||
toggle_field("standby_temperature_delta", have_ooze_prevention);
|
||||
|
||||
bool have_wipe_tower = config->opt_bool("wipe_tower");
|
||||
for (auto el : { "wipe_tower_x", "wipe_tower_y", "wipe_tower_width", "wipe_tower_rotation_angle", "wipe_tower_brim_width",
|
||||
"wipe_tower_bridging", "wipe_tower_no_sparse_layers", "single_extruder_multi_material_priming" })
|
||||
for (auto el : { "wipe_tower_x", "wipe_tower_y", "wipe_tower_width", "wipe_tower_rotation_angle", "wipe_tower_brim_width", "wipe_tower_cone_angle",
|
||||
"wipe_tower_extra_spacing", "wipe_tower_bridging", "wipe_tower_no_sparse_layers", "single_extruder_multi_material_priming" })
|
||||
toggle_field(el, have_wipe_tower);
|
||||
|
||||
toggle_field("avoid_crossing_curled_overhangs", !config->opt_bool("avoid_crossing_perimeters"));
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "GUI_App.hpp"
|
||||
#include "MainFrame.hpp"
|
||||
#include "wxExtensions.hpp"
|
||||
#include "format.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
@ -89,10 +90,10 @@ static wxString generate_html_row(const Config::Snapshot &snapshot, bool row_eve
|
||||
}
|
||||
|
||||
if (! compatible) {
|
||||
text += "<p align=\"right\">" + from_u8((boost::format(_utf8(L("Incompatible with this %s"))) % SLIC3R_APP_NAME).str()) + "</p>";
|
||||
text += "<p align=\"right\">" + format_wxstr(_L("Incompatible with this %s"), SLIC3R_APP_NAME) + "</p>";
|
||||
}
|
||||
else if (! snapshot_active)
|
||||
text += "<p align=\"right\"><a href=\"" + snapshot.id + "\">" + _(L("Activate")) + "</a></p>";
|
||||
text += "<p align=\"right\"><a href=\"" + snapshot.id + "\">" + _L("Activate") + "</a></p>";
|
||||
text += "</td>";
|
||||
text += "</tr>";
|
||||
return text;
|
||||
|
@ -56,6 +56,7 @@
|
||||
#include "MsgDialog.hpp"
|
||||
#include "UnsavedChangesDialog.hpp"
|
||||
#include "slic3r/Utils/AppUpdater.hpp"
|
||||
#include "slic3r/GUI/I18N.hpp"
|
||||
|
||||
#if defined(__linux__) && defined(__WXGTK3__)
|
||||
#define wxLinux_gtk3 true
|
||||
@ -288,7 +289,7 @@ PrinterPicker::PrinterPicker(wxWindow *parent, const VendorProfile &vendor, wxSt
|
||||
const auto &variant = model.variants[i];
|
||||
|
||||
const auto label = model.technology == ptFFF
|
||||
? from_u8((boost::format("%1% %2% %3%") % variant.name % _utf8(L("mm")) % _utf8(L("nozzle"))).str())
|
||||
? format_wxstr("%1% %2% %3%", variant.name, _L("mm"), _L("nozzle"))
|
||||
: from_u8(model.name);
|
||||
|
||||
if (i == 1) {
|
||||
@ -508,17 +509,17 @@ void ConfigWizardPage::append_spacer(int space)
|
||||
// Wizard pages
|
||||
|
||||
PageWelcome::PageWelcome(ConfigWizard *parent)
|
||||
: ConfigWizardPage(parent, from_u8((boost::format(
|
||||
: ConfigWizardPage(parent, format_wxstr(
|
||||
#ifdef __APPLE__
|
||||
_utf8(L("Welcome to the %s Configuration Assistant"))
|
||||
_L("Welcome to the %s Configuration Assistant")
|
||||
#else
|
||||
_utf8(L("Welcome to the %s Configuration Wizard"))
|
||||
_L("Welcome to the %s Configuration Wizard")
|
||||
#endif
|
||||
) % SLIC3R_APP_NAME).str()), _L("Welcome"))
|
||||
, welcome_text(append_text(from_u8((boost::format(
|
||||
_utf8(L("Hello, welcome to %s! This %s helps you with the initial configuration; just a few settings and you will be ready to print.")))
|
||||
% SLIC3R_APP_NAME
|
||||
% _utf8(ConfigWizard::name())).str())
|
||||
, SLIC3R_APP_NAME), _L("Welcome"))
|
||||
, welcome_text(append_text(format_wxstr(
|
||||
_L("Hello, welcome to %s! This %s helps you with the initial configuration; just a few settings and you will be ready to print.")
|
||||
, SLIC3R_APP_NAME
|
||||
, _(ConfigWizard::name()))
|
||||
))
|
||||
, cbox_reset(append(
|
||||
new wxCheckBox(this, wxID_ANY, _L("Remove user profiles (a snapshot will be taken beforehand)"))
|
||||
@ -576,7 +577,7 @@ PagePrinters::PagePrinters(ConfigWizard *parent,
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto picker_title = family.empty() ? wxString() : from_u8((boost::format(_utf8(L("%s Family"))) % family).str());
|
||||
const auto picker_title = family.empty() ? wxString() : format_wxstr(_L("%s Family"), family);
|
||||
auto *picker = new PrinterPicker(this, vendor, picker_title, MAX_COLS, *appconfig, filter);
|
||||
|
||||
picker->Bind(EVT_PRINTER_PICK, [this, appconfig](const PrinterPickerEvent &evt) {
|
||||
@ -786,11 +787,14 @@ void PageMaterials::set_compatible_printers_html_window(const std::vector<std::s
|
||||
const auto text_clr_str = encode_color(ColorRGB(text_clr.Red(), text_clr.Green(), text_clr.Blue()));
|
||||
wxString text;
|
||||
if (materials->technology == T_FFF && template_shown) {
|
||||
// TRN ConfigWizard: Materials : "%1%" = "Filaments"/"SLA materials"
|
||||
text = format_wxstr(_L("%1% visible for <b>(\"Template\")</b> printer are universal profiles available for all printers. These might not be compatible with your printer."), materials->technology == T_FFF ? _L("Filaments") : _L("SLA materials"));
|
||||
} else {
|
||||
// TRN ConfigWizard: Materials : "%1%" = "Filaments"/"SLA materials"
|
||||
wxString first_line = format_wxstr(_L("%1% marked with <b>*</b> are <b>not</b> compatible with some installed printers."), materials->technology == T_FFF ? _L("Filaments") : _L("SLA materials"));
|
||||
|
||||
if (all_printers) {
|
||||
// TRN ConfigWizard: Materials : "%1%" = "filament"/"SLA material"
|
||||
wxString second_line = format_wxstr(_L("All installed printers are compatible with the selected %1%."), materials->technology == T_FFF ? _L("filament") : _L("SLA material"));
|
||||
text = wxString::Format(
|
||||
"<html>"
|
||||
@ -1368,7 +1372,7 @@ Worker::Worker(wxWindow* parent)
|
||||
button_path->Bind(wxEVT_BUTTON, [this](wxCommandEvent& event) {
|
||||
boost::filesystem::path chosen_dest(boost::nowide::narrow(m_input_path->GetValue()));
|
||||
|
||||
wxDirDialog dialog(m_parent, L("Choose folder:"), chosen_dest.string() );
|
||||
wxDirDialog dialog(m_parent, _L("Choose folder") + ":", chosen_dest.string() );
|
||||
if (dialog.ShowModal() == wxID_OK)
|
||||
this->m_input_path->SetValue(dialog.GetPath());
|
||||
});
|
||||
@ -1420,11 +1424,11 @@ PageDownloader::PageDownloader(ConfigWizard* parent)
|
||||
box_allow_downloads->SetValue(box_allow_value);
|
||||
append(box_allow_downloads);
|
||||
|
||||
append_text(wxString::Format(_L(
|
||||
"If enabled, %s registers to start on custom URL on www.printables.com."
|
||||
" You will be able to use button with %s logo to open models in this %s."
|
||||
// TRN ConfigWizard : Downloader : %1% = "PrusaSlicer"
|
||||
append_text(format_wxstr(_L("If enabled, %1% registers to start on custom URL on www.printables.com."
|
||||
" You will be able to use button with %1% logo to open models in this %1%."
|
||||
" The model will be downloaded into folder you choose bellow."
|
||||
), SLIC3R_APP_NAME, SLIC3R_APP_NAME, SLIC3R_APP_NAME));
|
||||
), SLIC3R_APP_NAME));
|
||||
|
||||
#ifdef __linux__
|
||||
append_text(wxString::Format(_L(
|
||||
@ -1455,7 +1459,7 @@ bool DownloaderUtils::Worker::perform_register(const std::string& path_override/
|
||||
chosen_dest = aux_dest;
|
||||
ec.clear();
|
||||
if (chosen_dest.empty() || !boost::filesystem::is_directory(chosen_dest, ec) || ec) {
|
||||
std::string err_msg = GUI::format("%1%\n\n%2%",_L("Chosen directory for downloads does not Exists.") ,chosen_dest.string());
|
||||
std::string err_msg = GUI::format("%1%\n\n%2%",_L("Chosen directory for downloads does not exist.") ,chosen_dest.string());
|
||||
BOOST_LOG_TRIVIAL(error) << err_msg;
|
||||
show_error(m_parent, err_msg);
|
||||
return false;
|
||||
@ -1752,10 +1756,11 @@ void PageBedShape::apply_custom_config(DynamicPrintConfig &config)
|
||||
}
|
||||
|
||||
PageBuildVolume::PageBuildVolume(ConfigWizard* parent)
|
||||
// TRN ConfigWizard : Size of possible print, related on printer size
|
||||
: ConfigWizardPage(parent, _L("Build Volume"), _L("Build Volume"), 1)
|
||||
, build_volume(new DiamTextCtrl(this))
|
||||
{
|
||||
append_text(_L("Set vertical size of your printer."));
|
||||
append_text(_L("Set the printer height."));
|
||||
|
||||
wxString value = "200";
|
||||
build_volume->SetValue(value);
|
||||
@ -1792,7 +1797,7 @@ PageBuildVolume::PageBuildVolume(ConfigWizard* parent)
|
||||
}, build_volume->GetId());
|
||||
|
||||
auto* sizer_volume = new wxFlexGridSizer(3, 5, 5);
|
||||
auto* text_volume = new wxStaticText(this, wxID_ANY, _L("Max print height:"));
|
||||
auto* text_volume = new wxStaticText(this, wxID_ANY, _L("Max print height") + ":");
|
||||
auto* unit_volume = new wxStaticText(this, wxID_ANY, _L("mm"));
|
||||
sizer_volume->AddGrowableCol(0, 1);
|
||||
sizer_volume->Add(text_volume, 0, wxALIGN_CENTRE_VERTICAL);
|
||||
@ -1828,7 +1833,7 @@ PageDiameters::PageDiameters(ConfigWizard *parent)
|
||||
append_text(_L("Enter the diameter of your printer's hot end nozzle."));
|
||||
|
||||
auto *sizer_nozzle = new wxFlexGridSizer(3, 5, 5);
|
||||
auto *text_nozzle = new wxStaticText(this, wxID_ANY, _L("Nozzle Diameter:"));
|
||||
auto *text_nozzle = new wxStaticText(this, wxID_ANY, _L("Nozzle Diameter") + ":");
|
||||
auto *unit_nozzle = new wxStaticText(this, wxID_ANY, _L("mm"));
|
||||
sizer_nozzle->AddGrowableCol(0, 1);
|
||||
sizer_nozzle->Add(text_nozzle, 0, wxALIGN_CENTRE_VERTICAL);
|
||||
@ -1842,7 +1847,7 @@ PageDiameters::PageDiameters(ConfigWizard *parent)
|
||||
append_text(_L("Good precision is required, so use a caliper and do multiple measurements along the filament, then compute the average."));
|
||||
|
||||
auto *sizer_filam = new wxFlexGridSizer(3, 5, 5);
|
||||
auto *text_filam = new wxStaticText(this, wxID_ANY, _L("Filament Diameter:"));
|
||||
auto *text_filam = new wxStaticText(this, wxID_ANY, _L("Filament Diameter") + ":");
|
||||
auto *unit_filam = new wxStaticText(this, wxID_ANY, _L("mm"));
|
||||
sizer_filam->AddGrowableCol(0, 1);
|
||||
sizer_filam->Add(text_filam, 0, wxALIGN_CENTRE_VERTICAL);
|
||||
@ -1934,7 +1939,7 @@ PageTemperatures::PageTemperatures(ConfigWizard *parent)
|
||||
append_text(_L("A rule of thumb is 60 °C for PLA and 110 °C for ABS. Leave zero if you have no heated bed."));
|
||||
|
||||
auto *sizer_bed = new wxFlexGridSizer(3, 5, 5);
|
||||
auto *text_bed = new wxStaticText(this, wxID_ANY, _L("Bed Temperature:"));
|
||||
auto *text_bed = new wxStaticText(this, wxID_ANY, _L("Bed Temperature") + ":");
|
||||
auto *unit_bed = new wxStaticText(this, wxID_ANY, _L("°C"));
|
||||
sizer_bed->AddGrowableCol(0, 1);
|
||||
sizer_bed->Add(text_bed, 0, wxALIGN_CENTRE_VERTICAL);
|
||||
|
@ -8,8 +8,6 @@
|
||||
|
||||
#include <GL/glew.h>
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
||||
@ -44,17 +42,23 @@ void CoordAxes::render(const Transform3d& trafo, float emission_factor)
|
||||
shader->start_using();
|
||||
shader->set_uniform("emission_factor", emission_factor);
|
||||
|
||||
// Scale the axes if the camera is close to them to avoid issues
|
||||
// such as https://github.com/prusa3d/PrusaSlicer/issues/9483
|
||||
const Camera& camera = wxGetApp().plater()->get_camera();
|
||||
Transform3d scale_tr = Transform3d::Identity();
|
||||
scale_tr.scale(std::min(1., camera.get_inv_zoom() * 10.));
|
||||
|
||||
// x axis
|
||||
m_arrow.set_color(ColorRGBA::X());
|
||||
render_axis(*shader, trafo * Geometry::translation_transform(m_origin) * Geometry::rotation_transform({ 0.0, 0.5 * M_PI, 0.0 }));
|
||||
render_axis(*shader, trafo * Geometry::translation_transform(m_origin) * Geometry::rotation_transform({ 0.0, 0.5 * M_PI, 0.0 }) * scale_tr);
|
||||
|
||||
// y axis
|
||||
m_arrow.set_color(ColorRGBA::Y());
|
||||
render_axis(*shader, trafo * Geometry::translation_transform(m_origin) * Geometry::rotation_transform({ -0.5 * M_PI, 0.0, 0.0 }));
|
||||
render_axis(*shader, trafo * Geometry::translation_transform(m_origin) * Geometry::rotation_transform({ -0.5 * M_PI, 0.0, 0.0 }) * scale_tr);
|
||||
|
||||
// z axis
|
||||
m_arrow.set_color(ColorRGBA::Z());
|
||||
render_axis(*shader, trafo * Geometry::translation_transform(m_origin));
|
||||
render_axis(*shader, trafo * Geometry::translation_transform(m_origin) * scale_tr);
|
||||
|
||||
shader->stop_using();
|
||||
if (curr_shader != nullptr)
|
||||
@ -63,5 +67,3 @@ void CoordAxes::render(const Transform3d& trafo, float emission_factor)
|
||||
|
||||
} // GUI
|
||||
} // Slic3r
|
||||
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
@ -1,7 +1,6 @@
|
||||
#ifndef slic3r_CoordAxes_hpp_
|
||||
#define slic3r_CoordAxes_hpp_
|
||||
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
#include "GLModel.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
@ -55,6 +54,4 @@ public:
|
||||
} // GUI
|
||||
} // Slic3r
|
||||
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
|
||||
#endif // slic3r_CoordAxes_hpp_
|
||||
|
@ -106,7 +106,7 @@ Control::Control( wxWindow *parent,
|
||||
m_cog_icon_dim = m_bmp_cog.GetWidth();
|
||||
|
||||
m_selection = ssUndef;
|
||||
m_ticks.set_pause_print_msg(_utf8(L("Place bearings in slots and resume printing")));
|
||||
m_ticks.set_pause_print_msg(_u8L("Place bearings in slots and resume printing"));
|
||||
m_ticks.set_extruder_colors(&m_extruder_colors);
|
||||
|
||||
// slider events
|
||||
|
@ -147,7 +147,7 @@ void Downloader::start_download(const std::string& full_url)
|
||||
std::string escaped_url = FileGet::escape_url(full_url.substr(24));
|
||||
#endif
|
||||
if (!boost::starts_with(escaped_url, "https://") || !FileGet::is_subdomain(escaped_url, "printables.com")) {
|
||||
std::string msg = format(_L("Download won't start. Download URL doesn't point to https://files.printables.com : %1%"), escaped_url);
|
||||
std::string msg = format(_L("Download won't start. Download URL doesn't point to https://printables.com : %1%"), escaped_url);
|
||||
BOOST_LOG_TRIVIAL(error) << msg;
|
||||
NotificationManager* ntf_mngr = wxGetApp().notification_manager();
|
||||
ntf_mngr->push_notification(NotificationType::CustomNotification, NotificationManager::NotificationLevel::RegularNotificationLevel, msg);
|
||||
@ -178,7 +178,7 @@ void Downloader::on_error(wxCommandEvent& event)
|
||||
BOOST_LOG_TRIVIAL(error) << "Download error: " << event.GetString();
|
||||
NotificationManager* ntf_mngr = wxGetApp().notification_manager();
|
||||
ntf_mngr->set_download_URL_error(id, boost::nowide::narrow(event.GetString()));
|
||||
show_error(nullptr, format_wxstr(L"%1%\n%2%", _L("The download has failed:"), event.GetString()));
|
||||
show_error(nullptr, format_wxstr(L"%1%\n%2%", _L("The download has failed") + ":", event.GetString()));
|
||||
}
|
||||
void Downloader::on_complete(wxCommandEvent& event)
|
||||
{
|
||||
|
@ -190,7 +190,8 @@ void FileGet::priv::get_perform()
|
||||
//assert(file != NULL);
|
||||
if (file == NULL) {
|
||||
wxCommandEvent* evt = new wxCommandEvent(EVT_DWNLDR_FILE_ERROR);
|
||||
evt->SetString(GUI::format_wxstr(_L("Can't create file at %1%."), temp_path_wstring));
|
||||
// TRN %1% = file path
|
||||
evt->SetString(GUI::format_wxstr(_L("Can't create file at %1%"), temp_path_wstring));
|
||||
evt->SetInt(m_id);
|
||||
m_evt_handler->QueueEvent(evt);
|
||||
return;
|
||||
|
@ -226,7 +226,7 @@ void Field::get_value_by_opt_type(wxString& str, const bool check_value/* = true
|
||||
}
|
||||
|
||||
wxString label = m_opt.full_label.empty() ? _(m_opt.label) : _(m_opt.full_label);
|
||||
show_error(m_parent, from_u8((boost::format(_utf8(L("%s doesn't support percentage"))) % label).str()));
|
||||
show_error(m_parent, format_wxstr(_L("%s doesn't support percentage"), label));
|
||||
set_value(double_to_string(m_opt.min), true);
|
||||
m_value = double(m_opt.min);
|
||||
break;
|
||||
@ -299,7 +299,7 @@ void Field::get_value_by_opt_type(wxString& str, const bool check_value/* = true
|
||||
// Workaroud to avoid of using of the % for first layer height
|
||||
// see https://github.com/prusa3d/PrusaSlicer/issues/7418
|
||||
wxString label = m_opt.full_label.empty() ? _(m_opt.label) : _(m_opt.full_label);
|
||||
show_error(m_parent, from_u8((boost::format(_utf8(L("%s doesn't support percentage"))) % label).str()));
|
||||
show_error(m_parent, format_wxstr(_L("%s doesn't support percentage"), label));
|
||||
const wxString stVal = double_to_string(0.01, 2);
|
||||
set_value(stVal, true);
|
||||
m_value = into_u8(stVal);;
|
||||
@ -341,9 +341,10 @@ void Field::get_value_by_opt_type(wxString& str, const bool check_value/* = true
|
||||
|
||||
const std::string sidetext = m_opt.sidetext.rfind("mm/s") != std::string::npos ? "mm/s" : "mm";
|
||||
const wxString stVal = double_to_string(val, 2);
|
||||
const wxString msg_text = from_u8((boost::format(_utf8(L("Do you mean %s%% instead of %s %s?\n"
|
||||
"Select YES if you want to change this value to %s%%, \n"
|
||||
"or NO if you are sure that %s %s is a correct value."))) % stVal % stVal % sidetext % stVal % stVal % sidetext).str());
|
||||
// TRN %1% = Value, %2% = units
|
||||
const wxString msg_text = format_wxstr(_L("Do you mean %1%%% instead of %1% %2%?\n"
|
||||
"Select YES if you want to change this value to %1%%%, \n"
|
||||
"or NO if you are sure that %1% %2% is a correct value."), stVal, sidetext);
|
||||
WarningDialog dialog(m_parent, msg_text, _L("Parameter validation") + ": " + m_opt_id, wxYES | wxNO);
|
||||
if ((!infill_anchors || val > 100) && dialog.ShowModal() == wxID_YES) {
|
||||
set_value(from_u8((boost::format("%s%%") % stVal).str()), false/*true*/);
|
||||
|
@ -2253,7 +2253,7 @@ void GCodeViewer::load_shells(const Print& print)
|
||||
const WipeTowerData& wipe_tower_data = print.wipe_tower_data(extruders_count);
|
||||
const float depth = wipe_tower_data.depth;
|
||||
const float brim_width = wipe_tower_data.brim_width;
|
||||
m_shells.volumes.load_wipe_tower_preview(config.wipe_tower_x, config.wipe_tower_y, config.wipe_tower_width, depth, max_z, config.wipe_tower_rotation_angle,
|
||||
m_shells.volumes.load_wipe_tower_preview(config.wipe_tower_x, config.wipe_tower_y, config.wipe_tower_width, depth, max_z, config.wipe_tower_cone_angle, config.wipe_tower_rotation_angle,
|
||||
!print.is_step_done(psWipeTower), brim_width);
|
||||
}
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user