Merge branch 'master' of https://github.com/prusa3d/PrusaSlicer into et_gcode_viewer

This commit is contained in:
Enrico Turri 2020-03-03 08:34:51 +01:00
commit 9bc62287bd
108 changed files with 29542 additions and 21922 deletions

View file

@ -227,6 +227,9 @@ endif(WIN32)
add_definitions(-DwxUSE_UNICODE -D_UNICODE -DUNICODE -DWXINTL_NO_GETTEXT_MACRO)
# Disable unsafe implicit wxString to const char* / std::string and vice versa. This implicit conversion breaks the UTF-8 encoding quite often.
add_definitions(-DwxNO_UNSAFE_WXSTRING_CONV)
if (SLIC3R_PROFILE)
message("PrusaSlicer will be built with a Shiny invasive profiler")
add_definitions(-DSLIC3R_PROFILE)

View file

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 24.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.0" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 800 800" enable-background="new 0 0 800 800" xml:space="preserve">
<path fill="#ED6B21" d="M594.8,558.94v71.52H205.95v-71.52H594.8 M627.56,502.24H173.18c-13.21,0-23.93,10.71-23.93,23.93v137.06
c0,13.21,10.71,23.93,23.93,23.93h454.38c13.21,0,23.93-10.71,23.93-23.93V526.17C651.49,512.96,640.78,502.24,627.56,502.24
L627.56,502.24z"/>
<path fill="#ED6B21" d="M400.24,206.82l137.59,182.73H262.83L400.24,206.82 M400.23,128.4c-7.17,0-14.34,3.18-19.12,9.55
L178.06,407.94c-11.86,15.77-0.61,38.31,19.12,38.31h406.34c19.74,0,30.99-22.55,19.11-38.32l-203.3-269.99
C414.55,131.58,407.39,128.4,400.23,128.4L400.23,128.4z"/>
</svg>

After

Width:  |  Height:  |  Size: 899 B

View file

@ -1,168 +1,22 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
id="svg8"
version="1.1"
viewBox="0 0 3.7041666 3.7041667"
height="3.7041667mm"
width="3.7041667mm">
<defs
id="defs2">
<clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath3733">
<path
d="M 0,800 H 800 V 0 H 0 Z"
id="path3731" />
</clipPath>
<clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath4697">
<path
d="M 0,800 H 800 V 0 H 0 Z"
id="path4695" />
</clipPath>
<clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath4697-9">
<path
d="M 0,800 H 800 V 0 H 0 Z"
id="path4695-2" />
</clipPath>
</defs>
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
transform="translate(294.04601,-97.736694)"
id="layer1">
<g
transform="translate(-265.33929,12.851203)"
id="layer1-0">
<g
transform="matrix(1.31769,0,0,1.31769,-167.28747,-111.35623)"
id="layer1-3">
<g
id="g4685"
transform="matrix(0.00352778,0,0,-0.00352778,105.26858,151.76571)">
<path
d="M 381.663,302.607 H 558.791 V 65.846 H 381.663 Z"
style="fill:#d8d8db;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path4687" />
<path
d="m 470.227,302.607 h 95.411 V 65.846 h -95.411 z"
style="fill:#f7f7f8;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path4689" />
<g
id="g4691">
<g
id="g4693"
clip-path="url(#clipPath4697-9)">
<g
id="g4699"
transform="translate(380.7793,225.1963)">
<path
d="m 0,0 h 174.037 c 39.032,0 70.675,31.643 70.675,70.675 v 372.92 c 0,39.033 -31.643,70.675 -70.675,70.675 H 0 c -39.033,0 -70.675,-31.642 -70.675,-70.675 V 70.675 C -70.675,31.643 -39.033,0 0,0"
style="fill:#e96700;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path4701" />
</g>
<g
id="g4703"
transform="translate(377.0244,168.7666)">
<path
d="m 0,0 h -237.865 c -8.782,0 -15.902,7.12 -15.902,15.902 v 365.743 c 0,8.782 7.12,15.901 15.902,15.901 H 28.933 c 8.782,0 15.902,-7.119 15.902,-15.901 V 56.43 C 38.907,48.507 9.055,8.503 0,0"
style="fill:#666666;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path4705" />
</g>
<g
id="g4707"
transform="translate(421.8594,225.1963)">
<path
d="M 0,0 C -7.399,-10.049 -35.78,-47.927 -44.835,-56.43 H -282.7"
style="fill:#666666;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path4709" />
</g>
<g
id="g4711"
transform="translate(421.8594,225.1963)">
<path
d="M 0,0 C -5.876,-7.899 -35.78,-47.927 -44.835,-56.43"
style="fill:#666666;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path4713" />
</g>
<g
id="g4715"
transform="translate(333.957,198.1406)">
<path
d="m 0,0 h -22.969 c -2.196,0 -3.976,1.78 -3.976,3.976 v 81.276 c 0,2.195 1.78,3.976 3.976,3.976 H 0 c 2.196,0 3.976,-1.781 3.976,-3.976 V 3.976 C 3.976,1.78 2.196,0 0,0"
style="fill:#efee86;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path4717" />
</g>
<g
id="g4719"
transform="translate(297.957,198.1406)">
<path
d="m 0,0 h -22.969 c -2.196,0 -3.976,1.78 -3.976,3.976 v 81.276 c 0,2.195 1.78,3.976 3.976,3.976 H 0 c 2.196,0 3.976,-1.781 3.976,-3.976 V 3.976 C 3.976,1.78 2.196,0 0,0"
style="fill:#efee86;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path4721" />
</g>
<g
id="g4723"
transform="translate(261.957,198.1406)">
<path
d="m 0,0 h -22.969 c -2.196,0 -3.976,1.78 -3.976,3.976 v 81.276 c 0,2.195 1.78,3.976 3.976,3.976 H 0 c 2.196,0 3.976,-1.781 3.976,-3.976 V 3.976 C 3.976,1.78 2.196,0 0,0"
style="fill:#efee86;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path4725" />
</g>
<g
id="g4727"
transform="translate(225.957,198.1406)">
<path
d="m 0,0 h -22.969 c -2.196,0 -3.976,1.78 -3.976,3.976 v 81.276 c 0,2.195 1.78,3.976 3.976,3.976 H 0 c 2.196,0 3.976,-1.781 3.976,-3.976 V 3.976 C 3.976,1.78 2.196,0 0,0"
style="fill:#efee86;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path4729" />
</g>
<g
id="g4731"
transform="translate(189.957,198.1406)">
<path
d="m 0,0 h -22.969 c -2.196,0 -3.976,1.78 -3.976,3.976 v 81.276 c 0,2.195 1.78,3.976 3.976,3.976 H 0 c 2.196,0 3.976,-1.781 3.976,-3.976 V 3.976 C 3.976,1.78 2.196,0 0,0"
style="fill:#efee86;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path4733" />
</g>
<g
id="g4735"
transform="translate(369.2207,225.1963)">
<path
d="m 0,0 h -22.969 c -2.196,0 -3.976,1.78 -3.976,3.976 v 54.22 c 0,2.196 1.78,3.976 3.976,3.976 H 0 c 2.196,0 3.976,-1.78 3.976,-3.976 V 3.976 C 3.976,1.78 2.196,0 0,0"
style="fill:#efee86;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path4737" />
</g>
<path
d="m 450.019,104.056 h -50.577 v 33.128 h 50.577 z"
style="fill:#666666;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path4739" />
<path
d="m 543.221,104.056 h -50.576 v 33.128 h 50.576 z"
style="fill:#666666;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path4741" />
</g>
</g>
</g>
</g>
</g>
</g>
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 24.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.0" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 800 800" enable-background="new 0 0 800 800" xml:space="preserve">
<g>
<path fill="#808080" d="M580.82,576.8H462.03v0c0,3.06-0.99,6.04-2.82,8.49l-0.49,0.65c-36.26,48.48-43.59,55.36-45.99,57.62
c-1.47,1.38-3.2,2.4-5.06,3.04v89.54h88.56h88.56h6.85V575.98C588.11,576.52,584.5,576.8,580.82,576.8z M476.02,697.94h-50.58
v-33.13h50.58V697.94z M569.22,697.94h-50.58v-33.13h50.58V697.94z"/>
<path fill="#808080" d="M431.96,235.69h-266.8c-8.78,0-15.9,7.12-15.9,15.9v365.74c0,8.78,7.12,15.9,15.9,15.9h237.87
c9.06-8.5,38.91-48.51,44.83-56.43V251.59C447.86,242.81,440.74,235.69,431.96,235.69z M219.93,599.88c0,2.2-1.78,3.98-3.98,3.98
h-22.97c-2.2,0-3.98-1.78-3.98-3.98v-81.28c0-2.2,1.78-3.98,3.98-3.98h22.97c2.2,0,3.98,1.78,3.98,3.98V599.88z M255.93,599.88
c0,2.2-1.78,3.98-3.98,3.98h-22.97c-2.2,0-3.98-1.78-3.98-3.98v-81.28c0-2.2,1.78-3.98,3.98-3.98h22.97c2.2,0,3.98,1.78,3.98,3.98
V599.88z M291.93,599.88c0,2.2-1.78,3.98-3.98,3.98h-22.97c-2.2,0-3.98-1.78-3.98-3.98v-81.28c0-2.2,1.78-3.98,3.98-3.98h22.97
c2.2,0,3.98,1.78,3.98,3.98V599.88z M327.93,599.88c0,2.2-1.78,3.98-3.98,3.98h-22.97c-2.2,0-3.98-1.78-3.98-3.98v-81.28
c0-2.2,1.78-3.98,3.98-3.98h22.97c2.2,0,3.98,1.78,3.98,3.98V599.88z M363.93,599.88c0,2.2-1.78,3.98-3.98,3.98h-22.97
c-2.2,0-3.98-1.78-3.98-3.98v-81.28c0-2.2,1.78-3.98,3.98-3.98h22.97c2.2,0,3.98,1.78,3.98,3.98V599.88z M399.2,572.83
c0,2.2-1.78,3.98-3.98,3.98h-22.97c-2.2,0-3.98-1.78-3.98-3.98v-54.22c0-2.2,1.78-3.98,3.98-3.98h22.97c2.2,0,3.98,1.78,3.98,3.98
V572.83z"/>
<path fill="#ED6B21" d="M580.82,62.53H406.78c-39.03,0-70.67,31.64-70.67,70.67v88.31h95.85c16.58,0,30.08,13.49,30.08,30.08V576.8
h118.78c39.03,0,70.67-31.64,70.67-70.67V133.21C651.49,94.18,619.85,62.53,580.82,62.53z"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 6.8 KiB

After

Width:  |  Height:  |  Size: 2 KiB

View file

@ -1,25 +1,51 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 23.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!-- Generator: Adobe Illustrator 24.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.0" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 16 16" enable-background="new 0 0 16 16" xml:space="preserve">
<g id="support">
<polygon fill="none" stroke="#808080" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" points="8,1
2.31,4.79 2.31,8.57 2.31,8.79 2.31,10.47 8,14.25 13.69,10.47 13.69,8.79 13.69,8.57 13.69,4.79 "/>
<line fill="none" stroke="#ED6B21" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" x1="12.69" y1="15" x2="12.69" y2="12.44"/>
<line fill="none" stroke="#ED6B21" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" x1="13.87" y1="15" x2="13.87" y2="11.64"/>
<line fill="none" stroke="#ED6B21" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" x1="2.13" y1="15" x2="2.13" y2="11.64"/>
<line fill="none" stroke="#ED6B21" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" x1="3.33" y1="15" x2="3.33" y2="12.44"/>
<line fill="none" stroke="#ED6B21" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" x1="4.51" y1="15" x2="4.51" y2="13.22"/>
<line fill="none" stroke="#ED6B21" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" x1="5.66" y1="15" x2="5.66" y2="14"/>
<line fill="none" stroke="#ED6B21" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" x1="10.34" y1="15" x2="10.34" y2="14"/>
<line fill="none" stroke="#ED6B21" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" x1="11.5" y1="15" x2="11.5" y2="13.22"/>
<g id="hollowing">
<g>
<g>
<path fill="#808080" d="M9.73,13.27c-0.06-0.09-0.19-0.11-0.28-0.05l-1.28,0.85c-0.09,0.06-0.24,0.06-0.33,0l-1.28-0.85
c-0.09-0.06-0.22-0.04-0.28,0.05L6.1,13.52c-0.06,0.09-0.04,0.21,0.05,0.27l1.68,1.12c0.09,0.06,0.24,0.06,0.33,0l1.68-1.12
c0.09-0.06,0.11-0.18,0.05-0.27L9.73,13.27z"/>
</g>
<g>
<path fill="#808080" d="M8.17,1.14c-0.09-0.06-0.24-0.06-0.33,0L2.17,4.92C2.07,4.98,2,5.12,2,5.23v1.6c0,0.11,0,0.29,0,0.4v3.6
c0,0.11,0.07,0.25,0.17,0.31l2.82,1.88c0.09,0.06,0.22,0.04,0.28-0.05l0.18-0.25c0.06-0.09,0.04-0.21-0.05-0.27l-2.52-1.68
c-0.09-0.06-0.17-0.2-0.17-0.31V7.23c0-0.11,0-0.29,0-0.4V5.61c0-0.11,0.07-0.25,0.17-0.31l4.96-3.31c0.09-0.06,0.24-0.06,0.33,0
l4.96,3.31c0.09,0.06,0.17,0.2,0.17,0.31v1.22c0,0.11,0,0.29,0,0.4v3.22c0,0.11-0.07,0.25-0.17,0.31l-2.52,1.68
c-0.09,0.06-0.11,0.18-0.05,0.27l0.18,0.25c0.06,0.09,0.19,0.11,0.28,0.05l2.82-1.88c0.09-0.06,0.17-0.2,0.17-0.31v-3.6
c0-0.11,0-0.29,0-0.4v-1.6c0-0.11-0.07-0.25-0.17-0.31L8.17,1.14z"/>
</g>
</g>
<g>
<g>
<path fill="#ED6B21" d="M8.83,3.91c-0.07,0-0.14-0.02-0.2-0.06L8,3.43L7.37,3.85c-0.17,0.11-0.39,0.06-0.5-0.1
c-0.11-0.17-0.06-0.39,0.1-0.5L7.8,2.7c0.12-0.08,0.28-0.08,0.4,0l0.83,0.55c0.17,0.11,0.21,0.33,0.1,0.5
C9.06,3.85,8.95,3.91,8.83,3.91z"/>
</g>
<g>
<path fill="#ED6B21" d="M3.69,7.23c-0.2,0-0.36-0.16-0.36-0.36v-1c0-0.12,0.06-0.23,0.16-0.3l0.83-0.55
c0.17-0.11,0.39-0.06,0.5,0.1s0.06,0.39-0.1,0.5L4.05,6.06v0.81C4.05,7.07,3.89,7.23,3.69,7.23z"/>
</g>
<g>
<path fill="#ED6B21" d="M4.52,11.09c-0.07,0-0.14-0.02-0.2-0.06l-0.83-0.55c-0.1-0.07-0.16-0.18-0.16-0.3V9.19
c0-0.2,0.16-0.36,0.36-0.36s0.36,0.16,0.36,0.36v0.8l0.67,0.44c0.17,0.11,0.21,0.33,0.1,0.5C4.75,11.03,4.64,11.09,4.52,11.09z"
/>
</g>
<g>
<path fill="#ED6B21" d="M8,13.42c-0.07,0-0.14-0.02-0.2-0.06l-0.83-0.55c-0.17-0.11-0.21-0.33-0.1-0.5s0.33-0.21,0.5-0.1L8,12.63
l0.63-0.42c0.17-0.11,0.39-0.06,0.5,0.1s0.06,0.39-0.1,0.5L8.2,13.36C8.14,13.4,8.07,13.42,8,13.42z"/>
</g>
<g>
<path fill="#ED6B21" d="M11.48,11.09c-0.12,0-0.23-0.06-0.3-0.16c-0.11-0.17-0.07-0.39,0.1-0.5l0.67-0.44v-0.8
c0-0.2,0.16-0.36,0.36-0.36s0.36,0.16,0.36,0.36v0.99c0,0.12-0.06,0.23-0.16,0.3l-0.83,0.55C11.62,11.07,11.55,11.09,11.48,11.09
z"/>
</g>
<g>
<path fill="#ED6B21" d="M12.31,7.23c-0.2,0-0.36-0.16-0.36-0.36V6.06l-0.67-0.44c-0.17-0.11-0.21-0.33-0.1-0.5
c0.11-0.17,0.33-0.21,0.5-0.1l0.83,0.55c0.1,0.07,0.16,0.18,0.16,0.3v1C12.67,7.07,12.51,7.23,12.31,7.23z"/>
</g>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

View file

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 24.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.0" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 800 800" enable-background="new 0 0 800 800" xml:space="preserve">
<g>
<path fill="#FFFFFF" d="M580.82,576.8H462.03v0c0,3.06-0.99,6.04-2.82,8.49l-0.49,0.65c-36.26,48.48-43.59,55.36-45.99,57.62
c-1.47,1.38-3.2,2.4-5.06,3.04v89.54h88.56h88.56h6.85V575.98C588.11,576.52,584.5,576.8,580.82,576.8z M476.02,697.94h-50.58
v-33.13h50.58V697.94z M569.22,697.94h-50.58v-33.13h50.58V697.94z"/>
<path fill="#FFFFFF" d="M431.96,235.69h-266.8c-8.78,0-15.9,7.12-15.9,15.9v365.74c0,8.78,7.12,15.9,15.9,15.9h237.87
c9.06-8.5,38.91-48.51,44.83-56.43V251.59C447.86,242.81,440.74,235.69,431.96,235.69z M219.93,599.88c0,2.2-1.78,3.98-3.98,3.98
h-22.97c-2.2,0-3.98-1.78-3.98-3.98v-81.28c0-2.2,1.78-3.98,3.98-3.98h22.97c2.2,0,3.98,1.78,3.98,3.98V599.88z M255.93,599.88
c0,2.2-1.78,3.98-3.98,3.98h-22.97c-2.2,0-3.98-1.78-3.98-3.98v-81.28c0-2.2,1.78-3.98,3.98-3.98h22.97c2.2,0,3.98,1.78,3.98,3.98
V599.88z M291.93,599.88c0,2.2-1.78,3.98-3.98,3.98h-22.97c-2.2,0-3.98-1.78-3.98-3.98v-81.28c0-2.2,1.78-3.98,3.98-3.98h22.97
c2.2,0,3.98,1.78,3.98,3.98V599.88z M327.93,599.88c0,2.2-1.78,3.98-3.98,3.98h-22.97c-2.2,0-3.98-1.78-3.98-3.98v-81.28
c0-2.2,1.78-3.98,3.98-3.98h22.97c2.2,0,3.98,1.78,3.98,3.98V599.88z M363.93,599.88c0,2.2-1.78,3.98-3.98,3.98h-22.97
c-2.2,0-3.98-1.78-3.98-3.98v-81.28c0-2.2,1.78-3.98,3.98-3.98h22.97c2.2,0,3.98,1.78,3.98,3.98V599.88z M399.2,572.83
c0,2.2-1.78,3.98-3.98,3.98h-22.97c-2.2,0-3.98-1.78-3.98-3.98v-54.22c0-2.2,1.78-3.98,3.98-3.98h22.97c2.2,0,3.98,1.78,3.98,3.98
V572.83z"/>
<path fill="#ED6B21" d="M580.82,62.53H406.78c-39.03,0-70.67,31.64-70.67,70.67v88.31h95.85c16.58,0,30.08,13.49,30.08,30.08V576.8
h118.78c39.03,0,70.67-31.64,70.67-70.67V133.21C651.49,94.18,619.85,62.53,580.82,62.53z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2 KiB

View file

@ -1,25 +1,51 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 23.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!-- Generator: Adobe Illustrator 24.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.0" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 16 16" enable-background="new 0 0 16 16" xml:space="preserve">
<g id="support">
<polygon fill="none" stroke="#808080" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" points="8,1
2.31,4.79 2.31,8.57 2.31,8.79 2.31,10.47 8,14.25 13.69,10.47 13.69,8.79 13.69,8.57 13.69,4.79 "/>
<line fill="none" stroke="#ED6B21" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" x1="12.69" y1="15" x2="12.69" y2="12.44"/>
<line fill="none" stroke="#ED6B21" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" x1="13.87" y1="15" x2="13.87" y2="11.64"/>
<line fill="none" stroke="#ED6B21" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" x1="2.13" y1="15" x2="2.13" y2="11.64"/>
<line fill="none" stroke="#ED6B21" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" x1="3.33" y1="15" x2="3.33" y2="12.44"/>
<line fill="none" stroke="#ED6B21" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" x1="4.51" y1="15" x2="4.51" y2="13.22"/>
<line fill="none" stroke="#ED6B21" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" x1="5.66" y1="15" x2="5.66" y2="14"/>
<line fill="none" stroke="#ED6B21" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" x1="10.34" y1="15" x2="10.34" y2="14"/>
<line fill="none" stroke="#ED6B21" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" x1="11.5" y1="15" x2="11.5" y2="13.22"/>
<g id="hollowing">
<g>
<g>
<path fill="#FFFFFF" d="M9.73,13.27c-0.06-0.09-0.19-0.11-0.28-0.05l-1.28,0.85c-0.09,0.06-0.24,0.06-0.33,0l-1.28-0.85
c-0.09-0.06-0.22-0.04-0.28,0.05L6.1,13.52c-0.06,0.09-0.04,0.21,0.05,0.27l1.68,1.12c0.09,0.06,0.24,0.06,0.33,0l1.68-1.12
c0.09-0.06,0.11-0.18,0.05-0.27L9.73,13.27z"/>
</g>
<g>
<path fill="#FFFFFF" d="M8.17,1.14c-0.09-0.06-0.24-0.06-0.33,0L2.17,4.92C2.07,4.98,2,5.12,2,5.23v1.6c0,0.11,0,0.29,0,0.4v3.6
c0,0.11,0.07,0.25,0.17,0.31l2.82,1.88c0.09,0.06,0.22,0.04,0.28-0.05l0.18-0.25c0.06-0.09,0.04-0.21-0.05-0.27l-2.52-1.68
c-0.09-0.06-0.17-0.2-0.17-0.31V7.23c0-0.11,0-0.29,0-0.4V5.61c0-0.11,0.07-0.25,0.17-0.31l4.96-3.31c0.09-0.06,0.24-0.06,0.33,0
l4.96,3.31c0.09,0.06,0.17,0.2,0.17,0.31v1.22c0,0.11,0,0.29,0,0.4v3.22c0,0.11-0.07,0.25-0.17,0.31l-2.52,1.68
c-0.09,0.06-0.11,0.18-0.05,0.27l0.18,0.25c0.06,0.09,0.19,0.11,0.28,0.05l2.82-1.88c0.09-0.06,0.17-0.2,0.17-0.31v-3.6
c0-0.11,0-0.29,0-0.4v-1.6c0-0.11-0.07-0.25-0.17-0.31L8.17,1.14z"/>
</g>
</g>
<g>
<g>
<path fill="#ED6B21" d="M8.83,3.91c-0.07,0-0.14-0.02-0.2-0.06L8,3.43L7.37,3.85c-0.17,0.11-0.39,0.06-0.5-0.1
c-0.11-0.17-0.06-0.39,0.1-0.5L7.8,2.7c0.12-0.08,0.28-0.08,0.4,0l0.83,0.55c0.17,0.11,0.21,0.33,0.1,0.5
C9.06,3.85,8.95,3.91,8.83,3.91z"/>
</g>
<g>
<path fill="#ED6B21" d="M3.69,7.23c-0.2,0-0.36-0.16-0.36-0.36v-1c0-0.12,0.06-0.23,0.16-0.3l0.83-0.55
c0.17-0.11,0.39-0.06,0.5,0.1s0.06,0.39-0.1,0.5L4.05,6.06v0.81C4.05,7.07,3.89,7.23,3.69,7.23z"/>
</g>
<g>
<path fill="#ED6B21" d="M4.52,11.09c-0.07,0-0.14-0.02-0.2-0.06l-0.83-0.55c-0.1-0.07-0.16-0.18-0.16-0.3V9.19
c0-0.2,0.16-0.36,0.36-0.36s0.36,0.16,0.36,0.36v0.8l0.67,0.44c0.17,0.11,0.21,0.33,0.1,0.5C4.75,11.03,4.64,11.09,4.52,11.09z"
/>
</g>
<g>
<path fill="#ED6B21" d="M8,13.42c-0.07,0-0.14-0.02-0.2-0.06l-0.83-0.55c-0.17-0.11-0.21-0.33-0.1-0.5s0.33-0.21,0.5-0.1L8,12.63
l0.63-0.42c0.17-0.11,0.39-0.06,0.5,0.1s0.06,0.39-0.1,0.5L8.2,13.36C8.14,13.4,8.07,13.42,8,13.42z"/>
</g>
<g>
<path fill="#ED6B21" d="M11.48,11.09c-0.12,0-0.23-0.06-0.3-0.16c-0.11-0.17-0.07-0.39,0.1-0.5l0.67-0.44v-0.8
c0-0.2,0.16-0.36,0.36-0.36s0.36,0.16,0.36,0.36v0.99c0,0.12-0.06,0.23-0.16,0.3l-0.83,0.55C11.62,11.07,11.55,11.09,11.48,11.09
z"/>
</g>
<g>
<path fill="#ED6B21" d="M12.31,7.23c-0.2,0-0.36-0.16-0.36-0.36V6.06l-0.67-0.44c-0.17-0.11-0.21-0.33-0.1-0.5
c0.11-0.17,0.33-0.21,0.5-0.1l0.83,0.55c0.1,0.07,0.16,0.18,0.16,0.3v1C12.67,7.07,12.51,7.23,12.31,7.23z"/>
</g>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,4 +1,6 @@
min_slic3r_version = 2.2.0-alpha3
0.0.2 Updated for PrusaSlicer 2.2.0-rc
0.0.2-beta Update for PrusaSlicer 2.2.0-beta
0.0.2-alpha1 Extended list of default filaments to be installed
0.0.2-alpha0 Print bed textures are now configurable from the Preset Bundle. Requires PrusaSlicer 2.2.0-alpha3 and newer.
# The following line (max_slic3r_version) forces the users of PrusaSlicer 2.2.0-alpha3 and newer to update the profiles to 1.1.1-alpha3 and newer,

View file

@ -5,7 +5,7 @@
name = Creality
# Configuration version of this file. Config file will only be installed, if the config_version differs.
# This means, the server may force the PrusaSlicer configuration to be downgraded.
config_version = 0.0.2-alpha1
config_version = 0.0.2
# Where to get the updates from?
config_update_url = http://files.prusa3d.com/wp-content/uploads/repository/PrusaSlicer-settings-master/live/Creality/
# changelog_url = http://files.prusa3d.com/?latest=slicer-profiles&lng=%1%

View file

@ -1,4 +1,6 @@
min_slic3r_version = 2.2.0-alpha3
1.1.1 Added Verbatim and Fiberlogy PETG filament profiles. Updated auto cooling settings for ABS.
1.1.1-beta Updated for PrusaSlicer 2.2.0-beta
1.1.1-alpha4 Extended list of default filaments to be installed, top/bottom_solid_min_thickness defined, infill_acceleration changed etc
1.1.1-alpha3 Print bed textures are now configurable from the Preset Bundle. Requires PrusaSlicer 2.2.0-alpha3 and newer.
# The following line (max_slic3r_version) forces the users of PrusaSlicer 2.2.0-alpha3 and newer to update the profiles to 1.1.1-alpha3 and newer,
@ -8,6 +10,8 @@ min_slic3r_version = 2.2.0-alpha0
1.1.1-alpha2 Bumped up config version, so our in house customer will get updated profiles.
1.1.0 Filament aliases, Creality profiles and other goodies for PrusaSlicer 2.2.0-alpha0
min_slic3r_version = 2.1.1-beta0
1.0.8 Various changes in FFF profiles, new filaments/materials added. See changelog.
1.0.7 Updated layer height limits for MINI
1.0.6 Added Prusa MINI profiles
min_slic3r_version = 2.1.0-alpha0
1.0.5 Added SLA materials
@ -118,4 +122,4 @@ min_slic3r_version = 1.40.0-alpha
0.1.3 Fixed an incorrect position of the max_print_height parameter
0.1.2 Wipe tower changes
0.1.1 Minor print speed adjustments
0.1.0 Initial
0.1.0 Initial

View file

@ -5,7 +5,7 @@
name = Prusa Research
# Configuration version of this file. Config file will only be installed, if the config_version differs.
# This means, the server may force the PrusaSlicer configuration to be downgraded.
config_version = 1.1.1-alpha4
config_version = 1.1.1
# Where to get the updates from?
config_update_url = http://files.prusa3d.com/wp-content/uploads/repository/PrusaSlicer-settings-master/live/PrusaResearch/
changelog_url = http://files.prusa3d.com/?latest=slicer-profiles&lng=%1%
@ -1538,12 +1538,12 @@ start_filament_gcode = "M900 K0 ; Filament gcode"
[filament:*ABS*]
inherits = *common*
bed_temperature = 110
bridge_fan_speed = 30
bridge_fan_speed = 25
cooling = 0
disable_fan_first_layers = 3
fan_always_on = 0
fan_below_layer_time = 20
filament_colour = #3A80CA
filament_colour = #FFF2EC
filament_max_volumetric_speed = 11
filament_ramming_parameters = "120 100 5.70968 6.03226 7 8.25806 9 9.19355 9.3871 9.77419 10.129 10.3226 10.4516 10.5161| 0.05 5.69677 0.45 6.15484 0.95 8.76774 1.45 9.20323 1.95 9.95806 2.45 10.3871 2.95 10.5677 3.45 7.6 3.95 7.6 4.45 7.6 4.95 7.6"
filament_type = ABS
@ -1555,6 +1555,28 @@ temperature = 255
start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{elsif nozzle_diameter[0]==0.6}18{else}30{endif} ; Filament gcode"
compatible_printers_condition = printer_model!="MINI" and ! (printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK(2.5|3).*/ and single_extruder_multi_material)
[filament:*ABSC*]
inherits = *common*
bed_temperature = 110
bridge_fan_speed = 25
cooling = 1
disable_fan_first_layers = 4
fan_always_on = 0
fan_below_layer_time = 20
slowdown_below_layer_time = 20
filament_colour = #FFF2EC
filament_max_volumetric_speed = 11
filament_ramming_parameters = "120 100 5.70968 6.03226 7 8.25806 9 9.19355 9.3871 9.77419 10.129 10.3226 10.4516 10.5161| 0.05 5.69677 0.45 6.15484 0.95 8.76774 1.45 9.20323 1.95 9.95806 2.45 10.3871 2.95 10.5677 3.45 7.6 3.95 7.6 4.45 7.6 4.95 7.6"
filament_type = ABS
first_layer_bed_temperature = 100
first_layer_temperature = 255
max_fan_speed = 15
min_fan_speed = 15
min_print_speed = 15
temperature = 255
start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{elsif nozzle_diameter[0]==0.6}18{else}30{endif} ; Filament gcode"
compatible_printers_condition = printer_model!="MINI" and ! (printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK(2.5|3).*/ and single_extruder_multi_material)
[filament:*FLEX*]
inherits = *common*
bed_temperature = 50
@ -1744,7 +1766,7 @@ filament_cost = 25.4
filament_density = 1.24
[filament:Fillamentum ABS]
inherits = *ABS*
inherits = *ABSC*
filament_vendor = Fillamentum
filament_cost = 32.4
filament_density = 1.04
@ -1827,25 +1849,25 @@ temperature = 220
filament_retract_lift = 0.2
[filament:Generic ABS]
inherits = *ABS*
inherits = *ABSC*
filament_vendor = Generic
filament_cost = 27.82
filament_density = 1.04
[filament:Esun ABS]
inherits = *ABS*
inherits = *ABSC*
filament_vendor = Esun
filament_cost = 27.82
filament_density = 1.04
[filament:Hatchbox ABS]
inherits = *ABS*
inherits = *ABSC*
filament_vendor = Hatchbox
filament_cost = 27.82
filament_density = 1.04
[filament:Plasty Mladec ABS]
inherits = *ABS*
inherits = *ABSC*
filament_vendor = Plasty Mladec
filament_cost = 27.82
filament_density = 1.04
@ -1867,7 +1889,6 @@ inherits = *PLA*
filament_vendor = Generic
filament_cost = 25.4
filament_density = 1.24
filament_notes = "List of materials tested with standard PLA print settings:\n\nDas Filament\nEsun PLA\nEUMAKERS PLA\nFiberlogy HD-PLA\nFillamentum PLA\nFloreon3D\nHatchbox PLA\nPlasty Mladec PLA\nPrimavalue PLA\nProto pasta Matte Fiber\nVerbatim PLA\nVerbatim BVOH"
[filament:Generic FLEX]
inherits = *FLEX*
@ -1938,7 +1959,7 @@ filament_cost = 77.3
filament_density = 1.20
filament_type = PC
bed_temperature = 115
filament_colour = #3A80CA
filament_colour = #FFF2EC
first_layer_bed_temperature = 100
first_layer_temperature = 270
temperature = 270
@ -1954,7 +1975,6 @@ cooling = 0
fan_always_on = 0
filament_colour = #FFFFD7
filament_max_volumetric_speed = 3.8
filament_notes = "List of materials tested with standard PVA print settings:\n\nPrimaSelect PVA+\nICE FILAMENTS PVA 'NAUGHTY NATURAL'"
filament_ramming_parameters = "120 100 8.3871 8.6129 8.93548 9.22581 9.48387 9.70968 9.87097 10.0323 10.2258 10.4194 10.6452 10.8065| 0.05 8.34193 0.45 8.73548 0.95 9.34836 1.45 9.78385 1.95 10.0871 2.45 10.5161 2.95 10.8903 3.45 7.6 3.95 7.6 4.45 7.6 4.95 7.6"
filament_soluble = 1
filament_type = PVA
@ -1963,11 +1983,10 @@ start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_MODEL_MINI.*/}0{elsi
temperature = 195
[filament:Prusa ABS]
inherits = *ABS*
inherits = *ABSC*
filament_vendor = Made for Prusa
filament_cost = 27.82
filament_density = 1.08
filament_notes = "List of materials tested with standard ABS print settings:\n\nEsun ABS\nFil-A-Gehr ABS\nHatchboxABS\nPlasty Mladec ABS"
[filament:*ABS MMU2*]
inherits = Prusa ABS
@ -1984,12 +2003,10 @@ filament_unloading_speed = 20
[filament:Generic ABS @MMU2]
inherits = *ABS MMU2*
# alias = Generic ABS
filament_vendor = Generic
[filament:Prusament ASA @MMU2]
inherits = *ABS MMU2*
# alias = Prusament ASA
filament_vendor = Prusa Polymers
filament_cost = 35.28
filament_density = 1.07
@ -2013,7 +2030,6 @@ start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{el
[filament:Prusa ABS @MMU2]
inherits = *ABS MMU2*
# alias = Prusa ABS
filament_vendor = Made for Prusa
[filament:Plasty Mladec ABS @MMU2]
@ -2027,7 +2043,7 @@ filament_cost = 27.3
filament_density = 1.04
bridge_fan_speed = 50
cooling = 1
extrusion_multiplier = 0.9
extrusion_multiplier = 1
fan_always_on = 1
fan_below_layer_time = 10
filament_colour = #FFFFD7
@ -2063,7 +2079,20 @@ inherits = *PET*
filament_vendor = Made for Prusa
filament_cost = 27.82
filament_density = 1.27
filament_notes = "List of manufacturers tested with standard PETG print settings:\n\nE3D Edge\nPlasty Mladec PETG"
compatible_printers_condition = nozzle_diameter[0]!=0.6 and printer_model!="MK2SMM" and printer_model!="MINI" and ! (printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK(2.5|3).*/ and single_extruder_multi_material)
[filament:Verbatim PETG]
inherits = *PET*
filament_vendor = Verbatim
filament_cost = 27.90
filament_density = 1.27
compatible_printers_condition = nozzle_diameter[0]!=0.6 and printer_model!="MK2SMM" and printer_model!="MINI" and ! (printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK(2.5|3).*/ and single_extruder_multi_material)
[filament:Fiberlogy PETG]
inherits = *PET*
filament_vendor = Fiberlogy
filament_cost = 21.50
filament_density = 1.27
compatible_printers_condition = nozzle_diameter[0]!=0.6 and printer_model!="MK2SMM" and printer_model!="MINI" and ! (printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK(2.5|3).*/ and single_extruder_multi_material)
[filament:Prusament PETG]
@ -2078,11 +2107,9 @@ compatible_printers_condition = nozzle_diameter[0]!=0.6 and printer_model!="MK2S
[filament:Prusa PETG @0.6 nozzle]
inherits = *PET06*
# alias = Prusa PETG
filament_vendor = Made for Prusa
filament_cost = 27.82
filament_density = 1.27
filament_notes = "List of manufacturers tested with standard PETG print settings:\n\nE3D Edge\nPlasty Mladec PETG"
[filament:Prusament PETG @0.6 nozzle]
inherits = *PET06*
@ -2096,9 +2123,27 @@ filament_type = PETG
[filament:Plasty Mladec PETG @0.6 nozzle]
inherits = *PET06*
filament_vendor = Plasty Mladec
first_layer_temperature = 240
temperature = 250
filament_cost = 24.99
first_layer_temperature = 230
temperature = 240
filament_cost = 27.92
filament_density = 1.27
filament_type = PETG
[filament:Verbatim PETG @0.6 nozzle]
inherits = *PET06*
filament_vendor = Verbatim
first_layer_temperature = 230
temperature = 240
filament_cost = 27.90
filament_density = 1.27
filament_type = PETG
[filament:Fiberlogy PETG @0.6 nozzle]
inherits = *PET06*
filament_vendor = Fiberlogy
first_layer_temperature = 230
temperature = 240
filament_cost = 21.50
filament_density = 1.27
filament_type = PETG
@ -2112,7 +2157,6 @@ filament_cooling_initial_speed = 2
filament_cooling_moves = 1
filament_load_time = 15
filament_loading_speed = 14
filament_notes = PET
filament_ramming_parameters = "120 140 4.70968 4.74194 4.77419 4.80645 4.83871 4.87097 4.90323 5 5.25806 5.67742 6.29032 7.06452 7.83871 8.3871| 0.05 4.72901 0.45 4.73545 0.95 4.83226 1.45 4.88067 1.95 5.05483 2.45 5.93553 2.95 7.53556 3.45 8.6323 3.95 7.6 4.45 7.6 4.95 7.6"
filament_unload_time = 12
filament_unloading_speed = 20
@ -2128,7 +2172,6 @@ filament_max_volumetric_speed = 13
[filament:Generic PETG @MMU2]
inherits = *PET MMU2*
# alias = Generic PETG
filament_vendor = Generic
[filament:Plasty Mladec PETG @MMU2]
@ -2137,35 +2180,29 @@ filament_vendor = Plasty Mladec
[filament:Prusa PETG @MMU2]
inherits = *PET MMU2*
# alias = Prusa PETG
filament_vendor = Made for Prusa
[filament:Prusament PETG @MMU2]
inherits = *PET MMU2*
filament_type = PETG
# alias = Prusament PETG
filament_vendor = Prusa Polymers
[filament:Generic PETG @MMU2 0.6 nozzle]
inherits = *PET MMU2 06*
# alias = Generic PETG
filament_vendor = Generic
[filament:Prusa PETG @MMU2 0.6 nozzle]
inherits = *PET MMU2 06*
# alias = Prusa PETG
filament_vendor = Made for Prusa
[filament:Prusament PETG @MMU2 0.6 nozzle]
inherits = *PET MMU2 06*
filament_type = PETG
# alias = Prusament PETG
filament_vendor = Prusa Polymers
[filament:Plasty Mladec PETG @MMU2 0.6 nozzle]
inherits = *PET MMU2 06*
filament_type = PETG
# alias = Prusament PETG
filament_vendor = Plasty Mladec
[filament:Prusa PLA]
@ -2321,7 +2358,6 @@ fan_always_on = 0
fan_below_layer_time = 100
filament_colour = #FFFFD7
filament_max_volumetric_speed = 4
filament_notes = "List of materials tested with standard PVA print settings:\n\nVerbatim BVOH"
filament_soluble = 1
filament_type = PVA
first_layer_bed_temperature = 60
@ -2373,7 +2409,6 @@ filament_loading_speed = 14
filament_loading_speed_start = 19
filament_max_volumetric_speed = 3.8
filament_minimal_purge_on_wipe_tower = 15
filament_notes = "List of materials tested with standard PVA print settings:\n\nPrimaSelect PVA+"
filament_ramming_parameters = "120 110 3.83871 3.90323 3.96774 4.03226 4.09677 4.19355 4.3871 4.83871 5.67742 6.93548 8.54839 10.3226 11.9677 13.2581 14.129 14.5806| 0.05 3.8258 0.45 3.89676 0.95 4.05807 1.45 4.23548 1.95 5.18386 2.45 7.80651 2.95 11.5356 3.45 13.9872 3.95 14.7613 4.45 7.6 4.95 7.6"
filament_soluble = 1
filament_toolchange_delay = 0
@ -2404,7 +2439,6 @@ fan_always_on = 1
fan_below_layer_time = 100
filament_colour = #DEE0E6
filament_max_volumetric_speed = 5
filament_notes = "List of materials tested with standard PLA print settings:\n\nEsun PLA\nFiberlogy HD-PLA\nFillamentum PLA\nFloreon3D\nHatchbox PLA\nPlasty Mladec PLA\nPrimavalue PLA\nProto pasta Matte Fiber\nEUMAKERS PLA"
filament_type = PP
first_layer_bed_temperature = 100
first_layer_temperature = 220
@ -2445,7 +2479,6 @@ temperature = 270
[filament:ColorFabb XT-CF20 @MMU1]
inherits = *PETMMU1*
# alias = ColorFabb XT-CF20
filament_vendor = ColorFabb
compatible_printers_condition = nozzle_diameter[0]>0.35 and printer_model=="MK2SMM"
extrusion_multiplier = 1.2
@ -2460,7 +2493,6 @@ temperature = 260
[filament:ColorFabb nGen @MMU1]
inherits = *PETMMU1*
# alias = ColorFabb nGen
filament_vendor = ColorFabb
filament_cost = 21.2
filament_density = 1.2
@ -2474,16 +2506,13 @@ min_fan_speed = 20
[filament:E3D Edge @MMU1]
inherits = *PETMMU1*
# alias = E3D Edge
filament_vendor = E3D
filament_cost = 56.9
filament_density = 1.26
filament_type = EDGE
filament_notes = "List of manufacturers tested with standard PETG print settings:\n\nE3D Edge\nFillamentum CPE GH100\nPlasty Mladec PETG"
[filament:Fillamentum CPE @MMU1]
inherits = *PETMMU1*
# alias = Fillamentum CPE
filament_vendor = Fillamentum
filament_cost = 54.1
filament_density = 1.25
@ -2496,29 +2525,36 @@ temperature = 275
[filament:Generic PETG @MMU1]
inherits = *PETMMU1*
# alias = Generic PETG
filament_vendor = Generic
filament_cost = 27.82
filament_density = 1.27
[filament:Plasty Mladec PETG @MMU1]
inherits = *PETMMU1*
# alias = Generic PETG
filament_vendor = Plasty Mladec
filament_cost = 27.82
filament_density = 1.27
[filament:Verbatim PETG @MMU1]
inherits = *PETMMU1*
filament_vendor = Verbatim
filament_cost = 27.90
filament_density = 1.27
[filament:Fiberlogy PETG @MMU1]
inherits = *PETMMU1*
filament_vendor = Fiberlogy
filament_cost = 21.50
filament_density = 1.27
[filament:Prusa PETG @MMU1]
inherits = *PETMMU1*
# alias = Prusa PETG
filament_vendor = Made for Prusa
filament_cost = 27.82
filament_density = 1.27
filament_notes = "List of manufacturers tested with standard PETG print settings:\n\nE3D Edge\nPlasty Mladec PETG"
[filament:Prusament PETG @MMU1]
inherits = *PETMMU1*
# alias = Prusament PETG
filament_vendor = Prusa Polymers
first_layer_temperature = 240
temperature = 250
@ -2528,7 +2564,6 @@ filament_type = PETG
[filament:Taulman T-Glase @MMU1]
inherits = *PETMMU1*
# alias = Taulman T-Glase
filament_vendor = Taulman
filament_cost = 40
filament_density = 1.27
@ -2554,7 +2589,6 @@ compatible_printers_condition = printer_model=="MK2SMM"
[filament:Generic FLEX @MMU1]
inherits = *FLEX*
# alias = Generic FLEX
filament_vendor = Generic
filament_cost = 82
filament_density = 1.22
@ -2569,7 +2603,6 @@ compatible_printers_condition = printer_model=="MK2SMM"
[filament:Generic PETG @MINI]
inherits = Generic PETG; *PETMINI*
filament_vendor = Generic
# alias = Generic PETG
filament_cost = 27.82
filament_density = 1.27
compatible_printers_condition = printer_model=="MINI" and nozzle_diameter[0]!=0.6
@ -2581,35 +2614,79 @@ filament_cost = 27.82
filament_density = 1.27
compatible_printers_condition = printer_model=="MINI" and nozzle_diameter[0]!=0.6
[filament:Verbatim PETG @MINI]
inherits = Generic PETG; *PETMINI*
filament_vendor = Verbatim
filament_cost = 27.90
filament_density = 1.27
compatible_printers_condition = printer_model=="MINI" and nozzle_diameter[0]!=0.6
[filament:Fiberlogy PETG @MINI]
inherits = Generic PETG; *PETMINI*
filament_vendor = Fiberlogy
filament_cost = 21.50
filament_density = 1.27
compatible_printers_condition = printer_model=="MINI" and nozzle_diameter[0]!=0.6
[filament:Generic ABS @MINI]
inherits = Generic ABS; *ABSMINI*
filament_vendor = Generic
# alias = Generic ABS
filament_cost = 27.82
filament_density = 1.08
fan_always_on = 0
cooling = 1
min_fan_speed = 15
max_fan_speed = 15
slowdown_below_layer_time = 20
disable_fan_first_layers = 4
fan_below_layer_time = 20
bridge_fan_speed = 25
[filament:Esun ABS @MINI]
inherits = Generic ABS; *ABSMINI*
filament_vendor = Esun
filament_cost = 27.82
filament_density = 1.08
fan_always_on = 0
cooling = 1
min_fan_speed = 15
max_fan_speed = 15
slowdown_below_layer_time = 20
disable_fan_first_layers = 4
fan_below_layer_time = 20
bridge_fan_speed = 25
[filament:Hatchbox ABS @MINI]
inherits = Generic ABS; *ABSMINI*
filament_vendor = Hatchbox
filament_cost = 27.82
filament_density = 1.08
fan_always_on = 0
cooling = 1
min_fan_speed = 15
max_fan_speed = 15
slowdown_below_layer_time = 20
disable_fan_first_layers = 4
fan_below_layer_time = 20
bridge_fan_speed = 25
[filament:Plasty Mladec ABS @MINI]
inherits = Generic ABS; *ABSMINI*
filament_vendor = Plasty Mladec
filament_cost = 27.82
filament_density = 1.08
fan_always_on = 0
cooling = 1
min_fan_speed = 15
max_fan_speed = 15
slowdown_below_layer_time = 20
disable_fan_first_layers = 4
fan_below_layer_time = 20
bridge_fan_speed = 25
[filament:Prusament PETG @MINI]
inherits = Prusament PETG; *PETMINI*
filament_vendor = Prusa Polymers
# alias = Prusament PETG
first_layer_temperature = 240
temperature = 250
filament_density = 1.27
@ -2618,7 +2695,6 @@ compatible_printers_condition = printer_model=="MINI" and nozzle_diameter[0]!=0.
[filament:Prusament PETG @0.6 nozzle MINI]
inherits = Prusament PETG; *PETMINI06*
# alias = Prusament PETG
first_layer_temperature = 240
temperature = 250
filament_density = 1.27
@ -2626,16 +2702,21 @@ filament_cost = 24.99
[filament:Generic PETG @0.6 nozzle MINI]
inherits = Generic PETG; *PETMINI06*
# alias = Generic PETG
[filament:Plasty Mladec PETG @0.6 nozzle MINI]
inherits = Generic PETG; *PETMINI06*
filament_vendor = Plasty Mladec
# alias = Generic PETG
[filament:Verbatim PETG @0.6 nozzle MINI]
inherits = Generic PETG; *PETMINI06*
filament_vendor = Verbatim
[filament:Fiberlogy PETG @0.6 nozzle MINI]
inherits = Generic PETG; *PETMINI06*
filament_vendor = Fiberlogy
[filament:Prusament ASA @MINI]
inherits = Prusament ASA; *ABSMINI*
# alias = Prusament ASA
first_layer_temperature = 260
first_layer_bed_temperature = 100
temperature = 260
@ -2654,7 +2735,6 @@ filament_density = 1.07
[filament:Fillamentum Flexfill 98A @MINI]
inherits = SemiFlex or Flexfill 98A; *FLEXMINI*
# alias = Fillamentum Flexfill 98A
filament_vendor = Fillamentum
first_layer_temperature = 240
temperature = 240
@ -2662,7 +2742,6 @@ filament_max_volumetric_speed = 1.35
[filament:Generic FLEX @MINI]
inherits = SemiFlex or Flexfill 98A; *FLEXMINI*
# alias = Semiflex or Flex 98A
filament_vendor = Generic
fan_always_on = 0
bridge_fan_speed = 80
@ -2673,7 +2752,6 @@ filament_max_volumetric_speed = 1.35
[filament:AmazonBasics TPU @MINI]
inherits = *FLEXMINI*
# alias = AmazonBasics TPU
filament_vendor = AmazonBasics
filament_max_volumetric_speed = 1.5
first_layer_temperature = 235
@ -2689,7 +2767,6 @@ filament_density = 1.21
[filament:SainSmart TPU @MINI]
inherits = *FLEXMINI*
# alias = SainSmart TPU
filament_vendor = SainSmart
filament_max_volumetric_speed = 1.8
first_layer_temperature = 235
@ -2708,7 +2785,6 @@ filament_density = 1.21
[filament:Filatech FilaFlex40 @MINI]
inherits = *FLEXMINI*
# alias = Filatech FilaFlex40
filament_vendor = Filatech
filament_max_volumetric_speed = 1.8
fan_always_on = 1
@ -2728,7 +2804,6 @@ filament_cost = 51.45
[filament:Fillamentum Flexfill 92A @MINI]
inherits = *FLEXMINI*
# alias = Fillamentum Flexfill 92A
filament_vendor = Fillamentum
first_layer_temperature = 245
temperature = 245
@ -2753,7 +2828,6 @@ start_filament_gcode = "M900 K0 ; Filament gcode"
[filament:Fillamentum CPE @MINI]
inherits = Fillamentum CPE; *PETMINI*
# alias = Fillamentum CPE
first_layer_temperature = 265
first_layer_bed_temperature = 90
temperature = 265
@ -2763,25 +2837,29 @@ filament_density = 1.25
[filament:ColorFabb nGen @MINI]
inherits = ColorFabb nGen; *PETMINI*
# alias = ColorFabb nGen
filament_cost = 52.46
filament_density = 1.2
[filament:E3D PC-ABS @MINI]
inherits = E3D PC-ABS; *ABSMINI*
# alias = E3D PC-ABS
filament_density = 1.05
filament_cost = 28.80
[filament:Fillamentum ABS @MINI]
inherits = Fillamentum ABS; *ABSMINI*
# alias = Fillamentum ABS
filament_cost = 32.4
filament_density = 1.04
fan_always_on = 0
cooling = 1
min_fan_speed = 15
max_fan_speed = 15
slowdown_below_layer_time = 20
disable_fan_first_layers = 4
fan_below_layer_time = 20
bridge_fan_speed = 25
[filament:Fillamentum ASA @MINI]
inherits = Fillamentum ASA; *ABSMINI*
# alias = Fillamentum ASA
first_layer_temperature = 255
first_layer_bed_temperature = 100
temperature = 255
@ -2800,11 +2878,10 @@ filament_density = 1.07
[filament:Polymaker PC-Max @MINI]
inherits = Polymaker PC-Max; *ABSMINI*
# alias = Polymaker PC-Max
filament_type = PC
filament_max_volumetric_speed = 7
bed_temperature = 100
filament_colour = #3A80CA
filament_colour = #FFF2EC
first_layer_bed_temperature = 100
first_layer_temperature = 270
temperature = 270
@ -2814,14 +2891,20 @@ filament_density = 1.20
[filament:Prusa ABS @MINI]
inherits = *ABSMINI*
# alias = Prusa ABS
filament_vendor = Made for Prusa
filament_cost = 27.82
filament_density = 1.08
fan_always_on = 0
cooling = 1
min_fan_speed = 15
max_fan_speed = 15
slowdown_below_layer_time = 20
disable_fan_first_layers = 4
fan_below_layer_time = 20
bridge_fan_speed = 25
[filament:Generic HIPS @MINI]
inherits = *ABSMINI*
# alias = Generic HIPS
filament_vendor = Generic
filament_cost = 27.3
filament_density = 1.04
@ -2840,7 +2923,6 @@ temperature = 230
[filament:ColorFabb HT @MINI]
inherits = *PETMINI*
# alias = ColorFabb HT
filament_vendor = ColorFabb
bed_temperature = 100
bridge_fan_speed = 30
@ -2858,7 +2940,6 @@ temperature = 270
[filament:ColorFabb XT @MINI]
inherits = *PETMINI*
# alias = ColorFabb XT
filament_vendor = ColorFabb
filament_type = PETG
filament_cost = 62.9
@ -2869,7 +2950,6 @@ temperature = 270
[filament:ColorFabb XT-CF20 @MINI]
inherits = *PETMINI*
# alias = ColorFabb XT-CF20
filament_vendor = ColorFabb
compatible_printers_condition = nozzle_diameter[0]>0.35 and printer_model=="MINI"
extrusion_multiplier = 1.2
@ -2883,7 +2963,6 @@ temperature = 260
[filament:Taulman T-Glase @MINI]
inherits = *PETMINI*
# alias = Taulman T-Glase
filament_vendor = Taulman
filament_cost = 40
filament_density = 1.27
@ -2897,7 +2976,6 @@ min_fan_speed = 0
[filament:E3D Edge @MINI]
inherits = *PETMINI*
# alias = E3D Edge
filament_vendor = E3D
filament_cost = 56.9
filament_density = 1.26
@ -2905,7 +2983,6 @@ filament_type = EDGE
[filament:Prusa PETG @MINI]
inherits = *PETMINI*
# alias = Prusa PETG
filament_vendor = Made for Prusa
filament_cost = 27.82
filament_density = 1.27
@ -2913,7 +2990,6 @@ compatible_printers_condition = printer_model=="MINI" and nozzle_diameter[0]!=0.
[filament:Prusa PETG @0.6 nozzle MINI]
inherits = *PETMINI06*
# alias = Prusa PETG
filament_vendor = Made for Prusa
filament_cost = 27.82
filament_density = 1.27

View file

@ -855,7 +855,12 @@ Polygons top_level_islands(const Slic3r::Polygons &polygons)
}
// Outer offset shall not split the input contour into multiples. It is expected, that the solution will be non empty and it will contain just a single polygon.
ClipperLib::Paths fix_after_outer_offset(const ClipperLib::Path &input, ClipperLib::PolyFillType filltype, bool reverse_result)
ClipperLib::Paths fix_after_outer_offset(
const ClipperLib::Path &input,
// combination of default prameters to correspond to void ClipperOffset::Execute(Paths& solution, double delta)
// to produce a CCW output contour from CCW input contour for a positive offset.
ClipperLib::PolyFillType filltype, // = ClipperLib::pftPositive
bool reverse_result) // = false
{
ClipperLib::Paths solution;
if (! input.empty()) {
@ -867,8 +872,13 @@ ClipperLib::Paths fix_after_outer_offset(const ClipperLib::Path &input, ClipperL
return solution;
}
// Inner offset may split the source contour into multiple contours, but one shall not be inside the other.
ClipperLib::Paths fix_after_inner_offset(const ClipperLib::Path &input, ClipperLib::PolyFillType filltype, bool reverse_result)
// Inner offset may split the source contour into multiple contours, but one resulting contour shall not lie inside the other.
ClipperLib::Paths fix_after_inner_offset(
const ClipperLib::Path &input,
// combination of default prameters to correspond to void ClipperOffset::Execute(Paths& solution, double delta)
// to produce a CCW output contour from CCW input contour for a negative offset.
ClipperLib::PolyFillType filltype, // = ClipperLib::pftNegative
bool reverse_result) // = true
{
ClipperLib::Paths solution;
if (! input.empty()) {
@ -1041,12 +1051,20 @@ Polygons variable_offset_inner(const ExPolygon &expoly, const std::vector<std::v
// 1) Offset the outer contour.
ClipperLib::Paths contours = fix_after_inner_offset(mittered_offset_path_scaled(expoly.contour.points, deltas.front(), miter_limit), ClipperLib::pftNegative, true);
#ifndef NDEBUG
for (auto &c : contours)
assert(ClipperLib::Area(c) > 0.);
#endif /* NDEBUG */
// 2) Offset the holes one by one, collect the results.
ClipperLib::Paths holes;
holes.reserve(expoly.holes.size());
for (const Polygon& hole : expoly.holes)
append(holes, fix_after_outer_offset(mittered_offset_path_scaled(hole, deltas[1 + &hole - expoly.holes.data()], miter_limit), ClipperLib::pftPositive, false));
append(holes, fix_after_outer_offset(mittered_offset_path_scaled(hole, deltas[1 + &hole - expoly.holes.data()], miter_limit), ClipperLib::pftNegative, false));
#ifndef NDEBUG
for (auto &c : holes)
assert(ClipperLib::Area(c) > 0.);
#endif /* NDEBUG */
// 3) Subtract holes from the contours.
ClipperLib::Paths output;
@ -1077,12 +1095,20 @@ for (const std::vector<float>& ds : deltas)
// 1) Offset the outer contour.
ClipperLib::Paths contours = fix_after_outer_offset(mittered_offset_path_scaled(expoly.contour.points, deltas.front(), miter_limit), ClipperLib::pftPositive, false);
#ifndef NDEBUG
for (auto &c : contours)
assert(ClipperLib::Area(c) > 0.);
#endif /* NDEBUG */
// 2) Offset the holes one by one, collect the results.
ClipperLib::Paths holes;
holes.reserve(expoly.holes.size());
for (const Polygon& hole : expoly.holes)
append(holes, fix_after_inner_offset(mittered_offset_path_scaled(hole, deltas[1 + &hole - expoly.holes.data()], miter_limit), ClipperLib::pftPositive, true));
#ifndef NDEBUG
for (auto &c : holes)
assert(ClipperLib::Area(c) > 0.);
#endif /* NDEBUG */
// 3) Subtract holes from the contours.
ClipperLib::Paths output;
@ -1113,12 +1139,20 @@ for (const std::vector<float>& ds : deltas)
// 1) Offset the outer contour.
ClipperLib::Paths contours = fix_after_outer_offset(mittered_offset_path_scaled(expoly.contour.points, deltas.front(), miter_limit), ClipperLib::pftPositive, false);
#ifndef NDEBUG
for (auto &c : contours)
assert(ClipperLib::Area(c) > 0.);
#endif /* NDEBUG */
// 2) Offset the holes one by one, collect the results.
ClipperLib::Paths holes;
holes.reserve(expoly.holes.size());
for (const Polygon& hole : expoly.holes)
append(holes, fix_after_inner_offset(mittered_offset_path_scaled(hole, deltas[1 + &hole - expoly.holes.data()], miter_limit), ClipperLib::pftPositive, true));
#ifndef NDEBUG
for (auto &c : holes)
assert(ClipperLib::Area(c) > 0.);
#endif /* NDEBUG */
// 3) Subtract holes from the contours.
unscaleClipperPolygons(contours);
@ -1152,13 +1186,21 @@ ExPolygons variable_offset_inner_ex(const ExPolygon &expoly, const std::vector<s
#endif /* NDEBUG */
// 1) Offset the outer contour.
ClipperLib::Paths contours = fix_after_inner_offset(mittered_offset_path_scaled(expoly.contour.points, deltas.front(), miter_limit), ClipperLib::pftNegative, false);
ClipperLib::Paths contours = fix_after_inner_offset(mittered_offset_path_scaled(expoly.contour.points, deltas.front(), miter_limit), ClipperLib::pftNegative, true);
#ifndef NDEBUG
for (auto &c : contours)
assert(ClipperLib::Area(c) > 0.);
#endif /* NDEBUG */
// 2) Offset the holes one by one, collect the results.
ClipperLib::Paths holes;
holes.reserve(expoly.holes.size());
for (const Polygon& hole : expoly.holes)
append(holes, fix_after_outer_offset(mittered_offset_path_scaled(hole, deltas[1 + &hole - expoly.holes.data()], miter_limit), ClipperLib::pftNegative, true));
append(holes, fix_after_outer_offset(mittered_offset_path_scaled(hole, deltas[1 + &hole - expoly.holes.data()], miter_limit), ClipperLib::pftNegative, false));
#ifndef NDEBUG
for (auto &c : holes)
assert(ClipperLib::Area(c) > 0.);
#endif /* NDEBUG */
// 3) Subtract holes from the contours.
unscaleClipperPolygons(contours);

View file

@ -686,6 +686,7 @@ public:
ConfigOption* clone() const override { return new ConfigOptionString(*this); }
ConfigOptionString& operator=(const ConfigOption *opt) { this->set(opt); return *this; }
bool operator==(const ConfigOptionString &rhs) const { return this->value == rhs.value; }
bool empty() const { return this->value.empty(); }
std::string serialize() const override
{

View file

@ -13,6 +13,12 @@ static constexpr char ColorChangeCode[] = "M600";
static constexpr char PausePrintCode[] = "M601";
static constexpr char ToolChangeCode[] = "tool_change";
enum CustomGcodeType
{
cgtColorChange,
cgtPausePrint,
};
namespace CustomGCode {
struct Item

View file

@ -524,11 +524,22 @@ static inline void smooth_compensation_banded(const Points &contour, float band,
}
}
ExPolygon elephant_foot_compensation(const ExPolygon &input_expoly, const Flow &external_perimeter_flow, const double compensation)
#ifndef NDEBUG
static bool validate_expoly_orientation(const ExPolygon &expoly)
{
bool valid = expoly.contour.is_counter_clockwise();
for (auto &h : expoly.holes)
valid &= h.is_clockwise();
return valid;
}
#endif /* NDEBUG */
ExPolygon elephant_foot_compensation(const ExPolygon &input_expoly, double min_contour_width, const double compensation)
{
// The contour shall be wide enough to apply the external perimeter plus compensation on both sides.
double min_contour_width = double(external_perimeter_flow.scaled_width() + external_perimeter_flow.scaled_spacing());
assert(validate_expoly_orientation(input_expoly));
double scaled_compensation = scale_(compensation);
min_contour_width = scale_(min_contour_width);
double min_contour_width_compensated = min_contour_width + 2. * scaled_compensation;
// Make the search radius a bit larger for the averaging in contour_distance over a fan of rays to work.
double search_radius = min_contour_width_compensated + min_contour_width * 0.5;
@ -547,6 +558,7 @@ ExPolygon elephant_foot_compensation(const ExPolygon &input_expoly, const Flow &
{
EdgeGrid::Grid grid;
ExPolygon simplified = input_expoly.simplify(SCALED_EPSILON).front();
assert(validate_expoly_orientation(simplified));
BoundingBox bbox = get_extents(simplified.contour);
bbox.offset(SCALED_EPSILON);
grid.set_bbox(bbox);
@ -559,6 +571,7 @@ ExPolygon elephant_foot_compensation(const ExPolygon &input_expoly, const Flow &
Polygon &poly = (idx_contour == 0) ? resampled.contour : resampled.holes[idx_contour - 1];
std::vector<ResampledPoint> resampled_point_parameters;
poly.points = resample_polygon(poly.points, resample_interval, resampled_point_parameters);
assert(poly.is_counter_clockwise() == (idx_contour == 0));
std::vector<float> dists = contour_distance2(grid, idx_contour, poly.points, resampled_point_parameters, scaled_compensation, search_radius);
for (float &d : dists) {
// printf("Point %d, Distance: %lf\n", int(&d - dists.data()), unscale<double>(d));
@ -593,10 +606,18 @@ ExPolygon elephant_foot_compensation(const ExPolygon &input_expoly, const Flow &
assert(out_vec.size() == 1);
}
}
assert(validate_expoly_orientation(out));
return out;
}
ExPolygon elephant_foot_compensation(const ExPolygon &input, const Flow &external_perimeter_flow, const double compensation)
{
// The contour shall be wide enough to apply the external perimeter plus compensation on both sides.
double min_contour_width = double(external_perimeter_flow.width + external_perimeter_flow.spacing());
return elephant_foot_compensation(input, min_contour_width, compensation);
}
ExPolygons elephant_foot_compensation(const ExPolygons &input, const Flow &external_perimeter_flow, const double compensation)
{
ExPolygons out;
@ -606,4 +627,13 @@ ExPolygons elephant_foot_compensation(const ExPolygons &input, const Flow &exter
return out;
}
ExPolygons elephant_foot_compensation(const ExPolygons &input, double min_contour_width, const double compensation)
{
ExPolygons out;
out.reserve(input.size());
for (const ExPolygon &expoly : input)
out.emplace_back(elephant_foot_compensation(expoly, min_contour_width, compensation));
return out;
}
} // namespace Slic3r

View file

@ -8,6 +8,8 @@ namespace Slic3r {
class Flow;
ExPolygon elephant_foot_compensation(const ExPolygon &input, double min_countour_width, const double compensation);
ExPolygons elephant_foot_compensation(const ExPolygons &input, double min_countour_width, const double compensation);
ExPolygon elephant_foot_compensation(const ExPolygon &input, const Flow &external_perimeter_flow, const double compensation);
ExPolygons elephant_foot_compensation(const ExPolygons &input, const Flow &external_perimeter_flow, const double compensation);

View file

@ -11,18 +11,10 @@ void filter_by_extrusion_role_in_place(ExtrusionEntitiesPtr &extrusion_entities,
if (role != erMixed) {
auto first = extrusion_entities.begin();
auto last = extrusion_entities.end();
auto result = first;
while (first != last) {
// The caller wants only paths with a specific extrusion role.
auto role2 = (*first)->role();
if (role != role2) {
// This extrusion entity does not match the role asked.
assert(role2 != erMixed);
*result = *first;
++ result;
}
++ first;
}
extrusion_entities.erase(
std::remove_if(first, last, [&role](const ExtrusionEntity* ee) {
return ee->role() != role; }),
last);
}
}

View file

@ -11,6 +11,12 @@
namespace Slic3r {
FlowErrorNegativeSpacing::FlowErrorNegativeSpacing() :
FlowError("Flow::spacing() produced negative spacing. Did you set some extrusion width too small?") {}
FlowErrorNegativeFlow::FlowErrorNegativeFlow() :
FlowError("Flow::mm3_per_mm() produced negative flow. Did you set some extrusion width too small?") {}
// This static method returns a sane extrusion width default.
float Flow::auto_extrusion_width(FlowRole role, float nozzle_diameter)
{
@ -52,7 +58,7 @@ static inline FlowRole opt_key_to_flow_role(const std::string &opt_key)
static inline void throw_on_missing_variable(const std::string &opt_key, const char *dependent_opt_key)
{
throw std::runtime_error((boost::format(L("Cannot calculate extrusion width for %1%: Variable \"%2%\" not accessible.")) % opt_key % dependent_opt_key).str());
throw FlowErrorMissingVariable((boost::format(L("Cannot calculate extrusion width for %1%: Variable \"%2%\" not accessible.")) % opt_key % dependent_opt_key).str());
}
// Used to provide hints to the user on default extrusion width values, and to provide reasonable values to the PlaceholderParser.
@ -174,7 +180,7 @@ float Flow::spacing() const
#endif
// assert(res > 0.f);
if (res <= 0.f)
throw std::runtime_error("Flow::spacing() produced negative spacing. Did you set some extrusion width too small?");
throw FlowErrorNegativeSpacing();
return res;
}
@ -190,7 +196,7 @@ float Flow::spacing(const Flow &other) const
0.5 * this->spacing() + 0.5 * other.spacing());
// assert(res > 0.f);
if (res <= 0.f)
throw std::runtime_error("Flow::spacing() produced negative spacing. Did you set some extrusion width too small?");
throw FlowErrorNegativeSpacing();
return res;
}
@ -204,7 +210,7 @@ double Flow::mm3_per_mm() const
float(this->height * (this->width - this->height * (1. - 0.25 * PI)));
//assert(res > 0.);
if (res <= 0.)
throw std::runtime_error("Flow::mm3_per_mm() produced negative flow. Did you set some extrusion width too small?");
throw FlowErrorNegativeFlow();
return res;
}

View file

@ -27,6 +27,31 @@ enum FlowRole {
frSupportMaterialInterface,
};
class FlowError : public std::invalid_argument
{
public:
FlowError(const std::string& what_arg) : invalid_argument(what_arg) {}
FlowError(const char* what_arg) : invalid_argument(what_arg) {}
};
class FlowErrorNegativeSpacing : public FlowError
{
public:
FlowErrorNegativeSpacing();
};
class FlowErrorNegativeFlow : public FlowError
{
public:
FlowErrorNegativeFlow();
};
class FlowErrorMissingVariable : public FlowError
{
public:
FlowErrorMissingVariable(const std::string& what_arg) : FlowError(what_arg) {}
};
class Flow
{
public:

View file

@ -1060,9 +1060,9 @@ namespace DoExport {
print_statistics.clear();
print_statistics.estimated_normal_print_time = normal_time_estimator.get_time_dhm/*s*/();
print_statistics.estimated_silent_print_time = silent_time_estimator_enabled ? silent_time_estimator.get_time_dhm/*s*/() : "N/A";
print_statistics.estimated_normal_color_print_times = normal_time_estimator.get_color_times_dhms(true);
print_statistics.estimated_normal_custom_gcode_print_times = normal_time_estimator.get_custom_gcode_times_dhm(true);
if (silent_time_estimator_enabled)
print_statistics.estimated_silent_color_print_times = silent_time_estimator.get_color_times_dhms(true);
print_statistics.estimated_silent_custom_gcode_print_times = silent_time_estimator.get_custom_gcode_times_dhm(true);
print_statistics.total_toolchanges = std::max(0, wipe_tower_data.number_of_toolchanges);
if (! extruders.empty()) {
std::pair<std::string, unsigned int> out_filament_used_mm ("; filament used [mm] = ", 0);
@ -1104,11 +1104,11 @@ namespace DoExport {
print_statistics.total_wipe_tower_cost += has_wipe_tower ? (extruded_volume - extruder.extruded_volume())* extruder.filament_density() * 0.001 * extruder.filament_cost() * 0.001 : 0.;
}
filament_stats_string_out += out_filament_used_mm.first;
filament_stats_string_out += out_filament_used_cm3.first;
filament_stats_string_out += "\n" + out_filament_used_cm3.first;
if (out_filament_used_g.second)
filament_stats_string_out += out_filament_used_g.first;
filament_stats_string_out += "\n" + out_filament_used_g.first;
if (out_filament_cost.second)
filament_stats_string_out += out_filament_cost.first;
filament_stats_string_out += "\n" + out_filament_cost.first;
}
return filament_stats_string_out;
}
@ -1550,6 +1550,7 @@ void GCode::_do_export(Print& print, FILE* file)
m_writer.extruders(),
// Modifies
print.m_print_statistics));
_write(file, "\n");
_write_format(file, "; total filament used [g] = %.1lf\n", print.m_print_statistics.total_weight);
_write_format(file, "; total filament cost = %.1lf\n", print.m_print_statistics.total_cost);
if (print.m_print_statistics.total_toolchanges > 0)
@ -1852,7 +1853,7 @@ namespace ProcessLayer
if (!pause_print_msg.empty())
gcode += "M117 " + pause_print_msg + "\n";
// add tag for time estimator
//gcode += "; " + GCodeTimeEstimator::Pause_Print_Tag + "\n";
gcode += "; " + GCodeTimeEstimator::Pause_Print_Tag + "\n";
}
else // custom Gcode
{
@ -3436,7 +3437,7 @@ const std::vector<GCode::ObjectByExtruder::Island::Region>& GCode::ObjectByExtru
if (this_override == nullptr || (*this_override)[copy] == -int(extruder)-1)
target_eec.emplace_back(entities[i]);
}
for (; i < overrides.size(); ++ i)
for (; i < entities.size(); ++ i)
target_eec.emplace_back(entities[i]);
}
}

View file

@ -174,6 +174,7 @@ namespace Slic3r {
const std::string GCodeTimeEstimator::Silent_Last_M73_Output_Placeholder_Tag = "; _TE_SILENT_LAST_M73_OUTPUT_PLACEHOLDER";
const std::string GCodeTimeEstimator::Color_Change_Tag = "PRINT_COLOR_CHANGE";
const std::string GCodeTimeEstimator::Pause_Print_Tag = "PRINT_PAUSE";
GCodeTimeEstimator::GCodeTimeEstimator(EMode mode)
: m_mode(mode)
@ -212,8 +213,8 @@ namespace Slic3r {
}
_calculate_time();
if (m_needs_color_times && (m_color_time_cache != 0.0f))
m_color_times.push_back(m_color_time_cache);
if (m_needs_custom_gcode_times && (m_custom_gcode_time_cache != 0.0f))
m_custom_gcode_times.push_back({ cgtColorChange, m_custom_gcode_time_cache });
#if ENABLE_MOVE_STATS
_log_moves_stats();
@ -230,8 +231,8 @@ namespace Slic3r {
_calculate_time();
if (m_needs_color_times && (m_color_time_cache != 0.0f))
m_color_times.push_back(m_color_time_cache);
if (m_needs_custom_gcode_times && (m_custom_gcode_time_cache != 0.0f))
m_custom_gcode_times.push_back({ cgtColorChange, m_custom_gcode_time_cache });
#if ENABLE_MOVE_STATS
_log_moves_stats();
@ -245,8 +246,8 @@ namespace Slic3r {
m_parser.parse_file(file, boost::bind(&GCodeTimeEstimator::_process_gcode_line, this, _1, _2));
_calculate_time();
if (m_needs_color_times && (m_color_time_cache != 0.0f))
m_color_times.push_back(m_color_time_cache);
if (m_needs_custom_gcode_times && (m_custom_gcode_time_cache != 0.0f))
m_custom_gcode_times.push_back({ cgtColorChange, m_custom_gcode_time_cache });
#if ENABLE_MOVE_STATS
_log_moves_stats();
@ -263,8 +264,8 @@ namespace Slic3r {
m_parser.parse_line(line, action);
_calculate_time();
if (m_needs_color_times && (m_color_time_cache != 0.0f))
m_color_times.push_back(m_color_time_cache);
if (m_needs_custom_gcode_times && (m_custom_gcode_time_cache != 0.0f))
m_custom_gcode_times.push_back({ cgtColorChange, m_custom_gcode_time_cache});
#if ENABLE_MOVE_STATS
_log_moves_stats();
@ -351,8 +352,8 @@ namespace Slic3r {
}
// check tags
// remove color change tag
if (gcode_line == "; " + Color_Change_Tag)
// remove Color_Change_Tag and Pause_Print_Tag
if (gcode_line == "; " + Color_Change_Tag || gcode_line == "; " + Pause_Print_Tag)
continue;
// replaces placeholders for initial line M73 with the real lines
@ -717,25 +718,26 @@ namespace Slic3r {
return _get_time_minutes(get_time());
}
std::vector<float> GCodeTimeEstimator::get_color_times() const
std::vector<std::pair<CustomGcodeType, float>> GCodeTimeEstimator::get_custom_gcode_times() const
{
return m_color_times;
return m_custom_gcode_times;
}
std::vector<std::string> GCodeTimeEstimator::get_color_times_dhms(bool include_remaining) const
{
std::vector<std::string> ret;
float total_time = 0.0f;
for (float t : m_color_times)
// for (float t : m_color_times)
for (auto t : m_custom_gcode_times)
{
std::string time = _get_time_dhms(t);
std::string time = _get_time_dhms(t.second);
if (include_remaining)
{
time += " (";
time += _get_time_dhms(m_time - total_time);
time += ")";
}
total_time += t;
total_time += t.second;
ret.push_back(time);
}
return ret;
@ -745,20 +747,42 @@ namespace Slic3r {
{
std::vector<std::string> ret;
float total_time = 0.0f;
for (float t : m_color_times)
// for (float t : m_color_times)
for (auto t : m_custom_gcode_times)
{
std::string time = _get_time_minutes(t);
std::string time = _get_time_minutes(t.second);
if (include_remaining)
{
time += " (";
time += _get_time_minutes(m_time - total_time);
time += ")";
}
total_time += t;
total_time += t.second;
}
return ret;
}
std::vector<std::pair<CustomGcodeType, std::string>> GCodeTimeEstimator::get_custom_gcode_times_dhm(bool include_remaining) const
{
std::vector<std::pair<CustomGcodeType, std::string>> ret;
float total_time = 0.0f;
for (auto t : m_custom_gcode_times)
{
std::string time = _get_time_dhm(t.second);
if (include_remaining)
{
time += " (";
time += _get_time_dhm(m_time - total_time);
time += ")";
}
total_time += t.second;
ret.push_back({t.first, time});
}
return ret;
}
// Return an estimate of the memory consumed by the time estimator.
size_t GCodeTimeEstimator::memory_used() const
{
@ -791,9 +815,9 @@ namespace Slic3r {
m_last_st_synchronized_block_id = -1;
m_needs_color_times = false;
m_color_times.clear();
m_color_time_cache = 0.0f;
m_needs_custom_gcode_times = false;
m_custom_gcode_times.clear();
m_custom_gcode_time_cache = 0.0f;
}
void GCodeTimeEstimator::_reset_time()
@ -814,7 +838,7 @@ namespace Slic3r {
_recalculate_trapezoids();
m_time += get_additional_time();
m_color_time_cache += get_additional_time();
m_custom_gcode_time_cache += get_additional_time();
for (int i = m_last_st_synchronized_block_id + 1; i < (int)m_blocks.size(); ++i)
{
@ -835,7 +859,7 @@ namespace Slic3r {
it->second.time += block_time;
#endif // ENABLE_MOVE_STATS
m_color_time_cache += block_time;
m_custom_gcode_time_cache += block_time;
}
m_last_st_synchronized_block_id = (int)m_blocks.size() - 1;
@ -1466,26 +1490,34 @@ namespace Slic3r {
{
std::string comment = line.comment();
// color change tag
// Color_Change_Tag
size_t pos = comment.find(Color_Change_Tag);
if (pos != comment.npos)
{
_process_color_change_tag();
_process_custom_gcode_tag(cgtColorChange);
return true;
}
// Pause_Print_Tag
pos = comment.find(Pause_Print_Tag);
if (pos != comment.npos)
{
_process_custom_gcode_tag(cgtPausePrint);
return true;
}
return false;
}
void GCodeTimeEstimator::_process_color_change_tag()
void GCodeTimeEstimator::_process_custom_gcode_tag(CustomGcodeType code)
{
PROFILE_FUNC();
m_needs_color_times = true;
m_needs_custom_gcode_times = true;
_calculate_time();
if (m_color_time_cache != 0.0f)
if (m_custom_gcode_time_cache != 0.0f)
{
m_color_times.push_back(m_color_time_cache);
m_color_time_cache = 0.0f;
m_custom_gcode_times.push_back({code, m_custom_gcode_time_cache});
m_custom_gcode_time_cache = 0.0f;
}
}

View file

@ -4,6 +4,7 @@
#include "libslic3r.h"
#include "PrintConfig.hpp"
#include "GCodeReader.hpp"
#include "CustomGCode.hpp"
#define ENABLE_MOVE_STATS 0
@ -23,6 +24,7 @@ namespace Slic3r {
static const std::string Silent_Last_M73_Output_Placeholder_Tag;
static const std::string Color_Change_Tag;
static const std::string Pause_Print_Tag;
enum EMode : unsigned char
{
@ -240,10 +242,10 @@ namespace Slic3r {
int m_last_st_synchronized_block_id;
float m_time; // s
// data to calculate color print times
bool m_needs_color_times;
std::vector<float> m_color_times;
float m_color_time_cache;
// data to calculate custom code times
bool m_needs_custom_gcode_times;
std::vector<std::pair<CustomGcodeType, float>> m_custom_gcode_times;
float m_custom_gcode_time_cache;
#if ENABLE_MOVE_STATS
MovesStatsMap _moves_stats;
@ -369,8 +371,8 @@ namespace Slic3r {
// Returns the estimated time, in minutes (integer)
std::string get_time_minutes() const;
// Returns the estimated time, in seconds, for each color
std::vector<float> get_color_times() const;
// Returns the estimated time, in seconds, for each custom gcode
std::vector<std::pair<CustomGcodeType, float>> get_custom_gcode_times() const;
// Returns the estimated time, in format DDd HHh MMm SSs, for each color
// If include_remaining==true the strings will be formatted as: "time for color (remaining time at color start)"
@ -380,6 +382,10 @@ namespace Slic3r {
// If include_remaining==true the strings will be formatted as: "time for color (remaining time at color start)"
std::vector<std::string> get_color_times_minutes(bool include_remaining) const;
// Returns the estimated time, in format DDd HHh MMm, for each custom_gcode
// If include_remaining==true the strings will be formatted as: "time for custom_gcode (remaining time at color start)"
std::vector<std::pair<CustomGcodeType, std::string>> get_custom_gcode_times_dhm(bool include_remaining) const;
// Return an estimate of the memory consumed by the time estimator.
size_t memory_used() const;
@ -460,8 +466,8 @@ namespace Slic3r {
// Returns true if any tag has been processed
bool _process_tags(const GCodeReader::GCodeLine& line);
// Processes color change tag
void _process_color_change_tag();
// Processes ColorChangeTag and PausePrintTag
void _process_custom_gcode_tag(CustomGcodeType code);
// Simulates firmware st_synchronize() call
void _simulate_st_synchronize();

View file

@ -613,8 +613,12 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_
m_placeholder_parser.set("print_preset", new_full_config.option("print_settings_id")->clone());
m_placeholder_parser.set("filament_preset", new_full_config.option("filament_settings_id")->clone());
m_placeholder_parser.set("printer_preset", new_full_config.option("printer_settings_id")->clone());
// We want the filament overrides to be applied over their respective extruder parameters by the PlaceholderParser.
// see "Placeholders do not respect filament overrides." GH issue #3649
m_placeholder_parser.apply_config(filament_overrides);
// It is also safe to change m_config now after this->invalidate_state_by_config_options() call.
m_config.apply_only(new_full_config, print_diff, true);
//FIXME use move semantics once ConfigBase supports it.
m_config.apply(filament_overrides);
// Handle changes to object config defaults
m_default_object_config.apply_only(new_full_config, object_diff, true);
@ -1935,7 +1939,7 @@ void Print::_make_brim()
for (size_t i = 0; i < loops_trimmed_order.size();) {
// Find all pieces that the initial loop was split into.
size_t j = i + 1;
for (; j < loops_trimmed_order.size() && loops_trimmed_order[i].first == loops_trimmed_order[j].first; ++ j) ;
for (; j < loops_trimmed_order.size() && loops_trimmed_order[i].second == loops_trimmed_order[j].second; ++ j) ;
const ClipperLib_Z::Path &first_path = *loops_trimmed_order[i].first;
if (i + 1 == j && first_path.size() > 3 && first_path.front().X == first_path.back().X && first_path.front().Y == first_path.back().Y) {
auto *loop = new ExtrusionLoop();

View file

@ -153,15 +153,15 @@ public:
Layer* get_layer(int idx) { return m_layers[idx]; }
// Get a layer exactly at print_z.
const Layer* get_layer_at_printz(coordf_t print_z) const {
auto it = Slic3r::lower_bound_by_predicate(m_layers.begin(), m_layers.end(), [print_z](const Layer *layer) { return layer->print_z < print_z; });
auto it = Slic3r::lower_bound_by_predicate(m_layers.begin(), m_layers.end(), [print_z](const Layer *layer) { return layer->print_z < print_z; });
return (it == m_layers.end() || (*it)->print_z != print_z) ? nullptr : *it;
}
Layer* get_layer_at_printz(coordf_t print_z) { return const_cast<Layer*>(std::as_const(*this).get_layer_at_printz(print_z)); }
// Get a layer approximately at print_z.
const Layer* get_layer_at_printz(coordf_t print_z, coordf_t epsilon) const {
coordf_t limit = print_z + epsilon;
auto it = Slic3r::lower_bound_by_predicate(m_layers.begin(), m_layers.end(), [limit](const Layer *layer) { return layer->print_z < limit; });
return (it == m_layers.end() || (*it)->print_z < print_z - epsilon) ? nullptr : *it;
coordf_t limit = print_z - epsilon;
auto it = Slic3r::lower_bound_by_predicate(m_layers.begin(), m_layers.end(), [limit](const Layer *layer) { return layer->print_z < limit; });
return (it == m_layers.end() || (*it)->print_z > print_z + epsilon) ? nullptr : *it;
}
Layer* get_layer_at_printz(coordf_t print_z, coordf_t epsilon) { return const_cast<Layer*>(std::as_const(*this).get_layer_at_printz(print_z, epsilon)); }
@ -305,8 +305,8 @@ struct PrintStatistics
PrintStatistics() { clear(); }
std::string estimated_normal_print_time;
std::string estimated_silent_print_time;
std::vector<std::string> estimated_normal_color_print_times;
std::vector<std::string> estimated_silent_color_print_times;
std::vector<std::pair<CustomGcodeType, std::string>> estimated_normal_custom_gcode_print_times;
std::vector<std::pair<CustomGcodeType, std::string>> estimated_silent_custom_gcode_print_times;
double total_used_filament;
double total_extruded_volume;
double total_cost;
@ -326,8 +326,8 @@ struct PrintStatistics
void clear() {
estimated_normal_print_time.clear();
estimated_silent_print_time.clear();
estimated_normal_color_print_times.clear();
estimated_silent_color_print_times.clear();
estimated_normal_custom_gcode_print_times.clear();
estimated_silent_custom_gcode_print_times.clear();
total_used_filament = 0.;
total_extruded_volume = 0.;
total_cost = 0.;

View file

@ -113,6 +113,16 @@ void PrintConfigDef::init_common_params()
"If left blank, the default OS CA certificate repository is used.");
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionString(""));
def = this->add("elefant_foot_compensation", coFloat);
def->label = L("Elephant foot compensation");
def->category = L("Advanced");
def->tooltip = L("The first layer will be shrunk in the XY plane by the configured value "
"to compensate for the 1st layer squish aka an Elephant Foot effect.");
def->sidetext = L("mm");
def->min = 0;
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloat(0.2));
}
void PrintConfigDef::init_fff_params()
@ -371,16 +381,6 @@ void PrintConfigDef::init_fff_params()
def->min = 0;
def->set_default_value(new ConfigOptionFloat(6));
def = this->add("elefant_foot_compensation", coFloat);
def->label = L("Elephant foot compensation");
def->category = L("Advanced");
def->tooltip = L("The first layer will be shrunk in the XY plane by the configured value "
"to compensate for the 1st layer squish aka an Elephant Foot effect.");
def->sidetext = L("mm");
def->min = 0;
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloat(0));
def = this->add("end_gcode", coString);
def->label = L("End G-code");
def->tooltip = L("This end procedure is inserted at the end of the output file. "
@ -2442,6 +2442,15 @@ void PrintConfigDef::init_sla_params()
"to the sign of the correction.");
def->mode = comExpert;
def->set_default_value(new ConfigOptionFloat(0.0));
def = this->add("elefant_foot_min_width", coFloat);
def->label = L("Elephant foot minimum width");
def->category = L("Advanced");
def->tooltip = L("Minimum width of features to maintain when doing elephant foot compensation.");
def->sidetext = L("mm");
def->min = 0;
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloat(0.2));
def = this->add("gamma_correction", coFloat);
def->label = L("Printer gamma correction");
@ -2644,6 +2653,16 @@ void PrintConfigDef::init_sla_params()
def->max = 15;
def->mode = comSimple;
def->set_default_value(new ConfigOptionFloat(1.0));
def = this->add("support_max_bridges_on_pillar", coInt);
def->label = L("Max bridges on a pillar");
def->tooltip = L(
"Maximum number of bridges that can be placed on a pillar. Bridges "
"hold support point pinheads and connect to pillars as small branches.");
def->min = 0;
def->max = 50;
def->mode = comExpert;
def->set_default_value(new ConfigOptionInt(3));
def = this->add("support_pillar_connection_mode", coEnum);
def->label = L("Support pillar connection mode");
@ -2840,7 +2859,7 @@ void PrintConfigDef::init_sla_params()
def->min = 45;
def->max = 90;
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloat(45.0));
def->set_default_value(new ConfigOptionFloat(90.0));
def = this->add("pad_around_object", coBool);
def->label = L("Pad around object");

View file

@ -980,6 +980,9 @@ public:
// Radius in mm of the support pillars.
ConfigOptionFloat support_pillar_diameter /*= 0.8*/;
// How much bridge (supporting another pinhead) can be placed on a pillar.
ConfigOptionInt support_max_bridges_on_pillar;
// How the pillars are bridged together
ConfigOptionEnum<SLAPillarConnectionMode> support_pillar_connection_mode;
@ -1101,6 +1104,7 @@ protected:
OPT_PTR(support_head_penetration);
OPT_PTR(support_head_width);
OPT_PTR(support_pillar_diameter);
OPT_PTR(support_max_bridges_on_pillar);
OPT_PTR(support_pillar_connection_mode);
OPT_PTR(support_buildplate_only);
OPT_PTR(support_pillar_widening_factor);
@ -1175,6 +1179,8 @@ public:
ConfigOptionBool display_mirror_y;
ConfigOptionFloats relative_correction;
ConfigOptionFloat absolute_correction;
ConfigOptionFloat elefant_foot_compensation;
ConfigOptionFloat elefant_foot_min_width;
ConfigOptionFloat gamma_correction;
ConfigOptionFloat fast_tilt_time;
ConfigOptionFloat slow_tilt_time;
@ -1198,6 +1204,8 @@ protected:
OPT_PTR(display_orientation);
OPT_PTR(relative_correction);
OPT_PTR(absolute_correction);
OPT_PTR(elefant_foot_compensation);
OPT_PTR(elefant_foot_min_width);
OPT_PTR(gamma_correction);
OPT_PTR(fast_tilt_time);
OPT_PTR(slow_tilt_time);

View file

@ -1139,10 +1139,9 @@ void PrintObject::discover_vertical_shells()
}
#endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
polygons_append(holes, cache_top_botom_regions[idx_layer].holes);
{
if (int n_top_layers = region_config.top_solid_layers.value; n_top_layers > 0) {
// Gather top regions projected to this layer.
coordf_t print_z = layer->print_z;
int n_top_layers = region_config.top_solid_layers.value;
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 ||
@ -1159,10 +1158,9 @@ void PrintObject::discover_vertical_shells()
}
}
}
{
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();
int n_bottom_layers = region_config.bottom_solid_layers.value;
coordf_t bottom_z = layer->bottom_z();
for (int i = int(idx_layer) - 1;
i >= 0 &&
(i > int(idx_layer) - n_bottom_layers ||
@ -2356,6 +2354,9 @@ void PrintObject::discover_horizontal_shells()
for (size_t idx_surface_type = 0; idx_surface_type < 3; ++ idx_surface_type) {
m_print->throw_if_canceled();
SurfaceType type = (idx_surface_type == 0) ? stTop : (idx_surface_type == 1) ? stBottom : stBottomBridge;
int num_solid_layers = (type == stTop) ? region_config.top_solid_layers.value : region_config.bottom_solid_layers.value;
if (num_solid_layers == 0)
continue;
// Find slices of current type for current layer.
// Use slices instead of fill_surfaces, because they also include the perimeter area,
// which needs to be propagated in shells; we need to grow slices like we did for
@ -2384,9 +2385,9 @@ void PrintObject::discover_horizontal_shells()
// Scatter top / bottom regions to other layers. Scattering process is inherently serial, it is difficult to parallelize without locking.
for (int n = (type == stTop) ? int(i) - 1 : int(i) + 1;
(type == stTop) ?
(n >= 0 && (int(i) - n < region_config.top_solid_layers.value ||
(n >= 0 && (int(i) - n < num_solid_layers ||
print_z - m_layers[n]->print_z < region_config.top_solid_min_thickness.value - EPSILON)) :
(n < int(m_layers.size()) && (n - int(i) < region_config.bottom_solid_layers.value ||
(n < int(m_layers.size()) && (n - int(i) < num_solid_layers ||
m_layers[n]->bottom_z() - bottom_z < region_config.bottom_solid_min_thickness.value - EPSILON));
(type == stTop) ? -- n : ++ n)
{

View file

@ -41,7 +41,6 @@ const double SupportConfig::max_dual_pillar_height_mm = 35.0;
const double SupportConfig::optimizer_rel_score_diff = 1e-6;
const unsigned SupportConfig::optimizer_max_iterations = 1000;
const unsigned SupportConfig::pillar_cascade_neighbors = 3;
const unsigned SupportConfig::max_bridges_on_pillar = 3;
void SupportTree::retrieve_full_mesh(TriangleMesh &outmesh) const {
outmesh.merge(retrieve_mesh(MeshType::Support));

View file

@ -83,6 +83,8 @@ struct SupportConfig
// body. This is only useful when elevation is set to zero.
double pillar_base_safety_distance_mm = 0.5;
unsigned max_bridges_on_pillar = 3;
double head_fullwidth() const {
return 2 * head_front_radius_mm + head_width_mm +
2 * head_back_radius_mm - head_penetration_mm;
@ -103,7 +105,7 @@ struct SupportConfig
static const double optimizer_rel_score_diff;
static const unsigned optimizer_max_iterations;
static const unsigned pillar_cascade_neighbors;
static const unsigned max_bridges_on_pillar;
};
enum class MeshType { Support, Pad };

View file

@ -65,6 +65,8 @@ sla::SupportConfig make_support_cfg(const SLAPrintObjectConfig& c)
c.support_base_safety_distance.getFloat() < EPSILON ?
scfg.safety_distance_mm : c.support_base_safety_distance.getFloat();
scfg.max_bridges_on_pillar = unsigned(c.support_max_bridges_on_pillar.getInt());
return scfg;
}
@ -785,6 +787,8 @@ bool SLAPrint::invalidate_state_by_config_options(const std::vector<t_config_opt
"material_correction",
"relative_correction",
"absolute_correction",
"elefant_foot_compensation",
"elefant_foot_min_width",
"gamma_correction"
};
@ -944,6 +948,7 @@ bool SLAPrintObject::invalidate_state_by_config_options(const std::vector<t_conf
|| opt_key == "support_head_penetration"
|| opt_key == "support_head_width"
|| opt_key == "support_pillar_diameter"
|| opt_key == "support_max_bridges_on_pillar"
|| opt_key == "support_pillar_connection_mode"
|| opt_key == "support_buildplate_only"
|| opt_key == "support_base_diameter"
@ -1087,8 +1092,7 @@ const std::vector<ExPolygons> &SLAPrintObject::get_support_slices() const
const ExPolygons &SliceRecord::get_slice(SliceOrigin o) const
{
size_t idx = o == soModel ? m_model_slices_idx :
m_support_slices_idx;
size_t idx = o == soModel ? m_model_slices_idx : m_support_slices_idx;
if(m_po == nullptr) return EMPTY_SLICE;

View file

@ -152,6 +152,10 @@ public:
}
const ExPolygons& get_slice(SliceOrigin o) const;
size_t get_slice_idx(SliceOrigin o) const
{
return o == soModel ? m_model_slices_idx : m_support_slices_idx;
}
};
private:

View file

@ -8,6 +8,8 @@
#include <libslic3r/SLA/Pad.hpp>
#include <libslic3r/SLA/SupportPointGenerator.hpp>
#include <libslic3r/ElephantFootCompensation.hpp>
#include <libslic3r/ClipperUtils.hpp>
// For geometry algorithms with native Clipper types (no copies and conversions)
@ -78,6 +80,40 @@ SLAPrint::Steps::Steps(SLAPrint *print)
, objectstep_scale{(max_objstatus - min_objstatus) / (objcount * 100.0)}
{}
void SLAPrint::Steps::apply_printer_corrections(SLAPrintObject &po, SliceOrigin o)
{
if (o == soSupport && !po.m_supportdata) return;
auto faded_lyrs = size_t(po.m_config.faded_layers.getInt());
double min_w = m_print->m_printer_config.elefant_foot_min_width.getFloat() / 2.;
double start_efc = m_print->m_printer_config.elefant_foot_compensation.getFloat();
double doffs = m_print->m_printer_config.absolute_correction.getFloat();
coord_t clpr_offs = scaled(doffs);
faded_lyrs = std::min(po.m_slice_index.size(), faded_lyrs);
auto efc = [start_efc, faded_lyrs](size_t pos) {
return (faded_lyrs - 1 - pos) * start_efc / (faded_lyrs - 1);
};
std::vector<ExPolygons> &slices = o == soModel ?
po.m_model_slices :
po.m_supportdata->support_slices;
if (clpr_offs != 0) for (size_t i = 0; i < po.m_slice_index.size(); ++i) {
size_t idx = po.m_slice_index[i].get_slice_idx(o);
if (idx < slices.size())
slices[idx] = offset_ex(slices[idx], float(clpr_offs));
}
if (start_efc > 0.) for (size_t i = 0; i < faded_lyrs; ++i) {
size_t idx = po.m_slice_index[i].get_slice_idx(o);
if (idx < slices.size())
slices[idx] = elephant_foot_compensation(slices[idx], min_w, efc(i));
}
}
void SLAPrint::Steps::hollow_model(SLAPrintObject &po)
{
po.m_hollowing_data.reset();
@ -236,20 +272,15 @@ void SLAPrint::Steps::slice_model(SLAPrintObject &po)
}
auto mit = slindex_it;
double doffs = m_print->m_printer_config.absolute_correction.getFloat();
coord_t clpr_offs = scaled(doffs);
for(size_t id = 0;
for (size_t id = 0;
id < po.m_model_slices.size() && mit != po.m_slice_index.end();
id++)
{
// We apply the printer correction offset here.
if(clpr_offs != 0)
po.m_model_slices[id] =
offset_ex(po.m_model_slices[id], float(clpr_offs));
id++) {
mit->set_model_slice_idx(po, id); ++mit;
}
// We apply the printer correction offset here.
apply_printer_corrections(po, soModel);
if(po.m_config.supports_enable.getBool() || po.m_config.pad_enable.getBool())
{
po.m_supportdata.reset(new SLAPrintObject::SupportData(mesh));
@ -446,21 +477,15 @@ void SLAPrint::Steps::slice_supports(SLAPrintObject &po) {
auto heights = reserve_vector<float>(po.m_slice_index.size());
for(auto& rec : po.m_slice_index) heights.emplace_back(rec.slice_level());
sd->support_slices = sd->support_tree_ptr->slice(
heights, float(po.config().slice_closing_radius.value));
heights, float(po.config().slice_closing_radius.value));
}
double doffs = m_print->m_printer_config.absolute_correction.getFloat();
coord_t clpr_offs = scaled(doffs);
for (size_t i = 0; i < sd->support_slices.size() && i < po.m_slice_index.size(); ++i) {
// We apply the printer correction offset here.
if (clpr_offs != 0)
sd->support_slices[i] = offset_ex(sd->support_slices[i], float(clpr_offs));
for (size_t i = 0; i < sd->support_slices.size() && i < po.m_slice_index.size(); ++i)
po.m_slice_index[i].set_support_slice_idx(po, i);
}
apply_printer_corrections(po, soSupport);
// Using RELOAD_SLA_PREVIEW to tell the Plater to pass the update
// status to the 3D preview to load the SLA slices.

View file

@ -43,6 +43,8 @@ private:
bool canceled() const { return m_print->canceled(); }
void initialize_printer_input();
void apply_printer_corrections(SLAPrintObject &po, SliceOrigin o);
public:
Steps(SLAPrint *print);

View file

@ -43,10 +43,12 @@
//==================
// 2.2.0.beta1 techs
// 2.2.0.rc1 techs
//==================
#define ENABLE_2_2_0_BETA1 1
#define ENABLE_2_2_0_RC1 1
// Enable hack to remove crash when closing on OSX 10.9.5
#define ENABLE_HACK_CLOSING_ON_OSX_10_9_5 (1 && ENABLE_2_2_0_RC1)
//==================
// 2.3.0.alpha1 techs

View file

@ -64,15 +64,23 @@ extern std::string normalize_utf8_nfc(const char *src);
// for a short while, so the file may not be movable. Retry while we see recoverable errors.
extern std::error_code rename_file(const std::string &from, const std::string &to);
enum CopyFileResult {
SUCCESS = 0,
FAIL_COPY_FILE,
FAIL_FILES_DIFFERENT,
FAIL_RENAMING,
FAIL_CHECK_ORIGIN_NOT_OPENED,
FAIL_CHECK_TARGET_NOT_OPENED
};
// Copy a file, adjust the access attributes, so that the target is writable.
int copy_file_inner(const std::string &from, const std::string &to);
CopyFileResult copy_file_inner(const std::string &from, const std::string &to);
// Copy file to a temp file first, then rename it to the final file name.
// If with_check is true, then the content of the copied file is compared to the content
// of the source file before renaming.
extern int copy_file(const std::string &from, const std::string &to, const bool with_check = false);
extern CopyFileResult copy_file(const std::string &from, const std::string &to, const bool with_check = false);
// Compares two files, returns 0 if identical, -1 if different.
extern int check_copy(const std::string& origin, const std::string& copy);
// Compares two files if identical.
extern CopyFileResult check_copy(const std::string& origin, const std::string& copy);
// Ignore system and hidden files, which may be created by the DropBox synchronisation process.
// https://github.com/prusa3d/PrusaSlicer/issues/1298

View file

@ -417,7 +417,7 @@ std::error_code rename_file(const std::string &from, const std::string &to)
#endif
}
int copy_file_inner(const std::string& from, const std::string& to)
CopyFileResult copy_file_inner(const std::string& from, const std::string& to)
{
const boost::filesystem::path source(from);
const boost::filesystem::path target(to);
@ -433,38 +433,40 @@ int copy_file_inner(const std::string& from, const std::string& to)
boost::filesystem::permissions(target, perms, ec);
boost::filesystem::copy_file(source, target, boost::filesystem::copy_option::overwrite_if_exists, ec);
if (ec) {
return -1;
return FAIL_COPY_FILE;
}
boost::filesystem::permissions(target, perms, ec);
return 0;
return SUCCESS;
}
int copy_file(const std::string &from, const std::string &to, const bool with_check)
CopyFileResult copy_file(const std::string &from, const std::string &to, const bool with_check)
{
std::string to_temp = to + ".tmp";
int ret_val = copy_file_inner(from,to_temp);
if(ret_val == 0)
CopyFileResult ret_val = copy_file_inner(from,to_temp);
if(ret_val == SUCCESS)
{
if (with_check)
ret_val = check_copy(from, to_temp);
if (ret_val == 0 && rename_file(to_temp, to))
ret_val = -3;
ret_val = FAIL_RENAMING;
}
return ret_val;
}
int check_copy(const std::string &origin, const std::string &copy)
CopyFileResult check_copy(const std::string &origin, const std::string &copy)
{
std::ifstream f1(origin, std::ifstream::in | std::ifstream::binary | std::ifstream::ate);
std::ifstream f2(copy, std::ifstream::in | std::ifstream::binary | std::ifstream::ate);
boost::nowide::ifstream f1(origin, std::ifstream::in | std::ifstream::binary | std::ifstream::ate);
boost::nowide::ifstream f2(copy, std::ifstream::in | std::ifstream::binary | std::ifstream::ate);
if (f1.fail() || f2.fail())
return -2;
if (f1.fail())
return FAIL_CHECK_ORIGIN_NOT_OPENED;
if (f2.fail())
return FAIL_CHECK_TARGET_NOT_OPENED;
std::streampos fsize = f1.tellg();
if (fsize != f2.tellg())
return -2;
return FAIL_FILES_DIFFERENT;
f1.seekg(0, std::ifstream::beg);
f2.seekg(0, std::ifstream::beg);
@ -481,12 +483,12 @@ int check_copy(const std::string &origin, const std::string &copy)
if (origin_cnt != copy_cnt ||
(origin_cnt > 0 && std::memcmp(buffer_origin.data(), buffer_copy.data(), origin_cnt) != 0))
// Files are different.
return -2;
return FAIL_FILES_DIFFERENT;
fsize -= origin_cnt;
} while (f1.good() && f2.good());
// All data has been read and compared equal.
return (f1.eof() && f2.eof() && fsize == 0) ? 0 : -2;
return (f1.eof() && f2.eof() && fsize == 0) ? SUCCESS : FAIL_FILES_DIFFERENT;
}
// Ignore system and hidden files, which may be created by the DropBox synchronisation process.

View file

@ -105,20 +105,28 @@ void BackgroundSlicingProcess::process_fff()
GUI::RemovableDriveManager::get_instance().update();
bool with_check = GUI::RemovableDriveManager::get_instance().is_path_on_removable_drive(export_path);
int copy_ret_val = copy_file(m_temp_output_path, export_path, with_check);
if (with_check && copy_ret_val == -2)
{
std::string err_msg = "Copying of the temporary G-code to the output G-code failed. There might be problem with target device, please try exporting again or using different device. The corrupted output G-code is at " + export_path + ".tmp.";
throw std::runtime_error(_utf8(L(err_msg)));
}
else if (copy_ret_val == -3)
{
std::string err_msg = "Renaming of the G-code after copying to the selected destination folder has failed. Current path is " + export_path + ".tmp. Please try exporting again.";
throw std::runtime_error(_utf8(L(err_msg)));
}
else if ( copy_ret_val != 0)
{
throw std::runtime_error(_utf8(L("Copying of the temporary G-code to the output G-code failed. Maybe the SD card is write locked?")));
switch (copy_ret_val){
case SUCCESS: break; // no error
case FAIL_COPY_FILE:
throw std::runtime_error(_utf8(L("Copying of the temporary G-code to the output G-code failed. Maybe the SD card is write locked?")));
break;
case FAIL_FILES_DIFFERENT:
throw std::runtime_error((boost::format(_utf8(L("Copying of the temporary G-code to the output G-code failed. There might be problem with target device, please try exporting again or using different device. The corrupted output G-code is at %1%.tmp."))) % export_path).str());
break;
case FAIL_RENAMING:
throw std::runtime_error((boost::format(_utf8(L("Renaming of the G-code after copying to the selected destination folder has failed. Current path is %1%.tmp. Please try exporting again."))) % export_path).str());
break;
case FAIL_CHECK_ORIGIN_NOT_OPENED:
throw std::runtime_error((boost::format(_utf8(L("Copying of the temporary G-code has finished but the original code at %1% couldn't be opened during copy check. The output G-code is at %2%.tmp."))) % m_temp_output_path % export_path).str());
break;
case FAIL_CHECK_TARGET_NOT_OPENED:
throw std::runtime_error((boost::format(_utf8(L("Copying of the temporary G-code has finished but the exported code couldn't be opened during copy check. The output G-code is at %1%.tmp."))) % export_path).str());
break;
default:
BOOST_LOG_TRIVIAL(warning) << "Unexpected fail code(" << (int)copy_ret_val << ") durring copy_file() to " << export_path << ".";
break;
}
m_print->set_status(95, _utf8(L("Running post-processing scripts")));
run_post_process_scripts(export_path, m_fff_print->config());
m_print->set_status(100, (boost::format(_utf8(L("G-code file exported to %1%"))) % export_path).str());
@ -216,7 +224,7 @@ void BackgroundSlicingProcess::thread_proc()
wxString errmsg = wxString::Format(_(L("%s has encountered an error. It was likely caused by running out of memory. "
"If you are sure you have enough RAM on your system, this may also be a bug and we would "
"be glad if you reported it.")), SLIC3R_APP_NAME);
error = errmsg.ToStdString() + "\n\n" + std::string(ex.what());
error = std::string(errmsg.ToUTF8()) + "\n\n" + std::string(ex.what());
} catch (std::exception &ex) {
error = ex.what();
} catch (...) {
@ -484,7 +492,7 @@ void BackgroundSlicingProcess::prepare_upload()
if (m_print == m_fff_print) {
m_print->set_status(95, _utf8(L("Running post-processing scripts")));
if (copy_file(m_temp_output_path, source_path.string()) != 0) {
if (copy_file(m_temp_output_path, source_path.string()) != SUCCESS) {
throw std::runtime_error(_utf8(L("Copying of the temporary G-code to the output G-code failed")));
}
run_post_process_scripts(source_path.string(), m_fff_print->config());

View file

@ -220,7 +220,7 @@ wxPanel* BedShapePanel::init_texture_panel()
if (m_custom_texture != NONE)
{
if (!exists)
tooltip_text += _(L("Not found: "));
tooltip_text += _(L("Not found:")) + " ";
tooltip_text += _(m_custom_texture);
}
@ -299,7 +299,7 @@ wxPanel* BedShapePanel::init_model_panel()
if (m_custom_model != NONE)
{
if (!exists)
tooltip_text += _(L("Not found: "));
tooltip_text += _(L("Not found:")) + " ";
tooltip_text += _(m_custom_model);
}

View file

@ -43,6 +43,7 @@ Camera::Camera()
, m_distance(DefaultDistance)
, m_gui_scale(1.0)
, m_view_matrix(Transform3d::Identity())
, m_view_rotation(1., 0., 0., 0.)
, m_projection_matrix(Transform3d::Identity())
{
set_default_orientation();
@ -85,7 +86,13 @@ void Camera::select_next_type()
void Camera::set_target(const Vec3d& target)
{
translate_world(target - m_target);
Vec3d new_target = validate_target(target);
Vec3d new_displacement = new_target - m_target;
if (!new_displacement.isApprox(Vec3d::Zero()))
{
m_target = new_target;
m_view_matrix.translate(-new_displacement);
}
}
void Camera::update_zoom(double delta_zoom)
@ -299,17 +306,6 @@ void Camera::debug_render() const
}
#endif // ENABLE_CAMERA_STATISTICS
void Camera::translate_world(const Vec3d& displacement)
{
Vec3d new_target = validate_target(m_target + displacement);
Vec3d new_displacement = new_target - m_target;
if (!new_displacement.isApprox(Vec3d::Zero()))
{
m_target += new_displacement;
m_view_matrix.translate(-new_displacement);
}
}
void Camera::rotate_on_sphere(double delta_azimut_rad, double delta_zenit_rad, bool apply_limits)
{
m_zenit += Geometry::rad2deg(delta_zenit_rad);
@ -324,50 +320,23 @@ void Camera::rotate_on_sphere(double delta_azimut_rad, double delta_zenit_rad, b
}
}
// FIXME -> The following is a HACK !!!
// When the value of the zenit rotation is large enough, the following call to rotate() shows
// numerical instability introducing some scaling into m_view_matrix (verified by checking
// that the camera space unit vectors are no more unit).
// See also https://dev.prusa3d.com/browse/SPE-1082
// We split the zenit rotation into a set of smaller rotations which are then applied.
static const double MAX_ALLOWED = Geometry::deg2rad(0.1);
unsigned int zenit_steps_count = 1 + (unsigned int)(std::abs(delta_zenit_rad) / MAX_ALLOWED);
double zenit_step = delta_zenit_rad / (double)zenit_steps_count;
Vec3d target = m_target;
translate_world(-target);
if (zenit_step != 0.0)
{
Vec3d right = get_dir_right();
for (unsigned int i = 0; i < zenit_steps_count; ++i)
{
m_view_matrix.rotate(Eigen::AngleAxisd(zenit_step, right));
}
}
if (delta_azimut_rad != 0.0)
m_view_matrix.rotate(Eigen::AngleAxisd(delta_azimut_rad, Vec3d::UnitZ()));
translate_world(target);
Vec3d translation = m_view_matrix.translation() + m_view_rotation * m_target;
auto rot_z = Eigen::AngleAxisd(delta_azimut_rad, Vec3d::UnitZ());
m_view_rotation *= rot_z * Eigen::AngleAxisd(delta_zenit_rad, rot_z.inverse() * get_dir_right());
m_view_matrix.fromPositionOrientationScale(m_view_rotation * (- m_target) + translation, m_view_rotation, Vec3d(1., 1., 1.));
}
// Virtual trackball, rotate around an axis, where the eucledian norm of the axis gives the rotation angle in radians.
void Camera::rotate_local_around_target(const Vec3d& rotation_rad)
{
rotate_local_around_pivot(rotation_rad, m_target);
}
void Camera::rotate_local_around_pivot(const Vec3d& rotation_rad, const Vec3d& pivot)
{
// we use a copy of the pivot because a reference to the current m_target may be passed in (see i.e. rotate_local_around_target())
// and m_target is modified by the translate_world() calls
Vec3d center = pivot;
translate_world(-center);
m_view_matrix.rotate(Eigen::AngleAxisd(rotation_rad(0), get_dir_right()));
m_view_matrix.rotate(Eigen::AngleAxisd(rotation_rad(1), get_dir_up()));
m_view_matrix.rotate(Eigen::AngleAxisd(rotation_rad(2), get_dir_forward()));
translate_world(center);
update_zenit();
double angle = rotation_rad.norm();
if (std::abs(angle) > EPSILON) {
Vec3d translation = m_view_matrix.translation() + m_view_rotation * m_target;
Vec3d axis = m_view_rotation.conjugate() * rotation_rad.normalized();
m_view_rotation *= Eigen::Quaterniond(Eigen::AngleAxisd(angle, axis));
m_view_matrix.fromPositionOrientationScale(m_view_rotation * (-m_target) + translation, m_view_rotation, Vec3d(1., 1., 1.));
update_zenit();
}
}
double Camera::min_zoom() const
@ -588,6 +557,9 @@ void Camera::look_at(const Vec3d& position, const Vec3d& target, const Vec3d& up
m_view_matrix(3, 2) = 0.0;
m_view_matrix(3, 3) = 1.0;
// Initialize the rotation quaternion from the rotation submatrix of of m_view_matrix.
m_view_rotation = Eigen::Quaterniond(m_view_matrix.matrix().template block<3, 3>(0, 0));
update_zenit();
}
@ -598,8 +570,8 @@ void Camera::set_default_orientation()
double phi_rad = Geometry::deg2rad(45.0);
double sin_theta = ::sin(theta_rad);
Vec3d camera_pos = m_target + m_distance * Vec3d(sin_theta * ::sin(phi_rad), sin_theta * ::cos(phi_rad), ::cos(theta_rad));
m_view_matrix = Transform3d::Identity();
m_view_matrix.rotate(Eigen::AngleAxisd(theta_rad, Vec3d::UnitX())).rotate(Eigen::AngleAxisd(phi_rad, Vec3d::UnitZ())).translate(-camera_pos);
m_view_rotation = Eigen::AngleAxisd(theta_rad, Vec3d::UnitX()) * Eigen::AngleAxisd(phi_rad, Vec3d::UnitZ());
m_view_matrix.fromPositionOrientationScale(m_view_rotation * (- camera_pos), m_view_rotation, Vec3d(1., 1., 1.));
}
Vec3d Camera::validate_target(const Vec3d& target) const

View file

@ -43,6 +43,8 @@ private:
mutable std::array<int, 4> m_viewport;
mutable Transform3d m_view_matrix;
// We are calculating the rotation part of the m_view_matrix from m_view_rotation.
mutable Eigen::Quaterniond m_view_rotation;
mutable Transform3d m_projection_matrix;
mutable std::pair<double, double> m_frustrum_zs;
@ -107,7 +109,7 @@ public:
#endif // ENABLE_CAMERA_STATISTICS
// translate the camera in world space
void translate_world(const Vec3d& displacement);
void translate_world(const Vec3d& displacement) { this->set_target(m_target + displacement); }
// rotate the camera on a sphere having center == m_target and radius == m_distance
// using the given variations of spherical coordinates
@ -117,9 +119,6 @@ public:
// rotate the camera around three axes parallel to the camera local axes and passing through m_target
void rotate_local_around_target(const Vec3d& rotation_rad);
// rotate the camera around three axes parallel to the camera local axes and passing through the given pivot point
void rotate_local_around_pivot(const Vec3d& rotation_rad, const Vec3d& pivot);
// returns true if the camera z axis (forward) is pointing in the negative direction of the world z axis
bool is_looking_downward() const { return get_dir_forward().dot(Vec3d::UnitZ()) < 0.0; }

View file

@ -347,6 +347,7 @@ void ConfigManipulation::toggle_print_sla_options(DynamicPrintConfig* config)
toggle_field("support_head_penetration", supports_en);
toggle_field("support_head_width", supports_en);
toggle_field("support_pillar_diameter", supports_en);
toggle_field("support_max_bridges_on_pillar", supports_en);
toggle_field("support_pillar_connection_mode", supports_en);
toggle_field("support_buildplate_only", supports_en);
toggle_field("support_base_diameter", supports_en);

View file

@ -162,7 +162,7 @@ void ConfigSnapshotDialog::on_dpi_changed(const wxRect &suggested_rect)
void ConfigSnapshotDialog::onLinkClicked(wxHtmlLinkEvent &event)
{
m_snapshot_to_activate = event.GetLinkInfo().GetHref();
m_snapshot_to_activate = event.GetLinkInfo().GetHref().ToUTF8();
this->EndModal(wxID_CLOSE);
}

View file

@ -432,7 +432,7 @@ PageWelcome::PageWelcome(ConfigWizard *parent)
, welcome_text(append_text(wxString::Format(
_(L("Hello, welcome to %s! This %s helps you with the initial configuration; just a few settings and you will be ready to print.")),
SLIC3R_APP_NAME,
ConfigWizard::name())
_(ConfigWizard::name()))
))
, cbox_reset(append(
new wxCheckBox(this, wxID_ANY, _(L("Remove user profiles - install from scratch (a snapshot will be taken beforehand)")))
@ -748,7 +748,8 @@ PageCustom::PageCustom(ConfigWizard *parent)
cb_custom->Bind(wxEVT_CHECKBOX, [this](wxCommandEvent &event) {
tc_profile_name->Enable(custom_wanted());
wizard_p()->on_custom_setup();
wizard_p()->on_custom_setup(custom_wanted());
});
append(cb_custom);
@ -1396,7 +1397,7 @@ void ConfigWizard::priv::load_pages()
if (any_sla_selected) { index->add_page(page_sla_materials); }
// there should to be selected at least one printer
btn_finish->Enable(any_fff_selected || any_sla_selected);
btn_finish->Enable(any_fff_selected || any_sla_selected || custom_printer_selected);
index->add_page(page_update);
index->add_page(page_reload_from_disk);
@ -1599,8 +1600,9 @@ void ConfigWizard::priv::update_materials(Technology technology)
}
}
void ConfigWizard::priv::on_custom_setup()
void ConfigWizard::priv::on_custom_setup(const bool custom_wanted)
{
custom_printer_selected = custom_wanted;
load_pages();
}
@ -1723,6 +1725,8 @@ bool ConfigWizard::priv::on_bnt_finish()
if (any_sla_selected)
page_sla_materials->reload_presets();
// theres no need to check that filament is selected if we have only custom printer
if (custom_printer_selected && !any_fff_selected && !any_sla_selected) return true;
// check, that there is selected at least one filament/material
return check_materials_in_config(T_ANY);
}
@ -1751,13 +1755,13 @@ bool ConfigWizard::priv::check_materials_in_config(Technology technology, bool s
if (any_fff_selected && technology & T_FFF && !exist_preset(AppConfig::SECTION_FILAMENTS, filaments))
{
if (show_info_msg)
{
wxString message = _(L("You have to select at least one filament for selected printers")) + "\n\n\t" +
_(L("Do you want to automatic select default filaments?"));
ask_and_selected_default_materials(message, T_FFF);
}
return false;
if (show_info_msg)
{
wxString message = _(L("You have to select at least one filament for selected printers")) + "\n\n\t" +
_(L("Do you want to automatic select default filaments?"));
ask_and_selected_default_materials(message, T_FFF);
}
return false;
}
if (any_sla_selected && technology & T_SLA && !exist_preset(AppConfig::SECTION_MATERIALS, sla_materials))
@ -1875,6 +1879,7 @@ void ConfigWizard::priv::apply_config(AppConfig *app_config, PresetBundle *prese
if (bundle.second.is_prusa_bundle) { continue; }
const auto config = enabled_vendors.find(bundle.first);
if (config == enabled_vendors.end()) { continue; }
for (const auto &model : bundle.second.vendor_profile->models) {
const auto model_it = config->second.find(model.id);
if (model_it != config->second.end() && model_it->second.size() > 0) {
@ -1925,7 +1930,6 @@ bool ConfigWizard::priv::check_fff_selected()
for (const auto& printer: pages_3rdparty)
if (printer.second.first) // FFF page
ret |= printer.second.first->any_selected();
return ret;
}
@ -1942,7 +1946,7 @@ bool ConfigWizard::priv::check_sla_selected()
// Public
ConfigWizard::ConfigWizard(wxWindow *parent)
: DPIDialog(parent, wxID_ANY, wxString(SLIC3R_APP_NAME) + " - " + _(name().ToStdString()), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
: DPIDialog(parent, wxID_ANY, wxString(SLIC3R_APP_NAME) + " - " + _(name()), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
, p(new priv(this))
{
this->SetFont(wxGetApp().normal_font());
@ -1997,6 +2001,8 @@ ConfigWizard::ConfigWizard(wxWindow *parent)
// Pages for 3rd party vendors
p->create_3rdparty_pages(); // Needs to be done _before_ creating PageVendors
p->add_page(p->page_vendors = new PageVendors(this));
p->add_page(p->page_custom = new PageCustom(this));
p->custom_printer_selected = p->page_custom->custom_wanted();
p->any_sla_selected = p->check_sla_selected();
p->any_fff_selected = p->check_fff_selected();
@ -2008,7 +2014,7 @@ ConfigWizard::ConfigWizard(wxWindow *parent)
p->add_page(p->page_sla_materials = new PageMaterials(this, &p->sla_materials,
_(L("SLA Material Profiles Selection")) + " ", _(L("SLA Materials")), _(L("Layer height:")) ));
p->add_page(p->page_custom = new PageCustom(this));
p->add_page(p->page_update = new PageUpdate(this));
p->add_page(p->page_reload_from_disk = new PageReloadFromDisk(this));
p->add_page(p->page_mode = new PageMode(this));

View file

@ -447,6 +447,7 @@ struct ConfigWizard::priv
std::unique_ptr<DynamicPrintConfig> custom_config; // Backing for custom printer definition
bool any_fff_selected; // Used to decide whether to display Filaments page
bool any_sla_selected; // Used to decide whether to display SLA Materials page
bool custom_printer_selected;
wxScrolledWindow *hscroll = nullptr;
wxBoxSizer *hscroll_sizer = nullptr;
@ -497,7 +498,7 @@ struct ConfigWizard::priv
void set_run_reason(RunReason run_reason);
void update_materials(Technology technology);
void on_custom_setup();
void on_custom_setup(const bool custom_wanted);
void on_printer_pick(PagePrinters *page, const PrinterPickerEvent &evt);
void select_default_materials_for_printer_model(const std::vector<VendorProfile::PrinterModel> &models,
Technology technology,

View file

@ -77,6 +77,7 @@ Control::Control( wxWindow *parent,
m_selection = ssUndef;
m_ticks.set_pause_print_msg(_utf8(L("Place bearings in slots and resume printing")));
m_ticks.set_extruder_colors(&m_extruder_colors);
// slider events
this->Bind(wxEVT_PAINT, &Control::OnPaint, this);
@ -332,6 +333,13 @@ void Control::SetTicksValues(const CustomGCode::Info& custom_gcode_per_print_z)
Update();
}
void Control::SetDrawMode(bool is_sla_print, bool is_sequential_print)
{
m_draw_mode = is_sla_print ? dmSlaPrint :
is_sequential_print ? dmSequentialFffPrint :
dmRegular;
}
void Control::SetModeAndOnlyExtruder(const bool is_one_extruder_printed_model, const int only_extruder)
{
m_mode = !is_one_extruder_printed_model ? t_mode::MultiExtruder :
@ -344,6 +352,11 @@ void Control::SetModeAndOnlyExtruder(const bool is_one_extruder_printed_model, c
UseDefaultColors(m_mode == t_mode::SingleExtruder);
}
void Control::SetExtruderColors( const std::vector<std::string>& extruder_colors)
{
m_extruder_colors = extruder_colors;
}
void Control::get_lower_and_higher_position(int& lower_pos, int& higher_pos)
{
const double step = get_scroll_step();
@ -441,7 +454,7 @@ void Control::draw_info_line_with_icon(wxDC& dc, const wxPoint& pos, const Selec
dc.DrawLine(pt_beg, pt_end);
//draw action icon
if (m_is_enabled_tick_manipulation)
if (m_draw_mode == dmRegular)
draw_action_icon(dc, pt_beg, pt_end);
}
}
@ -612,10 +625,10 @@ void Control::draw_thumbs(wxDC& dc, const wxCoord& lower_pos, const wxCoord& hig
void Control::draw_ticks(wxDC& dc)
{
if (!m_is_enabled_tick_manipulation)
if (m_draw_mode == dmSlaPrint)
return;
dc.SetPen(m_is_enabled_tick_manipulation ? DARK_GREY_PEN : LIGHT_GREY_PEN );
dc.SetPen(m_draw_mode == dmRegular ? DARK_GREY_PEN : LIGHT_GREY_PEN );
int height, width;
get_size(&width, &height);
const wxCoord mid = is_horizontal() ? 0.5*height : 0.5*width;
@ -633,7 +646,11 @@ void Control::draw_ticks(wxDC& dc)
// get icon name if it is
std::string icon_name;
if (tick.gcode == ColorChangeCode || tick.gcode == ToolChangeCode) {
// if we have non-regular draw mode, all ticks should be marked with error icon
if (m_draw_mode != dmRegular)
icon_name = focused_tick ? "error_tick_f" : "error_tick";
else if (tick.gcode == ColorChangeCode || tick.gcode == ToolChangeCode) {
if (m_ticks.is_conflict_tick(tick, m_mode, m_only_extruder, m_values[tick.tick]))
icon_name = focused_tick ? "error_tick_f" : "error_tick";
}
@ -666,7 +683,7 @@ std::string Control::get_color_for_tool_change_tick(std::set<TickCode>::const_it
return it_n->color;
}
return it->color;
return m_extruder_colors[current_extruder-1]; // return a color for a specific extruder from the colors list
}
std::string Control::get_color_for_color_change_tick(std::set<TickCode>::const_iterator it) const
@ -682,6 +699,8 @@ std::string Control::get_color_for_color_change_tick(std::set<TickCode>::const_i
return it->color;
break;
}
if (it_n->gcode == ColorChangeCode && it_n->extruder == it->extruder)
return it->color;
}
if (!is_tool_change && it->extruder == def_extruder)
return it->color;
@ -705,7 +724,7 @@ wxRect Control::get_colored_band_rect()
void Control::draw_colored_band(wxDC& dc)
{
if (!m_is_enabled_tick_manipulation)
if (m_draw_mode != dmRegular)
return;
auto draw_band = [](wxDC& dc, const wxColour& clr, const wxRect& band_rc)
@ -725,7 +744,7 @@ void Control::draw_colored_band(wxDC& dc)
}
const int default_color_idx = m_mode==t_mode::MultiAsSingle ? std::max<int>(m_only_extruder - 1, 0) : 0;
draw_band(dc, wxColour(GUI::wxGetApp().plater()->get_extruder_colors_from_plater_config()[default_color_idx]), main_band);
draw_band(dc, wxColour(m_extruder_colors[default_color_idx]), main_band);
std::set<TickCode>::const_iterator tick_it = m_ticks.ticks.begin();
@ -771,7 +790,7 @@ void Control::draw_one_layer_icon(wxDC& dc)
void Control::draw_revert_icon(wxDC& dc)
{
if (m_ticks.empty() || !m_is_enabled_tick_manipulation)
if (m_ticks.empty() || m_draw_mode != dmRegular)
return;
int width, height;
@ -804,7 +823,7 @@ void Control::draw_cog_icon(wxDC& dc)
void Control::update_thumb_rect(const wxCoord& begin_x, const wxCoord& begin_y, const SelectedSlider& selection)
{
const wxRect& rect = wxRect(begin_x, begin_y, m_thumb_size.x, int(m_thumb_size.y*0.5));
const wxRect& rect = wxRect(begin_x, begin_y + (selection == ssLower ? int(m_thumb_size.y * 0.5) : 0), m_thumb_size.x, int(m_thumb_size.y*0.5));
if (selection == ssLower)
m_rect_lower_thumb = rect;
else
@ -822,10 +841,15 @@ int Control::get_value_from_position(const wxCoord x, const wxCoord y)
return int(m_min_value + double(height - SLIDER_MARGIN - y) / step + 0.5);
}
void Control::detect_selected_slider(const wxPoint& pt)
bool Control::detect_selected_slider(const wxPoint& pt)
{
m_selection = is_point_in_rect(pt, m_rect_lower_thumb) ? ssLower :
is_point_in_rect(pt, m_rect_higher_thumb) ? ssHigher : ssUndef;
if (is_point_in_rect(pt, m_rect_lower_thumb))
m_selection = ssLower;
else if(is_point_in_rect(pt, m_rect_higher_thumb))
m_selection = ssHigher;
else
return false; // pt doesn't referenced to any thumb
return true;
}
bool Control::is_point_in_rect(const wxPoint& pt, const wxRect& rect)
@ -880,7 +904,7 @@ void Control::OnLeftDown(wxMouseEvent& event)
m_mouse = maOneLayerIconClick;
else if (is_point_in_rect(pos, m_rect_cog_icon))
m_mouse = maCogIconClick;
else if (m_is_enabled_tick_manipulation)
else if (m_draw_mode == dmRegular)
{
if (is_point_in_rect(pos, m_rect_tick_action)) {
auto it = m_ticks.ticks.find(TickCode{ m_selection == ssLower ? m_lower_value : m_higher_value });
@ -890,6 +914,9 @@ void Control::OnLeftDown(wxMouseEvent& event)
m_mouse = maRevertIconClick;
}
if (m_mouse == maNone)
detect_selected_slider(pos);
event.Skip();
}
@ -931,6 +958,8 @@ wxString Control::get_tooltip(int tick/*=-1*/)
if (m_focus == fiColorBand)
return m_mode != t_mode::SingleExtruder ? "" :
_(L("Edit current color - Right click the colored slider segment"));
if (m_draw_mode == dmSlaPrint)
return ""; // no drawn ticks and no tooltips for them in SlaPrinting mode
wxString tooltip;
const auto tick_code_it = m_ticks.ticks.find(TickCode{tick});
@ -953,9 +982,9 @@ wxString Control::get_tooltip(int tick/*=-1*/)
// Show list of actions with new tick
tooltip += ( m_mode == t_mode::MultiAsSingle ?
_(L("Add extruder change - Left click")) :
m_mode == t_mode::SingleExtruder ?
_(L("Add color change - Left click for predefined color or"
"Shift + Left click for custom color selection")) :
m_mode == t_mode::SingleExtruder ?
_(L("Add color change - Left click for predefined color or "
"Shift + Left click for custom color selection")) :
_(L("Add color change - Left click")) ) + " " +
_(L("or press \"+\" key")) + "\n" + (
is_osx ?
@ -965,18 +994,23 @@ wxString Control::get_tooltip(int tick/*=-1*/)
if (tick_code_it != m_ticks.ticks.end()) // tick exists
{
if (m_draw_mode == dmSequentialFffPrint)
return _(L("The sequential print is on.\n"
"It's impossible to apply any custom G-code for objects printing sequentually.\n"
"This code won't be processed during G-code generation."));
// Show custom Gcode as a first string of tooltop
tooltip = " ";
tooltip += tick_code_it->gcode == ColorChangeCode ? (
m_mode == t_mode::SingleExtruder ?
tooltip += tick_code_it->gcode == ColorChangeCode ? ( m_mode == t_mode::SingleExtruder ?
from_u8((boost::format(_utf8(L("Color change (\"%1%\")"))) % tick_code_it->gcode ).str()) :
from_u8((boost::format(_utf8(L("Color change (\"%1%\") for Extruder %2%"))) %
tick_code_it->gcode % tick_code_it->extruder).str()) ) :
tick_code_it->gcode % tick_code_it->extruder).str()) ) :
tick_code_it->gcode == PausePrintCode ?
from_u8((boost::format(_utf8(L("Pause print (\"%1%\")"))) % tick_code_it->gcode ).str()) :
from_u8((boost::format(_utf8(L("Pause print (\"%1%\")"))) % tick_code_it->gcode ).str()) :
tick_code_it->gcode == ToolChangeCode ?
from_u8((boost::format(_utf8(L("Extruder (tool) is changed to Extruder \"%1%\""))) % tick_code_it->extruder ).str()) :
from_u8((boost::format(_utf8(L("\"%1%\""))) % tick_code_it->gcode ).str()) ;
from_u8((boost::format(_utf8(L("Extruder (tool) is changed to Extruder \"%1%\""))) %
tick_code_it->extruder ).str()) :
from_u8(tick_code_it->gcode);
// If tick is marked as a conflict (exclamation icon),
// we should to explain why
@ -1031,11 +1065,7 @@ void Control::OnMotion(wxMouseEvent& event)
const wxPoint pos = event.GetLogicalPosition(wxClientDC(this));
int tick = -1;
/* Note: Checking "!m_is_one_layer" is commented now because of
* it looks like unnecessary and cause a tooltip "One layer" showing when OneLayerLock is on
* #ysFIXME : Delete it after testing
* */
if (!m_is_left_down/* && !m_is_one_layer*/)
if (!m_is_left_down && !m_is_right_down)
{
if (is_point_in_rect(pos, m_rect_one_layer_icon))
m_focus = fiOneLayerIcon;
@ -1094,6 +1124,8 @@ void Control::append_change_extruder_menu_item(wxMenu* menu, bool switch_current
{
std::array<int, 2> active_extruders = get_active_extruders_for_tick(m_selection == ssLower ? m_lower_value : m_higher_value);
std::vector<wxBitmap*> icons = get_extruder_color_icons(true);
wxMenu* change_extruder_menu = new wxMenu();
for (int i = 1; i <= extruders_cnt; i++)
@ -1104,7 +1136,7 @@ void Control::append_change_extruder_menu_item(wxMenu* menu, bool switch_current
if (m_mode == t_mode::MultiAsSingle)
append_menu_item(change_extruder_menu, wxID_ANY, item_name, "",
[this, i](wxCommandEvent&) { add_code_as_tick(ToolChangeCode, i); }, "", menu,
[this, i](wxCommandEvent&) { add_code_as_tick(ToolChangeCode, i); }, *icons[i-1], menu,
[is_active_extruder]() { return !is_active_extruder; }, GUI::wxGetApp().plater());
}
@ -1169,7 +1201,7 @@ void Control::OnLeftUp(wxMouseEvent& event)
add_current_tick();
break;
case maCogIconClick :
if (m_mode == t_mode::MultiAsSingle)
if (m_mode == t_mode::MultiAsSingle && m_draw_mode == dmRegular)
show_cog_icon_context_menu();
else
jump_to_print_z();
@ -1320,23 +1352,19 @@ void Control::OnRightDown(wxMouseEvent& event)
const wxPoint pos = event.GetLogicalPosition(wxClientDC(this));
m_mouse = maNone;
if (m_is_enabled_tick_manipulation) {
if (m_draw_mode == dmRegular) {
if (is_point_in_rect(pos, m_rect_tick_action))
{
const int tick = m_selection == ssLower ? m_lower_value : m_higher_value;
m_mouse = m_ticks.ticks.find(TickCode{ tick }) == m_ticks.ticks.end() ?
maAddMenu : maEditMenu;
}
else if (m_mode == t_mode::SingleExtruder && is_point_in_rect(pos, get_colored_band_rect()))
else if (m_mode == t_mode::SingleExtruder && !detect_selected_slider(pos) && is_point_in_rect(pos, get_colored_band_rect()))
m_mouse = maForceColorEdit;
else if (m_mode == t_mode::MultiAsSingle && is_point_in_rect(pos, m_rect_cog_icon))
m_mouse = maCogIconMenu;
}
if (m_mouse != maNone)
return;
detect_selected_slider(pos);
if (!m_selection)
if (m_mouse != maNone || !detect_selected_slider(pos))
return;
if (m_selection == ssLower)
@ -1619,7 +1647,7 @@ static std::string get_pause_print_msg(const std::string& msg_in, double height)
static double get_print_z_to_jump(double active_print_z, double min_z, double max_z)
{
wxString msg_text = _(L("Enter the height you want to jump to")) + " :";
wxString msg_text = _(L("Enter the height you want to jump to")) + ":";
wxString msg_header = _(L("Jump to height"));
wxString msg_in = GUI::double_to_string(active_print_z);
@ -1766,15 +1794,16 @@ void Control::discard_all_thicks()
void Control::move_current_thumb_to_pos(wxPoint pos)
{
const int tick_val = get_tick_near_point(pos);
const int mouse_val = tick_val >= 0 && m_is_enabled_tick_manipulation ? tick_val :
const int mouse_val = tick_val >= 0 && m_draw_mode == dmRegular ? tick_val :
get_value_from_position(pos);
if (mouse_val >= 0)
{
// if (abs(mouse_val - m_lower_value) < abs(mouse_val - m_higher_value)) {
if (mouse_val <= m_lower_value) {
// if (mouse_val <= m_lower_value) {
if (m_selection == ssLower) {
SetLowerValue(mouse_val);
correct_lower_value();
m_selection = ssLower;
// m_selection = ssLower;
}
else {
SetHigherValue(mouse_val);
@ -1801,15 +1830,13 @@ void Control::edit_extruder_sequence()
int extruder = 0;
const int extr_cnt = m_extruders_sequence.extruders.size();
std::vector<std::string> colors = GUI::wxGetApp().plater()->get_extruder_colors_from_plater_config();
while (tick <= m_max_value)
{
const int cur_extruder = m_extruders_sequence.extruders[extruder];
bool meaningless_tick = tick == 0.0 && cur_extruder == extruder;
if (!meaningless_tick)
m_ticks.ticks.emplace(TickCode{tick, ToolChangeCode, cur_extruder + 1, colors[cur_extruder]});
m_ticks.ticks.emplace(TickCode{tick, ToolChangeCode, cur_extruder + 1, m_extruder_colors[cur_extruder]});
extruder++;
if (extruder == extr_cnt)
@ -1869,8 +1896,8 @@ bool Control::check_ticks_changed_event(const std::string& gcode)
return true;
wxString message = (m_ticks.mode == t_mode::SingleExtruder ?
_(L("The last color change data was saved for a single extruder printer profile.")) :
_(L("The last color change data was saved for a multiple extruder printer profile."))
_(L("The last color change data was saved for a single extruder printing.")) :
_(L("The last color change data was saved for a multi extruder printing."))
) + "\n" +
_(L("Your current changes will delete all saved color changes.")) + "\n\n\t" +
_(L("Are you sure you want to continue?"));
@ -1889,7 +1916,7 @@ bool Control::check_ticks_changed_event(const std::string& gcode)
_(L("The last color change data was saved for a multi extruder printing.")) + "\n\n" +
_(L("Select YES if you want to delete all saved tool changes, \n\t"
"NO if you want all tool changes switch to color changes, \n\t"
"or CANCEL to leave it unchanged")) + "\n\n\t" +
"or CANCEL to leave it unchanged.")) + "\n\n\t" +
_(L("Do you want to delete all saved tool changes?"))
) : ( // t_mode::MultiExtruder
_(L("The last color change data was saved for a multi extruder printing with tool changes for whole print.")) + "\n\n" +
@ -1924,8 +1951,7 @@ std::string TickCodeInfo::get_color_for_tick(TickCode tick, const std::string& c
return colors[m_default_color_idx % colors.size()];
}
std::vector<std::string> colors = GUI::wxGetApp().plater()->get_extruder_colors_from_plater_config();
std::string color = colors[extruder - 1];
std::string color = (*m_colors)[extruder - 1];
if (code == ColorChangeCode)
{

View file

@ -66,6 +66,13 @@ enum MouseAction
maRevertIconClick, // LeftMouseClick on "revert" icon
};
enum DrawMode
{
dmRegular,
dmSlaPrint,
dmSequentialFffPrint,
};
using t_mode = CustomGCode::Mode;
struct TickCode
@ -88,6 +95,8 @@ class TickCodeInfo
bool m_use_default_colors= false;
int m_default_color_idx = 0;
std::vector<std::string>* m_colors {nullptr};
std::string get_color_for_tick(TickCode tick, const std::string& code, const int extruder);
public:
@ -115,6 +124,8 @@ public:
bool suppressed_plus () { return m_suppress_plus; }
bool suppressed_minus() { return m_suppress_minus; }
void set_default_colors(bool default_colors_on) { m_use_default_colors = default_colors_on; }
void set_extruder_colors(std::vector<std::string>* extruder_colors) { m_colors = extruder_colors; }
};
@ -197,12 +208,12 @@ public:
CustomGCode::Info GetTicksValues() const;
void SetTicksValues(const Slic3r::CustomGCode::Info &custom_gcode_per_print_z);
void EnableTickManipulation(bool enable = true) { m_is_enabled_tick_manipulation = enable; }
void DisableTickManipulation() { EnableTickManipulation(false); }
void SetDrawMode(bool is_sla_print, bool is_sequential_print);
void SetManipulationMode(t_mode mode) { m_mode = mode; }
t_mode GetManipulationMode() const { return m_mode; }
void SetModeAndOnlyExtruder(const bool is_one_extruder_printed_model, const int only_extruder);
void SetExtruderColors(const std::vector<std::string>& extruder_colors);
bool is_horizontal() const { return m_style == wxSL_HORIZONTAL; }
bool is_one_layer() const { return m_is_one_layer; }
@ -261,7 +272,7 @@ protected:
void draw_thumb_text(wxDC& dc, const wxPoint& pos, const SelectedSlider& selection) const;
void update_thumb_rect(const wxCoord& begin_x, const wxCoord& begin_y, const SelectedSlider& selection);
void detect_selected_slider(const wxPoint& pt);
bool detect_selected_slider(const wxPoint& pt);
void correct_lower_value();
void correct_higher_value();
void move_current_thumb(const bool condition);
@ -323,9 +334,10 @@ private:
bool m_is_right_down = false;
bool m_is_one_layer = false;
bool m_is_focused = false;
bool m_is_enabled_tick_manipulation = true;
bool m_force_mode_apply = true;
DrawMode m_draw_mode = dmRegular;
t_mode m_mode = t_mode::SingleExtruder;
int m_only_extruder = -1;
@ -350,6 +362,8 @@ private:
std::vector<double> m_values;
TickCodeInfo m_ticks;
std::vector<std::string> m_extruder_colors;
// control's view variables
wxCoord SLIDER_MARGIN; // margin around slider

View file

@ -79,6 +79,11 @@ void Field::PostInitialize()
BUILD();
}
// Values of width to alignments of fields
int Field::def_width() { return wxOSX ? 8 : 7; }
int Field::def_width_wider() { return 14; }
int Field::def_width_thinner() { return 4; }
void Field::on_kill_focus()
{
// call the registered function if it is available
@ -240,6 +245,8 @@ void Field::get_value_by_opt_type(wxString& str, const bool check_value/* = true
set_value(wxString::Format("%s%%", stVal), false/*true*/);
str += "%%";
}
else
set_value(stVal, false); // it's no needed but can be helpful, when inputted value contained "," instead of "."
}
}
@ -367,14 +374,23 @@ void TextCtrl::BUILD() {
temp->Bind(wxEVT_KILL_FOCUS, ([this, temp](wxEvent& e)
{
e.Skip();
#ifdef __WXOSX__
// OSX issue: For some unknown reason wxEVT_KILL_FOCUS is emitted twice in a row
// Thus, suppress its second call
if (bKilledFocus) {
bKilledFocus = false;
return;
}
bKilledFocus = true;
#endif // __WXOSX__
#if !defined(__WXGTK__)
temp->GetToolTip()->Enable(true);
#endif // __WXGTK__
if (bEnterPressed) {
if (bEnterPressed)
bEnterPressed = false;
return;
}
propagate_value();
else
propagate_value();
}), temp->GetId());
// select all text using Ctrl+A
@ -423,10 +439,12 @@ bool TextCtrl::value_was_changed()
void TextCtrl::propagate_value()
{
if (is_defined_input_value<wxTextCtrl>(window, m_opt.type) && value_was_changed())
on_change_field();
else
if (!is_defined_input_value<wxTextCtrl>(window, m_opt.type) )
// on_kill_focus() cause a call of OptionsGroup::reload_config(),
// Thus, do it only when it's really needed (when undefined value was input)
on_kill_focus();
else if (value_was_changed())
on_change_field();
}
void TextCtrl::set_value(const boost::any& value, bool change_event/* = false*/) {

View file

@ -225,10 +225,10 @@ public:
bool get_enter_pressed() const { return bEnterPressed; }
void set_enter_pressed(bool pressed) { bEnterPressed = pressed; }
// Values of width to "systematic" alignments of fields
static int def_width() { return 7; }
static int def_width_wider() { return 14; }
static int def_width_thinner() { return 4; }
// Values of width to alignments of fields
static int def_width() ;
static int def_width_wider() ;
static int def_width_thinner() ;
protected:
RevertButton* m_Undo_btn = nullptr;
@ -274,6 +274,11 @@ class TextCtrl : public Field {
bool bChangedValueEvent = true;
void change_field_value(wxEvent& event);
#endif //__WXGTK__
#ifdef __WXOSX__
bool bKilledFocus = false;
#endif // __WXOSX__
public:
TextCtrl(const ConfigOptionDef& opt, const t_config_option_key& id) : Field(opt, id) {}
TextCtrl(wxWindow* parent, const ConfigOptionDef& opt, const t_config_option_key& id) : Field(parent, opt, id) {}

View file

@ -274,7 +274,7 @@ void GLCanvas3D::LayersEditing::render_overlay(const GLCanvas3D& canvas) const
if (ImGui::IsItemHovered())
{
ImGui::BeginTooltip();
ImGui::TextUnformatted(_(L("Higher print quality versus higher print speed.")));
ImGui::TextUnformatted(_(L("Higher print quality versus higher print speed.")).ToUTF8());
ImGui::EndTooltip();
}
@ -734,7 +734,7 @@ static void msw_disable_cleartype(wxFont &font)
++ startpos_weight;
size_t endpos_weight = font_desc.find(sep, startpos_weight);
// Parse the weight field.
unsigned int weight = atoi(font_desc(startpos_weight, endpos_weight - startpos_weight));
unsigned int weight = wxAtoi(font_desc(startpos_weight, endpos_weight - startpos_weight));
size_t startpos = endpos_weight;
for (size_t i = 0; i < 6; ++ i)
startpos = font_desc.find(sep, startpos + 1);
@ -982,12 +982,17 @@ void GLCanvas3D::LegendTexture::fill_color_print_legend_items( const GLCanvas3D
cp_legend_items.emplace_back(I18N::translate_utf8(L("Pause print or custom G-code")));
int cnt = custom_gcode_per_print_z.size();
int color_change_idx = color_cnt - extruders_cnt;
for (int i = cnt-1; i >= 0; --i)
if (custom_gcode_per_print_z[i].gcode == ColorChangeCode) {
::memcpy((void*)(colors.data() + color_pos), (const void*)(colors_in.data() + color_in_pos), 4 * sizeof(float));
color_pos += 4;
color_in_pos -= 4;
cp_legend_items.emplace_back((boost::format(I18N::translate_utf8(L("Color change for Extruder %d at %.2f mm"))) % custom_gcode_per_print_z[i].extruder % custom_gcode_per_print_z[i].print_z).str());
// create label for color change item
std::string id_str = std::to_string(color_change_idx--) + ": ";
cp_legend_items.emplace_back(id_str + (boost::format(I18N::translate_utf8(L("Color change for Extruder %d at %.2f mm"))) % custom_gcode_per_print_z[i].extruder % custom_gcode_per_print_z[i].print_z).str());
}
}
}
@ -1297,7 +1302,7 @@ void GLCanvas3D::Labels::render(const std::vector<const ModelInstance*>& sorted_
return owner.model_instance_id == id;
});
if (it != owners.end())
it->print_order = _(L("Seq.")) + "#: " + std::to_string(i + 1);
it->print_order = std::string((_(L("Seq."))).ToUTF8()) + "#: " + std::to_string(i + 1);
}
}
@ -3465,13 +3470,12 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
// if dragging over blank area with left button, rotate
if (m_hover_volume_idxs.empty() && m_mouse.is_start_position_3D_defined())
{
const Vec3d& orig = m_mouse.drag.start_position_3D;
double x = Geometry::deg2rad(pos(0) - orig(0)) * (double)TRACKBALLSIZE;
double y = Geometry::deg2rad(pos(1) - orig(1)) * (double)TRACKBALLSIZE;
const Vec3d rot = (Vec3d(pos.x(), pos.y(), 0.) - m_mouse.drag.start_position_3D) * (PI * TRACKBALLSIZE / 180.);
if (wxGetApp().plater()->get_mouse3d_controller().is_running() || (wxGetApp().app_config->get("use_free_camera") == "1"))
m_camera.rotate_local_around_target(Vec3d(y, x, 0.0));
// Virtual track ball (similar to the 3DConnexion mouse).
m_camera.rotate_local_around_target(Vec3d(rot.y(), rot.x(), 0.));
else
m_camera.rotate_on_sphere(x, y, wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() != ptSLA);
m_camera.rotate_on_sphere(rot.x(), rot.y(), wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() != ptSLA);
m_dirty = true;
}

View file

@ -16,6 +16,11 @@
#include <string>
#include <iostream>
#if ENABLE_HACK_CLOSING_ON_OSX_10_9_5
// Part of temporary hack to remove crash when closing on OSX 10.9.5
#include <wx/platinfo.h>
#endif // ENABLE_HACK_CLOSING_ON_OSX_10_9_5
#ifdef __APPLE__
#include "../Utils/MacDarkMode.hpp"
#endif // __APPLE__
@ -111,6 +116,9 @@ void GLCanvas3DManager::GLInfo::detect() const
m_max_tex_size /= 2;
if (Slic3r::total_physical_memory() / (1024 * 1024 * 1024) < 6)
m_max_tex_size /= 2;
if (GLEW_EXT_texture_filter_anisotropic)
glsafe(::glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &m_max_anisotropy));
@ -192,6 +200,11 @@ GLCanvas3DManager::EMultisampleState GLCanvas3DManager::s_multisample = GLCanvas
bool GLCanvas3DManager::s_compressed_textures_supported = false;
GLCanvas3DManager::EFramebufferType GLCanvas3DManager::s_framebuffers_type = GLCanvas3DManager::FB_None;
GLCanvas3DManager::GLInfo GLCanvas3DManager::s_gl_info;
#if ENABLE_HACK_CLOSING_ON_OSX_10_9_5
#ifdef __APPLE__
GLCanvas3DManager::OSInfo GLCanvas3DManager::s_os_info;
#endif // __APPLE__
#endif // ENABLE_HACK_CLOSING_ON_OSX_10_9_5
GLCanvas3DManager::GLCanvas3DManager()
: m_context(nullptr)
@ -223,6 +236,15 @@ bool GLCanvas3DManager::add(wxGLCanvas* canvas, Bed3D& bed, Camera& camera, GLTo
m_context = new wxGLContext(canvas);
if (m_context == nullptr)
return false;
#if ENABLE_HACK_CLOSING_ON_OSX_10_9_5
#ifdef __APPLE__
// Part of temporary hack to remove crash when closing on OSX 10.9.5
s_os_info.major = wxPlatformInfo::Get().GetOSMajorVersion();
s_os_info.minor = wxPlatformInfo::Get().GetOSMinorVersion();
s_os_info.micro = wxPlatformInfo::Get().GetOSMicroVersion();
#endif //__APPLE__
#endif // ENABLE_HACK_CLOSING_ON_OSX_10_9_5
}
canvas3D->set_context(m_context);
@ -307,6 +329,15 @@ void GLCanvas3DManager::destroy()
{
if (m_context != nullptr)
{
#if ENABLE_HACK_CLOSING_ON_OSX_10_9_5
#ifdef __APPLE__
// this is a temporary ugly hack to solve the crash happening when closing the application on OSX 10.9.5
// the crash is inside wxGLContext destructor
if (s_os_info.major == 10 && s_os_info.minor == 9 && s_os_info.micro == 5)
return;
#endif //__APPLE__
#endif // ENABLE_HACK_CLOSING_ON_OSX_10_9_5
delete m_context;
m_context = nullptr;
}

View file

@ -68,6 +68,17 @@ public:
void detect() const;
};
#if ENABLE_HACK_CLOSING_ON_OSX_10_9_5
#ifdef __APPLE__
struct OSInfo
{
int major{ 0 };
int minor{ 0 };
int micro{ 0 };
};
#endif //__APPLE__
#endif // ENABLE_HACK_CLOSING_ON_OSX_10_9_5
private:
enum EMultisampleState : unsigned char
{
@ -81,6 +92,11 @@ private:
CanvasesMap m_canvases;
wxGLContext* m_context;
static GLInfo s_gl_info;
#if ENABLE_HACK_CLOSING_ON_OSX_10_9_5
#ifdef __APPLE__
static OSInfo s_os_info;
#endif //__APPLE__
#endif // ENABLE_HACK_CLOSING_ON_OSX_10_9_5
bool m_gl_initialized;
static EMultisampleState s_multisample;
static bool s_compressed_textures_supported;

View file

@ -229,18 +229,30 @@ void show_error(wxWindow* parent, const wxString& message)
msg.ShowModal();
}
void show_error(wxWindow* parent, const char* message)
{
assert(message);
show_error(parent, wxString::FromUTF8(message));
}
void show_error_id(int id, const std::string& message)
{
auto *parent = id != 0 ? wxWindow::FindWindowById(id) : nullptr;
show_error(parent, from_u8(message));
show_error(parent, message);
}
void show_info(wxWindow* parent, const wxString& message, const wxString& title)
{
wxMessageDialog msg_wingow(parent, message, title.empty() ? _(L("Notice")) : title, wxOK | wxICON_INFORMATION);
wxMessageDialog msg_wingow(parent, message, wxString(SLIC3R_APP_NAME " - ") + (title.empty() ? _(L("Notice")) : title), wxOK | wxICON_INFORMATION);
msg_wingow.ShowModal();
}
void show_info(wxWindow* parent, const char* message, const char* title)
{
assert(message);
show_info(parent, wxString::FromUTF8(message), title ? wxString::FromUTF8(title) : wxString());
}
void warning_catcher(wxWindow* parent, const wxString& message)
{
wxMessageDialog msg(parent, message, _(L("Warning")), wxOK | wxICON_WARNING);

View file

@ -39,8 +39,12 @@ extern void add_menus(wxMenuBar *menu, int event_preferences_changed, int event_
void change_opt_value(DynamicPrintConfig& config, const t_config_option_key& opt_key, const boost::any& value, int opt_index = 0);
void show_error(wxWindow* parent, const wxString& message);
void show_error(wxWindow* parent, const char* message);
inline void show_error(wxWindow* parent, const std::string& message) { show_error(parent, message.c_str()); }
void show_error_id(int id, const std::string& message); // For Perl
void show_info(wxWindow* parent, const wxString& message, const wxString& title);
void show_info(wxWindow* parent, const wxString& message, const wxString& title = wxString());
void show_info(wxWindow* parent, const char* message, const char* title = nullptr);
inline void show_info(wxWindow* parent, const std::string& message,const std::string& title = std::string()) { show_info(parent, message.c_str(), title.c_str()); }
void warning_catcher(wxWindow* parent, const wxString& message);
// Creates a wxCheckListBoxComboPopup inside the given wxComboCtrl, filled with the given text and items.

View file

@ -187,8 +187,8 @@ bool GUI_App::on_init_inner()
wxString::Format("Resources path does not exist or is not a directory: %s", resources_dir));
// Profiles for the alpha are stored into the PrusaSlicer-alpha directory to not mix with the current release.
// SetAppName(SLIC3R_APP_KEY);
SetAppName(SLIC3R_APP_KEY "-alpha");
SetAppName(SLIC3R_APP_KEY);
// SetAppName(SLIC3R_APP_KEY "-beta");
SetAppDisplayName(SLIC3R_APP_NAME);
// Enable this to get the default Win32 COMCTRL32 behavior of static boxes.
@ -244,7 +244,7 @@ bool GUI_App::on_init_inner()
try {
preset_bundle->load_presets(*app_config);
} catch (const std::exception &ex) {
show_error(nullptr, from_u8(ex.what()));
show_error(nullptr, ex.what());
}
register_dpi_event();
@ -332,7 +332,11 @@ unsigned GUI_App::get_colour_approx_luma(const wxColour &colour)
bool GUI_App::dark_mode()
{
#if __APPLE__
return mac_dark_mode();
// The check for dark mode returns false positive on 10.12 and 10.13,
// which allowed setting dark menu bar and dock area, which is
// is detected as dark mode. We must run on at least 10.14 where the
// proper dark mode was first introduced.
return wxPlatformInfo::Get().CheckOSVersion(10, 14) && mac_dark_mode();
#else
const unsigned luma = get_colour_approx_luma(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
return luma < 128;
@ -754,7 +758,7 @@ Tab* GUI_App::get_tab(Preset::Type type)
{
for (Tab* tab: tabs_list)
if (tab->type() == type)
return tab->complited() ? tab : nullptr; // To avoid actions with no-completed Tab
return tab->completed() ? tab : nullptr; // To avoid actions with no-completed Tab
return nullptr;
}
@ -793,7 +797,7 @@ void GUI_App::add_config_menu(wxMenuBar *menu)
auto local_menu = new wxMenu();
wxWindowID config_id_base = wxWindow::NewControlId(int(ConfigMenuCnt));
const auto config_wizard_name = _(ConfigWizard::name(true).wx_str());
const auto config_wizard_name = _(ConfigWizard::name(true));
const auto config_wizard_tooltip = wxString::Format(_(L("Run %s")), config_wizard_name);
// Cmd+, is standard on OS X - what about other operating systems?
local_menu->Append(config_id_base + ConfigMenuWizard, config_wizard_name + dots, config_wizard_tooltip);
@ -819,7 +823,7 @@ void GUI_App::add_config_menu(wxMenuBar *menu)
local_menu->AppendSubMenu(mode_menu, _(L("Mode")), wxString::Format(_(L("%s View Mode")), SLIC3R_APP_NAME));
local_menu->AppendSeparator();
local_menu->Append(config_id_base + ConfigMenuLanguage, _(L("Change Application &Language")));
local_menu->Append(config_id_base + ConfigMenuLanguage, _(L("&Language")));
local_menu->AppendSeparator();
local_menu->Append(config_id_base + ConfigMenuFlashFirmware, _(L("Flash printer &firmware")), _(L("Upload a firmware image into an Arduino based printer")));
// TODO: for when we're able to flash dictionaries
@ -1241,7 +1245,7 @@ void GUI_App::check_updates(const bool verbose)
}
}
catch (const std::exception & ex) {
show_error(nullptr, from_u8(ex.what()));
show_error(nullptr, ex.what());
}

View file

@ -77,7 +77,9 @@ static int extruders_count()
static void take_snapshot(const wxString& snapshot_name)
{
wxGetApp().plater()->take_snapshot(snapshot_name);
Plater* plater = wxGetApp().plater();
if (plater)
plater->take_snapshot(snapshot_name);
}
ObjectList::ObjectList(wxWindow* parent) :
@ -287,6 +289,7 @@ void ObjectList::create_objects_ctrl()
GetColumn(colName)->SetWidth(20*em);
GetColumn(colPrint)->SetWidth(3*em);
GetColumn(colExtruder)->SetWidth(8*em);
GetColumn(colEditing) ->SetWidth(7*em);
}
}
@ -1541,7 +1544,8 @@ wxMenuItem* ObjectList::append_menu_item_settings(wxMenu* menu_)
// If there are selected more then one instance but not all of them
// don't add settings menu items
const Selection& selection = scene_selection();
if (selection.is_multiple_full_instance() && !selection.is_single_full_object())
if (selection.is_multiple_full_instance() && !selection.is_single_full_object() ||
selection.is_multiple_volume() || selection.is_mixed() ) // more than one volume(part) is selected on the scene
return nullptr;
const auto sel_vol = get_selected_model_volume();
@ -1560,7 +1564,11 @@ wxMenuItem* ObjectList::append_menu_item_settings(wxMenu* menu_)
// Add frequently settings
const ItemType item_type = m_objects_model->GetItemType(GetSelection());
const bool is_object_settings = item_type & itObject || item_type & itInstance || selection.is_single_full_object();
if (item_type == itUndef && !selection.is_single_full_object())
return nullptr;
const bool is_object_settings = item_type & itObject || item_type & itInstance ||
// multi-selection in ObjectList, but full_object in Selection
(item_type == itUndef && selection.is_single_full_object());
create_freq_settings_popupmenu(menu, is_object_settings);
if (mode == comAdvanced)
@ -1577,11 +1585,14 @@ wxMenuItem* ObjectList::append_menu_item_settings(wxMenu* menu_)
return menu->Append(menu_item);
}
wxMenuItem* ObjectList::append_menu_item_change_type(wxMenu* menu)
wxMenuItem* ObjectList::append_menu_item_change_type(wxMenu* menu, wxWindow* parent/* = nullptr*/)
{
return append_menu_item(menu, wxID_ANY, _(L("Change type")), "",
[this](wxCommandEvent&) { change_part_type(); }, "", menu);
[this](wxCommandEvent&) { change_part_type(); }, "", menu,
[this]() {
wxDataViewItem item = GetSelection();
return item.IsOk() || m_objects_model->GetItemType(item) == itVolume;
}, parent);
}
wxMenuItem* ObjectList::append_menu_item_instance_to_object(wxMenu* menu, wxWindow* parent)
@ -1656,35 +1667,51 @@ void ObjectList::append_menu_item_reload_from_disk(wxMenu* menu) const
[]() { return wxGetApp().plater()->can_reload_from_disk(); }, wxGetApp().plater());
}
void ObjectList::append_menu_item_change_extruder(wxMenu* menu) const
void ObjectList::append_menu_item_change_extruder(wxMenu* menu)
{
const wxString name = _(L("Change extruder"));
const std::vector<wxString> names = {_(L("Change extruder")), _(L("Set extruder for selected items")) };
// Delete old menu item
const int item_id = menu->FindItem(name);
if (item_id != wxNOT_FOUND)
menu->Destroy(item_id);
for (const wxString& name : names) {
const int item_id = menu->FindItem(name);
if (item_id != wxNOT_FOUND)
menu->Destroy(item_id);
}
const int extruders_cnt = extruders_count();
const wxDataViewItem item = GetSelection();
if (item && extruders_cnt > 1)
{
DynamicPrintConfig& config = get_item_config(item);
if (extruders_cnt <= 1)
return;
const int initial_extruder = !config.has("extruder") ? 0 :
config.option<ConfigOptionInt>("extruder")->value;
wxDataViewItemArray sels;
GetSelections(sels);
if (sels.IsEmpty())
return;
wxMenu* extruder_selection_menu = new wxMenu();
std::vector<wxBitmap*> icons = get_extruder_color_icons(true);
wxMenu* extruder_selection_menu = new wxMenu();
const wxString& name = sels.Count()==1 ? names[0] : names[1];
for (int i = 0; i <= extruders_cnt; i++)
{
const wxString& item_name = i == 0 ? _(L("Default")) : wxString::Format("%d", i);
append_menu_radio_item(extruder_selection_menu, wxID_ANY, item_name, "",
[this, i](wxCommandEvent&) { set_extruder_for_selected_items(i); }, menu)->Check(i == initial_extruder);
}
menu->AppendSubMenu(extruder_selection_menu, name, _(L("Select new extruder for the object/part")));
int initial_extruder = -1; // negative value for multiple object/part selection
if (sels.Count()==1) {
DynamicPrintConfig& config = get_item_config(sels[0]);
initial_extruder = !config.has("extruder") ? 0 :
config.option<ConfigOptionInt>("extruder")->value;
}
for (int i = 0; i <= extruders_cnt; i++)
{
bool is_active_extruder = i == initial_extruder;
int icon_idx = i == 0 ? 0 : i - 1;
const wxString& item_name = (i == 0 ? _(L("Default")) : wxString::Format(_(L("Extruder %d")), i)) +
(is_active_extruder ? " (" + _(L("active")) + ")" : "");
append_menu_item(extruder_selection_menu, wxID_ANY, item_name, "",
[this, i](wxCommandEvent&) { set_extruder_for_selected_items(i); }, *icons[icon_idx], menu,
[is_active_extruder]() { return !is_active_extruder; }, GUI::wxGetApp().plater());
}
menu->AppendSubMenu(extruder_selection_menu, name);
}
void ObjectList::append_menu_item_delete(wxMenu* menu)
@ -3159,7 +3186,9 @@ void ObjectList::update_selections()
for (auto obj_ins : objects_content_list) {
if (obj_ins.first == glv_obj_idx) {
if (obj_ins.second.find(glv_ins_idx) != obj_ins.second.end()) {
if (obj_ins.second.find(glv_ins_idx) != obj_ins.second.end() &&
!selection.is_from_single_instance() ) // a case when volumes of different types are selected
{
if (glv_ins_idx == 0 && (*m_objects)[glv_obj_idx]->instances.size() == 1)
sels.Add(m_objects_model->GetItemById(glv_obj_idx));
else
@ -3385,7 +3414,7 @@ bool ObjectList::check_last_selection(wxString& msg_str)
(type & itInstance && !(m_selection_mode & smInstance))
)
{
// Inform user why selection isn't complited
// Inform user why selection isn't completed
const wxString item_type = m_selection_mode & smInstance ? _(L("Object or Instance")) :
m_selection_mode & smVolume ? _(L("Part")) : _(L("Layer"));
@ -3905,7 +3934,9 @@ void ObjectList::OnEditingDone(wxDataViewEvent &event)
m_last_selected_column = -1;
#endif //__WXMSW__
wxGetApp().plater()->set_current_canvas_as_dirty();
Plater* plater = wxGetApp().plater();
if (plater)
plater->set_current_canvas_as_dirty();
}
void ObjectList::show_multi_selection_menu()
@ -3921,9 +3952,7 @@ void ObjectList::show_multi_selection_menu()
wxMenu* menu = new wxMenu();
if (extruders_count() > 1)
append_menu_item(menu, wxID_ANY, _(L("Set extruder for selected items")),
_(L("Select extruder number for selected objects and/or parts")),
[this](wxCommandEvent&) { extruder_selection(); }, "", menu);
append_menu_item_change_extruder(menu);
append_menu_item(menu, wxID_ANY, _(L("Reload from disk")), _(L("Reload the selected volumes from disk")),
[this](wxCommandEvent&) { wxGetApp().plater()->reload_from_disk(); }, "", menu, []() {

View file

@ -241,14 +241,14 @@ public:
wxMenuItem* append_menu_item_split(wxMenu* menu);
wxMenuItem* append_menu_item_layers_editing(wxMenu* menu, wxWindow* parent);
wxMenuItem* append_menu_item_settings(wxMenu* menu);
wxMenuItem* append_menu_item_change_type(wxMenu* menu);
wxMenuItem* append_menu_item_change_type(wxMenu* menu, wxWindow* parent = nullptr);
wxMenuItem* append_menu_item_instance_to_object(wxMenu* menu, wxWindow* parent);
wxMenuItem* append_menu_item_printable(wxMenu* menu, wxWindow* parent);
void append_menu_items_osx(wxMenu* menu);
wxMenuItem* append_menu_item_fix_through_netfabb(wxMenu* menu);
void append_menu_item_export_stl(wxMenu* menu) const;
void append_menu_item_reload_from_disk(wxMenu* menu) const;
void append_menu_item_change_extruder(wxMenu* menu) const;
void append_menu_item_change_extruder(wxMenu* menu);
void append_menu_item_delete(wxMenu* menu);
void append_menu_item_scale_selection_to_fit_print_volume(wxMenu* menu);
void create_object_popupmenu(wxMenu *menu);

View file

@ -595,7 +595,9 @@ void Preview::update_view_type(bool slice_completed)
void Preview::create_double_slider()
{
m_slider = new DoubleSlider::Control(this, wxID_ANY, 0, 0, 0, 100);
m_slider->EnableTickManipulation(wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() == ptFFF);
bool sla_print_technology = wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() == ptSLA;
bool sequential_print = wxGetApp().preset_bundle->prints.get_edited_preset().config.opt_bool("complete_objects");
m_slider->SetDrawMode(sla_print_technology, sequential_print);
m_double_slider_sizer->Add(m_slider, 0, wxEXPAND, 0);
@ -709,7 +711,11 @@ void Preview::update_double_slider(const std::vector<double>& layers_z, bool kee
m_slider->SetTicksValues(ticks_info_from_model);
m_slider->EnableTickManipulation(wxGetApp().plater()->printer_technology() == ptFFF);
bool sla_print_technology = wxGetApp().plater()->printer_technology() == ptSLA;
bool sequential_print = wxGetApp().preset_bundle->prints.get_edited_preset().config.opt_bool("complete_objects");
m_slider->SetDrawMode(sla_print_technology, sequential_print);
m_slider->SetExtruderColors(wxGetApp().plater()->get_extruder_colors_from_plater_config());
}
void Preview::update_double_slider_mode()

View file

@ -112,6 +112,9 @@ int get_dpi_for_window(wxWindow *window)
#elif defined __APPLE__
// TODO
return DPI_DEFAULT;
#else // freebsd and others
// TODO
return DPI_DEFAULT;
#endif
}

View file

@ -5,10 +5,6 @@
#include "slic3r/GUI/GUI_App.hpp"
#include "slic3r/GUI/GLCanvas3D.hpp"
#include "libslic3r/SLAPrint.hpp"
#include "slic3r/GUI/MeshUtils.hpp"
@ -138,7 +134,7 @@ void GLGizmoBase::Grabber::render_face(float half_size) const
}
GLGizmoBase::GLGizmoBase(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id, CommonGizmosData* common_data_ptr)
GLGizmoBase::GLGizmoBase(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id)
: m_parent(parent)
, m_group_id(-1)
, m_state(Off)
@ -149,7 +145,6 @@ GLGizmoBase::GLGizmoBase(GLCanvas3D& parent, const std::string& icon_filename, u
, m_dragging(false)
, m_imgui(wxGetApp().imgui())
, m_first_input_window_render(true)
, m_c(common_data_ptr)
{
::memcpy((void*)m_base_color, (const void*)DEFAULT_BASE_COLOR, 4 * sizeof(float));
::memcpy((void*)m_drag_color, (const void*)DEFAULT_DRAG_COLOR, 4 * sizeof(float));
@ -306,88 +301,5 @@ unsigned char picking_checksum_alpha_channel(unsigned char red, unsigned char gr
}
bool CommonGizmosData::update_from_backend(GLCanvas3D& canvas, ModelObject* model_object)
{
recent_update = false;
if (m_model_object != model_object
|| (model_object && m_model_object_id != model_object->id())) {
m_model_object = model_object;
m_print_object_idx = -1;
m_mesh_raycaster.reset();
m_object_clipper.reset();
m_supports_clipper.reset();
m_old_mesh = nullptr;
m_mesh = nullptr;
m_backend_mesh_transformed.clear();
if (m_model_object) {
m_active_instance = canvas.get_selection().get_instance_idx();
m_active_instance_bb_radius = m_model_object->instance_bounding_box(m_active_instance).radius();
}
recent_update = true;
}
if (! m_model_object || ! canvas.get_selection().is_from_single_instance())
return false;
int old_po_idx = m_print_object_idx;
// First we need a pointer to the respective SLAPrintObject. The index into objects vector is
// cached so we don't have todo it on each render. We only search for the po if needed:
if (m_print_object_idx < 0 || (int)canvas.sla_print()->objects().size() != m_print_objects_count) {
m_print_objects_count = canvas.sla_print()->objects().size();
m_print_object_idx = -1;
for (const SLAPrintObject* po : canvas.sla_print()->objects()) {
++m_print_object_idx;
if (po->model_object()->id() == m_model_object->id())
break;
}
}
m_mesh = nullptr;
// Load either the model_object mesh, or one provided by the backend
// This mesh does not account for the possible Z up SLA offset.
// The backend mesh needs to be transformed and because a pointer to it is
// saved, a copy is stored as a member (FIXME)
if (m_print_object_idx >=0) {
const SLAPrintObject* po = canvas.sla_print()->objects()[m_print_object_idx];
if (po->is_step_done(slaposDrillHoles)) {
m_backend_mesh_transformed = po->get_mesh_to_print();
m_backend_mesh_transformed.transform(canvas.sla_print()->sla_trafo(*m_model_object).inverse());
m_mesh = &m_backend_mesh_transformed;
m_has_drilled_mesh = true;
}
}
if (! m_mesh) {
m_mesh = &m_model_object->volumes.front()->mesh();
m_backend_mesh_transformed.clear();
m_has_drilled_mesh = false;
}
m_model_object_id = m_model_object->id();
if (m_mesh != m_old_mesh) {
wxBusyCursor wait;
m_mesh_raycaster.reset(new MeshRaycaster(*m_mesh));
m_object_clipper.reset();
m_supports_clipper.reset();
m_old_mesh = m_mesh;
m_clipping_plane_distance = 0.f;
m_clipping_plane_distance_stash = 0.f;
recent_update = true;
return true;
}
if (! recent_update)
recent_update = m_print_object_idx < 0 && old_po_idx >= 0;
return recent_update;
}
} // namespace GUI
} // namespace Slic3r

View file

@ -30,7 +30,6 @@ static const float CONSTRAINED_COLOR[4] = { 0.5f, 0.5f, 0.5f, 1.0f };
class ImGuiWrapper;
class CommonGizmosData;
class GLCanvas3D;
class ClippingPlane;
@ -101,13 +100,11 @@ protected:
mutable std::vector<Grabber> m_grabbers;
ImGuiWrapper* m_imgui;
bool m_first_input_window_render;
CommonGizmosData* m_c = nullptr;
public:
GLGizmoBase(GLCanvas3D& parent,
const std::string& icon_filename,
unsigned int sprite_id,
CommonGizmosData* common_data = nullptr);
unsigned int sprite_id);
virtual ~GLGizmoBase() {}
bool init() { return on_init(); }
@ -185,57 +182,6 @@ protected:
// were not interpolated by alpha blending or multi sampling.
extern unsigned char picking_checksum_alpha_channel(unsigned char red, unsigned char green, unsigned char blue);
class MeshRaycaster;
class MeshClipper;
class CommonGizmosData {
public:
const TriangleMesh* mesh() const {
return (! m_mesh ? nullptr : m_mesh); //(m_cavity_mesh ? m_cavity_mesh.get() : m_mesh));
}
bool update_from_backend(GLCanvas3D& canvas, ModelObject* model_object);
bool recent_update = false;
ModelObject* m_model_object = nullptr;
const TriangleMesh* m_mesh;
std::unique_ptr<MeshRaycaster> m_mesh_raycaster;
std::unique_ptr<MeshClipper> m_object_clipper;
std::unique_ptr<MeshClipper> m_supports_clipper;
//std::unique_ptr<TriangleMesh> m_cavity_mesh;
//std::unique_ptr<GLVolume> m_volume_with_cavity;
int m_active_instance = -1;
float m_active_instance_bb_radius = 0;
ObjectID m_model_object_id = 0;
int m_print_object_idx = -1;
int m_print_objects_count = -1;
int m_old_timestamp = -1;
float m_clipping_plane_distance = 0.f;
std::unique_ptr<ClippingPlane> m_clipping_plane;
void stash_clipping_plane() {
m_clipping_plane_distance_stash = m_clipping_plane_distance;
}
void unstash_clipping_plane() {
m_clipping_plane_distance = m_clipping_plane_distance_stash;
}
bool has_drilled_mesh() const { return m_has_drilled_mesh; }
private:
const TriangleMesh* m_old_mesh;
TriangleMesh m_backend_mesh_transformed;
float m_clipping_plane_distance_stash = 0.f;
bool m_has_drilled_mesh = false;
};
} // namespace GUI
} // namespace Slic3r

View file

@ -17,11 +17,10 @@
namespace Slic3r {
namespace GUI {
GLGizmoHollow::GLGizmoHollow(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id, CommonGizmosData* cd)
: GLGizmoBase(parent, icon_filename, sprite_id, cd)
GLGizmoHollow::GLGizmoHollow(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id)
: GLGizmoBase(parent, icon_filename, sprite_id)
, m_quadric(nullptr)
{
m_c->m_clipping_plane.reset(new ClippingPlane(Vec3d::Zero(), 0.));
m_quadric = ::gluNewQuadric();
if (m_quadric != nullptr)
// using GLU_FILL does not work when the instance's transformation
@ -58,19 +57,30 @@ void GLGizmoHollow::set_sla_support_data(ModelObject*, const Selection&)
{
if (m_c->recent_update) {
if (m_state == On)
m_c->build_AABB_if_needed();
update_clipping_plane(m_c->m_clipping_plane_was_moved);
// This is a temporary and not very nice hack, to make sure that
// if the cp was moved by the data returned by backend, it will
// remember its direction. FIXME: Refactor this mess and make
// the clipping plane itself part of the shared data.
if (! m_c->m_clipping_plane_was_moved && m_c->m_clipping_plane_distance == 0.25f)
m_c->m_clipping_plane_was_moved = true;
if (m_c->m_model_object) {
reload_cache();
if (m_c->has_drilled_mesh())
m_holes_in_drilled_mesh = m_c->m_model_object->sla_drain_holes;
}
}
if (m_state == On) {
m_parent.toggle_model_objects_visibility(false);
m_parent.toggle_model_objects_visibility(true, m_c->m_model_object, m_c->m_active_instance);
m_parent.toggle_sla_auxiliaries_visibility(m_show_supports, m_c->m_model_object, m_c->m_active_instance);
}
else
m_parent.toggle_model_objects_visibility(true, nullptr, -1);
if (m_state == On) {
m_parent.toggle_model_objects_visibility(false);
m_parent.toggle_model_objects_visibility(true, m_c->m_model_object, m_c->m_active_instance);
m_parent.toggle_sla_auxiliaries_visibility(m_show_supports, m_c->m_model_object, m_c->m_active_instance);
}
}
@ -242,7 +252,7 @@ void GLGizmoHollow::render_points(const Selection& selection, bool picking) cons
const sla::DrainHole& drain_hole = m_c->m_model_object->sla_drain_holes[i];
const bool& point_selected = m_selected[i];
if (is_mesh_point_clipped((drain_hole.pos+HoleStickOutLength*drain_hole.normal).cast<double>()))
if (is_mesh_point_clipped((drain_hole.pos+m_c->HoleStickOutLength*drain_hole.normal).cast<double>()))
continue;
// First decide about the color of the point.
@ -417,8 +427,8 @@ bool GLGizmoHollow::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_pos
pos_and_normal.second(1)/scaling(1),
pos_and_normal.second(2)/scaling(2));
m_c->m_model_object->sla_drain_holes.emplace_back(pos_and_normal.first + HoleStickOutLength * pos_and_normal.second/* normal_transformed.normalized()*/,
-pos_and_normal.second, m_new_hole_radius, m_new_hole_height+HoleStickOutLength);
m_c->m_model_object->sla_drain_holes.emplace_back(pos_and_normal.first + m_c->HoleStickOutLength * pos_and_normal.second/* normal_transformed.normalized()*/,
-pos_and_normal.second, m_new_hole_radius, m_new_hole_height);
m_selected.push_back(false);
assert(m_selected.size() == m_c->m_model_object->sla_drain_holes.size());
m_parent.set_as_dirty();
@ -507,7 +517,8 @@ bool GLGizmoHollow::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_pos
if (action == SLAGizmoEventType::MouseWheelUp && control_down) {
m_c->m_clipping_plane_distance = std::min(1.f, m_c->m_clipping_plane_distance + 0.01f);
update_clipping_plane(true);
update_clipping_plane(m_c->m_clipping_plane_was_moved);
m_c->m_clipping_plane_was_moved = true;
return true;
}
@ -545,7 +556,7 @@ void GLGizmoHollow::on_update(const UpdateData& data)
std::pair<Vec3f, Vec3f> pos_and_normal;
if (! unproject_on_mesh(data.mouse_pos.cast<double>(), pos_and_normal))
return;
m_c->m_model_object->sla_drain_holes[m_hover_id].pos = pos_and_normal.first + HoleStickOutLength * pos_and_normal.second;
m_c->m_model_object->sla_drain_holes[m_hover_id].pos = pos_and_normal.first + m_c->HoleStickOutLength * pos_and_normal.second;
m_c->m_model_object->sla_drain_holes[m_hover_id].normal = -pos_and_normal.second;
}
}
@ -697,9 +708,9 @@ void GLGizmoHollow::on_render_input_window(float x, float y, float bottom_limit)
double closing_d_max = opts[2].second->max;
ConfigOptionMode closing_d_mode = opts[2].second->mode;
m_desc["offset"] = _(opts[0].second->label).ToUTF8() + wxString(":");
m_desc["quality"] = _(opts[1].second->label).ToUTF8() + wxString(":");
m_desc["closing_distance"] = _(opts[2].second->label).ToUTF8() + wxString(":");
m_desc["offset"] = _(opts[0].second->label) + ":";
m_desc["quality"] = _(opts[1].second->label) + ":";
m_desc["closing_distance"] = _(opts[2].second->label) + ":";
RENDER_AGAIN:
@ -743,14 +754,16 @@ RENDER_AGAIN:
}
m_imgui->disabled_begin(! m_enable_hollowing);
float max_tooltip_width = ImGui::GetFontSize() * 20.0f;
m_imgui->text(m_desc.at("offset"));
ImGui::SameLine(settings_sliders_left);
ImGui::PushItemWidth(window_width - settings_sliders_left);
ImGui::SliderFloat(" ", &offset, offset_min, offset_max, "%.1f");
ImGui::SliderFloat(" ", &offset, offset_min, offset_max, "%.1f mm");
if (ImGui::IsItemHovered()) {
ImGui::BeginTooltip();
ImGui::TextUnformatted(_(opts[0].second->tooltip).ToUTF8());
ImGui::PushTextWrapPos(max_tooltip_width);
ImGui::TextUnformatted((_utf8(opts[0].second->tooltip)).c_str());
ImGui::PopTextWrapPos();
ImGui::EndTooltip();
}
bool slider_clicked = ImGui::IsItemClicked(); // someone clicked the slider
@ -763,7 +776,9 @@ RENDER_AGAIN:
ImGui::SliderFloat(" ", &quality, quality_min, quality_max, "%.1f");
if (ImGui::IsItemHovered()) {
ImGui::BeginTooltip();
ImGui::TextUnformatted(_(opts[1].second->tooltip).ToUTF8());
ImGui::PushTextWrapPos(max_tooltip_width);
ImGui::TextUnformatted((_utf8(opts[1].second->tooltip)).c_str());
ImGui::PopTextWrapPos();
ImGui::EndTooltip();
}
slider_clicked |= ImGui::IsItemClicked();
@ -774,10 +789,12 @@ RENDER_AGAIN:
if (current_mode >= closing_d_mode) {
m_imgui->text(m_desc.at("closing_distance"));
ImGui::SameLine(settings_sliders_left);
ImGui::SliderFloat(" ", &closing_d, closing_d_min, closing_d_max, "%.1f");
ImGui::SliderFloat(" ", &closing_d, closing_d_min, closing_d_max, "%.1f mm");
if (ImGui::IsItemHovered()) {
ImGui::BeginTooltip();
ImGui::TextUnformatted(_(opts[2].second->tooltip).ToUTF8());
ImGui::PushTextWrapPos(max_tooltip_width);
ImGui::TextUnformatted((_utf8(opts[2].second->tooltip)).c_str());
ImGui::PopTextWrapPos();
ImGui::EndTooltip();
}
slider_clicked |= ImGui::IsItemClicked();
@ -823,7 +840,7 @@ RENDER_AGAIN:
ImGui::PushItemWidth(window_width - diameter_slider_left);
float diam = 2.f * m_new_hole_radius;
ImGui::SliderFloat("", &diam, 1.f, diameter_upper_cap, "%.1f");
ImGui::SliderFloat("", &diam, 1.f, diameter_upper_cap, "%.1f mm");
m_new_hole_radius = diam / 2.f;
bool clicked = ImGui::IsItemClicked();
bool edited = ImGui::IsItemEdited();
@ -831,9 +848,9 @@ RENDER_AGAIN:
m_imgui->text(m_desc["hole_depth"]);
ImGui::SameLine(diameter_slider_left);
m_new_hole_height -= HoleStickOutLength;
ImGui::SliderFloat(" ", &m_new_hole_height, 0.f, 10.f, "%.1f");
m_new_hole_height += HoleStickOutLength;
m_new_hole_height -= m_c->HoleStickOutLength;
ImGui::SliderFloat(" ", &m_new_hole_height, 0.f, 10.f, "%.1f mm");
m_new_hole_height += m_c->HoleStickOutLength;
clicked |= ImGui::IsItemClicked();
edited |= ImGui::IsItemEdited();
@ -897,8 +914,10 @@ RENDER_AGAIN:
ImGui::SameLine(clipping_slider_left);
ImGui::PushItemWidth(window_width - clipping_slider_left);
if (ImGui::SliderFloat(" ", &m_c->m_clipping_plane_distance, 0.f, 1.f, "%.2f"))
update_clipping_plane(true);
if (ImGui::SliderFloat(" ", &m_c->m_clipping_plane_distance, 0.f, 1.f, "%.2f")) {
update_clipping_plane(m_c->m_clipping_plane_was_moved);
m_c->m_clipping_plane_was_moved = true;
}
// make sure supports are shown/hidden as appropriate
if (m_imgui->checkbox(m_desc["show_supports"], m_show_supports)) {
@ -981,7 +1000,9 @@ void GLGizmoHollow::on_set_state()
//Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("SLA gizmo turned on")));
//m_c->update_from_backend(m_parent, m_c->m_model_object);
m_c->unstash_clipping_plane();
update_clipping_plane(m_c->m_clipping_plane_distance != 0.f);
update_clipping_plane(m_c->m_clipping_plane_was_moved);
m_c->build_AABB_if_needed();
// we'll now reload support points:
if (m_c->m_model_object)
@ -1082,7 +1103,7 @@ void GLGizmoHollow::select_point(int i)
if (i == AllPoints) {
m_new_hole_radius = m_c->m_model_object->sla_drain_holes[0].radius;
m_new_hole_height = m_c->m_model_object->sla_drain_holes[0].height - HoleStickOutLength;
m_new_hole_height = m_c->m_model_object->sla_drain_holes[0].height;
}
}
else {
@ -1091,7 +1112,7 @@ void GLGizmoHollow::select_point(int i)
m_selected[i] = true;
m_selection_empty = false;
m_new_hole_radius = m_c->m_model_object->sla_drain_holes[i].radius;
m_new_hole_height = m_c->m_model_object->sla_drain_holes[i].height - HoleStickOutLength;
m_new_hole_height = m_c->m_model_object->sla_drain_holes[i].height;
}
}
@ -1128,6 +1149,13 @@ void GLGizmoHollow::update_clipping_plane(bool keep_normal) const
}
void GLGizmoHollow::on_set_hover_id()
{
if (int(m_c->m_model_object->sla_drain_holes.size()) <= m_hover_id)
m_hover_id = -1;
}
} // namespace GUI

View file

@ -16,6 +16,7 @@ namespace GUI {
class ClippingPlane;
class MeshClipper;
class MeshRaycaster;
class CommonGizmosData;
enum class SLAGizmoEventType : unsigned char;
class GLGizmoHollow : public GLGizmoBase
@ -24,13 +25,11 @@ private:
mutable double m_z_shift = 0.;
bool unproject_on_mesh(const Vec2d& mouse_pos, std::pair<Vec3f, Vec3f>& pos_and_normal);
const float HoleStickOutLength = 1.f;
GLUquadricObj* m_quadric;
public:
GLGizmoHollow(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id, CommonGizmosData* cd);
GLGizmoHollow(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id);
~GLGizmoHollow() override;
void set_sla_support_data(ModelObject* model_object, const Selection& selection);
bool gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down, bool alt_down, bool control_down);
@ -44,6 +43,7 @@ public:
bool is_selection_rectangle_dragging() const { return m_selection_rectangle.is_dragging(); }
void update_clipping_plane(bool keep_normal = false) const;
void set_common_data_ptr(CommonGizmosData* ptr) { m_c = ptr; }
private:
bool on_init() override;
@ -74,6 +74,8 @@ private:
sla::DrainHoles m_holes_stash;
CommonGizmosData* m_c = nullptr;
//std::unique_ptr<ClippingPlane> m_clipping_plane;
// This map holds all translated description texts, so they can be easily referenced during layout calculations
@ -101,12 +103,7 @@ private:
protected:
void on_set_state() override;
void on_set_hover_id() override
{
if (int(m_c->m_model_object->sla_drain_holes.size()) <= m_hover_id)
m_hover_id = -1;
}
void on_set_hover_id() override;
void on_start_dragging() override;
void on_stop_dragging() override;
void on_render_input_window(float x, float y, float bottom_limit) override;

View file

@ -22,12 +22,11 @@
namespace Slic3r {
namespace GUI {
GLGizmoSlaSupports::GLGizmoSlaSupports(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id, CommonGizmosData* cd)
: GLGizmoBase(parent, icon_filename, sprite_id, cd)
GLGizmoSlaSupports::GLGizmoSlaSupports(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id)
: GLGizmoBase(parent, icon_filename, sprite_id)
, m_quadric(nullptr)
, m_its(nullptr)
{
m_c->m_clipping_plane.reset(new ClippingPlane(Vec3d::Zero(), 0.));
{
m_quadric = ::gluNewQuadric();
if (m_quadric != nullptr)
// using GLU_FILL does not work when the instance's transformation
@ -64,19 +63,22 @@ bool GLGizmoSlaSupports::on_init()
void GLGizmoSlaSupports::set_sla_support_data(ModelObject* model_object, const Selection& selection)
{
if (m_c->recent_update) {
if (m_state == On) {
m_parent.toggle_model_objects_visibility(false);
m_parent.toggle_model_objects_visibility(/*! m_c->m_cavity_mesh*/ true, m_c->m_model_object, m_c->m_active_instance);
m_parent.toggle_sla_auxiliaries_visibility(! m_editing_mode, m_c->m_model_object, m_c->m_active_instance);
}
else
m_parent.toggle_model_objects_visibility(true, nullptr, -1);
if (m_state == On)
m_c->build_AABB_if_needed();
update_clipping_plane(m_c->m_clipping_plane_was_moved);
disable_editing_mode();
if (m_c->m_model_object)
reload_cache();
}
if (m_state == On) {
m_parent.toggle_model_objects_visibility(false);
m_parent.toggle_model_objects_visibility(true, m_c->m_model_object, m_c->m_active_instance);
m_parent.toggle_sla_auxiliaries_visibility(! m_editing_mode, m_c->m_model_object, m_c->m_active_instance);
}
// If we triggered autogeneration before, check backend and fetch results if they are there
if (m_c->m_model_object) {
if (m_c->m_model_object->sla_points_status == sla::PointsStatus::Generating)
@ -342,6 +344,9 @@ void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking)
render_color[3] = 0.7f;
glsafe(::glColor4fv(render_color));
for (const sla::DrainHole& drain_hole : m_c->m_model_object->sla_drain_holes) {
if (is_mesh_point_clipped((drain_hole.pos+m_c->HoleStickOutLength*drain_hole.normal).cast<double>()))
continue;
// Inverse matrix of the instance scaling is applied so that the mark does not scale with the object.
glsafe(::glPushMatrix());
glsafe(::glTranslatef(drain_hole.pos(0), drain_hole.pos(1), drain_hole.pos(2)));
@ -587,7 +592,8 @@ bool GLGizmoSlaSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
if (action == SLAGizmoEventType::MouseWheelUp && control_down) {
m_c->m_clipping_plane_distance = std::min(1.f, m_c->m_clipping_plane_distance + 0.01f);
update_clipping_plane(true);
update_clipping_plane(m_c->m_clipping_plane_was_moved);
m_c->m_clipping_plane_was_moved = true;
return true;
}
@ -913,8 +919,10 @@ RENDER_AGAIN:
ImGui::SameLine(clipping_slider_left);
ImGui::PushItemWidth(window_width - clipping_slider_left);
if (ImGui::SliderFloat(" ", &m_c->m_clipping_plane_distance, 0.f, 1.f, "%.2f"))
update_clipping_plane(true);
if (ImGui::SliderFloat(" ", &m_c->m_clipping_plane_distance, 0.f, 1.f, "%.2f")) {
update_clipping_plane(m_c->m_clipping_plane_was_moved);
m_c->m_clipping_plane_was_moved = true;
}
if (m_imgui->button("?")) {
@ -999,7 +1007,9 @@ void GLGizmoSlaSupports::on_set_state()
Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("SLA gizmo turned on")));
m_c->unstash_clipping_plane();
update_clipping_plane(m_c->m_clipping_plane_distance != 0.f);
update_clipping_plane(m_c->m_clipping_plane_was_moved);
m_c->build_AABB_if_needed();
// we'll now reload support points:
@ -1007,9 +1017,10 @@ void GLGizmoSlaSupports::on_set_state()
reload_cache();
m_parent.toggle_model_objects_visibility(false);
if (m_c->m_model_object /*&& ! m_c->m_cavity_mesh*/)
if (m_c->m_model_object) {
m_parent.toggle_model_objects_visibility(true, m_c->m_model_object, m_c->m_active_instance);
m_parent.toggle_sla_auxiliaries_visibility(! m_editing_mode, m_c->m_model_object, m_c->m_active_instance);
m_parent.toggle_sla_auxiliaries_visibility(! m_editing_mode, m_c->m_model_object, m_c->m_active_instance);
}
// Set default head diameter from config.
const DynamicPrintConfig& cfg = wxGetApp().preset_bundle->sla_prints.get_edited_preset().config;

View file

@ -16,6 +16,7 @@ namespace GUI {
class ClippingPlane;
class MeshClipper;
class MeshRaycaster;
class CommonGizmosData;
enum class SLAGizmoEventType : unsigned char;
class GLGizmoSlaSupports : public GLGizmoBase
@ -69,7 +70,7 @@ private:
};
public:
GLGizmoSlaSupports(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id, CommonGizmosData* cd);
GLGizmoSlaSupports(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id);
~GLGizmoSlaSupports() override;
void set_sla_support_data(ModelObject* model_object, const Selection& selection);
bool gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down, bool alt_down, bool control_down);
@ -81,6 +82,7 @@ public:
bool has_backend_supports() const;
void reslice_SLA_supports(bool postpone_error_messages = false) const;
void update_clipping_plane(bool keep_normal = false) const;
void set_common_data_ptr(CommonGizmosData* ptr) { m_c = ptr; }
private:
bool on_init() override;
@ -116,6 +118,8 @@ private:
bool m_selection_empty = true;
EState m_old_state = Off; // to be able to see that the gizmo has just been closed (see on_set_state)
CommonGizmosData* m_c = nullptr;
//mutable std::unique_ptr<MeshClipper> m_object_clipper;
//mutable std::unique_ptr<MeshClipper> m_supports_clipper;

View file

@ -6,6 +6,8 @@
#include "slic3r/GUI/GUI_ObjectManipulation.hpp"
#include "slic3r/GUI/PresetBundle.hpp"
#include "slic3r/Utils/UndoRedo.hpp"
#include "libslic3r/SLAPrint.hpp"
#include "slic3r/GUI/MeshUtils.hpp"
#include <GL/glew.h>
#include <wx/glcanvas.h>
@ -83,16 +85,18 @@ bool GLGizmosManager::init()
return false;
}
m_common_gizmos_data.reset(new CommonGizmosData());
// Order of gizmos in the vector must match order in EType!
m_gizmos.emplace_back(new GLGizmoMove3D(m_parent, "move.svg", 0));
m_gizmos.emplace_back(new GLGizmoScale3D(m_parent, "scale.svg", 1));
m_gizmos.emplace_back(new GLGizmoRotate3D(m_parent, "rotate.svg", 2));
m_gizmos.emplace_back(new GLGizmoFlatten(m_parent, "place.svg", 3));
m_gizmos.emplace_back(new GLGizmoCut(m_parent, "cut.svg", 4));
m_gizmos.emplace_back(new GLGizmoHollow(m_parent, "hollow.svg", 5, m_common_gizmos_data.get()));
m_gizmos.emplace_back(new GLGizmoSlaSupports(m_parent, "sla_supports.svg", 6, m_common_gizmos_data.get()));
m_gizmos.emplace_back(new GLGizmoHollow(m_parent, "hollow.svg", 5));
m_gizmos.emplace_back(new GLGizmoSlaSupports(m_parent, "sla_supports.svg", 6));
m_common_gizmos_data.reset(new CommonGizmosData());
dynamic_cast<GLGizmoHollow*>(m_gizmos[Hollow].get())->set_common_data_ptr(m_common_gizmos_data.get());
dynamic_cast<GLGizmoSlaSupports*>(m_gizmos[SlaSupports].get())->set_common_data_ptr(m_common_gizmos_data.get());
for (auto& gizmo : m_gizmos) {
if (! gizmo->init()) {
@ -345,25 +349,18 @@ void GLGizmosManager::set_flattening_data(const ModelObject* model_object)
void GLGizmosManager::set_sla_support_data(ModelObject* model_object)
{
if (!m_enabled || m_gizmos.empty())
if (! m_enabled
|| m_gizmos.empty()
|| wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() != ptSLA)
return;
m_common_gizmos_data->update_from_backend(m_parent, model_object);
auto* gizmo_supports = dynamic_cast<GLGizmoSlaSupports*>(m_gizmos[SlaSupports].get());
auto* gizmo_hollow = dynamic_cast<GLGizmoHollow*>(m_gizmos[Hollow].get());
// Update common data for hollowing and sla support gizmos.
if (wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() == ptSLA) {
if (m_common_gizmos_data->update_from_backend(m_parent, model_object)) {
// FIXME: this is a hack to make that the clipping plane is
// updated when the update set its position to zero. The clipping
// plane itself should be common, including the update_function.
// Then update_from_backend could do it itself.
gizmo_supports->update_clipping_plane();
gizmo_hollow->update_clipping_plane();
}
}
// note: sla support gizmo takes care of updating the common data.
// following lines are thus dependent
gizmo_supports->set_sla_support_data(model_object, m_parent.get_selection());
gizmo_hollow->set_sla_support_data(model_object, m_parent.get_selection());
}
@ -1058,5 +1055,135 @@ bool GLGizmosManager::grabber_contains_mouse() const
return (curr != nullptr) ? (curr->get_hover_id() != -1) : false;
}
CommonGizmosData::CommonGizmosData()
{
m_clipping_plane.reset(new ClippingPlane(Vec3d::Zero(), 0.));
}
bool CommonGizmosData::update_from_backend(GLCanvas3D& canvas, ModelObject* model_object)
{
recent_update = false;
bool object_changed = false;
if (m_model_object != model_object
|| (model_object && m_model_object_id != model_object->id())) {
m_model_object = model_object;
m_print_object_idx = -1;
m_mesh_raycaster.reset();
m_object_clipper.reset();
m_supports_clipper.reset();
m_old_mesh = nullptr;
m_mesh = nullptr;
m_backend_mesh_transformed.clear();
object_changed = true;
recent_update = true;
}
if (m_model_object) {
int active_inst = canvas.get_selection().get_instance_idx();
if (m_active_instance != active_inst) {
m_active_instance = active_inst;
m_active_instance_bb_radius = m_model_object->instance_bounding_box(m_active_instance).radius();
recent_update = true;
}
}
if (! m_model_object || ! canvas.get_selection().is_from_single_instance())
return false;
int old_po_idx = m_print_object_idx;
// First we need a pointer to the respective SLAPrintObject. The index into objects vector is
// cached so we don't have todo it on each render. We only search for the po if needed:
if (m_print_object_idx < 0 || (int)canvas.sla_print()->objects().size() != m_print_objects_count) {
m_print_objects_count = canvas.sla_print()->objects().size();
m_print_object_idx = -1;
for (const SLAPrintObject* po : canvas.sla_print()->objects()) {
++m_print_object_idx;
if (po->model_object()->id() == m_model_object->id())
break;
}
}
bool mesh_exchanged = false;
m_mesh = nullptr;
// Load either the model_object mesh, or one provided by the backend
// This mesh does not account for the possible Z up SLA offset.
// The backend mesh needs to be transformed and because a pointer to it is
// saved, a copy is stored as a member (FIXME)
if (m_print_object_idx >=0) {
const SLAPrintObject* po = canvas.sla_print()->objects()[m_print_object_idx];
if (po->is_step_done(slaposDrillHoles)) {
m_backend_mesh_transformed = po->get_mesh_to_print();
m_backend_mesh_transformed.transform(canvas.sla_print()->sla_trafo(*m_model_object).inverse());
m_mesh = &m_backend_mesh_transformed;
m_has_drilled_mesh = true;
mesh_exchanged = true;
}
}
if (! m_mesh) {
m_mesh = &m_model_object->volumes.front()->mesh();
m_backend_mesh_transformed.clear();
m_has_drilled_mesh = false;
}
m_model_object_id = m_model_object->id();
if (m_mesh != m_old_mesh) {
// Update clipping plane position.
float new_clp_pos = m_clipping_plane_distance;
if (object_changed) {
new_clp_pos = 0.f;
m_clipping_plane_was_moved = false;
} else {
// After we got a drilled mesh, move the cp to 25%. This only applies when
// the hollowing gizmo is active and hollowing is enabled
if (m_clipping_plane_distance == 0.f && mesh_exchanged && m_has_drilled_mesh) {
const DynamicPrintConfig& cfg =
(m_model_object && m_model_object->config.has("hollowing_enable"))
? m_model_object->config
: wxGetApp().preset_bundle->sla_prints.get_edited_preset().config;
if (cfg.has("hollowing_enable") && cfg.opt_bool("hollowing_enable")
&& canvas.get_gizmos_manager().get_current_type() == GLGizmosManager::Hollow) {
new_clp_pos = 0.25f;
m_clipping_plane_was_moved = false; // so it uses current camera direction
}
}
}
m_clipping_plane_distance = new_clp_pos;
m_clipping_plane_distance_stash = new_clp_pos;
m_schedule_aabb_calculation = true;
recent_update = true;
return true;
}
if (! recent_update)
recent_update = m_print_object_idx < 0 && old_po_idx >= 0;
return recent_update;
}
void CommonGizmosData::build_AABB_if_needed()
{
if (! m_schedule_aabb_calculation)
return;
wxBusyCursor wait;
m_mesh_raycaster.reset(new MeshRaycaster(*m_mesh));
m_object_clipper.reset();
m_supports_clipper.reset();
m_old_mesh = m_mesh;
m_schedule_aabb_calculation = false;
}
} // namespace GUI
} // namespace Slic3r

View file

@ -227,6 +227,65 @@ private:
bool grabber_contains_mouse() const;
};
class MeshRaycaster;
class MeshClipper;
// This class is only for sharing SLA related data between SLA gizmos
// and its synchronization with backend data. It should not be misused
// for anything else.
class CommonGizmosData {
public:
CommonGizmosData();
const TriangleMesh* mesh() const {
return (! m_mesh ? nullptr : m_mesh); //(m_cavity_mesh ? m_cavity_mesh.get() : m_mesh));
}
bool update_from_backend(GLCanvas3D& canvas, ModelObject* model_object);
bool recent_update = false;
static constexpr float HoleStickOutLength = 1.f;
ModelObject* m_model_object = nullptr;
const TriangleMesh* m_mesh;
std::unique_ptr<MeshRaycaster> m_mesh_raycaster;
std::unique_ptr<MeshClipper> m_object_clipper;
std::unique_ptr<MeshClipper> m_supports_clipper;
//std::unique_ptr<TriangleMesh> m_cavity_mesh;
//std::unique_ptr<GLVolume> m_volume_with_cavity;
int m_active_instance = -1;
float m_active_instance_bb_radius = 0;
ObjectID m_model_object_id = 0;
int m_print_object_idx = -1;
int m_print_objects_count = -1;
int m_old_timestamp = -1;
float m_clipping_plane_distance = 0.f;
std::unique_ptr<ClippingPlane> m_clipping_plane;
bool m_clipping_plane_was_moved = false;
void stash_clipping_plane() {
m_clipping_plane_distance_stash = m_clipping_plane_distance;
}
void unstash_clipping_plane() {
m_clipping_plane_distance = m_clipping_plane_distance_stash;
}
bool has_drilled_mesh() const { return m_has_drilled_mesh; }
void build_AABB_if_needed();
private:
const TriangleMesh* m_old_mesh;
TriangleMesh m_backend_mesh_transformed;
float m_clipping_plane_distance_stash = 0.f;
bool m_has_drilled_mesh = false;
bool m_schedule_aabb_calculation = false;
};
} // namespace GUI
} // namespace Slic3r

View file

@ -40,21 +40,25 @@ namespace I18N {
inline wxString translate(const wchar_t *s) { return wxGetTranslation(s); }
inline wxString translate(const std::string &s) { return wxGetTranslation(wxString(s.c_str(), wxConvUTF8)); }
inline wxString translate(const std::wstring &s) { return wxGetTranslation(s.c_str()); }
inline wxString translate(const wxString &s) { return wxGetTranslation(s); }
inline wxString translate(const char *s, const char *plural, unsigned int n) { return wxGetTranslation(wxString(s, wxConvUTF8), wxString(plural, wxConvUTF8), n); }
inline wxString translate(const wchar_t *s, const wchar_t *plural, unsigned int n) { return wxGetTranslation(s, plural, n); }
inline wxString translate(const std::string &s, const std::string &plural, unsigned int n) { return wxGetTranslation(wxString(s.c_str(), wxConvUTF8), wxString(plural.c_str(), wxConvUTF8), n); }
inline wxString translate(const std::wstring &s, const std::wstring &plural, unsigned int n) { return wxGetTranslation(s.c_str(), plural.c_str(), n); }
inline wxString translate(const wxString &s, const wxString &plural, unsigned int n) { return wxGetTranslation(s, plural, n); }
inline std::string translate_utf8(const char *s) { return wxGetTranslation(wxString(s, wxConvUTF8)).ToUTF8().data(); }
inline std::string translate_utf8(const wchar_t *s) { return wxGetTranslation(s).ToUTF8().data(); }
inline std::string translate_utf8(const std::string &s) { return wxGetTranslation(wxString(s.c_str(), wxConvUTF8)).ToUTF8().data(); }
inline std::string translate_utf8(const std::wstring &s) { return wxGetTranslation(s.c_str()).ToUTF8().data(); }
inline std::string translate_utf8(const wxString &s) { return wxGetTranslation(s).ToUTF8().data(); }
inline std::string translate_utf8(const char *s, const char *plural, unsigned int n) { return translate(s, plural, n).ToUTF8().data(); }
inline std::string translate_utf8(const wchar_t *s, const wchar_t *plural, unsigned int n) { return translate(s, plural, n).ToUTF8().data(); }
inline std::string translate_utf8(const std::string &s, const std::string &plural, unsigned int n) { return translate(s, plural, n).ToUTF8().data(); }
inline std::string translate_utf8(const std::wstring &s, const std::wstring &plural, unsigned int n) { return translate(s, plural, n).ToUTF8().data(); }
inline std::string translate_utf8(const wxString &s, const wxString &plural, unsigned int n) { return translate(s, plural, n).ToUTF8().data(); }
#if wxCHECK_VERSION(3, 1, 1)
#define _wxGetTranslation_ctx(S, CTX) wxGetTranslation((S), wxEmptyString, (CTX))
@ -66,11 +70,13 @@ namespace I18N {
inline wxString translate(const wchar_t *s, const char* ctx) { return _wxGetTranslation_ctx(s, ctx); }
inline wxString translate(const std::string &s, const char* ctx) { return _wxGetTranslation_ctx(wxString(s.c_str(), wxConvUTF8), ctx); }
inline wxString translate(const std::wstring &s, const char* ctx) { return _wxGetTranslation_ctx(s.c_str(), ctx); }
inline wxString translate(const wxString &s, const char* ctx) { return _wxGetTranslation_ctx(s, ctx); }
inline wxString translate_utf8(const char *s, const char* ctx) { return _wxGetTranslation_ctx(wxString(s, wxConvUTF8), ctx).ToUTF8().data(); }
inline wxString translate_utf8(const wchar_t *s, const char* ctx) { return _wxGetTranslation_ctx(s, ctx).ToUTF8().data(); }
inline wxString translate_utf8(const std::string &s, const char* ctx) { return _wxGetTranslation_ctx(wxString(s.c_str(), wxConvUTF8), ctx).ToUTF8().data(); }
inline wxString translate_utf8(const std::wstring &s, const char* ctx) { return _wxGetTranslation_ctx(s.c_str(), ctx).ToUTF8().data(); }
inline std::string translate_utf8(const char *s, const char* ctx) { return _wxGetTranslation_ctx(wxString(s, wxConvUTF8), ctx).ToUTF8().data(); }
inline std::string translate_utf8(const wchar_t *s, const char* ctx) { return _wxGetTranslation_ctx(s, ctx).ToUTF8().data(); }
inline std::string translate_utf8(const std::string &s, const char* ctx) { return _wxGetTranslation_ctx(wxString(s.c_str(), wxConvUTF8), ctx).ToUTF8().data(); }
inline std::string translate_utf8(const std::wstring &s, const char* ctx) { return _wxGetTranslation_ctx(s.c_str(), ctx).ToUTF8().data(); }
inline std::string translate_utf8(const wxString &s, const char* ctx) { return _wxGetTranslation_ctx(s, ctx).ToUTF8().data(); }
#undef _wxGetTranslation_ctx
} // namespace I18N

View file

@ -286,6 +286,12 @@ bool ImGuiWrapper::input_double(const std::string &label, const double &value, c
return ImGui::InputDouble(label.c_str(), const_cast<double*>(&value), 0.0f, 0.0f, format.c_str());
}
bool ImGuiWrapper::input_double(const wxString &label, const double &value, const std::string &format)
{
auto label_utf8 = into_u8(label);
return input_double(label_utf8, value, format);
}
bool ImGuiWrapper::input_vec3(const std::string &label, const Vec3d &value, float width, const std::string &format)
{
bool value_changed = false;

View file

@ -63,6 +63,7 @@ public:
bool button(const wxString &label);
bool radio_button(const wxString &label, bool active);
bool input_double(const std::string &label, const double &value, const std::string &format = "%.3f");
bool input_double(const wxString &label, const double &value, const std::string &format = "%.3f");
bool input_vec3(const std::string &label, const Vec3d &value, float width, const std::string &format = "%.3f");
bool checkbox(const wxString &label, bool &value);
void text(const char *label);

View file

@ -158,7 +158,7 @@ void KBShortcutsDialog::fill_shortcuts()
{ "Shift+A", L("Arrange selection") },
{ "+", L("Add Instance of the selected object") },
{ "-", L("Remove Instance of the selected object") },
{ ctrl, L("Press to select multiple object\nor move multiple object with mouse") },
{ ctrl, L("Press to select multiple objects\nor move multiple objects with mouse") },
{ "Shift+", L("Press to activate selection rectangle") },
{ alt, L("Press to activate deselection rectangle") },
{ L("Arrow Up"), L("Move selection 10 mm in positive Y direction") },
@ -192,7 +192,7 @@ void KBShortcutsDialog::fill_shortcuts()
m_full_shortcuts.push_back(std::make_pair(_(L("Plater")), plater_shortcuts));
Shortcuts gizmos_shortcuts = {
{ "Shift+", L("Press to to snap by 5% in Gizmo scale\nor to snap by 1mm in Gizmo move") },
{ "Shift+", L("Press to snap by 5% in Gizmo scale\nor to snap by 1mm in Gizmo move") },
{ "F", L("Scale selection to fit print volume\nin Gizmo scale") },
{ ctrl, L("Press to activate one direction scaling in Gizmo scale") },
{ alt, L("Press to scale (in Gizmo scale) or rotate (in Gizmo rotate)\nselected objects around their own center") },

View file

@ -143,6 +143,9 @@ DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_S
wxGetApp().persist_window_geometry(this, true);
update_ui_from_settings(); // FIXME (?)
if (m_plater != nullptr)
m_plater->show_action_buttons(true);
}
void MainFrame::update_title()
@ -419,18 +422,19 @@ void MainFrame::init_menubar()
m_plater->load_project(filename);
else
{
wxMessageDialog msg(this, _(L("The selected project is no more available")), _(L("Error")));
msg.ShowModal();
m_recent_projects.RemoveFileFromHistory(file_id);
std::vector<std::string> recent_projects;
size_t count = m_recent_projects.GetCount();
for (size_t i = 0; i < count; ++i)
wxMessageDialog msg(this, _(L("The selected project is no longer available.\nDo you want to remove it from the recent projects list ?")), _(L("Error")), wxYES_NO | wxYES_DEFAULT);
if (msg.ShowModal() == wxID_YES)
{
recent_projects.push_back(into_u8(m_recent_projects.GetHistoryFile(i)));
m_recent_projects.RemoveFileFromHistory(file_id);
std::vector<std::string> recent_projects;
size_t count = m_recent_projects.GetCount();
for (size_t i = 0; i < count; ++i)
{
recent_projects.push_back(into_u8(m_recent_projects.GetHistoryFile(i)));
}
wxGetApp().app_config->set_recent_projects(recent_projects);
wxGetApp().app_config->save();
}
wxGetApp().app_config->set_recent_projects(recent_projects);
wxGetApp().app_config->save();
}
}, wxID_FILE1, wxID_FILE9);
@ -1148,11 +1152,12 @@ void MainFrame::add_to_recent_projects(const wxString& filename)
// Update the UI based on the current preferences.
void MainFrame::update_ui_from_settings()
{
const bool bp_on = wxGetApp().app_config->get("background_processing") == "1";
// const bool bp_on = wxGetApp().app_config->get("background_processing") == "1";
// m_menu_item_reslice_now->Enable(!bp_on);
m_plater->sidebar().show_reslice(!bp_on);
m_plater->sidebar().show_export(bp_on);
m_plater->sidebar().Layout();
// m_plater->sidebar().show_reslice(!bp_on);
// m_plater->sidebar().show_export(bp_on);
// m_plater->sidebar().Layout();
if (m_plater)
m_plater->update_ui_from_settings();
for (auto tab: wxGetApp().tabs_list)

View file

@ -162,8 +162,8 @@ bool Mouse3DController::State::apply(Camera& camera)
if (has_rotation())
{
Vec3d rotation = (m_rotation_params.scale * m_rotation.queue.front()).cast<double>();
camera.rotate_local_around_target(Vec3d(Geometry::deg2rad(rotation(0)), Geometry::deg2rad(-rotation(2)), Geometry::deg2rad(-rotation(1))));
Vec3d rot = (m_rotation_params.scale * m_rotation.queue.front()).cast<double>() * (PI / 180.);
camera.rotate_local_around_target(Vec3d(rot.x(), - rot.z(), rot.y()));
m_rotation.queue.pop();
ret = true;
}

View file

@ -1185,6 +1185,26 @@ void ObjectDataViewModel::SetExtruder(const wxString& extruder, wxDataViewItem i
SetValue(value, item, colExtruder);
}
void ObjectDataViewModel::AddAllChildren(const wxDataViewItem& parent)
{
ObjectDataViewModelNode* node = (ObjectDataViewModelNode*)parent.GetID();
if (!node || node->GetChildCount() == 0)
return;
wxDataViewItemArray array;
const size_t count = node->GetChildCount();
for (size_t pos = 0; pos < count; pos++) {
ObjectDataViewModelNode* child = node->GetChildren().Item(pos);
array.Add(wxDataViewItem((void*)child));
ItemAdded(parent, wxDataViewItem((void*)child));
}
for (const auto item : array)
AddAllChildren(item);
m_ctrl->Expand(parent);
};
wxDataViewItem ObjectDataViewModel::ReorganizeChildren( const int current_volume_id,
const int new_volume_id,
const wxDataViewItem &parent)
@ -1205,6 +1225,10 @@ wxDataViewItem ObjectDataViewModel::ReorganizeChildren( const int current_volume
node_parent->Insert(deleted_node, new_volume_id+shift);
ItemAdded(parent, wxDataViewItem(deleted_node));
// If some item has a children, just to add a deleted item is not enough on Linux
// We should to add all its children separately
AddAllChildren(wxDataViewItem(deleted_node));
//update volume_id value for child-nodes
auto children = node_parent->GetChildren();
int id_frst = current_volume_id < new_volume_id ? current_volume_id : new_volume_id;
@ -1227,6 +1251,10 @@ wxDataViewItem ObjectDataViewModel::ReorganizeObjects( const int current_id, co
m_objects.emplace(m_objects.begin() + new_id, deleted_node);
ItemAdded(wxDataViewItem(nullptr), wxDataViewItem(deleted_node));
// If some item has a children, just to add a deleted item is not enough on Linux
// We should to add all its children separately
AddAllChildren(wxDataViewItem(deleted_node));
return wxDataViewItem(deleted_node);
}

View file

@ -504,8 +504,9 @@ public:
void UpdateExtruderBitmap(wxDataViewItem item);
private:
wxDataViewItem AddRoot(const wxDataViewItem& parent_item, const ItemType root_type);
wxDataViewItem AddInstanceRoot(const wxDataViewItem& parent_item);
wxDataViewItem AddRoot(const wxDataViewItem& parent_item, const ItemType root_type);
wxDataViewItem AddInstanceRoot(const wxDataViewItem& parent_item);
void AddAllChildren(const wxDataViewItem& parent);
};

View file

@ -129,8 +129,14 @@ void OptionsGroup::append_line(const Line& line, wxStaticText** full_Label/* = n
m_options.emplace(opt.opt_id, opt);
// Set sidetext width for a better alignment of options in line
if (option_set.size() > 1)
// "m_show_modified_btns==true" means that options groups are in tabs
if (option_set.size() > 1 && m_show_modified_btns) {
sidetext_width = Field::def_width_thinner();
/* Temporary commented till UI-review will be completed
if (m_show_modified_btns) // means that options groups are in tabs
sublabel_width = Field::def_width();
*/
}
// add mode value for current line to m_options_mode
if (!option_set.empty())
@ -248,15 +254,16 @@ void OptionsGroup::append_line(const Line& line, wxStaticText** full_Label/* = n
ConfigOptionDef option = opt.opt;
wxSizer* sizer_tmp = sizer;
// add label if any
if (option.label != "") {
if (!option.label.empty()) {
//! To correct translation by context have to use wxGETTEXT_IN_CONTEXT macro from wxWidget 3.1.1
wxString str_label = (option.label == L_CONTEXT("Top", "Layers") || option.label == L_CONTEXT("Bottom", "Layers")) ?
_CTX(option.label, "Layers") :
_(option.label);
label = new wxStaticText(this->ctrl_parent(), wxID_ANY, str_label + ": ", wxDefaultPosition, wxDefaultSize);
label = new wxStaticText(this->ctrl_parent(), wxID_ANY, str_label + ": ", wxDefaultPosition, //wxDefaultSize);
wxSize(sublabel_width != -1 ? sublabel_width * wxGetApp().em_unit() : -1, -1), wxALIGN_RIGHT);
label->SetBackgroundStyle(wxBG_STYLE_PAINT);
label->SetFont(wxGetApp().normal_font());
sizer_tmp->Add(label, 0, /*wxALIGN_RIGHT |*/ wxALIGN_CENTER_VERTICAL, 0);
sizer_tmp->Add(label, 0, wxALIGN_CENTER_VERTICAL, 0);
}
// add field

View file

@ -97,6 +97,7 @@ public:
wxFont sidetext_font {wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT) };
wxFont label_font {wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT) };
int sidetext_width{ -1 };
int sublabel_width{ -1 };
/// Returns a copy of the pointer of the parent wxWindow.
/// Accessor function is because users are not allowed to change the parent

View file

@ -262,6 +262,11 @@ PresetBitmapComboBox(parent, wxSize(15 * wxGetApp().em_unit(), -1)),
m_em_unit(wxGetApp().em_unit())
{
SetFont(wxGetApp().normal_font());
#ifdef _WIN32
// Workaround for ignoring CBN_EDITCHANGE events, which are processed after the content of the combo box changes, so that
// the index of the item inside CBN_EDITCHANGE may no more be valid.
EnableTextChangedEvents(false);
#endif /* _WIN32 */
Bind(wxEVT_COMBOBOX, [this](wxCommandEvent &evt) {
auto selected_item = this->GetSelection();
@ -322,7 +327,7 @@ PresetBitmapComboBox(parent, wxSize(15 * wxGetApp().em_unit(), -1)),
dialog.CenterOnParent();
if (dialog.ShowModal() == wxID_OK)
{
colors->values[extruder_idx] = dialog.GetColourData().GetColour().GetAsString(wxC2S_HTML_SYNTAX);
colors->values[extruder_idx] = dialog.GetColourData().GetColour().GetAsString(wxC2S_HTML_SYNTAX).ToStdString();
DynamicPrintConfig cfg_new = *cfg;
cfg_new.set_key_value("extruder_colour", colors);
@ -870,8 +875,8 @@ Sidebar::Sidebar(Plater *parent)
(*btn)->Hide();
};
init_scalable_btn(&p->btn_send_gcode , "export_gcode", _(L("Send to printer")));
init_scalable_btn(&p->btn_remove_device, "cross" , _(L("Remove device")));
init_scalable_btn(&p->btn_send_gcode , "export_gcode", _(L("Send to printer")) + "\tCtrl+Shift+G");
init_scalable_btn(&p->btn_remove_device, "eject_sd" , _(L("Remove device")));
init_scalable_btn(&p->btn_export_gcode_removable, "export_to_sd", _(L("Export to SD card / Flash drive")));
// regular buttons "Slice now" and "Export G-code"
@ -1233,42 +1238,59 @@ void Sidebar::update_sliced_info_sizer()
p->sliced_info->SetTextAndShow(siFilament_m, info_text, new_label);
p->sliced_info->SetTextAndShow(siFilament_mm3, wxString::Format("%.2f", ps.total_extruded_volume));
p->sliced_info->SetTextAndShow(siFilament_g, wxString::Format("%.2f", ps.total_weight));
p->sliced_info->SetTextAndShow(siFilament_g, ps.total_weight == 0.0 ? "N/A" : wxString::Format("%.2f", ps.total_weight));
new_label = _(L("Cost"));
if (is_wipe_tower)
new_label += wxString::Format(" :\n - %s\n - %s", _(L("objects")), _(L("wipe tower")));
info_text = is_wipe_tower ?
info_text = ps.total_cost == 0.0 ? "N/A" :
is_wipe_tower ?
wxString::Format("%.2f \n%.2f \n%.2f", ps.total_cost,
(ps.total_cost - ps.total_wipe_tower_cost),
ps.total_wipe_tower_cost) :
wxString::Format("%.2f", ps.total_cost);
p->sliced_info->SetTextAndShow(siCost, info_text, new_label);
p->sliced_info->SetTextAndShow(siCost, info_text, new_label);
if (ps.estimated_normal_print_time == "N/A" && ps.estimated_silent_print_time == "N/A")
p->sliced_info->SetTextAndShow(siEstimatedTime, "N/A");
else {
new_label = _(L("Estimated printing time")) +" :";
info_text = "";
if (ps.estimated_normal_print_time != "N/A") {
new_label += wxString::Format("\n - %s", _(L("normal mode")));
info_text += wxString::Format("\n%s", ps.estimated_normal_print_time);
for (int i = (int)ps.estimated_normal_color_print_times.size() - 1; i >= 0; --i)
wxString str_color = _(L("Color"));
wxString str_pause = _(L("Pause"));
auto fill_labels = [str_color, str_pause](const std::vector<std::pair<CustomGcodeType, std::string>>& times,
wxString& new_label, wxString& info_text)
{
int color_change_count = 0;
for (auto time : times)
if (time.first == cgtColorChange)
color_change_count++;
for (int i = (int)times.size() - 1; i >= 0; --i)
{
new_label += wxString::Format("\n - %s%d", _(L("Color")) + " ", i + 1);
info_text += wxString::Format("\n%s", ps.estimated_normal_color_print_times[i]);
if (i == 0 || times[i - 1].first == cgtPausePrint)
new_label += wxString::Format("\n - %s%d", str_color + " ", color_change_count);
else if (times[i - 1].first == cgtColorChange)
new_label += wxString::Format("\n - %s%d", str_color + " ", color_change_count--);
if (i != (int)times.size() - 1 && times[i].first == cgtPausePrint)
new_label += wxString::Format(" -> %s", str_pause);
info_text += wxString::Format("\n%s", times[i].second);
}
};
if (ps.estimated_normal_print_time != "N/A") {
new_label += wxString::Format("\n - %s", _(L("normal mode")));
info_text += wxString::Format("\n%s", ps.estimated_normal_print_time);
fill_labels(ps.estimated_normal_custom_gcode_print_times, new_label, info_text);
}
if (ps.estimated_silent_print_time != "N/A") {
new_label += wxString::Format("\n - %s", _(L("stealth mode")));
new_label += wxString::Format("\n - %s", _(L("stealth mode")));
info_text += wxString::Format("\n%s", ps.estimated_silent_print_time);
for (int i = (int)ps.estimated_silent_color_print_times.size() - 1; i >= 0; --i)
{
new_label += wxString::Format("\n - %s%d", _(L("Color")) + " ", i + 1);
info_text += wxString::Format("\n%s", ps.estimated_silent_color_print_times[i]);
}
fill_labels(ps.estimated_silent_custom_gcode_print_times, new_label, info_text);
}
p->sliced_info->SetTextAndShow(siEstimatedTime, info_text, new_label);
}
@ -2248,7 +2270,7 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
auto *nozzle_dmrs = config->opt<ConfigOptionFloats>("nozzle_diameter");
bool one_by_one = input_files.size() == 1 || nozzle_dmrs->values.size() <= 1;
bool one_by_one = input_files.size() == 1 || printer_technology == ptSLA || nozzle_dmrs->values.size() <= 1;
if (! one_by_one) {
for (const auto &path : input_files) {
if (std::regex_match(path.string(), pattern_bundle)) {
@ -3067,10 +3089,10 @@ unsigned int Plater::priv::update_background_process(bool force_validation, bool
auto *top_level_wnd = dynamic_cast<wxTopLevelWindow*>(p);
if (! postpone_error_messages && top_level_wnd && top_level_wnd->IsActive()) {
// The error returned from the Print needs to be translated into the local language.
GUI::show_error(this->q, _(err));
GUI::show_error(this->q, err);
} else {
// Show the error message once the main window gets activated.
this->delayed_error_message = _(err);
this->delayed_error_message = err;
}
return_state |= UPDATE_BACKGROUND_PROCESS_INVALID;
}
@ -3260,7 +3282,7 @@ void Plater::priv::reload_from_disk()
else
missing_input_paths.push_back(volume->source.input_file);
}
else if (!object->input_file.empty() && !volume->name.empty())
else if (!object->input_file.empty() && volume->is_model_part() && !volume->name.empty())
missing_input_paths.push_back(volume->name);
}
@ -3324,7 +3346,7 @@ void Plater::priv::reload_from_disk()
const auto& path = input_paths[i].string();
wxBusyCursor wait;
wxBusyInfo info(_(L("Reload from: ")) + from_u8(path), q->get_current_canvas3D()->get_wxglcanvas());
wxBusyInfo info(_(L("Reload from:")) + " " + from_u8(path), q->get_current_canvas3D()->get_wxglcanvas());
Model new_model;
try
@ -4039,7 +4061,7 @@ bool Plater::priv::complit_init_part_menu()
part_menu.AppendSeparator();
auto obj_list = sidebar->obj_list();
obj_list->append_menu_item_change_type(&part_menu);
obj_list->append_menu_item_change_type(&part_menu, q);
return true;
}
@ -4736,8 +4758,8 @@ void Plater::set_number_of_copies(/*size_t num*/)
ModelObject* model_object = p->model.objects[obj_idx];
const int num = wxGetNumberFromUser( " ", _("Enter the number of copies:"),
_("Copies of the selected object"), model_object->instances.size(), 0, 1000, this );
const int num = wxGetNumberFromUser( " ", _(L("Enter the number of copies:")),
_(L("Copies of the selected object")), model_object->instances.size(), 0, 1000, this );
if (num < 0)
return;
@ -5187,8 +5209,10 @@ void Plater::drive_ejected_callback()
if (RemovableDriveManager::get_instance().get_did_eject())
{
RemovableDriveManager::get_instance().set_did_eject(false);
wxString message = "Unmounting successful. The device " + RemovableDriveManager::get_instance().get_ejected_name() + "(" + RemovableDriveManager::get_instance().get_ejected_path() + ")" + " can now be safely removed from the computer.";
wxMessageBox(message);
show_info(this,
(boost::format(_utf8(L("Unmounting successful. The device %s(%s) can now be safely removed from the computer.")))
% RemovableDriveManager::get_instance().get_ejected_name()
% RemovableDriveManager::get_instance().get_ejected_path()).str());
}
p->show_action_buttons(false);
}
@ -5337,11 +5361,6 @@ void Plater::on_config_change(const DynamicPrintConfig &config)
}
}
{
const auto prin_host_opt = p->config->option<ConfigOptionString>("print_host");
p->sidebar->show_send(prin_host_opt != nullptr && !prin_host_opt->value.empty());
}
if (bed_shape_changed)
p->set_bed_shape(p->config->option<ConfigOptionPoints>("bed_shape")->values,
p->config->option<ConfigOptionString>("bed_custom_texture")->value,
@ -5581,6 +5600,7 @@ void Plater::suppress_background_process(const bool stop_background_process)
void Plater::fix_through_netfabb(const int obj_idx, const int vol_idx/* = -1*/) { p->fix_through_netfabb(obj_idx, vol_idx); }
void Plater::update_object_menu() { p->update_object_menu(); }
void Plater::show_action_buttons(const bool is_ready_to_slice) const { p->show_action_buttons(is_ready_to_slice); }
void Plater::copy_selection_to_clipboard()
{

View file

@ -239,6 +239,7 @@ public:
std::vector<std::string> get_colors_for_color_print() const;
void update_object_menu();
void show_action_buttons(const bool is_ready_to_slice) const;
wxString get_project_filename(const wxString& extension = wxEmptyString) const;
void set_project_filename(const wxString& filename);

View file

@ -313,9 +313,9 @@ std::string Preset::label() const
return this->name + (this->is_dirty ? g_suffix_modified : "");
}
bool is_compatible_with_print(const PresetWithVendorProfile &preset, const PresetWithVendorProfile &active_print)
bool is_compatible_with_print(const PresetWithVendorProfile &preset, const PresetWithVendorProfile &active_print, const PresetWithVendorProfile &active_printer)
{
if (preset.vendor != nullptr && preset.vendor != active_print.vendor)
if (preset.vendor != nullptr && preset.vendor != active_printer.vendor)
// The current profile has a vendor assigned and it is different from the active print's vendor.
return false;
auto &condition = preset.preset.compatible_prints_condition();
@ -374,12 +374,23 @@ void Preset::set_visible_from_appconfig(const AppConfig &app_config)
if (type == TYPE_PRINTER) {
const std::string &model = config.opt_string("printer_model");
const std::string &variant = config.opt_string("printer_variant");
if (model.empty() || variant.empty()) { return; }
if (model.empty() || variant.empty())
return;
is_visible = app_config.get_variant(vendor->id, model, variant);
} else if (type == TYPE_FILAMENT) {
is_visible = app_config.has("filaments", name);
} else if (type == TYPE_SLA_MATERIAL) {
is_visible = app_config.has("sla_materials", name);
} else if (type == TYPE_FILAMENT || type == TYPE_SLA_MATERIAL) {
const char *section_name = (type == TYPE_FILAMENT) ? "filaments" : "sla_materials";
if (app_config.has_section(section_name)) {
// Check whether this profile is marked as "installed" in PrusaSlicer.ini,
// or whether a profile is marked as "installed", which this profile may have been renamed from.
const std::map<std::string, std::string> &installed = app_config.get_section(section_name);
auto has = [&installed](const std::string &name) {
auto it = installed.find(name);
return it != installed.end() && ! it->second.empty();
};
is_visible = has(this->name);
for (auto it = this->renamed_from.begin(); ! is_visible && it != this->renamed_from.end(); ++ it)
is_visible = has(*it);
}
}
}
@ -480,6 +491,7 @@ const std::vector<std::string>& Preset::sla_print_options()
"support_head_penetration",
"support_head_width",
"support_pillar_diameter",
"support_max_bridges_on_pillar",
"support_pillar_connection_mode",
"support_buildplate_only",
"support_pillar_widening_factor",
@ -557,6 +569,8 @@ const std::vector<std::string>& Preset::sla_printer_options()
"fast_tilt_time", "slow_tilt_time", "area_fill",
"relative_correction",
"absolute_correction",
"elefant_foot_compensation",
"elefant_foot_min_width",
"gamma_correction",
"min_exposure_time", "max_exposure_time",
"min_initial_exposure_time", "max_initial_exposure_time",
@ -683,19 +697,51 @@ Preset& PresetCollection::load_preset(const std::string &path, const std::string
return this->load_preset(path, name, std::move(cfg), select);
}
static bool profile_print_params_same(const DynamicPrintConfig &cfg1, const DynamicPrintConfig &cfg2)
enum class ProfileHostParams
{
t_config_option_keys diff = cfg1.diff(cfg2);
Same,
Different,
Anonymized,
};
static ProfileHostParams profile_host_params_same_or_anonymized(const DynamicPrintConfig &cfg_old, const DynamicPrintConfig &cfg_new)
{
auto opt_print_host_old = cfg_old.option<ConfigOptionString>("print_host");
auto opt_printhost_apikey_old = cfg_old.option<ConfigOptionString>("printhost_apikey");
auto opt_printhost_cafile_old = cfg_old.option<ConfigOptionString>("printhost_cafile");
auto opt_print_host_new = cfg_new.option<ConfigOptionString>("print_host");
auto opt_printhost_apikey_new = cfg_new.option<ConfigOptionString>("printhost_apikey");
auto opt_printhost_cafile_new = cfg_new.option<ConfigOptionString>("printhost_cafile");
// If the new print host data is undefined, use the old data.
bool new_print_host_undefined = (opt_print_host_new == nullptr || opt_print_host_new ->empty()) &&
(opt_printhost_apikey_new == nullptr || opt_printhost_apikey_new ->empty()) &&
(opt_printhost_cafile_new == nullptr || opt_printhost_cafile_new ->empty());
if (new_print_host_undefined)
return ProfileHostParams::Anonymized;
auto opt_same = [](const ConfigOptionString *l, const ConfigOptionString *r) {
return ((l == nullptr || l->empty()) && (r == nullptr || r->empty())) ||
(l != nullptr && r != nullptr && l->value == r->value);
};
return (opt_same(opt_print_host_old, opt_print_host_new) && opt_same(opt_printhost_apikey_old, opt_printhost_apikey_new) &&
opt_same(opt_printhost_cafile_old, opt_printhost_cafile_new)) ? ProfileHostParams::Same : ProfileHostParams::Different;
}
static bool profile_print_params_same(const DynamicPrintConfig &cfg_old, const DynamicPrintConfig &cfg_new)
{
t_config_option_keys diff = cfg_old.diff(cfg_new);
// Following keys are used by the UI, not by the slicing core, therefore they are not important
// when comparing profiles for equality. Ignore them.
for (const char *key : { "compatible_prints", "compatible_prints_condition",
"compatible_printers", "compatible_printers_condition", "inherits",
"print_settings_id", "filament_settings_id", "sla_print_settings_id", "sla_material_settings_id", "printer_settings_id",
"printer_model", "printer_variant", "default_print_profile", "default_filament_profile", "default_sla_print_profile", "default_sla_material_profile",
"printhost_apikey", "printhost_cafile" })
"print_host", "printhost_apikey", "printhost_cafile" })
diff.erase(std::remove(diff.begin(), diff.end(), key), diff.end());
// Preset with the same name as stored inside the config exists.
return diff.empty();
return diff.empty() && profile_host_params_same_or_anonymized(cfg_old, cfg_new) != ProfileHostParams::Different;
}
// Load a preset from an already parsed config file, insert it into the sorted sequence of presets
@ -724,11 +770,25 @@ Preset& PresetCollection::load_external_preset(
it = this->find_preset_renamed(original_name);
found = it != m_presets.end();
}
if (found && profile_print_params_same(it->config, cfg)) {
// The preset exists and it matches the values stored inside config.
if (select)
this->select_preset(it - m_presets.begin());
return *it;
if (found) {
if (profile_print_params_same(it->config, cfg)) {
// The preset exists and it matches the values stored inside config.
if (select)
this->select_preset(it - m_presets.begin());
return *it;
}
if (profile_host_params_same_or_anonymized(it->config, cfg) == ProfileHostParams::Anonymized) {
// The project being loaded is anonymized. Replace the empty host keys of the loaded profile with the data from the original profile.
// See "Octoprint Settings when Opening a .3MF file" GH issue #3244
auto opt_update = [it, &cfg](const std::string &opt_key) {
auto opt = it->config.option<ConfigOptionString>(opt_key);
if (opt != nullptr)
cfg.set_key_value(opt_key, opt->clone());
};
opt_update("print_host");
opt_update("printhost_apikey");
opt_update("printhost_cafile");
}
}
// Update the "inherits" field.
std::string &inherits = Preset::inherits(cfg);
@ -994,7 +1054,7 @@ void PresetCollection::set_default_suppressed(bool default_suppressed)
}
}
size_t PresetCollection::update_compatible_internal(const PresetWithVendorProfile &active_printer, const PresetWithVendorProfile *active_print, bool unselect_if_incompatible)
size_t PresetCollection::update_compatible_internal(const PresetWithVendorProfile &active_printer, const PresetWithVendorProfile *active_print, PresetSelectCompatibleType unselect_if_incompatible)
{
DynamicPrintConfig config;
config.set_key_value("printer_preset", new ConfigOptionString(active_printer.preset.name));
@ -1006,10 +1066,12 @@ size_t PresetCollection::update_compatible_internal(const PresetWithVendorProfil
Preset &preset_selected = m_presets[idx_preset];
Preset &preset_edited = selected ? m_edited_preset : preset_selected;
const PresetWithVendorProfile this_preset_with_vendor_profile = this->get_preset_with_vendor_profile(preset_edited);
bool was_compatible = preset_edited.is_compatible;
preset_edited.is_compatible = is_compatible_with_printer(this_preset_with_vendor_profile, active_printer, &config);
if (active_print != nullptr)
preset_edited.is_compatible &= is_compatible_with_print(this_preset_with_vendor_profile, *active_print);
if (! preset_edited.is_compatible && selected && unselect_if_incompatible)
preset_edited.is_compatible &= is_compatible_with_print(this_preset_with_vendor_profile, *active_print, active_printer);
if (! preset_edited.is_compatible && selected &&
(unselect_if_incompatible == PresetSelectCompatibleType::Always || (unselect_if_incompatible == PresetSelectCompatibleType::OnlyIfWasCompatible && was_compatible)))
m_idx_selected = -1;
if (selected)
preset_selected.is_compatible = preset_edited.is_compatible;
@ -1324,7 +1386,7 @@ inline t_config_option_keys deep_diff(const ConfigBase &config_this, const Confi
const ConfigOption *other_opt = config_other.option(opt_key);
if (this_opt != nullptr && other_opt != nullptr && *this_opt != *other_opt)
{
if (opt_key == "bed_shape" || opt_key == "compatible_prints" || opt_key == "compatible_printers") {
if (opt_key == "bed_shape" || opt_key == "thumbnails" || opt_key == "compatible_prints" || opt_key == "compatible_printers") {
diff.emplace_back(opt_key);
continue;
}

View file

@ -247,10 +247,19 @@ protected:
static std::string remove_suffix_modified(const std::string &name);
};
bool is_compatible_with_print (const PresetWithVendorProfile &preset, const PresetWithVendorProfile &active_print);
bool is_compatible_with_print (const PresetWithVendorProfile &preset, const PresetWithVendorProfile &active_print, const PresetWithVendorProfile &active_printer);
bool is_compatible_with_printer(const PresetWithVendorProfile &preset, const PresetWithVendorProfile &active_printer, const DynamicPrintConfig *extra_config);
bool is_compatible_with_printer(const PresetWithVendorProfile &preset, const PresetWithVendorProfile &active_printer);
enum class PresetSelectCompatibleType {
// Never select a compatible preset if the newly selected profile is not compatible.
Never,
// Only select a compatible preset if the active profile used to be compatible, but it is no more.
OnlyIfWasCompatible,
// Always select a compatible preset if the active profile is no more compatible.
Always
};
// Collections of presets of the same type (one of the Print, Filament or Printer type).
class PresetCollection
{
@ -412,13 +421,13 @@ public:
// For Print / Filament presets, disable those, which are not compatible with the printer.
template<typename PreferedCondition>
void update_compatible(const PresetWithVendorProfile &active_printer, const PresetWithVendorProfile *active_print, bool select_other_if_incompatible, PreferedCondition prefered_condition)
void update_compatible(const PresetWithVendorProfile &active_printer, const PresetWithVendorProfile *active_print, PresetSelectCompatibleType select_other_if_incompatible, PreferedCondition prefered_condition)
{
if (this->update_compatible_internal(active_printer, active_print, select_other_if_incompatible) == (size_t)-1)
// Find some other compatible preset, or the "-- default --" preset.
this->select_preset(this->first_compatible_idx(prefered_condition));
}
void update_compatible(const PresetWithVendorProfile &active_printer, const PresetWithVendorProfile *active_print, bool select_other_if_incompatible)
void update_compatible(const PresetWithVendorProfile &active_printer, const PresetWithVendorProfile *active_print, PresetSelectCompatibleType select_other_if_incompatible)
{ this->update_compatible(active_printer, active_print, select_other_if_incompatible, [](const std::string&){return true;}); }
size_t num_visible() const { return std::count_if(m_presets.begin(), m_presets.end(), [](const Preset &preset){return preset.is_visible;}); }
@ -515,7 +524,7 @@ private:
std::deque<Preset>::const_iterator find_preset_renamed(const std::string &name) const
{ return const_cast<PresetCollection*>(this)->find_preset_renamed(name); }
size_t update_compatible_internal(const PresetWithVendorProfile &active_printer, const PresetWithVendorProfile *active_print, bool unselect_if_incompatible);
size_t update_compatible_internal(const PresetWithVendorProfile &active_printer, const PresetWithVendorProfile *active_print, PresetSelectCompatibleType unselect_if_incompatible);
static std::vector<std::string> dirty_options(const Preset *edited, const Preset *reference, const bool is_printer_type = false);

View file

@ -238,7 +238,7 @@ void PresetBundle::load_presets(AppConfig &config, const std::string &preferred_
errors_cummulative += err.what();
}
this->update_multi_material_filament_presets();
this->update_compatible(false);
this->update_compatible(PresetSelectCompatibleType::Never);
if (! errors_cummulative.empty())
throw std::runtime_error(errors_cummulative);
@ -424,7 +424,7 @@ void PresetBundle::load_selections(AppConfig &config, const std::string &preferr
// or from the preferred_model_id suggestion passed in by ConfigWizard.
// If the printer profile enumerated by the config are not visible, select an alternate preset.
// Do not select alternate profiles for the print / filament profiles as those presets
// will be selected by the following call of this->update_compatible(true).
// will be selected by the following call of this->update_compatible(PresetSelectCompatibleType::Always).
const Preset *initial_printer = printers.find_preset(initial_printer_profile_name);
const Preset *preferred_printer = printers.find_by_model_id(preferred_model_id);
@ -457,7 +457,7 @@ void PresetBundle::load_selections(AppConfig &config, const std::string &preferr
// Always try to select a compatible print and filament preset to the current printer preset,
// as the application may have been closed with an active "external" preset, which does not
// exist.
this->update_compatible(true);
this->update_compatible(PresetSelectCompatibleType::Always);
this->update_multi_material_filament_presets();
}
@ -889,7 +889,7 @@ void PresetBundle::load_config_file_config(const std::string &name_or_path, bool
default: break;
}
this->update_compatible(false);
this->update_compatible(PresetSelectCompatibleType::Never);
}
// Load the active configuration of a config bundle from a boost property_tree. This is a private method called from load_config_file.
@ -951,7 +951,7 @@ void PresetBundle::load_config_file_config_bundle(const std::string &path, const
for (size_t i = 1; i < std::min(tmp_bundle.filament_presets.size(), this->filament_presets.size()); ++ i)
this->filament_presets[i] = load_one(this->filaments, tmp_bundle.filaments, tmp_bundle.filament_presets[i], false);
this->update_compatible(false);
this->update_compatible(PresetSelectCompatibleType::Never);
}
// Process the Config Bundle loaded as a Boost property tree.
@ -1351,7 +1351,7 @@ size_t PresetBundle::load_configbundle(const std::string &path, unsigned int fla
this->update_multi_material_filament_presets();
for (size_t i = 0; i < std::min(this->filament_presets.size(), active_filaments.size()); ++ i)
this->filament_presets[i] = filaments.find_preset(active_filaments[i], true)->name;
this->update_compatible(false);
this->update_compatible(PresetSelectCompatibleType::Never);
}
return presets_loaded;
@ -1399,7 +1399,7 @@ void PresetBundle::update_multi_material_filament_presets()
}
}
void PresetBundle::update_compatible(bool select_other_if_incompatible)
void PresetBundle::update_compatible(PresetSelectCompatibleType select_other_print_if_incompatible, PresetSelectCompatibleType select_other_filament_if_incompatible)
{
const Preset &printer_preset = this->printers.get_edited_preset();
const PresetWithVendorProfile printer_preset_with_vendor_profile = this->printers.get_preset_with_vendor_profile(printer_preset);
@ -1412,25 +1412,32 @@ void PresetBundle::update_compatible(bool select_other_if_incompatible)
const std::string &prefered_print_profile = printer_preset.config.opt_string("default_print_profile");
const std::vector<std::string> &prefered_filament_profiles = printer_preset.config.option<ConfigOptionStrings>("default_filament_profile")->values;
prefered_print_profile.empty() ?
this->prints.update_compatible(printer_preset_with_vendor_profile, nullptr, select_other_if_incompatible) :
this->prints.update_compatible(printer_preset_with_vendor_profile, nullptr, select_other_if_incompatible,
this->prints.update_compatible(printer_preset_with_vendor_profile, nullptr, select_other_print_if_incompatible) :
this->prints.update_compatible(printer_preset_with_vendor_profile, nullptr, select_other_print_if_incompatible,
[&prefered_print_profile](const std::string& profile_name) { return profile_name == prefered_print_profile; });
const PresetWithVendorProfile print_preset_with_vendor_profile = this->prints.get_edited_preset_with_vendor_profile();
// Remember whether the filament profiles were compatible before updating the filament compatibility.
std::vector<char> filament_preset_was_compatible(this->filament_presets.size(), false);
for (size_t idx = 0; idx < this->filament_presets.size(); ++ idx) {
std::string &filament_name = this->filament_presets[idx];
Preset *preset = this->filaments.find_preset(filament_name, false);
filament_preset_was_compatible[idx] = preset != nullptr && preset->is_compatible;
}
prefered_filament_profiles.empty() ?
this->filaments.update_compatible(printer_preset_with_vendor_profile, &print_preset_with_vendor_profile, select_other_if_incompatible) :
this->filaments.update_compatible(printer_preset_with_vendor_profile, &print_preset_with_vendor_profile, select_other_if_incompatible,
this->filaments.update_compatible(printer_preset_with_vendor_profile, &print_preset_with_vendor_profile, select_other_filament_if_incompatible) :
this->filaments.update_compatible(printer_preset_with_vendor_profile, &print_preset_with_vendor_profile, select_other_filament_if_incompatible,
[&prefered_filament_profiles](const std::string& profile_name)
{ return std::find(prefered_filament_profiles.begin(), prefered_filament_profiles.end(), profile_name) != prefered_filament_profiles.end(); });
if (select_other_if_incompatible) {
if (select_other_filament_if_incompatible != PresetSelectCompatibleType::Never) {
// Verify validity of the current filament presets.
if (this->filament_presets.size() == 1)
this->filament_presets.front() = this->filaments.get_edited_preset().name;
else
{
for (size_t idx = 0; idx < this->filament_presets.size(); ++idx) {
if (this->filament_presets.size() == 1) {
if (select_other_filament_if_incompatible == PresetSelectCompatibleType::Always || filament_preset_was_compatible.front())
this->filament_presets.front() = this->filaments.get_edited_preset().name;
} else {
for (size_t idx = 0; idx < this->filament_presets.size(); ++ idx) {
std::string &filament_name = this->filament_presets[idx];
Preset *preset = this->filaments.find_preset(filament_name, false);
if (preset == nullptr || !preset->is_compatible) {
if (preset == nullptr || (! preset->is_compatible && (select_other_filament_if_incompatible == PresetSelectCompatibleType::Always || filament_preset_was_compatible[idx]))) {
// Pick a compatible profile. If there are prefered_filament_profiles, use them.
if (prefered_filament_profiles.empty())
filament_name = this->filaments.first_compatible().name;
@ -1453,13 +1460,13 @@ void PresetBundle::update_compatible(bool select_other_if_incompatible)
const PresetWithVendorProfile sla_print_preset_with_vendor_profile = this->sla_prints.get_edited_preset_with_vendor_profile();
const std::string &prefered_sla_print_profile = printer_preset.config.opt_string("default_sla_print_profile");
(prefered_sla_print_profile.empty()) ?
this->sla_prints.update_compatible(printer_preset_with_vendor_profile, nullptr, select_other_if_incompatible) :
this->sla_prints.update_compatible(printer_preset_with_vendor_profile, nullptr, select_other_if_incompatible,
this->sla_prints.update_compatible(printer_preset_with_vendor_profile, nullptr, select_other_print_if_incompatible) :
this->sla_prints.update_compatible(printer_preset_with_vendor_profile, nullptr, select_other_print_if_incompatible,
[&prefered_sla_print_profile](const std::string& profile_name){ return profile_name == prefered_sla_print_profile; });
const std::string &prefered_sla_material_profile = printer_preset.config.opt_string("default_sla_material_profile");
prefered_sla_material_profile.empty() ?
this->sla_materials.update_compatible(printer_preset_with_vendor_profile, &sla_print_preset_with_vendor_profile, select_other_if_incompatible) :
this->sla_materials.update_compatible(printer_preset_with_vendor_profile, &sla_print_preset_with_vendor_profile, select_other_if_incompatible,
this->sla_materials.update_compatible(printer_preset_with_vendor_profile, &sla_print_preset_with_vendor_profile, select_other_filament_if_incompatible) :
this->sla_materials.update_compatible(printer_preset_with_vendor_profile, &sla_print_preset_with_vendor_profile, select_other_filament_if_incompatible,
[&prefered_sla_material_profile](const std::string& profile_name){ return profile_name == prefered_sla_material_profile; });
break;
}

View file

@ -127,7 +127,8 @@ public:
// Also updates the is_visible flag of each preset.
// If select_other_if_incompatible is true, then the print or filament preset is switched to some compatible
// preset if the current print or filament preset is not compatible.
void update_compatible(bool select_other_if_incompatible);
void update_compatible(PresetSelectCompatibleType select_other_print_if_incompatible, PresetSelectCompatibleType select_other_filament_if_incompatible);
void update_compatible(PresetSelectCompatibleType select_other_if_incompatible) { this->update_compatible(select_other_if_incompatible, select_other_if_incompatible); }
void load_default_preset_bitmaps();

View file

@ -262,12 +262,16 @@ std::string PresetHints::recommended_thin_wall_thickness(const PresetBundle &pre
int num_lines = std::min(num_perimeters * 2, 10);
out += (boost::format(_utf8(L("Recommended object thin wall thickness for layer height %.2f and"))) % layer_height).str() + " ";
// Start with the width of two closely spaced
double width = external_perimeter_flow.width + external_perimeter_flow.spacing();
for (int i = 2; i <= num_lines; thin_walls ? ++ i : i += 2) {
if (i > 2)
out += ", ";
out += (boost::format(_utf8(L("%d lines: %.2f mm"))) % i % width).str() + " ";
width += perimeter_flow.spacing() * (thin_walls ? 1.f : 2.f);
try {
double width = external_perimeter_flow.width + external_perimeter_flow.spacing();
for (int i = 2; i <= num_lines; thin_walls ? ++ i : i += 2) {
if (i > 2)
out += ", ";
out += (boost::format(_utf8(L("%d lines: %.2f mm"))) % i % width).str() + " ";
width += perimeter_flow.spacing() * (thin_walls ? 1.f : 2.f);
}
} catch (const FlowErrorNegativeSpacing &) {
out = _utf8(L("Recommended object thin wall thickness: Not available due to excessively small extrusion width."));
}
}
return out;

View file

@ -275,7 +275,7 @@ void PrintHostQueueDialog::on_error(Event &evt)
on_list_select();
GUI::show_error(nullptr, std::move(errormsg));
GUI::show_error(nullptr, errormsg);
}
void PrintHostQueueDialog::on_cancel(Event &evt)

Some files were not shown because too many files have changed in this diff Show more