Merge branch 'master' of https://github.com/Prusa-Development/PrusaSlicerPrivate into et_picking_parts_fix
This commit is contained in:
commit
2e0d21d2e2
41 changed files with 3251 additions and 458 deletions
|
@ -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.
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
@ -669,8 +681,9 @@ 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;
|
||||
VoronoiDiagramStatus status = detect_voronoi_diagram_known_issues(voronoi_diagram, segments);
|
||||
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.";
|
||||
}
|
||||
|
||||
|
@ -759,8 +771,8 @@ process_voronoi_diagram:
|
|||
// diagram on slightly rotated input polygons that usually make the Voronoi generator generate a non-degenerated 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);
|
||||
status = VoronoiDiagramStatus::OTHER_TYPE_OF_VORONOI_DIAGRAM_DEGENERATION;
|
||||
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 ab_weight = (A.w + B.w) / 2;
|
||||
const int64_t bc_weight = (B.w + C.w) / 2;
|
||||
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)
|
||||
|
|
|
@ -71,7 +71,7 @@ static const constexpr int UNARRANGED = -1;
|
|||
/// polygon belongs: UNARRANGED means no place for the polygon
|
||||
/// (also the initial state before arrange), 0..N means the index of the bed.
|
||||
/// Zero is the physical bed, larger than zero means a virtual bed.
|
||||
struct ArrangePolygon {
|
||||
struct ArrangePolygon {
|
||||
ExPolygon poly; /// The 2D silhouette to be arranged
|
||||
Vec2crd translation{0, 0}; /// The translation of the poly
|
||||
double rotation{0.0}; /// The rotation of the poly in radians
|
||||
|
|
|
@ -2958,6 +2958,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", "");
|
||||
|
||||
|
|
|
@ -438,6 +438,10 @@ void GCode::PlaceholderParserIntegration::reset()
|
|||
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();
|
||||
|
@ -463,10 +467,19 @@ void GCode::PlaceholderParserIntegration::init(const GCodeWriter &writer)
|
|||
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);
|
||||
|
@ -483,10 +496,22 @@ void GCode::PlaceholderParserIntegration::update_from_gcodewriter(const GCodeWri
|
|||
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) {
|
||||
|
@ -3384,10 +3409,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
|
||||
|
|
|
@ -362,6 +362,10 @@ private:
|
|||
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;
|
||||
|
|
|
@ -3508,6 +3508,17 @@ void GCodeProcessor::post_process()
|
|||
ret += buf;
|
||||
}
|
||||
}
|
||||
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());
|
||||
ret += buf;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -566,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 {
|
||||
|
|
|
@ -1373,43 +1373,56 @@ void PrintObject::discover_vertical_shells()
|
|||
}
|
||||
#endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
|
||||
polygons_append(holes, cache_top_botom_regions[idx_layer].holes);
|
||||
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;
|
||||
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);
|
||||
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];
|
||||
if (! holes.empty())
|
||||
holes = intersection(holes, cache.holes);
|
||||
if (! cache.top_surfaces.empty()) {
|
||||
polygons_append(shell, cache.top_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.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
|
||||
{
|
||||
|
|
|
@ -511,8 +511,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(
|
||||
_u8L("Slicing had to be stopped due to an internal error: "
|
||||
"Inconsistent slice index."));
|
||||
format(_u8L("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());
|
||||
|
|
|
@ -579,6 +579,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);
|
||||
|
|
|
@ -430,6 +430,16 @@ public:
|
|||
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.
|
||||
|
|
|
@ -1879,6 +1879,15 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
|
|||
size_t volume_idx;
|
||||
};
|
||||
|
||||
// SLA steps to pull the preview meshes for.
|
||||
typedef std::array<SLAPrintObjectStep, 3> SLASteps;
|
||||
SLASteps sla_steps = { slaposDrillHoles, slaposSupportTree, slaposPad };
|
||||
struct SLASupportState {
|
||||
std::array<PrintStateBase::StateWithTimeStamp, std::tuple_size<SLASteps>::value> step;
|
||||
};
|
||||
// State of the sla_steps for all SLAPrintObjects.
|
||||
std::vector<SLASupportState> sla_support_state;
|
||||
|
||||
std::vector<size_t> instance_ids_selected;
|
||||
std::vector<size_t> map_glvolume_old_to_new(m_volumes.volumes.size(), size_t(-1));
|
||||
std::vector<GLVolumeState> deleted_volumes;
|
||||
|
@ -1904,6 +1913,37 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
|
|||
}
|
||||
}
|
||||
|
||||
if (printer_technology == ptSLA) {
|
||||
const SLAPrint* sla_print = this->sla_print();
|
||||
#ifndef NDEBUG
|
||||
// Verify that the SLAPrint object is synchronized with m_model.
|
||||
check_model_ids_equal(*m_model, sla_print->model());
|
||||
#endif // NDEBUG
|
||||
sla_support_state.reserve(sla_print->objects().size());
|
||||
for (const SLAPrintObject* print_object : sla_print->objects()) {
|
||||
SLASupportState state;
|
||||
for (size_t istep = 0; istep < sla_steps.size(); ++istep) {
|
||||
state.step[istep] = print_object->step_state_with_timestamp(sla_steps[istep]);
|
||||
if (state.step[istep].state == PrintStateBase::State::Done) {
|
||||
std::shared_ptr<const indexed_triangle_set> m = print_object->get_mesh_to_print();
|
||||
if (m == nullptr || m->empty())
|
||||
// Consider the DONE step without a valid mesh as invalid for the purpose
|
||||
// of mesh visualization.
|
||||
state.step[istep].state = PrintStateBase::State::Invalidated;
|
||||
else {
|
||||
for (const ModelInstance* model_instance : print_object->model_object()->instances) {
|
||||
// Only the instances, which are currently printable, will have the SLA support structures kept.
|
||||
// The instances outside the print bed will have the GLVolumes of their support structures released.
|
||||
if (model_instance->is_printable())
|
||||
aux_volume_state.emplace_back(state.step[istep].timestamp, model_instance->id());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
sla_support_state.emplace_back(state);
|
||||
}
|
||||
}
|
||||
|
||||
std::sort(model_volume_state.begin(), model_volume_state.end(), model_volume_state_lower);
|
||||
std::sort(aux_volume_state.begin(), aux_volume_state.end(), model_volume_state_lower);
|
||||
// Release all ModelVolume based GLVolumes not found in the current Model. Find the GLVolume of a hollowed mesh.
|
||||
|
@ -2018,6 +2058,75 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
|
|||
}
|
||||
}
|
||||
|
||||
if (printer_technology == ptSLA) {
|
||||
size_t idx = 0;
|
||||
const SLAPrint *sla_print = this->sla_print();
|
||||
std::vector<double> shift_zs(m_model->objects.size(), 0);
|
||||
double relative_correction_z = sla_print->relative_correction().z();
|
||||
if (relative_correction_z <= EPSILON)
|
||||
relative_correction_z = 1.;
|
||||
for (const SLAPrintObject *print_object : sla_print->objects()) {
|
||||
SLASupportState &state = sla_support_state[idx ++];
|
||||
const ModelObject *model_object = print_object->model_object();
|
||||
// Find an index of the ModelObject
|
||||
int object_idx;
|
||||
// There may be new SLA volumes added to the scene for this print_object.
|
||||
// Find the object index of this print_object in the Model::objects list.
|
||||
auto it = std::find(sla_print->model().objects.begin(), sla_print->model().objects.end(), model_object);
|
||||
assert(it != sla_print->model().objects.end());
|
||||
object_idx = it - sla_print->model().objects.begin();
|
||||
// Cache the Z offset to be applied to all volumes with this object_idx.
|
||||
shift_zs[object_idx] = print_object->get_current_elevation() / relative_correction_z;
|
||||
// Collect indices of this print_object's instances, for which the SLA support meshes are to be added to the scene.
|
||||
// pairs of <instance_idx, print_instance_idx>
|
||||
std::vector<std::pair<size_t, size_t>> instances[std::tuple_size<SLASteps>::value];
|
||||
for (size_t print_instance_idx = 0; print_instance_idx < print_object->instances().size(); ++ print_instance_idx) {
|
||||
const SLAPrintObject::Instance &instance = print_object->instances()[print_instance_idx];
|
||||
// Find index of ModelInstance corresponding to this SLAPrintObject::Instance.
|
||||
auto it = std::find_if(model_object->instances.begin(), model_object->instances.end(),
|
||||
[&instance](const ModelInstance *mi) { return mi->id() == instance.instance_id; });
|
||||
assert(it != model_object->instances.end());
|
||||
int instance_idx = it - model_object->instances.begin();
|
||||
for (size_t istep = 0; istep < sla_steps.size(); ++istep) {
|
||||
if (state.step[istep].state == PrintStateBase::State::Done) {
|
||||
// Check whether there is an existing auxiliary volume to be updated, or a new auxiliary volume to be created.
|
||||
ModelVolumeState key(state.step[istep].timestamp, instance.instance_id.id);
|
||||
auto it = std::lower_bound(aux_volume_state.begin(), aux_volume_state.end(), key, model_volume_state_lower);
|
||||
assert(it != aux_volume_state.end() && it->geometry_id == key.geometry_id);
|
||||
if (it->new_geometry()) {
|
||||
// This can be an SLA support structure that should not be rendered (in case someone used undo
|
||||
// to revert to before it was generated). If that's the case, we should not generate anything.
|
||||
if (model_object->sla_points_status != sla::PointsStatus::NoPoints)
|
||||
instances[istep].emplace_back(std::pair<size_t, size_t>(instance_idx, print_instance_idx));
|
||||
else
|
||||
shift_zs[object_idx] = 0.;
|
||||
}
|
||||
else {
|
||||
// Recycling an old GLVolume. Update the Object/Instance indices into the current Model.
|
||||
m_volumes.volumes[it->volume_idx]->composite_id = GLVolume::CompositeID(object_idx, m_volumes.volumes[it->volume_idx]->volume_idx(), instance_idx);
|
||||
m_volumes.volumes[it->volume_idx]->set_instance_transformation(model_object->instances[instance_idx]->get_transformation());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t istep = 0; istep < sla_steps.size(); ++istep) {
|
||||
if (!instances[istep].empty())
|
||||
m_volumes.load_object_auxiliary(print_object, object_idx, instances[istep], sla_steps[istep], state.step[istep].timestamp);
|
||||
}
|
||||
}
|
||||
|
||||
// Shift-up all volumes of the object so that it has the right elevation with respect to the print bed
|
||||
for (GLVolume* volume : m_volumes.volumes) {
|
||||
const ModelObject* model_object = (volume->object_idx() < (int)m_model->objects.size()) ? m_model->objects[volume->object_idx()] : nullptr;
|
||||
if (model_object != nullptr && model_object->instances[volume->instance_idx()]->is_printable()) {
|
||||
const SLAPrintObject* po = sla_print->get_print_object_by_model_object_id(model_object->id());
|
||||
if (po != nullptr)
|
||||
volume->set_sla_shift_z(po->get_current_elevation() / sla_print->relative_correction().z());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (printer_technology == ptFFF && m_config->has("nozzle_diameter")) {
|
||||
// Should the wipe tower be visualized ?
|
||||
unsigned int extruders_count = (unsigned int)dynamic_cast<const ConfigOptionFloats*>(m_config->option("nozzle_diameter"))->values.size();
|
||||
|
@ -2054,7 +2163,7 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
|
|||
}
|
||||
|
||||
update_volumes_colors_by_extruder();
|
||||
// Update selection indices based on the old/new GLVolumeCollection.
|
||||
// Update selection indices based on the old/new GLVolumeCollection.
|
||||
if (m_selection.get_mode() == Selection::Instance)
|
||||
m_selection.instances_changed(instance_ids_selected);
|
||||
else
|
||||
|
@ -3486,6 +3595,9 @@ void GLCanvas3D::do_move(const std::string& snapshot_type)
|
|||
int instance_idx = v->instance_idx();
|
||||
int volume_idx = v->volume_idx();
|
||||
|
||||
if (volume_idx < 0)
|
||||
continue;
|
||||
|
||||
std::pair<int, int> done_id(object_idx, instance_idx);
|
||||
|
||||
if (0 <= object_idx && object_idx < (int)m_model->objects.size()) {
|
||||
|
@ -3500,7 +3612,7 @@ void GLCanvas3D::do_move(const std::string& snapshot_type)
|
|||
#else
|
||||
model_object->instances[instance_idx]->set_offset(v->get_instance_offset());
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
else if (volume_idx >= 0 && selection_mode == Selection::Volume)
|
||||
else if (selection_mode == Selection::Volume)
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
model_object->volumes[volume_idx]->set_transformation(v->get_volume_transformation());
|
||||
#else
|
||||
|
@ -3591,6 +3703,9 @@ void GLCanvas3D::do_rotate(const std::string& snapshot_type)
|
|||
const int instance_idx = v->instance_idx();
|
||||
const int volume_idx = v->volume_idx();
|
||||
|
||||
if (volume_idx < 0)
|
||||
continue;
|
||||
|
||||
done.insert(std::pair<int, int>(object_idx, instance_idx));
|
||||
|
||||
// Rotate instances/volumes.
|
||||
|
@ -3667,6 +3782,9 @@ void GLCanvas3D::do_scale(const std::string& snapshot_type)
|
|||
const int instance_idx = v->instance_idx();
|
||||
const int volume_idx = v->volume_idx();
|
||||
|
||||
if (volume_idx < 0)
|
||||
continue;
|
||||
|
||||
done.insert(std::pair<int, int>(object_idx, instance_idx));
|
||||
|
||||
// Rotate instances/volumes
|
||||
|
@ -3680,7 +3798,7 @@ void GLCanvas3D::do_scale(const std::string& snapshot_type)
|
|||
model_object->instances[instance_idx]->set_offset(v->get_instance_offset());
|
||||
#endif // ENABLE_WORLD_COORDINATE
|
||||
}
|
||||
else if (selection_mode == Selection::Volume && volume_idx >= 0) {
|
||||
else if (selection_mode == Selection::Volume) {
|
||||
#if ENABLE_WORLD_COORDINATE
|
||||
model_object->instances[instance_idx]->set_transformation(v->get_instance_transformation());
|
||||
model_object->volumes[volume_idx]->set_transformation(v->get_volume_transformation());
|
||||
|
@ -6795,9 +6913,9 @@ void GLCanvas3D::_load_sla_shells()
|
|||
// adds objects' volumes
|
||||
for (const SLAPrintObject* obj : print->objects()) {
|
||||
unsigned int initial_volumes_count = (unsigned int)m_volumes.volumes.size();
|
||||
for (const SLAPrintObject::Instance& instance : obj->instances()) {
|
||||
std::shared_ptr<const indexed_triangle_set> m = obj->get_mesh_to_print();
|
||||
if (m && !m->empty()) {
|
||||
std::shared_ptr<const indexed_triangle_set> m = obj->get_mesh_to_print();
|
||||
if (m && !m->empty()) {
|
||||
for (const SLAPrintObject::Instance& instance : obj->instances()) {
|
||||
add_volume(*obj, 0, instance, *m, GLVolume::MODEL_COLOR[0], true);
|
||||
// Set the extruder_id and volume_id to achieve the same color as in the 3D scene when
|
||||
// through the update_volumes_colors_by_extruder() call.
|
||||
|
@ -6808,7 +6926,7 @@ void GLCanvas3D::_load_sla_shells()
|
|||
add_volume(*obj, -int(slaposPad), instance, pad_mesh, GLVolume::SLA_PAD_COLOR, false);
|
||||
}
|
||||
}
|
||||
double shift_z = obj->get_current_elevation();
|
||||
const double shift_z = obj->get_current_elevation();
|
||||
for (unsigned int i = initial_volumes_count; i < m_volumes.volumes.size(); ++ i) {
|
||||
// apply shift z
|
||||
m_volumes.volumes[i]->set_sla_shift_z(shift_z);
|
||||
|
|
|
@ -875,6 +875,7 @@ void GLGizmoCut3D::on_set_state()
|
|||
}
|
||||
m_selected.clear();
|
||||
m_parent.set_use_color_clip_plane(false);
|
||||
m_c->selection_info()->set_use_shift(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1238,7 +1239,10 @@ BoundingBoxf3 GLGizmoCut3D::transformed_bounding_box(const Vec3d& plane_center,
|
|||
{
|
||||
const Selection& selection = m_parent.get_selection();
|
||||
|
||||
const Vec3d& instance_offset = selection.get_first_volume()->get_instance_offset();
|
||||
const auto first_volume = selection.get_first_volume();
|
||||
Vec3d instance_offset = first_volume->get_instance_offset();
|
||||
instance_offset[Z] += first_volume->get_sla_shift_z();
|
||||
|
||||
const auto cut_matrix = Transform3d::Identity() * rotation_m.inverse() * translation_transform(instance_offset - plane_center);
|
||||
|
||||
const Selection::IndicesList& idxs = selection.get_volume_idxs();
|
||||
|
@ -1356,6 +1360,12 @@ void GLGizmoCut3D::render_clipper_cut()
|
|||
|
||||
void GLGizmoCut3D::on_render()
|
||||
{
|
||||
if (m_state == On) {
|
||||
// This gizmo is showing the object elevated. Tell the common
|
||||
// SelectionInfo object to lie about the actual shift.
|
||||
m_c->selection_info()->set_use_shift(true);
|
||||
}
|
||||
|
||||
update_clipper();
|
||||
|
||||
init_picking_models();
|
||||
|
@ -2288,7 +2298,10 @@ bool GLGizmoCut3D::process_cut_line(SLAGizmoEventType action, const Vec2d& mouse
|
|||
const Vec3d new_plane_center = m_bb_center + cross_dir * cross_dir.dot(pt - m_bb_center);
|
||||
// update transformed bb
|
||||
const auto new_tbb = transformed_bounding_box(new_plane_center, m);
|
||||
const Vec3d& instance_offset = m_parent.get_selection().get_first_volume()->get_instance_offset();
|
||||
const GLVolume* first_volume = m_parent.get_selection().get_first_volume();
|
||||
Vec3d instance_offset = first_volume->get_instance_offset();
|
||||
instance_offset[Z] += first_volume->get_sla_shift_z();
|
||||
|
||||
const Vec3d trans_center_pos = m.inverse() * (new_plane_center - instance_offset) + new_tbb.center();
|
||||
if (new_tbb.contains(trans_center_pos)) {
|
||||
Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Cut by line"), UndoRedo::SnapshotType::GizmoAction);
|
||||
|
|
|
@ -223,6 +223,10 @@ enum class IconType : unsigned {
|
|||
system_selector,
|
||||
open_file,
|
||||
exclamation,
|
||||
lock,
|
||||
lock_bold,
|
||||
unlock,
|
||||
unlock_bold,
|
||||
// automatic calc of icon's count
|
||||
_count
|
||||
};
|
||||
|
@ -779,12 +783,12 @@ GLGizmoEmboss::GuiCfg GLGizmoEmboss::create_gui_configuration()
|
|||
ImGui::CalcTextSize(tr.boldness.c_str()).x,
|
||||
ImGui::CalcTextSize(tr.skew_ration.c_str()).x,
|
||||
ImGui::CalcTextSize(tr.from_surface.c_str()).x,
|
||||
ImGui::CalcTextSize(tr.rotation.c_str()).x,
|
||||
ImGui::CalcTextSize(tr.rotation.c_str()).x + cfg.icon_width + 2*space,
|
||||
ImGui::CalcTextSize(tr.keep_up.c_str()).x,
|
||||
ImGui::CalcTextSize(tr.collection.c_str()).x });
|
||||
cfg.advanced_input_offset = max_advanced_text_width
|
||||
+ 3 * space + cfg.indent;
|
||||
|
||||
cfg.lock_offset = cfg.advanced_input_offset - (cfg.icon_width + space);
|
||||
// calculate window size
|
||||
float window_title = line_height + 2*style.FramePadding.y + 2 * style.WindowTitleAlign.y;
|
||||
float input_height = line_height_with_spacing + 2*style.FramePadding.y;
|
||||
|
@ -806,9 +810,9 @@ GLGizmoEmboss::GuiCfg GLGizmoEmboss::create_gui_configuration()
|
|||
+ 2 * (cfg.icon_width + space);
|
||||
cfg.minimal_window_size = ImVec2(window_width, window_height);
|
||||
|
||||
// 9 = useSurface, charGap, lineGap, bold, italic, surfDist, rotation, keepUp, textFaceToCamera
|
||||
// 8 = useSurface, charGap, lineGap, bold, italic, surfDist, rotation, textFaceToCamera
|
||||
// 4 = 1px for fix each edit image of drag float
|
||||
float advance_height = input_height * 9 + 8;
|
||||
float advance_height = input_height * 8 + 8;
|
||||
cfg.minimal_window_size_with_advance =
|
||||
ImVec2(cfg.minimal_window_size.x,
|
||||
cfg.minimal_window_size.y + advance_height);
|
||||
|
@ -2652,8 +2656,8 @@ void GLGizmoEmboss::draw_height(bool use_inch)
|
|||
{
|
||||
float &value = m_style_manager.get_style().prop.size_in_mm;
|
||||
const EmbossStyle* stored_style = m_style_manager.get_stored_style();
|
||||
const float *stored = ((stored_style)? &stored_style->prop.size_in_mm : nullptr);
|
||||
const char *size_format = ((use_inch) ? "%.2f in" : "%.1f mm");
|
||||
const float *stored = (stored_style != nullptr)? &stored_style->prop.size_in_mm : nullptr;
|
||||
const char *size_format = use_inch ? "%.2f in" : "%.1f mm";
|
||||
const std::string revert_text_size = _u8L("Revert text size.");
|
||||
const std::string& name = m_gui_cfg->translations.height;
|
||||
if (rev_input_mm(name, value, stored, revert_text_size, 0.1f, 1.f, size_format, use_inch, m_scale_height))
|
||||
|
@ -2913,10 +2917,10 @@ void GLGizmoEmboss::draw_advanced()
|
|||
&stored_style->prop.distance : nullptr;
|
||||
m_imgui->disabled_begin(!allowe_surface_distance);
|
||||
|
||||
bool use_inch = wxGetApp().app_config->get_bool("use_inches");
|
||||
const std::string undo_move_tooltip = _u8L("Undo translation");
|
||||
const wxString move_tooltip = _L("Distance of the center of text from model surface");
|
||||
bool is_moved = false;
|
||||
bool use_inch = wxGetApp().app_config->get_bool("use_inches");
|
||||
if (use_inch) {
|
||||
std::optional<float> distance_inch;
|
||||
if (distance.has_value()) distance_inch = (*distance * ObjectManipulation::mm_to_in);
|
||||
|
@ -2982,16 +2986,23 @@ void GLGizmoEmboss::draw_advanced()
|
|||
process();
|
||||
}
|
||||
|
||||
ImGui::Text("%s", tr.keep_up.c_str());
|
||||
ImGui::SameLine(m_gui_cfg->advanced_input_offset);
|
||||
if (ImGui::Checkbox("##keep_up", &m_keep_up)) {
|
||||
// Keep up - lock button icon
|
||||
ImGui::SameLine(m_gui_cfg->lock_offset);
|
||||
const IconManager::Icon &icon = get_icon(m_icons, m_keep_up ? IconType::lock : IconType::unlock, IconState::activable);
|
||||
const IconManager::Icon &icon_hover = get_icon(m_icons, m_keep_up ? IconType::lock_bold : IconType::unlock_bold, IconState::activable);
|
||||
const IconManager::Icon &icon_disable = get_icon(m_icons, m_keep_up ? IconType::lock : IconType::unlock, IconState::disabled);
|
||||
if (button(icon, icon_hover, icon_disable)) {
|
||||
m_keep_up = !m_keep_up;
|
||||
if (m_keep_up) {
|
||||
// copy angle to volume
|
||||
m_volume->text_configuration->style.prop.angle = font_prop.angle;
|
||||
}
|
||||
}
|
||||
if (ImGui::IsItemHovered())
|
||||
ImGui::SetTooltip("%s", _u8L("Lock the text's rotation when moving text along the object's surface.").c_str());
|
||||
ImGui::SetTooltip("%s", (m_keep_up?
|
||||
_u8L("Unlock the text's rotation when moving text along the object's surface."):
|
||||
_u8L("Lock the text's rotation when moving text along the object's surface.")
|
||||
).c_str());
|
||||
|
||||
// when more collection add selector
|
||||
if (ff.font_file->infos.size() > 1) {
|
||||
|
@ -3270,7 +3281,11 @@ void GLGizmoEmboss::init_icons()
|
|||
"make_unbold.svg",
|
||||
"search.svg",
|
||||
"open.svg",
|
||||
"exclamation.svg"
|
||||
"exclamation.svg",
|
||||
"lock_closed.svg", // lock,
|
||||
"lock_closed_f.svg",// lock_bold,
|
||||
"lock_open.svg", // unlock,
|
||||
"lock_open_f.svg" // unlock_bold,
|
||||
};
|
||||
assert(filenames.size() == static_cast<size_t>(IconType::_count));
|
||||
std::string path = resources_dir() + "/icons/";
|
||||
|
@ -3395,6 +3410,7 @@ bool priv::start_create_volume_on_surface_job(
|
|||
{
|
||||
assert(gl_volume != nullptr);
|
||||
if (gl_volume == nullptr) return false;
|
||||
if (gl_volume->volume_idx() < 0) return false;
|
||||
|
||||
Plater *plater = wxGetApp().plater();
|
||||
const ModelObjectPtrs &objects = plater->model().objects;
|
||||
|
@ -3445,7 +3461,7 @@ void priv::find_closest_volume(const Selection &selection,
|
|||
for (unsigned int id : indices) {
|
||||
const GLVolume *gl_volume = selection.get_volume(id);
|
||||
const ModelVolume *volume = get_model_volume(*gl_volume, objects);
|
||||
if (!volume->is_model_part()) continue;
|
||||
if (volume == nullptr || !volume->is_model_part()) continue;
|
||||
Slic3r::Polygon hull = CameraUtils::create_hull2d(camera, *gl_volume);
|
||||
Vec2d c = hull.centroid().cast<double>();
|
||||
Vec2d d = c - screen_center;
|
||||
|
|
|
@ -182,6 +182,8 @@ private:
|
|||
float input_offset = 0.f;
|
||||
float advanced_input_offset = 0.f;
|
||||
|
||||
float lock_offset = 0.f;
|
||||
|
||||
ImVec2 text_size;
|
||||
|
||||
// maximal size of face name image
|
||||
|
@ -254,7 +256,7 @@ private:
|
|||
std::vector<wxString> bad = {};
|
||||
|
||||
// Configuration of font encoding
|
||||
static const wxFontEncoding encoding = wxFontEncoding::wxFONTENCODING_SYSTEM;
|
||||
static constexpr wxFontEncoding encoding = wxFontEncoding::wxFONTENCODING_SYSTEM;
|
||||
|
||||
// Identify if preview texture exists
|
||||
GLuint texture_id = 0;
|
||||
|
|
|
@ -101,6 +101,8 @@ void GLGizmoHollow::on_render()
|
|||
|
||||
m_selection_rectangle.render(m_parent);
|
||||
m_c->object_clipper()->render_cut();
|
||||
if (are_sla_supports_shown())
|
||||
m_c->supports_clipper()->render_cut();
|
||||
|
||||
glsafe(::glDisable(GL_BLEND));
|
||||
}
|
||||
|
@ -772,6 +774,14 @@ RENDER_AGAIN:
|
|||
if (m_imgui->slider_float("##clp_dist", &clp_dist, 0.f, 1.f, "%.2f"))
|
||||
m_c->object_clipper()->set_position_by_ratio(clp_dist, true);
|
||||
|
||||
// make sure supports are shown/hidden as appropriate
|
||||
ImGui::Separator();
|
||||
bool show_sups = are_sla_supports_shown();
|
||||
if (m_imgui->checkbox(m_desc["show_supports"], show_sups)) {
|
||||
show_sla_supports(show_sups);
|
||||
force_refresh = true;
|
||||
}
|
||||
|
||||
m_imgui->disabled_end();
|
||||
m_imgui->end();
|
||||
|
||||
|
|
|
@ -30,7 +30,8 @@ CommonGizmosDataID GLGizmoSlaBase::on_get_requirements() const
|
|||
int(CommonGizmosDataID::SelectionInfo)
|
||||
| int(CommonGizmosDataID::InstancesHider)
|
||||
| int(CommonGizmosDataID::Raycaster)
|
||||
| int(CommonGizmosDataID::ObjectClipper));
|
||||
| int(CommonGizmosDataID::ObjectClipper)
|
||||
| int(CommonGizmosDataID::SupportsClipper));
|
||||
}
|
||||
|
||||
void GLGizmoSlaBase::update_volumes()
|
||||
|
@ -50,27 +51,54 @@ void GLGizmoSlaBase::update_volumes()
|
|||
|
||||
TriangleMesh backend_mesh;
|
||||
std::shared_ptr<const indexed_triangle_set> preview_mesh_ptr = po->get_mesh_to_print();
|
||||
if (preview_mesh_ptr)
|
||||
backend_mesh = TriangleMesh{*preview_mesh_ptr};
|
||||
if (preview_mesh_ptr != nullptr)
|
||||
backend_mesh = TriangleMesh(*preview_mesh_ptr);
|
||||
|
||||
if (!backend_mesh.empty()) {
|
||||
// The backend has generated a valid mesh. Use it
|
||||
backend_mesh.transform(po->trafo().inverse());
|
||||
m_volumes.volumes.emplace_back(new GLVolume());
|
||||
GLVolume* new_volume = m_volumes.volumes.back();
|
||||
new_volume->model.init_from(backend_mesh);
|
||||
new_volume->set_instance_transformation(po->model_object()->instances[m_parent.get_selection().get_instance_idx()]->get_transformation());
|
||||
new_volume->set_sla_shift_z(po->get_current_elevation());
|
||||
new_volume->mesh_raycaster = std::make_unique<GUI::MeshRaycaster>(backend_mesh);
|
||||
auto last_comp_step = static_cast<int>(po->last_completed_step());
|
||||
if (last_comp_step == slaposCount)
|
||||
last_comp_step = -1;
|
||||
|
||||
m_input_enabled = last_comp_step >= m_min_sla_print_object_step;
|
||||
if (m_input_enabled)
|
||||
new_volume->selected = true; // to set the proper color
|
||||
else
|
||||
new_volume->set_color(DISABLED_COLOR);
|
||||
|
||||
const int object_idx = m_parent.get_selection().get_object_idx();
|
||||
const int instance_idx = m_parent.get_selection().get_instance_idx();
|
||||
const Geometry::Transformation& inst_trafo = po->model_object()->instances[instance_idx]->get_transformation();
|
||||
const double current_elevation = po->get_current_elevation();
|
||||
|
||||
auto add_volume = [this, object_idx, instance_idx, &inst_trafo, current_elevation](const TriangleMesh& mesh, int volume_id, bool add_mesh_raycaster = false) {
|
||||
GLVolume* volume = m_volumes.volumes.emplace_back(new GLVolume());
|
||||
volume->model.init_from(mesh);
|
||||
volume->set_instance_transformation(inst_trafo);
|
||||
volume->set_sla_shift_z(current_elevation);
|
||||
if (add_mesh_raycaster)
|
||||
volume->mesh_raycaster = std::make_unique<GUI::MeshRaycaster>(mesh);
|
||||
if (m_input_enabled)
|
||||
volume->selected = true; // to set the proper color
|
||||
else
|
||||
volume->set_color(DISABLED_COLOR);
|
||||
volume->composite_id = GLVolume::CompositeID(object_idx, volume_id, instance_idx);
|
||||
};
|
||||
|
||||
const Transform3d po_trafo_inverse = po->trafo().inverse();
|
||||
|
||||
// main mesh
|
||||
backend_mesh.transform(po_trafo_inverse);
|
||||
add_volume(backend_mesh, 0, true);
|
||||
|
||||
// supports mesh
|
||||
TriangleMesh supports_mesh = po->support_mesh();
|
||||
if (!supports_mesh.empty()) {
|
||||
supports_mesh.transform(po_trafo_inverse);
|
||||
add_volume(supports_mesh, -int(slaposSupportTree));
|
||||
}
|
||||
|
||||
// pad mesh
|
||||
TriangleMesh pad_mesh = po->pad_mesh();
|
||||
if (!pad_mesh.empty()) {
|
||||
pad_mesh.transform(po_trafo_inverse);
|
||||
add_volume(pad_mesh, -int(slaposPad));
|
||||
}
|
||||
}
|
||||
|
||||
if (m_volumes.volumes.empty()) {
|
||||
|
@ -110,16 +138,20 @@ void GLGizmoSlaBase::render_volumes()
|
|||
clipping_plane.set_normal(-clipping_plane.get_normal());
|
||||
m_volumes.set_clipping_plane(clipping_plane.get_data());
|
||||
|
||||
m_volumes.render(GLVolumeCollection::ERenderType::Opaque, false, camera.get_view_matrix(), camera.get_projection_matrix());
|
||||
shader->stop_using();
|
||||
for (GLVolume* v : m_volumes.volumes) {
|
||||
v->is_active = m_show_sla_supports || (!v->is_sla_pad() && !v->is_sla_support());
|
||||
}
|
||||
|
||||
m_volumes.render(GLVolumeCollection::ERenderType::Opaque, true, camera.get_view_matrix(), camera.get_projection_matrix());
|
||||
shader->stop_using();
|
||||
}
|
||||
|
||||
void GLGizmoSlaBase::register_volume_raycasters_for_picking()
|
||||
{
|
||||
for (size_t i = 0; i < m_volumes.volumes.size(); ++i) {
|
||||
const GLVolume* v = m_volumes.volumes[i];
|
||||
m_volume_raycasters.emplace_back(m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, VOLUME_RAYCASTERS_BASE_ID + (int)i, *v->mesh_raycaster, v->world_matrix()));
|
||||
if (!v->is_sla_pad() && !v->is_sla_support())
|
||||
m_volume_raycasters.emplace_back(m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, VOLUME_RAYCASTERS_BASE_ID + (int)i, *v->mesh_raycaster, v->world_matrix()));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -40,11 +40,15 @@ protected:
|
|||
|
||||
bool unproject_on_mesh(const Vec2d& mouse_pos, std::pair<Vec3f, Vec3f>& pos_and_normal);
|
||||
|
||||
bool are_sla_supports_shown() const { return m_show_sla_supports; }
|
||||
void show_sla_supports(bool show) { m_show_sla_supports = show; }
|
||||
|
||||
const GLVolumeCollection &volumes() const { return m_volumes; }
|
||||
|
||||
private:
|
||||
GLVolumeCollection m_volumes;
|
||||
bool m_input_enabled{ false };
|
||||
bool m_show_sla_supports{ false };
|
||||
int m_min_sla_print_object_step{ -1 };
|
||||
std::vector<std::shared_ptr<SceneRaycasterItem>> m_volume_raycasters;
|
||||
};
|
||||
|
|
|
@ -24,8 +24,10 @@ namespace Slic3r {
|
|||
namespace GUI {
|
||||
|
||||
GLGizmoSlaSupports::GLGizmoSlaSupports(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id)
|
||||
: GLGizmoSlaBase(parent, icon_filename, sprite_id, slaposDrillHoles)
|
||||
{}
|
||||
: GLGizmoSlaBase(parent, icon_filename, sprite_id, slaposDrillHoles)
|
||||
{
|
||||
show_sla_supports(true);
|
||||
}
|
||||
|
||||
bool GLGizmoSlaSupports::on_init()
|
||||
{
|
||||
|
@ -126,6 +128,7 @@ void GLGizmoSlaSupports::on_render()
|
|||
|
||||
m_selection_rectangle.render(m_parent);
|
||||
m_c->object_clipper()->render_cut();
|
||||
m_c->supports_clipper()->render_cut();
|
||||
|
||||
glsafe(::glDisable(GL_BLEND));
|
||||
}
|
||||
|
|
|
@ -453,83 +453,74 @@ void SupportsClipper::on_update()
|
|||
if (! mo || ! is_sla)
|
||||
return;
|
||||
|
||||
const GLCanvas3D* canvas = get_pool()->get_canvas();
|
||||
const PrintObjects& print_objects = canvas->sla_print()->objects();
|
||||
const SLAPrintObject* print_object = (m_print_object_idx >= 0 && m_print_object_idx < int(print_objects.size()))
|
||||
? print_objects[m_print_object_idx]
|
||||
: nullptr;
|
||||
const SLAPrintObject* po = get_pool()->selection_info()->print_object();
|
||||
if (po == nullptr)
|
||||
return;
|
||||
|
||||
// Find the respective SLAPrintObject.
|
||||
if (m_print_object_idx < 0 || m_print_objects_count != int(print_objects.size())) {
|
||||
m_print_objects_count = print_objects.size();
|
||||
m_print_object_idx = -1;
|
||||
for (const SLAPrintObject* po : print_objects) {
|
||||
++m_print_object_idx;
|
||||
if (po->model_object()->id() == mo->id()) {
|
||||
print_object = po;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (po->get_mesh_to_print() == nullptr) {
|
||||
// The object has been not sliced yet. We better dump the cached data.
|
||||
m_supports_clipper.reset();
|
||||
m_pad_clipper.reset();
|
||||
return;
|
||||
}
|
||||
|
||||
if (print_object
|
||||
&& print_object->is_step_done(slaposSupportTree)
|
||||
&& ! print_object->support_mesh().empty())
|
||||
{
|
||||
// If the supports are already calculated, save the timestamp of the respective step
|
||||
// so we can later tell they were recalculated.
|
||||
size_t timestamp = print_object->step_state_with_timestamp(slaposSupportTree).timestamp;
|
||||
if (! m_clipper || timestamp != m_old_timestamp) {
|
||||
// The timestamp has changed.
|
||||
m_clipper.reset(new MeshClipper);
|
||||
// The mesh should already have the shared vertices calculated.
|
||||
m_clipper->set_mesh(print_object->support_mesh().its);
|
||||
m_old_timestamp = timestamp;
|
||||
}
|
||||
const TriangleMesh& support_mesh = po->support_mesh();
|
||||
if (support_mesh.empty()) {
|
||||
// The supports are not available yet. We better dump the cached data.
|
||||
m_supports_clipper.reset();
|
||||
}
|
||||
else {
|
||||
m_supports_clipper.reset(new MeshClipper);
|
||||
m_supports_clipper->set_mesh(support_mesh.its);
|
||||
}
|
||||
|
||||
const TriangleMesh& pad_mesh = po->pad_mesh();
|
||||
if (pad_mesh.empty()) {
|
||||
// The supports are not available yet. We better dump the cached data.
|
||||
m_pad_clipper.reset();
|
||||
}
|
||||
else {
|
||||
m_pad_clipper.reset(new MeshClipper);
|
||||
m_pad_clipper->set_mesh(pad_mesh.its);
|
||||
}
|
||||
else
|
||||
// The supports are not valid. We better dump the cached data.
|
||||
m_clipper.reset();
|
||||
}
|
||||
|
||||
|
||||
void SupportsClipper::on_release()
|
||||
{
|
||||
m_clipper.reset();
|
||||
m_old_timestamp = 0;
|
||||
m_supports_clipper.reset();
|
||||
m_pad_clipper.reset();
|
||||
m_print_object_idx = -1;
|
||||
}
|
||||
|
||||
void SupportsClipper::render_cut() const
|
||||
{
|
||||
const CommonGizmosDataObjects::ObjectClipper* ocl = get_pool()->object_clipper();
|
||||
if (ocl->get_position() == 0.
|
||||
|| ! m_clipper)
|
||||
if (ocl->get_position() == 0.)
|
||||
return;
|
||||
|
||||
const SLAPrintObject* po = get_pool()->selection_info()->print_object();
|
||||
if (po == nullptr)
|
||||
return;
|
||||
|
||||
Geometry::Transformation po_trafo(po->trafo());
|
||||
|
||||
const SelectionInfo* sel_info = get_pool()->selection_info();
|
||||
const ModelObject* mo = sel_info->model_object();
|
||||
const Geometry::Transformation inst_trafo = mo->instances[sel_info->get_active_instance()]->get_transformation();
|
||||
//Geometry::Transformation vol_trafo = mo->volumes.front()->get_transformation();
|
||||
Geometry::Transformation trafo = inst_trafo;// * vol_trafo;
|
||||
trafo.set_offset(trafo.get_offset() + Vec3d(0., 0., sel_info->get_sla_shift()));
|
||||
Geometry::Transformation inst_trafo = sel_info->model_object()->instances[sel_info->get_active_instance()]->get_transformation();
|
||||
inst_trafo = Geometry::Transformation(inst_trafo.get_matrix() * po_trafo.get_matrix().inverse());
|
||||
inst_trafo.set_offset(inst_trafo.get_offset() + Vec3d(0.0, 0.0, sel_info->get_sla_shift()));
|
||||
|
||||
if (m_supports_clipper != nullptr) {
|
||||
m_supports_clipper->set_plane(*ocl->get_clipping_plane());
|
||||
m_supports_clipper->set_transformation(inst_trafo);
|
||||
m_supports_clipper->render_cut({ 1.0f, 0.f, 0.37f, 1.0f });
|
||||
}
|
||||
|
||||
// Get transformation of supports
|
||||
Geometry::Transformation supports_trafo = trafo;
|
||||
supports_trafo.set_scaling_factor(Vec3d::Ones());
|
||||
supports_trafo.set_offset(Vec3d(trafo.get_offset()(0), trafo.get_offset()(1), sel_info->get_sla_shift()));
|
||||
supports_trafo.set_rotation(Vec3d(0., 0., trafo.get_rotation()(2)));
|
||||
// I don't know why, but following seems to be correct.
|
||||
supports_trafo.set_mirror(Vec3d(trafo.get_mirror()(0) * trafo.get_mirror()(1) * trafo.get_mirror()(2),
|
||||
1,
|
||||
1.));
|
||||
|
||||
m_clipper->set_plane(*ocl->get_clipping_plane());
|
||||
m_clipper->set_transformation(supports_trafo);
|
||||
|
||||
m_clipper->render_cut({ 1.0f, 0.f, 0.37f, 1.0f });
|
||||
m_clipper->render_contour({ 1.f, 1.f, 1.f, 1.f });
|
||||
if (m_pad_clipper != nullptr) {
|
||||
m_pad_clipper->set_plane(*ocl->get_clipping_plane());
|
||||
m_pad_clipper->set_transformation(inst_trafo);
|
||||
m_pad_clipper->render_cut({ 0.6f, 0.f, 0.222f, 1.0f });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -293,10 +293,10 @@ protected:
|
|||
void on_release() override;
|
||||
|
||||
private:
|
||||
size_t m_old_timestamp = 0;
|
||||
int m_print_object_idx = -1;
|
||||
int m_print_objects_count = 0;
|
||||
std::unique_ptr<MeshClipper> m_clipper;
|
||||
std::unique_ptr<MeshClipper> m_supports_clipper;
|
||||
std::unique_ptr<MeshClipper> m_pad_clipper;
|
||||
};
|
||||
|
||||
} // namespace CommonGizmosDataObjects
|
||||
|
|
|
@ -2,6 +2,9 @@
|
|||
|
||||
#include "libslic3r/BuildVolume.hpp"
|
||||
#include "libslic3r/Model.hpp"
|
||||
#include "libslic3r/Print.hpp"
|
||||
#include "libslic3r/SLAPrint.hpp"
|
||||
#include "libslic3r/Geometry/ConvexHull.hpp"
|
||||
|
||||
#include "slic3r/GUI/Plater.hpp"
|
||||
#include "slic3r/GUI/GLCanvas3D.hpp"
|
||||
|
@ -11,6 +14,7 @@
|
|||
#include "slic3r/GUI/NotificationManager.hpp"
|
||||
#include "slic3r/GUI/format.hpp"
|
||||
|
||||
|
||||
#include "libnest2d/common.hpp"
|
||||
|
||||
#include <numeric>
|
||||
|
@ -93,28 +97,28 @@ void ArrangeJob::prepare_all() {
|
|||
|
||||
void ArrangeJob::prepare_selected() {
|
||||
clear_input();
|
||||
|
||||
|
||||
Model &model = m_plater->model();
|
||||
double stride = bed_stride(m_plater);
|
||||
|
||||
|
||||
std::vector<const Selection::InstanceIdxsList *>
|
||||
obj_sel(model.objects.size(), nullptr);
|
||||
|
||||
for (auto &s : m_plater->get_selection().get_content())
|
||||
if (s.first < int(obj_sel.size()))
|
||||
obj_sel[size_t(s.first)] = &s.second;
|
||||
|
||||
|
||||
// Go through the objects and check if inside the selection
|
||||
for (size_t oidx = 0; oidx < model.objects.size(); ++oidx) {
|
||||
const Selection::InstanceIdxsList * instlist = obj_sel[oidx];
|
||||
ModelObject *mo = model.objects[oidx];
|
||||
|
||||
|
||||
std::vector<bool> inst_sel(mo->instances.size(), false);
|
||||
|
||||
|
||||
if (instlist)
|
||||
for (auto inst_id : *instlist)
|
||||
inst_sel[size_t(inst_id)] = true;
|
||||
|
||||
|
||||
for (size_t i = 0; i < inst_sel.size(); ++i) {
|
||||
ModelInstance * mi = mo->instances[i];
|
||||
ArrangePolygon &&ap = get_arrange_poly_(mi);
|
||||
|
@ -123,11 +127,11 @@ void ArrangeJob::prepare_selected() {
|
|||
(inst_sel[i] ? m_selected :
|
||||
m_unselected) :
|
||||
m_unprintable;
|
||||
|
||||
|
||||
cont.emplace_back(std::move(ap));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (auto wti = get_wipe_tower(*m_plater)) {
|
||||
ArrangePolygon &&ap = get_arrange_poly(wti, m_plater);
|
||||
|
||||
|
@ -135,14 +139,120 @@ void ArrangeJob::prepare_selected() {
|
|||
m_unselected;
|
||||
cont.emplace_back(std::move(ap));
|
||||
}
|
||||
|
||||
|
||||
// If the selection was empty arrange everything
|
||||
if (m_selected.empty()) m_selected.swap(m_unselected);
|
||||
|
||||
if (m_selected.empty())
|
||||
m_selected.swap(m_unselected);
|
||||
|
||||
// The strides have to be removed from the fixed items. For the
|
||||
// arrangeable (selected) items bed_idx is ignored and the
|
||||
// translation is irrelevant.
|
||||
for (auto &p : m_unselected) p.translation(X) -= p.bed_idx * stride;
|
||||
for (auto &p : m_unselected)
|
||||
p.translation(X) -= p.bed_idx * stride;
|
||||
}
|
||||
|
||||
static void update_arrangepoly_slaprint(arrangement::ArrangePolygon &ret,
|
||||
const SLAPrintObject &po,
|
||||
const ModelInstance &inst)
|
||||
{
|
||||
// The 1.1 multiplier is a safety gap, as the offset might be bigger
|
||||
// in sharp edges of a polygon, depending on clipper's offset algorithm
|
||||
coord_t pad_infl = 0;
|
||||
{
|
||||
double infl = po.config().pad_enable.getBool() * (
|
||||
po.config().pad_brim_size.getFloat() +
|
||||
po.config().pad_around_object.getBool() *
|
||||
po.config().pad_object_gap.getFloat() );
|
||||
|
||||
pad_infl = scaled(1.1 * infl);
|
||||
}
|
||||
|
||||
auto laststep = po.last_completed_step();
|
||||
|
||||
if (laststep < slaposCount && laststep > slaposSupportTree) {
|
||||
auto omesh = po.get_mesh_to_print();
|
||||
auto &smesh = po.support_mesh();
|
||||
|
||||
Vec3d rotation = inst.get_rotation();
|
||||
rotation.z() = 0.;
|
||||
Transform3f trafo_instance =
|
||||
Geometry::assemble_transform(inst.get_offset().z() * Vec3d::UnitZ(),
|
||||
rotation,
|
||||
inst.get_scaling_factor(),
|
||||
inst.get_mirror()).cast<float>();
|
||||
|
||||
trafo_instance = trafo_instance * po.trafo().cast<float>().inverse();
|
||||
|
||||
auto polys = reserve_vector<Polygon>(3);
|
||||
auto zlvl = -po.get_elevation();
|
||||
|
||||
if (omesh) {
|
||||
polys.emplace_back(its_convex_hull_2d_above(*omesh, trafo_instance, zlvl));
|
||||
ret.poly.contour = polys.back();
|
||||
ret.poly.holes = {};
|
||||
}
|
||||
|
||||
polys.emplace_back(its_convex_hull_2d_above(smesh.its, trafo_instance, zlvl));
|
||||
ret.poly.contour = Geometry::convex_hull(polys);
|
||||
ret.poly.holes = {};
|
||||
}
|
||||
|
||||
ret.inflation = pad_infl;
|
||||
}
|
||||
|
||||
static coord_t brim_offset(const PrintObject &po, const ModelInstance &inst)
|
||||
{
|
||||
const BrimType brim_type = po.config().brim_type.value;
|
||||
const float brim_separation = po.config().brim_separation.getFloat();
|
||||
const float brim_width = po.config().brim_width.getFloat();
|
||||
const bool has_outer_brim = brim_type == BrimType::btOuterOnly ||
|
||||
brim_type == BrimType::btOuterAndInner;
|
||||
|
||||
// How wide is the brim? (in scaled units)
|
||||
return has_outer_brim ? scaled(brim_width + brim_separation) : 0;
|
||||
}
|
||||
|
||||
template<class It>
|
||||
Polygon support_layers_chull (Points &pts, It from_lyr, It to_lyr) {
|
||||
|
||||
size_t cap = 0;
|
||||
for (auto it = from_lyr; it != to_lyr; ++it) {
|
||||
for (const ExPolygon &expoly : (*it)->support_islands)
|
||||
cap += expoly.contour.points.size();
|
||||
}
|
||||
|
||||
pts.reserve(pts.size() + cap);
|
||||
|
||||
for (auto it = from_lyr; it != to_lyr; ++it) {
|
||||
for (const ExPolygon &expoly : (*it)->support_islands)
|
||||
std::copy(expoly.contour.begin(), expoly.contour.end(),
|
||||
std::back_inserter(pts));
|
||||
}
|
||||
|
||||
Polygon ret = Geometry::convex_hull(pts);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void update_arrangepoly_fffprint(arrangement::ArrangePolygon &ret,
|
||||
const PrintObject &po,
|
||||
const ModelInstance &inst)
|
||||
{
|
||||
auto laststep = po.last_completed_step();
|
||||
|
||||
coord_t infl = brim_offset(po, inst);
|
||||
|
||||
if (laststep < posCount && laststep > posSupportMaterial) {
|
||||
Points pts = std::move(ret.poly.contour.points);
|
||||
Polygon poly = support_layers_chull(pts,
|
||||
po.support_layers().begin(),
|
||||
po.support_layers().end());
|
||||
|
||||
ret.poly.contour = std::move(poly);
|
||||
ret.poly.holes = {};
|
||||
}
|
||||
|
||||
ret.inflation = infl;
|
||||
}
|
||||
|
||||
arrangement::ArrangePolygon ArrangeJob::get_arrange_poly_(ModelInstance *mi)
|
||||
|
@ -159,9 +269,38 @@ arrangement::ArrangePolygon ArrangeJob::get_arrange_poly_(ModelInstance *mi)
|
|||
return ap;
|
||||
}
|
||||
|
||||
coord_t get_skirt_offset(const Plater* plater) {
|
||||
float skirt_inset = 0.f;
|
||||
// Try to subtract the skirt from the bed shape so we don't arrange outside of it.
|
||||
if (plater->printer_technology() == ptFFF && plater->fff_print().has_skirt()) {
|
||||
const auto& print = plater->fff_print();
|
||||
skirt_inset = print.config().skirts.value * print.skirt_flow().width() +
|
||||
print.config().skirt_distance.value;
|
||||
}
|
||||
|
||||
return scaled(skirt_inset);
|
||||
}
|
||||
|
||||
void ArrangeJob::prepare()
|
||||
{
|
||||
wxGetKeyState(WXK_SHIFT) ? prepare_selected() : prepare_all();
|
||||
|
||||
coord_t min_offset = 0;
|
||||
for (auto &ap : m_selected) {
|
||||
min_offset = std::max(ap.inflation, min_offset);
|
||||
}
|
||||
|
||||
if (m_plater->printer_technology() == ptSLA) {
|
||||
// Apply the max offset for all the objects
|
||||
for (auto &ap : m_selected) {
|
||||
ap.inflation = min_offset;
|
||||
}
|
||||
} else { // it's fff, brims only need to be minded from bed edges
|
||||
for (auto &ap : m_selected) {
|
||||
ap.inflation = 0;
|
||||
}
|
||||
m_min_bed_inset = min_offset;
|
||||
}
|
||||
}
|
||||
|
||||
void ArrangeJob::process(Ctl &ctl)
|
||||
|
@ -174,6 +313,8 @@ void ArrangeJob::process(Ctl &ctl)
|
|||
prepare();
|
||||
params = get_arrange_params(m_plater);
|
||||
get_bed_shape(*m_plater->config(), bed);
|
||||
coord_t min_inset = get_skirt_offset(m_plater) + m_min_bed_inset;
|
||||
params.min_bed_distance = std::max(params.min_bed_distance, min_inset);
|
||||
}).wait();
|
||||
|
||||
auto count = unsigned(m_selected.size() + m_unprintable.size());
|
||||
|
@ -286,7 +427,26 @@ template<>
|
|||
arrangement::ArrangePolygon get_arrange_poly(ModelInstance *inst,
|
||||
const Plater * plater)
|
||||
{
|
||||
return get_arrange_poly(PtrWrapper{inst}, plater);
|
||||
auto ap = get_arrange_poly(PtrWrapper{inst}, plater);
|
||||
|
||||
auto obj_id = inst->get_object()->id();
|
||||
if (plater->printer_technology() == ptSLA) {
|
||||
const SLAPrintObject *po =
|
||||
plater->sla_print().get_print_object_by_model_object_id(obj_id);
|
||||
|
||||
if (po) {
|
||||
update_arrangepoly_slaprint(ap, *po, *inst);
|
||||
}
|
||||
} else {
|
||||
const PrintObject *po =
|
||||
plater->fff_print().get_print_object_by_model_object_id(obj_id);
|
||||
|
||||
if (po) {
|
||||
update_arrangepoly_fffprint(ap, *po, *inst);
|
||||
}
|
||||
}
|
||||
|
||||
return ap;
|
||||
}
|
||||
|
||||
arrangement::ArrangeParams get_arrange_params(Plater *p)
|
||||
|
|
|
@ -21,6 +21,8 @@ class ArrangeJob : public Job
|
|||
|
||||
ArrangePolygons m_selected, m_unselected, m_unprintable;
|
||||
std::vector<ModelInstance*> m_unarranged;
|
||||
coord_t m_min_bed_inset = 0.;
|
||||
|
||||
Plater *m_plater;
|
||||
|
||||
// clear m_selected and m_unselected, reserve space for next usage
|
||||
|
@ -102,6 +104,8 @@ arrangement::ArrangePolygon get_arrange_poly(ModelInstance *inst,
|
|||
|
||||
arrangement::ArrangeParams get_arrange_params(Plater *p);
|
||||
|
||||
coord_t get_skirt_offset(const Plater* plater);
|
||||
|
||||
}} // namespace Slic3r::GUI
|
||||
|
||||
#endif // ARRANGEJOB_HPP
|
||||
|
|
|
@ -483,10 +483,46 @@ TriangleMesh priv::create_default_mesh()
|
|||
return triangle_mesh;
|
||||
}
|
||||
|
||||
namespace{
|
||||
void update_volume_name(const ModelVolume &volume, const ObjectList *obj_list)
|
||||
{
|
||||
if (obj_list == nullptr)
|
||||
return;
|
||||
|
||||
const std::vector<ModelObject *>* objects = obj_list->objects();
|
||||
if (objects == nullptr)
|
||||
return;
|
||||
|
||||
int object_idx = -1;
|
||||
int volume_idx = -1;
|
||||
for (size_t oi = 0; oi < objects->size(); ++oi) {
|
||||
const ModelObject *mo = objects->at(oi);
|
||||
if (mo == nullptr)
|
||||
continue;
|
||||
if (volume.get_object()->id() != mo->id())
|
||||
continue;
|
||||
const ModelVolumePtrs& volumes = mo->volumes;
|
||||
for (size_t vi = 0; vi < volumes.size(); ++vi) {
|
||||
const ModelVolume *mv = volumes[vi];
|
||||
if (mv == nullptr)
|
||||
continue;
|
||||
if (mv->id() == volume.id()){
|
||||
object_idx = static_cast<int>(oi);
|
||||
volume_idx = static_cast<int>(vi);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (volume_idx > 0)
|
||||
break;
|
||||
}
|
||||
obj_list->update_name_in_list(object_idx, volume_idx);
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateJob::update_volume(ModelVolume *volume,
|
||||
TriangleMesh &&mesh,
|
||||
const TextConfiguration &text_configuration,
|
||||
const std::string &volume_name)
|
||||
std::string_view volume_name)
|
||||
{
|
||||
// check inputs
|
||||
bool is_valid_input =
|
||||
|
@ -506,19 +542,12 @@ void UpdateJob::update_volume(ModelVolume *volume,
|
|||
// discard information about rotation, should not be stored in volume
|
||||
volume->text_configuration->style.prop.angle.reset();
|
||||
|
||||
GUI_App &app = wxGetApp(); // may be move to input
|
||||
GLCanvas3D *canvas = app.plater()->canvas3D();
|
||||
const Selection &selection = canvas->get_selection();
|
||||
const GLVolume *gl_volume = selection.get_volume(*selection.get_volume_idxs().begin());
|
||||
int object_idx = gl_volume->object_idx();
|
||||
GUI_App &app = wxGetApp(); // may be move ObjectList and Plater to input?
|
||||
|
||||
// update volume name in right panel( volume / object name)
|
||||
if (volume->name != volume_name) {
|
||||
volume->name = volume_name;
|
||||
|
||||
// update volume name in right panel( volume / object name)
|
||||
int volume_idx = gl_volume->volume_idx();
|
||||
ObjectList *obj_list = app.obj_list();
|
||||
obj_list->update_name_in_list(object_idx, volume_idx);
|
||||
update_volume_name(*volume, app.obj_list());
|
||||
}
|
||||
|
||||
// When text is object.
|
||||
|
@ -528,11 +557,12 @@ void UpdateJob::update_volume(ModelVolume *volume,
|
|||
volume->get_object()->ensure_on_bed();
|
||||
|
||||
// redraw scene
|
||||
bool refresh_immediately = false;
|
||||
canvas->reload_scene(refresh_immediately);
|
||||
Plater *plater = app.plater();
|
||||
if (plater == nullptr)
|
||||
return;
|
||||
|
||||
// Change buttons "Export G-code" into "Slice now"
|
||||
canvas->post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS));
|
||||
// Update Model and redraw scene
|
||||
plater->update();
|
||||
}
|
||||
|
||||
void priv::update_volume(TriangleMesh &&mesh, const DataUpdate &data, Transform3d* tr)
|
||||
|
@ -646,8 +676,9 @@ void priv::create_volume(
|
|||
if (manager.get_current_type() != GLGizmosManager::Emboss)
|
||||
manager.open_gizmo(GLGizmosManager::Emboss);
|
||||
|
||||
// redraw scene
|
||||
canvas->reload_scene(true);
|
||||
// update model and redraw scene
|
||||
//canvas->reload_scene(true);
|
||||
plater->update();
|
||||
}
|
||||
|
||||
ModelVolume *priv::get_volume(ModelObjectPtrs &objects,
|
||||
|
|
|
@ -145,7 +145,7 @@ public:
|
|||
static void update_volume(ModelVolume *volume,
|
||||
TriangleMesh &&mesh,
|
||||
const TextConfiguration &text_configuration,
|
||||
const std::string &volume_name);
|
||||
std::string_view volume_name);
|
||||
};
|
||||
|
||||
struct SurfaceVolumeData
|
||||
|
|
|
@ -18,6 +18,7 @@ void FillBedJob::prepare()
|
|||
m_selected.clear();
|
||||
m_unselected.clear();
|
||||
m_bedpts.clear();
|
||||
m_min_bed_inset = 0.;
|
||||
|
||||
m_object_idx = m_plater->get_selected_object_idx();
|
||||
if (m_object_idx == -1)
|
||||
|
@ -29,7 +30,7 @@ void FillBedJob::prepare()
|
|||
m_selected.reserve(model_object->instances.size());
|
||||
for (ModelInstance *inst : model_object->instances)
|
||||
if (inst->printable) {
|
||||
ArrangePolygon ap = get_arrange_poly(PtrWrapper{inst}, m_plater);
|
||||
ArrangePolygon ap = get_arrange_poly(inst, m_plater);
|
||||
// Existing objects need to be included in the result. Only
|
||||
// the needed amount of object will be added, no more.
|
||||
++ap.priority;
|
||||
|
@ -101,6 +102,23 @@ void FillBedJob::prepare()
|
|||
for (auto &p : m_unselected)
|
||||
if (p.bed_idx > 0)
|
||||
p.translation(X) -= p.bed_idx * stride;
|
||||
|
||||
coord_t min_offset = 0;
|
||||
for (auto &ap : m_selected) {
|
||||
min_offset = std::max(ap.inflation, min_offset);
|
||||
}
|
||||
|
||||
if (m_plater->printer_technology() == ptSLA) {
|
||||
// Apply the max offset for all the objects
|
||||
for (auto &ap : m_selected) {
|
||||
ap.inflation = min_offset;
|
||||
}
|
||||
} else { // it's fff, brims only need to be minded from bed edges
|
||||
for (auto &ap : m_selected) {
|
||||
ap.inflation = 0;
|
||||
}
|
||||
m_min_bed_inset = min_offset;
|
||||
}
|
||||
}
|
||||
|
||||
void FillBedJob::process(Ctl &ctl)
|
||||
|
@ -110,6 +128,8 @@ void FillBedJob::process(Ctl &ctl)
|
|||
ctl.call_on_main_thread([this, ¶ms] {
|
||||
prepare();
|
||||
params = get_arrange_params(m_plater);
|
||||
coord_t min_inset = get_skirt_offset(m_plater) + m_min_bed_inset;
|
||||
params.min_bed_distance = std::max(params.min_bed_distance, min_inset);
|
||||
}).wait();
|
||||
ctl.update_status(0, statustxt);
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@ class FillBedJob : public Job
|
|||
|
||||
ArrangePolygons m_selected;
|
||||
ArrangePolygons m_unselected;
|
||||
coord_t m_min_bed_inset = 0.;
|
||||
|
||||
Points m_bedpts;
|
||||
|
||||
|
|
|
@ -1396,6 +1396,18 @@ void Selection::scale_to_fit_print_volume(const BuildVolume& volume)
|
|||
// used to keep track whether the undo/redo snapshot has already been taken
|
||||
bool undoredo_snapshot = false;
|
||||
|
||||
if (wxGetApp().plater()->printer_technology() == ptSLA) {
|
||||
// remove SLA auxiliary volumes from the selection to ensure that the proper bounding box is calculated
|
||||
std::vector<unsigned int> to_remove;
|
||||
for (unsigned int i : m_list) {
|
||||
if ((*m_volumes)[i]->volume_idx() < 0)
|
||||
to_remove.push_back(i);
|
||||
}
|
||||
|
||||
if (!to_remove.empty())
|
||||
remove_volumes(m_mode, to_remove);
|
||||
}
|
||||
|
||||
switch (volume.type())
|
||||
{
|
||||
case BuildVolume::Type::Rectangle: { undoredo_snapshot = fit_rectangle(volume, !undoredo_snapshot); break; }
|
||||
|
@ -3006,7 +3018,7 @@ static void verify_instances_rotation_synchronized(const Model &model, const GLV
|
|||
continue;
|
||||
const Transform3d::ConstLinearPart& rotation0 = volumes[idx_volume_first]->get_instance_transformation().get_matrix().linear();
|
||||
for (int i = idx_volume_first + 1; i < (int)volumes.size(); ++i)
|
||||
if (volumes[i]->object_idx() == idx_object) {
|
||||
if (volumes[i]->object_idx() == idx_object && volumes[i]->volume_idx() >= 0) {
|
||||
const Transform3d::ConstLinearPart& rotation = volumes[i]->get_instance_transformation().get_matrix().linear();
|
||||
assert(is_rotation_xy_synchronized(rotation, rotation0));
|
||||
}
|
||||
|
|
|
@ -9,50 +9,6 @@
|
|||
#include "libslic3r/Emboss.hpp"
|
||||
|
||||
namespace Slic3r::GUI {
|
||||
|
||||
/// <summary>
|
||||
/// Calculate offset from mouse position to center of text
|
||||
/// </summary>
|
||||
/// <param name="screen_coor">Position on screen[in Px] e.g. mouse position</param>
|
||||
/// <param name="volume">Selected volume(text)</param>
|
||||
/// <param name="camera">Actual position and view direction of camera</param>
|
||||
/// <returns>Offset in screen coordinate</returns>
|
||||
static Vec2d calc_screen_offset_to_volume_center(const Vec2d &screen_coor, const ModelVolume &volume, const Camera &camera)
|
||||
{
|
||||
const Transform3d &volume_tr = volume.get_matrix();
|
||||
assert(volume.text_configuration.has_value());
|
||||
|
||||
auto calc_offset = [&screen_coor, &volume_tr, &camera, &volume](const Transform3d &instrance_tr) -> Vec2d {
|
||||
Transform3d to_world = instrance_tr * volume_tr;
|
||||
|
||||
// Use fix of .3mf loaded tranformation when exist
|
||||
if (volume.text_configuration->fix_3mf_tr.has_value())
|
||||
to_world = to_world * (*volume.text_configuration->fix_3mf_tr);
|
||||
// zero point of volume in world coordinate system
|
||||
Vec3d volume_center = to_world.translation();
|
||||
// screen coordinate of volume center
|
||||
Vec2i coor = CameraUtils::project(camera, volume_center);
|
||||
return coor.cast<double>() - screen_coor;
|
||||
};
|
||||
|
||||
auto object = volume.get_object();
|
||||
assert(!object->instances.empty());
|
||||
// Speed up for one instance
|
||||
if (object->instances.size() == 1)
|
||||
return calc_offset(object->instances.front()->get_matrix());
|
||||
|
||||
Vec2d nearest_offset;
|
||||
double nearest_offset_size = std::numeric_limits<double>::max();
|
||||
for (const ModelInstance *instance : object->instances) {
|
||||
Vec2d offset = calc_offset(instance->get_matrix());
|
||||
double offset_size = offset.norm();
|
||||
if (nearest_offset_size < offset_size)
|
||||
continue;
|
||||
nearest_offset_size = offset_size;
|
||||
nearest_offset = offset;
|
||||
}
|
||||
return nearest_offset;
|
||||
}
|
||||
|
||||
// Calculate scale in world for check in debug
|
||||
[[maybe_unused]] static std::optional<double> calc_scale(const Matrix3d &from, const Matrix3d &to, const Vec3d &dir)
|
||||
|
@ -109,7 +65,8 @@ bool on_mouse_surface_drag(const wxMouseEvent &mouse_event,
|
|||
gl_volumes[hovered_idx_] != gl_volume)
|
||||
return false;
|
||||
|
||||
const ModelObject *object = get_model_object(*gl_volume, canvas.get_model()->objects);
|
||||
const ModelObjectPtrs &objects = canvas.get_model()->objects;
|
||||
const ModelObject *object = get_model_object(*gl_volume, objects);
|
||||
assert(object != nullptr);
|
||||
if (object == nullptr)
|
||||
return false;
|
||||
|
@ -148,7 +105,26 @@ bool on_mouse_surface_drag(const wxMouseEvent &mouse_event,
|
|||
// wxCoord == int --> wx/types.h
|
||||
Vec2i mouse_coord(mouse_event.GetX(), mouse_event.GetY());
|
||||
Vec2d mouse_pos = mouse_coord.cast<double>();
|
||||
Vec2d mouse_offset = calc_screen_offset_to_volume_center(mouse_pos, *volume, camera);
|
||||
|
||||
// world_matrix_fixed() without sla shift
|
||||
Transform3d to_world = world_matrix_fixed(*gl_volume, objects);
|
||||
|
||||
// zero point of volume in world coordinate system
|
||||
Vec3d volume_center = to_world.translation();
|
||||
// screen coordinate of volume center
|
||||
Vec2i coor = CameraUtils::project(camera, volume_center);
|
||||
Vec2d mouse_offset = coor.cast<double>() - mouse_pos;
|
||||
Vec2d mouse_offset_without_sla_shift = mouse_offset;
|
||||
if (double sla_shift = gl_volume->get_sla_shift_z(); !is_approx(sla_shift, 0.)) {
|
||||
Transform3d to_world_without_sla_move = instance->get_matrix() * volume->get_matrix();
|
||||
if (volume->text_configuration.has_value() && volume->text_configuration->fix_3mf_tr.has_value())
|
||||
to_world_without_sla_move = to_world_without_sla_move * (*volume->text_configuration->fix_3mf_tr);
|
||||
// zero point of volume in world coordinate system
|
||||
volume_center = to_world_without_sla_move.translation();
|
||||
// screen coordinate of volume center
|
||||
coor = CameraUtils::project(camera, volume_center);
|
||||
mouse_offset_without_sla_shift = coor.cast<double>() - mouse_pos;
|
||||
}
|
||||
|
||||
Transform3d volume_tr = gl_volume->get_volume_transformation().get_matrix();
|
||||
|
||||
|
@ -165,7 +141,7 @@ bool on_mouse_surface_drag(const wxMouseEvent &mouse_event,
|
|||
std::optional<float> start_angle;
|
||||
if (up_limit.has_value())
|
||||
start_angle = Emboss::calc_up(world_tr, *up_limit);
|
||||
surface_drag = SurfaceDrag{mouse_offset, world_tr, instance_tr_inv, gl_volume, condition, start_angle};
|
||||
surface_drag = SurfaceDrag{mouse_offset, world_tr, instance_tr_inv, gl_volume, condition, start_angle, true, mouse_offset_without_sla_shift};
|
||||
|
||||
// disable moving with object by mouse
|
||||
canvas.enable_moving(false);
|
||||
|
@ -181,7 +157,7 @@ bool on_mouse_surface_drag(const wxMouseEvent &mouse_event,
|
|||
// wxCoord == int --> wx/types.h
|
||||
Vec2i mouse_coord(mouse_event.GetX(), mouse_event.GetY());
|
||||
Vec2d mouse_pos = mouse_coord.cast<double>();
|
||||
Vec2d offseted_mouse = mouse_pos + surface_drag->mouse_offset;
|
||||
Vec2d offseted_mouse = mouse_pos + surface_drag->mouse_offset_without_sla_shift;
|
||||
|
||||
std::optional<RaycastManager::Hit> hit = ray_from_camera(
|
||||
raycast_manager, offseted_mouse, camera, &surface_drag->condition);
|
||||
|
|
|
@ -39,6 +39,9 @@ struct SurfaceDrag
|
|||
|
||||
// Flag whether coordinate hit some volume
|
||||
bool exist_hit = true;
|
||||
|
||||
// hold screen coor offset of cursor from object center without SLA shift
|
||||
Vec2d mouse_offset_without_sla_shift;
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -689,4 +689,58 @@ TEST_CASE("Arachne - #8846 - Degenerated Voronoi diagram - Voronoi edges interse
|
|||
|
||||
// Total extrusion length should be around 500mm when the part is ok and 680mm when it has perimeters in places where they shouldn't be.
|
||||
REQUIRE(total_extrusion_length <= scaled<int64_t>(500.));
|
||||
}
|
||||
|
||||
// This test case was distilled from GitHub issue #10034.
|
||||
// In this test case previous rotation by PI / 6 wasn't able to fix non-planar Voronoi diagram.
|
||||
TEST_CASE("Arachne - #10034 - Degenerated Voronoi diagram - That wasn't fixed by rotation by PI / 6", "[ArachneDegeneratedDiagram10034RotationNotWorks]") {
|
||||
Polygon poly_0 = {
|
||||
Point(43612632, -25179766), Point(58456010, 529710), Point(51074898, 17305660), Point(49390982, 21042355),
|
||||
Point(48102357, 23840161), Point(46769686, 26629546), Point(45835761, 28472742), Point(45205450, 29623133),
|
||||
Point(45107431, 29878059), Point(45069846, 30174950), Point(45069846, 50759533), Point(-45069846, 50759533),
|
||||
Point(-45069852, 29630557), Point(-45105780, 29339980), Point(-45179725, 29130704), Point(-46443313, 26398986),
|
||||
Point(-52272109, 13471493), Point(-58205450, 95724), Point(-29075091, -50359531), Point(29075086, -50359531),
|
||||
};
|
||||
|
||||
Polygon poly_1 = {
|
||||
Point(-37733905, 45070445), Point(-37813254, 45116257), Point(-39353851, 47784650), Point(-39353851, 47876274),
|
||||
Point(-38632470, 49125743), Point(-38553121, 49171555), Point(-33833475, 49171555), Point(-33754126, 49125743),
|
||||
Point(-33032747, 47876277), Point(-33032747, 47784653), Point(-34007855, 46095721), Point(-34573350, 45116257),
|
||||
Point(-34652699, 45070445),
|
||||
};
|
||||
|
||||
Polygon poly_2 = {
|
||||
Point(-44016799, 40706401), Point(-44116953, 40806555), Point(-44116953, 46126289), Point(-44016799, 46226443),
|
||||
Point(-42211438, 46226443), Point(-42132089, 46180631), Point(-40591492, 43512233), Point(-40591492, 43420609),
|
||||
Point(-41800123, 41327194), Point(-42132089, 40752213), Point(-42211438, 40706401),
|
||||
};
|
||||
|
||||
Polygon poly_3 = {
|
||||
Point(6218189, 10966609), Point(6138840, 11012421), Point(4598238, 13680817), Point(4598238, 13772441), Point(6138840, 16440843),
|
||||
Point(6218189, 16486655), Point(9299389, 16486655), Point(9378738, 16440843), Point(10919340, 13772441), Point(10919340, 13680817),
|
||||
Point(10149039, 12346618), Point(9378738, 11012421), Point(9299389, 10966609),
|
||||
};
|
||||
|
||||
Polygon poly_4 = {
|
||||
Point(13576879, 6718065), Point(13497530, 6763877), Point(11956926, 9432278), Point(11956926, 9523902),
|
||||
Point(13497528, 12192302), Point(13576877, 12238114), Point(16658079, 12238112), Point(16737428, 12192300),
|
||||
Point(18278031, 9523904), Point(18278031, 9432280), Point(17507729, 8098077), Point(16737428, 6763877),
|
||||
Point(16658079, 6718065),
|
||||
};
|
||||
|
||||
Polygons polygons = {
|
||||
poly_0, poly_1, poly_2, poly_3, poly_4,
|
||||
};
|
||||
|
||||
coord_t ext_perimeter_spacing = 407079;
|
||||
coord_t perimeter_spacing = 407079;
|
||||
coord_t inset_count = 1;
|
||||
|
||||
Arachne::WallToolPaths wall_tool_paths(polygons, ext_perimeter_spacing, perimeter_spacing, inset_count, 0, 0.2, PrintObjectConfig::defaults(), PrintConfig::defaults());
|
||||
wall_tool_paths.generate();
|
||||
std::vector<Arachne::VariableWidthLines> perimeters = wall_tool_paths.getToolPaths();
|
||||
|
||||
#ifdef ARACHNE_DEBUG_OUT
|
||||
export_perimeters_to_svg(debug_out_path("arachne-degenerated-diagram-10034-rotation-not-works.svg"), polygons, perimeters, union_ex(wall_tool_paths.getInnerContour()));
|
||||
#endif
|
||||
}
|
Loading…
Add table
Reference in a new issue