From 2d79c6504f0fcdc95fa8c19125701655bdf73236 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tiago=20Concei=C3=A7=C3=A3o?= Date: Sat, 24 Jul 2021 02:55:43 +0100 Subject: [PATCH] v2.15.1 - **(Improvement) CWS:** - Remove light-off delay from the format - Sync movements with a delay time - Auto convert the light-off delay time to wait before cure time when required - **(Improvement) CTB:** - When positively set the 'Wait time before cure' property on a CTBv3 or lower, it will compute the right light-off delay with that extra time into consideration - When positively set any of the light-off delays on a CTBv4 it will auto zero the 'Wait times' properties and vice-versa - Automation to set light-off delay on file load, will no longer do when any of 'Wait times' are defined for a CTBv4 - (Improvement) PrusaSlicer printers that use .cws format, implement the wait times on printer notes - (Fix) GCode parser: Commented commands were being parsed - (Fix) Exposure time information on bottom status bar was inverted, showing normal/bottom time instead of bottom/normal - (Fix) macOS: Installing libusb is no longer a requirement --- CHANGELOG.md | 15 + Documentation/rgb.cws/Photonsters.url | 5 + Documentation/rgb.cws/decode.jpg | Bin 0 -> 57503 bytes Documentation/rgb.cws/encode.jpg | Bin 0 -> 55479 bytes PrusaSlicer/printer/Nova3D Bene4 Mono.ini | 4 +- PrusaSlicer/printer/Nova3D Elfin.ini | 4 +- PrusaSlicer/printer/Phrozen Sonic Mini.ini | 4 +- PrusaSlicer/printer/Wanhao D7.ini | 4 +- UVtools.Core/FileFormats/CWSFile.cs | 8 +- UVtools.Core/FileFormats/ChituboxFile.cs | 50 ++- UVtools.Core/FileFormats/FileFormat.cs | 4 +- UVtools.Core/GCode/GCodeBuilder.cs | 288 +++++++++++------- UVtools.Core/GCode/GCodeLayer.cs | 10 + .../Operations/OperationCalculator.cs | 41 +-- UVtools.Core/UVtools.Core.csproj | 2 +- UVtools.WPF/MainWindow.axaml.cs | 53 ++-- UVtools.WPF/UVtools.WPF.csproj | 2 +- 17 files changed, 335 insertions(+), 159 deletions(-) create mode 100644 Documentation/rgb.cws/Photonsters.url create mode 100644 Documentation/rgb.cws/decode.jpg create mode 100644 Documentation/rgb.cws/encode.jpg diff --git a/CHANGELOG.md b/CHANGELOG.md index b334b34..339a7f7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,20 @@ # Changelog +## 24/07/2021 - v2.15.1 + +- **(Improvement) CWS:** + - Remove light-off delay from the format + - Sync movements with a delay time + - Auto convert the light-off delay time to wait before cure time when required +- **(Improvement) CTB:** + - When positively set the 'Wait time before cure' property on a CTBv3 or lower, it will compute the right light-off delay with that extra time into consideration + - When positively set any of the light-off delays on a CTBv4 it will auto zero the 'Wait times' properties and vice-versa + - Automation to set light-off delay on file load, will no longer do when any of 'Wait times' are defined for a CTBv4 +- (Improvement) PrusaSlicer printers that use .cws format, implement the wait times on printer notes +- (Fix) GCode parser: Commented commands were being parsed +- (Fix) Exposure time information on bottom status bar was inverted, showing normal/bottom time instead of bottom/normal +- (Fix) macOS: Installing libusb is no longer a requirement + ## 16/07/2021 - v2.15.0 - **File formats:** diff --git a/Documentation/rgb.cws/Photonsters.url b/Documentation/rgb.cws/Photonsters.url new file mode 100644 index 0000000..e6b9d1a --- /dev/null +++ b/Documentation/rgb.cws/Photonsters.url @@ -0,0 +1,5 @@ +[{000214A0-0000-0000-C000-000000000046}] +Prop3=19,11 +[InternetShortcut] +IDList= +URL=https://www.facebook.com/Photonsters/posts/1198980267222618 diff --git a/Documentation/rgb.cws/decode.jpg b/Documentation/rgb.cws/decode.jpg new file mode 100644 index 0000000000000000000000000000000000000000..4e41c2e5452da331785e87da0e1964fb3313da01 GIT binary patch literal 57503 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 literal 0 HcmV?d00001 diff --git a/Documentation/rgb.cws/encode.jpg b/Documentation/rgb.cws/encode.jpg new file mode 100644 index 0000000000000000000000000000000000000000..28d3aa3b0a0de37a4aad7725a5405d5b77fa5470 GIT binary patch literal 55479 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≦F9Rokr)F|B4n1RWX7U)aTgS1mg?yiyCjyL z!wqndf01&OWJW+T^I(~!7P`eI(4s%jQj>&1tAO%zG372kgDx=(Dw%G8_%`l5l}t>K z%mP?u(VuOna({*|M@OK%O9rk3z{pgz$z*lNEHtB*f+ZFsn3kT)EH&`>bxP1~6I|+q zS#`nOx@3BzWXb^*cIyAhncn{#{cSM3&Hn=wx}`2YKz;xP=$9OP0?f4(C9}AR2ZU@EyFVZIEEg5R}0&hva4UgDl2ViAw3iGGp zT@X|Q6x9I3Hoy@0A-BDMv!}Pb|1aSgVWa{w2W9c~`2n1kl^V*Zy=bu~k`vyFKwbws0K_I8ftT{5L@a3W@g;v3}BCS$&}%y4wxvw zp#diB2SaV+0*_fkKwt>_vG;b|RuRDZ+e`fK1_eag8u6R<0mR;G z(5)g4Yg3rN&>e6^ATVeUz$Z4qEjN>M0}M!;d0Yt5v282BV>eM+02HRbAh@@u{+<7~ z1^#V;|4|l@2i_GrObzT+L5K)Q@Ecb6uhxJOdRg<-!f1;H#X30B#V5MwLuOg|&d0mp zKZA3Fmv5X>vRDmW=kB=q{WXKSW$Ua7dw9g1E@aJMEYJFF6ZSCfa`fe+r-wHV6nHra zK5!&kxo!T$NpQuHY?;5kFrfrjlWqRYkZnS*Jtsls9p{;|r1#Hd|6rV4{TwPF90V+H z33p0!Glj!9w9^vrX%a@WgA1zhE0DfLuZ-h$kD;WAc-NTBm9e7O87h5 zG3HN?0}l7eCTj?|DqVM)*9-M1xGsh@9`|1v9Lb@Z(VZSjzz%P)0?+$-&)c?qWUD)| z8aV$Rx_E9%!YWY0>e!xgU`*&|t zjT00o^*jq5OfK2co#wV>1y_|CSBRYk!DgLWO#@kik^VAl?ihbGVN7ac$b+jHcK0D> z=5}w5b1swxo?sx*P>^5>=Q#MoZu(yGSP=w!mEie1>fEeqdudMq&G3C01KJEzc-$KLrWk$}BPGj5D~uJ{u>=jK>C z3HFH@+QNR)@{3P@Xy7D*bsxo&!GpV`)D$0D^(p#3H4G0vMjeHodzFpI90kD?RovG! zM1d(Q!zZU0mfXnjx)5O}!XW~ObEop!c z!2mxoZ)z!SdY`KM4H`t^etF{aAx2?(lGdXhR8K&>dbODb5pc?Lc4H#8lp%}~cCY1^ zM#~f}8zBup4t)uK0^{scA{Y#3a6t#;x-hv3qf1zB9z8wP|EfOdrT5s2Fb>8;BM(c% z%1)kFC?=PQls}0SuHqqfav!sjv?P~$fT>7c$+@8qR&lr&XX|nkL1oZD+b)@qNu}WwPqL^==z|0z79#JPddd* zO1@frBczoJqo0~m?JeSXQ{a}KkGOI!NEIHrP(lQwbz}!e+MAy7XNtg}2@1;iDE&Cl zQW~D0f*EN8vcRwC?m402_0unMK;LLj3zQpYPc_AupJEP`D*&U{=oX4dgGO{)yT&aF zuBoh3(T)*!`>lry%o!Li^F3AuFTMBY6{Um-^vhqeZXF3`K@ih?qDb!yS+-Z!NHO*D zgDdq;bi6!;qFEH`hatGY4*mqMv0-xDPMnJiIVZdcpQW31!5#dx?rTRn3wPfwqK3{$wBhyxXD2R1A-?>Oq?+~ zlZIM6ZWiQgh|`4KOzLw2DTCY=8(oSa>SI<^mb$ErH-s+~K!{+qFil>{3RIO7%g-lj0Q&NwL1=?lK^k(@nAY{+qIr^+taPCWSd70~?8m&!tWBjq>Gqq$G zvcOk&-^PGTFDiad~q@oFe8CE6} zKCQVbAcLKC`Dxb_9e#9#UQ&EWjOeU91tEYU>l*3ILPH6m!v6QcoaEWy`_Jv_3i5Rh ztzZRLC%HVy$!|o_j_b9jdYcen(yIE5;dPhHk2b}3U<5wSVO%7ntpiyw7|2A4VAM71 z0bwXoTIgDXQIGKGtC#%_80S<;VNS>~y_Gj=Y~h$piJ4$BSsEhw8?l^o3-3hau7wbE zUzq1crBFRKlWXM}VoDj8uy5{39t2*@f?j+@B$dGhH#S)k~PV(2LitA;i+)si1I zZH5W_Aoh7ptb@IfH)y3Ke5qRCkuYdO6f-I6`hXNOopjKa(LFxFZ%ycMLTlZXT;#OE z2=*1qOiY9M*-=^!+Gw`d9%`=w^U4Lm#!Xn=L-$Im&|GX1b|UdjN#I_v)miTQ>dP{` ziUO1yjGTx0(X&ExlR$UGoeI7XS@G@#BPc&smxu62_bH#6G3!2w^vsimnIvpa$L$H5 zQ@rc%y{uCx#+=h2Gx>Prdkwj?PiWjkibP%FFA(O9fotMH^i4)$9)D{>Khf@lk3In) zz0uC_c8n8pKxb9b?_j%_M1E6*A5%OxGj-pgS+u!X=L>d@dY?-Fu8$y*HA%%6uu-P; zkkl(ZClc50de^X`5ZhN+{ci+b0Ku+ut6G7e}JQ$7x2K++#pI@q{#bl~A`A(yHXfM?vodW&9zm zQ6db~2CVhbEk4siH#M5M`Lue=?iX3VK|)Ch$C{9{^2zhEr%M7;BoY`ZxS<-FDh)@I zL?4kh(>Plwn&nuS(Z0O|3?=rrYN36$QLi-_nLwF$h}MNmpHlt;St{A{jS-qeuyGsb z!cCBtAzTwZg4bm=8~Vb9$CjfsNS_7{oF+SHd&KY4ouieAdAK%|$RFwBbKIpE6RBnT ziS86P^~-*cFW3r1W<|U9noBkw9>mGSOhlM7Xl*YiD@J(hyL_7ZWJx;jxvLy7s?L@I zrZ>9Z!AsbKTtT(=y^Ay%iK6~)*hAe2c%uYg=DnfQ{up~I-xnsz(F!l>hROr-Yflui zfC$4rSS>$D`1H;7urzON`32N^dWz5tz4C+bk&OsAbd3xX8<;jn*xaPJNRdYJ;_W-H zI^o(Erahcbir7EX!Aph_5**`|Hr!5v0-++PmZ$;qqb-dg{S41-d%zRdUs}Wn%1iJg z-7u(B5Q47Jx%k0`-n>+JoPhN5vLDmW;=qnDCW$-bs>wz^ZLh!=VI&woyET%kR_+&I z;)cwxHHpt1eKN}C3#LhqM7a5t4J^~T(qhnT^yS2&7aXvslq^XgdS>3b_YyH#!NT7^ zL@DUA%z%Z9Fg&74a2YC&_zuuXwSzaV7#RBpq>Z$+xo2Faz#xh12|!>>mIwswn4bN4 z6u~{6=>Eoo$96 z`_wlP?vA(zFV)xlUp&exp;rFk3mE}pCvW6aBG5-38<~=fs&?tuS`M4C3(*d<^(NiW z(Rd;lseyv)Mgxp4)rO7`6)Ve^Q(B?#=tKuAJxpYiK>PwxvV$)pOhI>{vW)MGJt`&I zKl&fMd^E+9gJ3}E?g?&eYHT-CH)%L=dZTCP{r7XWDz(1Or{Czw-kNiv8?H@xfPSEy zo5fo7*3{au+zn01=}TFBQ5+)&v0~&L#7rTtr1vZxRb~GLvI2b*h;zuHWFZ%S0O9l% zQd(83hbj<*YTY5LvSYQ*3W?It4P=vFum+tlsbm2?@j*oz*$PnY6`$6pl89Pb*>G%i zgP2TbQbhA{0X{{ic%l#{82XiaDn@LCQqz@~P$M-}t%>MDNg#PddH4lg-?!=EAI$_V z=2fm8r~E)nu_7F9$OSj!Et^tmW{{i~d3dxyQ~|}JGLDvm(jh=hL{GW}!)#xbd5`Hf z#2dUq-g}po7$-^-XsP=`i#bGDn9ueAtnq(-6&&7HvXqqe7UVuFI5>j*rR+BoHFJ0Ic(-=ejJB!MmSVi)X&#y6ITxIjr7;wvh-(~BWPgC{(s24rY1qTT@X>J>H z%W`RKdiOimR%%n0Hb0!2 zzF4k0P(^y|ES(oeCaJ>$m_e1bbIj4{=o1O^c=xj1u{>*qLJ>R9RWs{)p?d<)sAr zDGA900r|`FEOBUucO`@*_sUQIkX9YAD}3jA@iE^tr|z`r4fl-f=n0p*Uh(3!8V0UQ z3c8g)gU0m3DWq>@qE{{-9?rL~nf)pqd2%3tU3r@QxK3p3vc62I_?L?2DpInGXYI)t zGP*bZo&qm#hN|CcezIab07jl{?*J?Hu5(6cp~U7+`}hsMF1nePJ#(*bP7)Y;9#jP$ zf^t$iJsOKu15evoMtBZYU(Mt*^;TXeR3lD%-i^90O@FDk^33IHX)U}n^^sX$Df9B1 zo>5KaUNt{|4zLhS+`Gr!bbyI6|DK5mTNUOlPw0gTtMN54<**>QZ0Xgohl%=CZ#RJe@vLvzeK60m(mZqK=5OvSAujJF2&xQMYcKh=*F| zu<|uO7p@3*+RD(p6a|MUYttRLfH}NPVvAPJqhc;kMEN#>ElQ9N0W{oj6V+8cufB60 zj6*va)0g~7(H*&P3{fJOV0do}4x}e`lr-*lTCmHczJf}Yd&LKM&zmrw>@cn>JDDTC zPXn9))}Q5Qc{X;%-_)aZ(L{!q=yy7m-BWIq9CT<173boz!8gij(RsZ`J)zn>uSI z*mX>C&Tm{53MFrTz1aBVdH6DWy<&SqQ|9jx6*3$ z|Flv;ybzq#~{uM8(%%kDK*WLLQrqU~+b_aIheBVlad~4dgY2^CsPyS*%6*0Prbflh=OB;L@hLNm)9_12VR;) zeJXFEFe_>Xd?md#g>NH)-fwWINWyA6uF-wxoB0mL$fl+Dc9cLMLDN<~y@gHu;$3E- z^R9C_vMw8l9z3Cou4 zs{Dcb9OajcuE>a>&hJoAdx<>*Un74ly-Ai zb#%P90^JUe?H0w-3BqGef(+W*dI9R$f2n-s!ZA$iP==IZYjW5))cM@4B6T)j8lOp< zjk1PualQm-9RiG$Bx2nPI%`3B`C+X&?$Mj0fiZB;OjT-gqP{xb6h7kT;0laWCM!PU z>y&wD<|MHC&KgnS`#bbraB``Khw7_Qnx}PXn{FrA4R{JwP5|u~fBi&#kNT2Zkylun$8)LlO58Hs zzp1FwRpJm2{6M#QXeo$F^K40xzskiZNdf4*Q8P~}C5^=uT-g0yN z2)TT?lgqKXzn{@8SnE46F317AeqBOOPUNwWxgeeQF{y{Is|U<;3jb?LmHg`}bpfYT z!j4j0&bifZnKAG1-Q1QY|Inh=&lg$^Rf78?1R9>5C9n+8K%kkhF+RV7ui5|^8 zH?H&^#P$#_$NND9Ka%7w)N=UNnPG5vuD3`iAgoE9ZmFMy-Ip&D^JQ2-A+avFw>cq; zgvwO}01Ub3bk_Z&q2{!B#tlqzV2jW%wbyB5;x6W~7OG9_)$C+!ICuroj9{EdExl6& zXw$<+qH&kkl`H&sirSzR_B~lC=~}n#ukJ9zyV%yejwev9sR= z&SS8*Cq81b9DYy`<8S;FaI5<>?H-T8=__n0Ks*rCCl#N;eh?pf;-YgJx~VMQp+}cLzr8nnwApU0`r&2?`Xj7?coc9R$@=1AZm7Eu z;w)5@fHe#N1R&B|l!nP??W#6`BbZWN-?OV``y|=v_UwTHVTnY~F=r!coa@zni8pAZ zb>4*g1-kmS)o_&oPvVhh1ADyV1;y)@w%20;Hl5dbN~}s4AjMlm-)sm_J-L?>fD`SZ zQ!4uL%PR2ag|HD{A8XbNqwRh{lxz~twQvx0WUdi{=tO}BL>kOd&L0|rD5>C2_=pE5 z-9IhVb9K=O5yO~J=sG{&ciKKqGT1;u(~BqZ6$HUFBvvyg@pm0P5>k&?hVu(+wpZ%q zYnTK1%~aSN;I_=$Cdj31`KEA<`&4iKhO*IOY`%7y{0NoV=f8v7NIyIRAUgs}fsf0* zW%HcCyOTann_iR3ekS5lZ{N^%Ah9m1K+_AX@1e)in(wX{GqTF7K9_L(84T~h-$I4d z^}l}gL-yn=zM54qa7z@G(+3umLvXeJK_B)nN1to7$&Z^g@NJOx_HZO!9baAT^R8GMp>%UdH6x4o#l(#(|N2(=? zm6ZT_K^TtKtwie{qr%f~7DFT{Z3r>pnmL3eWpaOk61Q+I*+wCaOxDm4QEH;jEdspj zv{5OM_(Hg)908Jhkv|+ynrZm~u>b=+MF$r|@k{7J**Jz8HaVONaz|NVuj*6~)YS=H zjcCSWNA%c}#>LbLq91YJa|k3D+XOX%64InFfE1koA%$G@(qrx0Cm!L z8KmdSYF|tJDmm@e_o?vzzoO7Fkn|6~x0J+}VgoXr&Hwv)6nMV`)s=aF6VLcH_ null; public override uint ResolutionX { @@ -542,6 +541,7 @@ namespace UVtools.Core.FileFormats { GCode = new GCodeBuilder { + SyncMovementsWithDelay = true, UseComments = true, GCodePositioningType = GCodeBuilder.GCodePositioningTypes.Partial, GCodeSpeedUnit = GCodeBuilder.GCodeSpeedUnits.MillimetersPerMinute, diff --git a/UVtools.Core/FileFormats/ChituboxFile.cs b/UVtools.Core/FileFormats/ChituboxFile.cs index db930c6..512ae46 100644 --- a/UVtools.Core/FileFormats/ChituboxFile.cs +++ b/UVtools.Core/FileFormats/ChituboxFile.cs @@ -1294,13 +1294,31 @@ namespace UVtools.Core.FileFormats public override float BottomLightOffDelay { get => PrintParametersSettings.BottomLightOffDelay; - set => base.BottomLightOffDelay = PrintParametersSettings.BottomLightOffDelay = (float)Math.Round(value, 2); + set + { + base.BottomLightOffDelay = PrintParametersSettings.BottomLightOffDelay = (float) Math.Round(value, 2); + if (HeaderSettings.Version >= 4 && value > 0) + { + WaitTimeBeforeCure = 0; + WaitTimeAfterCure = 0; + WaitTimeAfterLift = 0; + } + } } public override float LightOffDelay { get => PrintParametersSettings.LightOffDelay; - set => base.LightOffDelay = HeaderSettings.LightOffDelay = PrintParametersSettings.LightOffDelay = (float)Math.Round(value, 2); + set + { + base.LightOffDelay = HeaderSettings.LightOffDelay = PrintParametersSettings.LightOffDelay = (float) Math.Round(value, 2); + if (HeaderSettings.Version >= 4 && value > 0) + { + WaitTimeBeforeCure = 0; + WaitTimeAfterCure = 0; + WaitTimeAfterLift = 0; + } + } } public override float BottomWaitTimeBeforeCure => WaitTimeBeforeCure; @@ -1309,8 +1327,22 @@ namespace UVtools.Core.FileFormats get => HeaderSettings.Version >= 4 ? PrintParametersV4Settings.RestTimeAfterRetract : 0; set { - if (HeaderSettings.Version < 4) return; + if (HeaderSettings.Version < 4) + { + if (value > 0) + { + SetBottomLightOffDelay(value); + SetNormalLightOffDelay(value); + } + + return; + } base.WaitTimeBeforeCure = SlicerInfoSettings.RestTimeAfterRetract = PrintParametersV4Settings.RestTimeAfterRetract = (float)Math.Round(value, 2); + if (value > 0) + { + BottomLightOffDelay = 0; + LightOffDelay = 0; + } } } @@ -1327,7 +1359,12 @@ namespace UVtools.Core.FileFormats set { if (HeaderSettings.Version < 4) return; - base.WaitTimeAfterCure = PrintParametersV4Settings.RestTimeBeforeLift = (float)Math.Round(value, 2); + base.WaitTimeAfterCure = PrintParametersV4Settings.RestTimeBeforeLift = (float) Math.Round(value, 2); + if (value > 0) + { + BottomLightOffDelay = 0; + LightOffDelay = 0; + } } } @@ -1369,6 +1406,11 @@ namespace UVtools.Core.FileFormats { if (HeaderSettings.Version < 4) return; base.WaitTimeAfterLift = SlicerInfoSettings.RestTimeAfterLift = SlicerInfoSettings.RestTimeAfterLift2 = PrintParametersV4Settings.RestTimeAfterLift = (float)Math.Round(value, 2); + if (value > 0) + { + BottomLightOffDelay = 0; + LightOffDelay = 0; + } } } diff --git a/UVtools.Core/FileFormats/FileFormat.cs b/UVtools.Core/FileFormats/FileFormat.cs index ae96149..5f627c4 100644 --- a/UVtools.Core/FileFormats/FileFormat.cs +++ b/UVtools.Core/FileFormats/FileFormat.cs @@ -1079,12 +1079,12 @@ namespace UVtools.Core.FileFormats if (CanUseBottomExposureTime) { - str += ExposureTime.ToString(CultureInfo.InvariantCulture); + str += BottomExposureTime.ToString(CultureInfo.InvariantCulture); } if (CanUseExposureTime) { if (!string.IsNullOrEmpty(str)) str += '/'; - str += BottomExposureTime.ToString(CultureInfo.InvariantCulture); + str += ExposureTime.ToString(CultureInfo.InvariantCulture); } if (!string.IsNullOrEmpty(str)) str += 's'; diff --git a/UVtools.Core/GCode/GCodeBuilder.cs b/UVtools.Core/GCode/GCodeBuilder.cs index 8bdbfff..282c624 100644 --- a/UVtools.Core/GCode/GCodeBuilder.cs +++ b/UVtools.Core/GCode/GCodeBuilder.cs @@ -19,6 +19,7 @@ using Org.BouncyCastle.Asn1.Cms; using UVtools.Core.Extensions; using UVtools.Core.FileFormats; using UVtools.Core.Objects; +using UVtools.Core.Operations; namespace UVtools.Core.GCode { @@ -98,12 +99,14 @@ namespace UVtools.Core.GCode #region Members private readonly StringBuilder _gcode = new(); - private bool _useTailComma = true; - private bool _useComments = true; + private GCodePositioningTypes _gCodePositioningType = GCodePositioningTypes.Absolute; private GCodeTimeUnits _gCodeTimeUnit = GCodeTimeUnits.Milliseconds; private GCodeSpeedUnits _gCodeSpeedUnit = GCodeSpeedUnits.MillimetersPerMinute; private GCodeShowImageTypes _gCodeShowImageType = GCodeShowImageTypes.FilenameNonZeroPNG; + private bool _syncMovementsWithDelay; + private bool _useTailComma = true; + private bool _useComments = true; private ushort _maxLedPower = byte.MaxValue; private uint _lineCount; private GCodeMoveCommands _layerMoveCommand; @@ -149,6 +152,12 @@ namespace UVtools.Core.GCode set => RaiseAndSetIfChanged(ref _endGCodeMoveCommand, value); } + public bool SyncMovementsWithDelay + { + get => _syncMovementsWithDelay; + set => RaiseAndSetIfChanged(ref _syncMovementsWithDelay, value); + } + public bool UseTailComma { get => _useTailComma; @@ -384,12 +393,12 @@ namespace UVtools.Core.GCode AppendMoveG1(z, feedRate); } - public void AppendLiftMoveGx(float upZ, float upFeedRate, float downZ, float downFeedRate, float waitAfterLift = 0, float waitAfterRetract = 0) + public void AppendLiftMoveGx(float upZ, float upFeedRate, float downZ, float downFeedRate, float waitAfterLift = 0, float waitAfterRetract = 0, Layer layer = null) { if (_layerMoveCommand == GCodeMoveCommands.G0) - AppendLiftMoveG0(upZ, upFeedRate, downZ, downFeedRate, waitAfterLift, waitAfterRetract); + AppendLiftMoveG0(upZ, upFeedRate, downZ, downFeedRate, waitAfterLift, waitAfterRetract, layer); else - AppendLiftMoveG1(upZ, upFeedRate, downZ, downFeedRate, waitAfterLift, waitAfterRetract); + AppendLiftMoveG1(upZ, upFeedRate, downZ, downFeedRate, waitAfterLift, waitAfterRetract, layer); } @@ -399,10 +408,17 @@ namespace UVtools.Core.GCode AppendLine(CommandMoveG0, z, feedRate); } - public void AppendLiftMoveG0(float upZ, float upFeedRate, float downZ, float downFeedRate, float waitAfterLift = 0, float waitAfterRetract = 0) + public void AppendLiftMoveG0(float upZ, float upFeedRate, float downZ, float downFeedRate, float waitAfterLift = 0, float waitAfterRetract = 0, Layer layer = null) { if (upZ == 0 || upFeedRate <= 0) return; AppendLineOverrideComment(CommandMoveG0, "Z Lift", upZ, upFeedRate); // Z Lift + if (_syncMovementsWithDelay && layer is not null) + { + // Finish this + var seconds = OperationCalculator.LightOffDelayC.CalculateSecondsLiftOnly(layer.LiftHeight, layer.LiftSpeed, 0.75f); + var time = ConvertFromSeconds(seconds); + AppendWaitG4($"0{time}", "Sync movement"); + } if (waitAfterLift > 0) { @@ -412,6 +428,13 @@ namespace UVtools.Core.GCode if (downZ != 0 && downFeedRate > 0) { AppendLineOverrideComment(CommandMoveG0, "Retract to layer height", downZ, downFeedRate); + if (_syncMovementsWithDelay && layer is not null) + { + // Finish this + var seconds = OperationCalculator.LightOffDelayC.CalculateSecondsLiftOnly(layer.LiftHeight, layer.RetractSpeed, 0.75f); + var time = ConvertFromSeconds(seconds); + AppendWaitG4($"0{time}", "Sync movement"); + } } if (waitAfterRetract > 0) @@ -426,10 +449,20 @@ namespace UVtools.Core.GCode AppendLine(CommandMoveG1, z, feedRate); } - public void AppendLiftMoveG1(float upZ, float upFeedRate, float downZ, float downFeedRate, float waitAfterLift = 0, float waitAfterRetract = 0) + public void AppendLiftMoveG1(float upZ, float upFeedRate, float downZ, float downFeedRate, float waitAfterLift = 0, float waitAfterRetract = 0, Layer layer = null) { if (upZ == 0 || upFeedRate <= 0) return; AppendLineOverrideComment(CommandMoveG1, "Lift Z", upZ, upFeedRate); // Z Lift + if (_syncMovementsWithDelay && layer is not null) + { + // Finish this + var seconds = OperationCalculator.LightOffDelayC.CalculateSecondsLiftOnly(layer.LiftHeight, layer.LiftSpeed, 0.75f); + if (seconds > layer.WaitTimeAfterLift) // Fix if wait time already include this + { + var time = ConvertFromSeconds(seconds); + AppendWaitG4($"0{time}", "Sync movement"); + } + } if (waitAfterLift > 0) { @@ -439,6 +472,16 @@ namespace UVtools.Core.GCode if (downZ != 0 && downFeedRate > 0) { AppendLineOverrideComment(CommandMoveG1, "Retract to layer height", downZ, downFeedRate); + if (_syncMovementsWithDelay && layer is not null) + { + // Finish this + var seconds = OperationCalculator.LightOffDelayC.CalculateSecondsLiftOnly(layer.LiftHeight, layer.RetractSpeed, 0.75f); + if (seconds > layer.WaitTimeBeforeCure) // Fix if wait time already include this + { + var time = ConvertFromSeconds(seconds); + AppendWaitG4($"0{time}", "Sync movement"); + } + } } if (waitAfterRetract > 0) @@ -453,6 +496,13 @@ namespace UVtools.Core.GCode AppendLineOverrideComment(CommandWaitG4, comment, time); } + public void AppendWaitG4(string timeStr, string comment = null) + { + if (!float.TryParse(timeStr, out var time)) return; + if (time < 0) return; + AppendLineOverrideComment(CommandWaitG4, comment, timeStr); + } + public void AppendTurnLightM106(ushort value) { AppendLineOverrideComment(CommandTurnLEDM106, "Turn LED " + (value == 0 ? "OFF" : "ON"), value); @@ -560,7 +610,7 @@ namespace UVtools.Core.GCode if (liftHeight > 0 && liftZPosAbs > layer.PositionZ) { - AppendLiftMoveGx(liftZPos, liftSpeed, retractPos, retractSpeed, waitAfterLift); + AppendLiftMoveGx(liftZPos, liftSpeed, retractPos, retractSpeed, waitAfterLift, 0, layer); } else if (lastZPosition < layer.PositionZ) // Ensure Z is on correct position { @@ -675,7 +725,8 @@ namespace UVtools.Core.GCode string line; while ((line = reader.ReadLine()) != null) { - if(string.IsNullOrWhiteSpace(line)) continue; + line = line.Trim(); + if (string.IsNullOrWhiteSpace(line)) continue; // Search for and switch position type when needed if (line.StartsWith(CommandPositioningAbsoluteG90.Command)) @@ -690,145 +741,174 @@ namespace UVtools.Core.GCode continue; } - var match = Regex.Match(line, CommandShowImageM6054.ToStringWithoutComments(GetShowImageString(@"(\d+)")), RegexOptions.IgnoreCase); - if (match.Success && match.Groups.Count >= 2) // Begin new layer + Match match = null; + + // Display image + if (line.StartsWith(CommandShowImageM6054.Command)) { - var layerIndex = uint.Parse(match.Groups[1].Value); - if (_gCodeShowImageType is GCodeShowImageTypes.FilenameNonZeroPNG or GCodeShowImageTypes.LayerIndexNonZero) layerIndex--; - if (layerIndex > slicerFile.LayerCount) + match = Regex.Match(line, + CommandShowImageM6054.ToStringWithoutComments(GetShowImageString(@"(\d+)")), + RegexOptions.IgnoreCase); + if (match.Success && match.Groups.Count >= 2) // Begin new layer { - throw new FileLoadException($"GCode parser detected the layer {layerIndex}, but the file was sliced to {slicerFile.LayerCount} layers.", slicerFile.FileFullPath); + var layerIndex = uint.Parse(match.Groups[1].Value); + if (_gCodeShowImageType is GCodeShowImageTypes.FilenameNonZeroPNG or GCodeShowImageTypes + .LayerIndexNonZero) layerIndex--; + if (layerIndex > slicerFile.LayerCount) + { + throw new FileLoadException( + $"GCode parser detected the layer {layerIndex}, but the file was sliced to {slicerFile.LayerCount} layers.", + slicerFile.FileFullPath); + } + + // Propagate values before switch to the new layer + layerBlock.PositionZ ??= positionZ; + layerBlock.SetLayer(); + + layerBlock.Init(); + layerBlock.LayerIndex = layerIndex; + + continue; } - - // Propagate values before switch to the new layer - layerBlock.PositionZ ??= positionZ; - layerBlock.SetLayer(); - - layerBlock.Init(); - layerBlock.LayerIndex = layerIndex; - - continue; } if (!layerBlock.IsValid) continue; // No layer yet found to work on, skip - // Check moves - var moveG0Regex = Regex.Match(line, CommandMoveG0.ToStringWithoutComments(@"([+-]?([0-9]*[.])?[0-9]+)", @"(([0-9]*[.])?[0-9]+)"), RegexOptions.IgnoreCase); - var moveG1Regex = Regex.Match(line, CommandMoveG1.ToStringWithoutComments(@"([+-]?([0-9]*[.])?[0-9]+)", @"(([0-9]*[.])?[0-9]+)"), RegexOptions.IgnoreCase); - match = moveG0Regex.Success && moveG0Regex.Groups.Count >= 2 ? moveG0Regex : moveG1Regex; - - if (match.Success && match.Groups.Count >= 4 && !layerBlock.RetractSpeed.HasValue) + if (line.StartsWith(CommandMoveG0.Command) || line.StartsWith(CommandMoveG1.Command)) { - float pos = float.Parse(match.Groups[1].Value, CultureInfo.InvariantCulture); - float speed = ConvertToMillimetersPerMinute(float.Parse(match.Groups[3].Value, CultureInfo.InvariantCulture)); + var moveG0Regex = Regex.Match(line, + CommandMoveG0.ToStringWithoutComments(@"([+-]?([0-9]*[.])?[0-9]+)", @"(([0-9]*[.])?[0-9]+)"), + RegexOptions.IgnoreCase); + var moveG1Regex = Regex.Match(line, + CommandMoveG1.ToStringWithoutComments(@"([+-]?([0-9]*[.])?[0-9]+)", @"(([0-9]*[.])?[0-9]+)"), + RegexOptions.IgnoreCase); + match = moveG0Regex.Success && moveG0Regex.Groups.Count >= 2 ? moveG0Regex : moveG1Regex; - if (!layerBlock.PositionZ.HasValue) // Lift or pos, set here for now + if (match.Success && match.Groups.Count >= 4 && !layerBlock.RetractSpeed.HasValue) { + float pos = float.Parse(match.Groups[1].Value, CultureInfo.InvariantCulture); + float speed = ConvertToMillimetersPerMinute(float.Parse(match.Groups[3].Value, CultureInfo.InvariantCulture)); + + if (!layerBlock.PositionZ.HasValue) // Lift or pos, set here for now + { + switch (positionType) + { + case GCodePositioningTypes.Absolute: + layerBlock.PositionZ = pos; + break; + case GCodePositioningTypes.Partial: + layerBlock.PositionZ = Layer.RoundHeight(positionZ + pos); + break; + } + + layerBlock.LiftSpeed = speed; + continue; + } + + + // ~90% sure its retract here, still is possible to bug this with 2 lifts + layerBlock.RetractSpeed = speed; + switch (positionType) { case GCodePositioningTypes.Absolute: - layerBlock.PositionZ = pos; + layerBlock.LiftHeight = Layer.RoundHeight(layerBlock.PositionZ.Value - pos); + layerBlock.PositionZ = positionZ = pos; break; case GCodePositioningTypes.Partial: - layerBlock.PositionZ = Layer.RoundHeight(positionZ + pos); + layerBlock.LiftHeight = layerBlock.PositionZ - positionZ; + layerBlock.PositionZ = positionZ = Layer.RoundHeight(layerBlock.PositionZ.Value + pos); break; } - layerBlock.LiftSpeed = speed; continue; } - - - // ~90% sure its retract here, still is possible to bug this with 2 lifts - layerBlock.RetractSpeed = speed; - - switch (positionType) - { - case GCodePositioningTypes.Absolute: - layerBlock.LiftHeight = Layer.RoundHeight(layerBlock.PositionZ.Value - pos); - layerBlock.PositionZ = positionZ = pos; - break; - case GCodePositioningTypes.Partial: - layerBlock.LiftHeight = layerBlock.PositionZ - positionZ; - layerBlock.PositionZ = positionZ = Layer.RoundHeight(layerBlock.PositionZ.Value + pos); - break; - } - - continue; } // Check for waits - match = Regex.Match(line, CommandWaitG4.ToStringWithoutComments(@"(([0-9]*[.])?[0-9]+)"), RegexOptions.IgnoreCase); - if (match.Success && match.Groups.Count >= 2) + if (line.StartsWith(CommandWaitG4.Command)) { - var waitTime = float.Parse(match.Groups[1].Value); - - if (layerBlock.PositionZ.HasValue && !layerBlock.RetractSpeed.HasValue) // Must be wait time after lift, if not, don't blame me! + match = Regex.Match(line, CommandWaitG4.ToStringWithoutComments(@"(([0-9]*[.])?[0-9]+)"), + RegexOptions.IgnoreCase); + if (match.Success && match.Groups.Count >= 2) { - layerBlock.WaitTimeAfterLift ??= 0; - layerBlock.WaitTimeAfterLift += ConvertToSeconds(waitTime); - continue; - } + if (_syncMovementsWithDelay && match.Groups[1].Value.StartsWith('0')) continue; // Sync movement delay, skip - if (!layerBlock.LightPWM.HasValue) // Before cure - { - layerBlock.WaitTimeBeforeCure ??= 0; - layerBlock.WaitTimeBeforeCure += ConvertToSeconds(waitTime); - continue; - } + var waitTime = float.Parse(match.Groups[1].Value); - if (layerBlock.IsExposing) // Must be exposure time, if not, don't blame me! - { - layerBlock.ExposureTime ??= 0; - layerBlock.ExposureTime += ConvertToSeconds(waitTime); - continue; - } + if (layerBlock.PositionZ.HasValue && + !layerBlock.RetractSpeed.HasValue) // Must be wait time after lift, if not, don't blame me! + { + layerBlock.WaitTimeAfterLift ??= 0; + layerBlock.WaitTimeAfterLift += ConvertToSeconds(waitTime); + continue; + } - if (layerBlock.IsAfterLightOff) - { - if (!layerBlock.WaitTimeBeforeCure.HasValue) // Novamaker fix, delay on last line, broke logic but safer + if (!layerBlock.LightPWM.HasValue) // Before cure { layerBlock.WaitTimeBeforeCure ??= 0; layerBlock.WaitTimeBeforeCure += ConvertToSeconds(waitTime); + continue; } - else + + if (layerBlock.IsExposing) // Must be exposure time, if not, don't blame me! { - layerBlock.WaitTimeAfterCure ??= 0; - layerBlock.WaitTimeAfterCure += ConvertToSeconds(waitTime); + layerBlock.ExposureTime ??= 0; + layerBlock.ExposureTime += ConvertToSeconds(waitTime); + continue; } - + + if (layerBlock.IsAfterLightOff) + { + if (!layerBlock.WaitTimeBeforeCure + .HasValue) // Novamaker fix, delay on last line, broke logic but safer + { + layerBlock.WaitTimeBeforeCure ??= 0; + layerBlock.WaitTimeBeforeCure += ConvertToSeconds(waitTime); + } + else + { + layerBlock.WaitTimeAfterCure ??= 0; + layerBlock.WaitTimeAfterCure += ConvertToSeconds(waitTime); + } + + continue; + } + continue; } - - continue; } // Check LightPWM - match = Regex.Match(line, CommandTurnLEDM106.ToStringWithoutComments(@"(\d+)"), RegexOptions.IgnoreCase); - if (match.Success && match.Groups.Count >= 2) + if (line.StartsWith(CommandTurnLEDM106.Command)) { - byte pwm; - if (_maxLedPower == byte.MaxValue) + match = Regex.Match(line, CommandTurnLEDM106.ToStringWithoutComments(@"(\d+)"), + RegexOptions.IgnoreCase); + if (match.Success && match.Groups.Count >= 2) { - pwm = byte.Parse(match.Groups[1].Value); - } - else - { - ushort pwmValue = ushort.Parse(match.Groups[1].Value); - pwm = (byte)(pwmValue * byte.MaxValue / _maxLedPower); - } + byte pwm; + if (_maxLedPower == byte.MaxValue) + { + pwm = byte.Parse(match.Groups[1].Value); + } + else + { + ushort pwmValue = ushort.Parse(match.Groups[1].Value); + pwm = (byte) (pwmValue * byte.MaxValue / _maxLedPower); + } - if (pwm == 0 && layerBlock.LightPWM.HasValue) - { - layerBlock.IsAfterLightOff = true; - } - else if(!layerBlock.IsAfterLightOff) - { - layerBlock.LightPWM = pwm; - } + if (pwm == 0 && layerBlock.LightPWM.HasValue) + { + layerBlock.IsAfterLightOff = true; + } + else if (!layerBlock.IsAfterLightOff) + { + layerBlock.LightPWM = pwm; + } - continue; + continue; + } } } diff --git a/UVtools.Core/GCode/GCodeLayer.cs b/UVtools.Core/GCode/GCodeLayer.cs index a2bdfe4..bf60c02 100644 --- a/UVtools.Core/GCode/GCodeLayer.cs +++ b/UVtools.Core/GCode/GCodeLayer.cs @@ -8,6 +8,7 @@ using System; using UVtools.Core.FileFormats; +using UVtools.Core.Operations; namespace UVtools.Core.GCode { @@ -118,6 +119,15 @@ namespace UVtools.Core.GCode layer.WaitTimeAfterLift = WaitTimeAfterLift ?? 0; layer.RetractSpeed = RetractSpeed ?? SlicerFile.RetractSpeed; layer.LightPWM = LightPWM ?? SlicerFile.GetInitialLayerValueOrNormal(layerIndex, SlicerFile.BottomLightPWM, SlicerFile.LightPWM); + + if (SlicerFile.GCode.SyncMovementsWithDelay) // Dirty fix of the value + { + var syncTime = OperationCalculator.LightOffDelayC.CalculateSeconds(layer.LiftHeight, layer.LiftSpeed, layer.RetractSpeed, 1.5f); + if (syncTime < layer.WaitTimeBeforeCure) + { + layer.WaitTimeBeforeCure = (float) Math.Round(layer.WaitTimeBeforeCure - syncTime, 2); + } + } } } } diff --git a/UVtools.Core/Operations/OperationCalculator.cs b/UVtools.Core/Operations/OperationCalculator.cs index 3ea2fe4..6cf526b 100644 --- a/UVtools.Core/Operations/OperationCalculator.cs +++ b/UVtools.Core/Operations/OperationCalculator.cs @@ -271,23 +271,35 @@ namespace UVtools.Core.Operations _bottomWaitTime = bottomWaitTime; } - public static decimal CalculateSeconds(decimal liftHeight, decimal liftSpeed, decimal retract, decimal waitTime = 0) + public static decimal CalculateSeconds(decimal liftHeight, decimal liftSpeed, decimal retractSpeed, decimal extraWaitTime = 0) { - try + var time = extraWaitTime; + if (liftSpeed > 0) { - return Math.Round(liftHeight / (liftSpeed / 60m) + liftHeight / (retract / 60m) + waitTime, 2); + time += liftHeight / (liftSpeed / 60m); } - catch (Exception) + if (retractSpeed > 0) { - return 0; + time += liftHeight / (retractSpeed / 60m); } + + return Math.Round(time, 2); } - public static float CalculateSeconds(float liftHeight, float liftSpeed, float retract, float extraWaitTime = 0) + public static float CalculateSeconds(float liftHeight, float liftSpeed, float retractSpeed, float extraWaitTime = 0) { - if (liftSpeed == 0 || retract == 0) return extraWaitTime; - return (float) Math.Round(liftHeight / (liftSpeed / 60f) + liftHeight / (retract / 60f) + extraWaitTime, 2); - + var time = extraWaitTime; + if (liftSpeed > 0) + { + time += liftHeight / (liftSpeed / 60f); + } + if (retractSpeed > 0) + { + time += liftHeight / (retractSpeed / 60f); + } + + return (float)Math.Round(time, 2); + } public static uint CalculateMilliseconds(float liftHeight, float liftSpeed, float retract, float extraWaitTime = 0) => @@ -296,15 +308,8 @@ namespace UVtools.Core.Operations public static float CalculateSecondsLiftOnly(float liftHeight, float liftSpeed, float extraWaitTime = 0) { - try - { - return (float)Math.Round(liftHeight / (liftSpeed / 60f) + extraWaitTime, 2); - } - catch (Exception) - { - return 0; - } - + if (liftSpeed <= 0) return extraWaitTime; + return (float)Math.Round(liftHeight / (liftSpeed / 60f) + extraWaitTime, 2); } public static uint CalculateMillisecondsLiftOnly(float liftHeight, float liftSpeed, float extraWaitTime = 0) => diff --git a/UVtools.Core/UVtools.Core.csproj b/UVtools.Core/UVtools.Core.csproj index d1da60f..654fa5e 100644 --- a/UVtools.Core/UVtools.Core.csproj +++ b/UVtools.Core/UVtools.Core.csproj @@ -10,7 +10,7 @@ https://github.com/sn4k3/UVtools https://github.com/sn4k3/UVtools MSLA/DLP, file analysis, calibration, repair, conversion and manipulation - 2.15.0 + 2.15.1 Copyright © 2020 PTRTECH UVtools.png AnyCPU;x64 diff --git a/UVtools.WPF/MainWindow.axaml.cs b/UVtools.WPF/MainWindow.axaml.cs index 3b8bb8a..925e554 100644 --- a/UVtools.WPF/MainWindow.axaml.cs +++ b/UVtools.WPF/MainWindow.axaml.cs @@ -1125,33 +1125,52 @@ namespace UVtools.WPF SlicerFile.CanUseBottomLightOffDelay && (Settings.Automations.ChangeOnlyLightOffDelayIfZero && SlicerFile.BottomLightOffDelay == 0 || !Settings.Automations.ChangeOnlyLightOffDelayIfZero)) { - float lightOff = Settings.Automations.LightOffDelaySetMode switch + if (SlicerFile is ChituboxFile chituboxFile && + chituboxFile.HeaderSettings.Version >= 4 && + (chituboxFile.WaitTimeBeforeCure > 0 || chituboxFile.WaitTimeAfterCure > 0 || chituboxFile.WaitTimeAfterLift > 0)) { - Enumerations.LightOffDelaySetMode.UpdateWithExtraDelay => SlicerFile.CalculateBottomLightOffDelay((float) Settings.Automations.BottomLightOffDelay), - Enumerations.LightOffDelaySetMode.UpdateWithoutExtraDelay => SlicerFile.CalculateBottomLightOffDelay(), - _ => 0 - }; - if (lightOff != SlicerFile.BottomLightOffDelay) - { - modified = true; - SlicerFile.BottomLightOffDelay = lightOff; + // Ignore this automation } + else + { + float lightOff = Settings.Automations.LightOffDelaySetMode switch + { + Enumerations.LightOffDelaySetMode.UpdateWithExtraDelay => SlicerFile.CalculateBottomLightOffDelay((float)Settings.Automations.BottomLightOffDelay), + Enumerations.LightOffDelaySetMode.UpdateWithoutExtraDelay => SlicerFile.CalculateBottomLightOffDelay(), + _ => 0 + }; + if (lightOff != SlicerFile.BottomLightOffDelay) + { + modified = true; + SlicerFile.BottomLightOffDelay = lightOff; + } + } + } if (Settings.Automations.LightOffDelaySetMode != Enumerations.LightOffDelaySetMode.NoAction && SlicerFile.CanUseLightOffDelay && (Settings.Automations.ChangeOnlyLightOffDelayIfZero && SlicerFile.LightOffDelay == 0 || !Settings.Automations.ChangeOnlyLightOffDelayIfZero)) { - float lightOff = Settings.Automations.LightOffDelaySetMode switch + if (SlicerFile is ChituboxFile chituboxFile && + chituboxFile.HeaderSettings.Version >= 4 && + (chituboxFile.WaitTimeBeforeCure > 0 || chituboxFile.WaitTimeAfterCure > 0 || chituboxFile.WaitTimeAfterLift > 0)) { - Enumerations.LightOffDelaySetMode.UpdateWithExtraDelay => SlicerFile.CalculateNormalLightOffDelay((float)Settings.Automations.LightOffDelay), - Enumerations.LightOffDelaySetMode.UpdateWithoutExtraDelay => SlicerFile.CalculateNormalLightOffDelay(), - _ => 0 - }; - if (lightOff != SlicerFile.LightOffDelay) + // Ignore this automation + } + else { - modified = true; - SlicerFile.LightOffDelay = lightOff; + float lightOff = Settings.Automations.LightOffDelaySetMode switch + { + Enumerations.LightOffDelaySetMode.UpdateWithExtraDelay => SlicerFile.CalculateNormalLightOffDelay((float)Settings.Automations.LightOffDelay), + Enumerations.LightOffDelaySetMode.UpdateWithoutExtraDelay => SlicerFile.CalculateNormalLightOffDelay(), + _ => 0 + }; + if (lightOff != SlicerFile.LightOffDelay) + { + modified = true; + SlicerFile.LightOffDelay = lightOff; + } } } diff --git a/UVtools.WPF/UVtools.WPF.csproj b/UVtools.WPF/UVtools.WPF.csproj index e2a8f43..23296a9 100644 --- a/UVtools.WPF/UVtools.WPF.csproj +++ b/UVtools.WPF/UVtools.WPF.csproj @@ -12,7 +12,7 @@ LICENSE https://github.com/sn4k3/UVtools Git - 2.15.0 + 2.15.1