From e1d9393e510d86ce6e67614d99d9ca98c1e9b74e Mon Sep 17 00:00:00 2001 From: Filip Sykala - NTB T15p Date: Fri, 8 Dec 2023 16:22:35 +0100 Subject: [PATCH 01/91] Fix: invalid distance from surface when load from 3mf --- src/libslic3r/EmbossShape.hpp | 2 +- src/slic3r/GUI/SurfaceDrag.cpp | 13 +++++++++---- src/slic3r/GUI/SurfaceDrag.hpp | 3 ++- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/libslic3r/EmbossShape.hpp b/src/libslic3r/EmbossShape.hpp index 9094d2ad5d..3e4a950037 100644 --- a/src/libslic3r/EmbossShape.hpp +++ b/src/libslic3r/EmbossShape.hpp @@ -105,7 +105,7 @@ struct EmbossShape // Note: image is only cache it is not neccessary to store // Store file data as plain string - assert(file_data != nullptr); + // For Embossed text file_data are nullptr ar(path, path_in_3mf, (file_data != nullptr) ? *file_data : std::string("")); } template void load(Archive &ar) { diff --git a/src/slic3r/GUI/SurfaceDrag.cpp b/src/slic3r/GUI/SurfaceDrag.cpp index 39573dbf96..c200b6e0ed 100644 --- a/src/slic3r/GUI/SurfaceDrag.cpp +++ b/src/slic3r/GUI/SurfaceDrag.cpp @@ -198,15 +198,20 @@ std::optional calc_distance(const GLVolume &gl_volume, RaycastManager &ra if (volume->is_the_only_one_part()) return {}; + if (!volume->emboss_shape.has_value()) + return {}; + RaycastManager::AllowVolumes condition = create_condition(object->volumes, volume->id()); RaycastManager::Meshes meshes = create_meshes(canvas, condition); raycaster.actualize(*instance, &condition, &meshes); - return calc_distance(gl_volume, raycaster, &condition); + return calc_distance(gl_volume, raycaster, &condition, volume->emboss_shape->fix_3mf_tr); } -std::optional calc_distance(const GLVolume &gl_volume, const RaycastManager &raycaster, const RaycastManager::ISkip *condition) -{ +std::optional calc_distance(const GLVolume &gl_volume, const RaycastManager &raycaster, + const RaycastManager::ISkip *condition, const std::optional& fix) { Transform3d w = gl_volume.world_matrix(); + if (fix.has_value()) + w = w * fix->inverse(); Vec3d p = w.translation(); Vec3d dir = -get_z_base(w); auto hit_opt = raycaster.closest_hit(p, dir, condition); @@ -589,7 +594,7 @@ bool start_dragging(const Vec2d &mouse_pos, std::optional start_distance; if (!volume->emboss_shape->projection.use_surface) - start_distance = calc_distance(gl_volume, raycast_manager, &condition); + start_distance = calc_distance(gl_volume, raycast_manager, &condition, volume->emboss_shape->fix_3mf_tr); surface_drag = SurfaceDrag{mouse_offset, world_tr, instance_tr_inv, gl_volume_ptr, condition, start_angle, start_distance, true, mouse_offset_without_sla_shift}; diff --git a/src/slic3r/GUI/SurfaceDrag.hpp b/src/slic3r/GUI/SurfaceDrag.hpp index 9f1c0e3c07..414279f767 100644 --- a/src/slic3r/GUI/SurfaceDrag.hpp +++ b/src/slic3r/GUI/SurfaceDrag.hpp @@ -89,7 +89,8 @@ std::optional calc_surface_offset(const Selection &selection, RaycastMana /// Contain model /// Calculated distance from surface std::optional calc_distance(const GLVolume &gl_volume, RaycastManager &raycaster, GLCanvas3D &canvas); -std::optional calc_distance(const GLVolume &gl_volume, const RaycastManager &raycaster, const RaycastManager::ISkip *condition); +std::optional calc_distance(const GLVolume &gl_volume, const RaycastManager &raycaster, + const RaycastManager::ISkip *condition, const std::optional& fix); /// /// Calculate up vector angle From 9e6d58861fbc77cd4d6cb0e7a3e80b26ca5d02bf Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Mon, 18 Dec 2023 13:58:27 +0100 Subject: [PATCH 02/91] Switch OpenVDB repository to prusa3d --- deps/+OpenVDB/OpenVDB.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/+OpenVDB/OpenVDB.cmake b/deps/+OpenVDB/OpenVDB.cmake index cfafa0376e..6211f346c5 100644 --- a/deps/+OpenVDB/OpenVDB.cmake +++ b/deps/+OpenVDB/OpenVDB.cmake @@ -15,7 +15,7 @@ endif () add_cmake_project(OpenVDB # 8.2 patched - URL https://github.com/tamasmeszaros/openvdb/archive/a68fd58d0e2b85f01adeb8b13d7555183ab10aa5.zip + URL https://github.com/prusa3d/openvdb/archive/a68fd58d0e2b85f01adeb8b13d7555183ab10aa5.zip URL_HASH SHA256=f353e7b99bd0cbfc27ac9082de51acf32a8bc0b3e21ff9661ecca6f205ec1d81 CMAKE_ARGS -DCMAKE_POSITION_INDEPENDENT_CODE=ON From 3042b6d456e966ee2611449b00cfdde4bcf71921 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Thu, 21 Dec 2023 16:03:13 +0100 Subject: [PATCH 03/91] Fix for #10419 - Layer change colour dialog opens off screen in 2.6 --- src/slic3r/GUI/DoubleSlider.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slic3r/GUI/DoubleSlider.cpp b/src/slic3r/GUI/DoubleSlider.cpp index dda268f2a0..96313e19b1 100644 --- a/src/slic3r/GUI/DoubleSlider.cpp +++ b/src/slic3r/GUI/DoubleSlider.cpp @@ -2239,7 +2239,7 @@ static std::string get_new_color(const std::string& color) data->SetChooseFull(1); data->SetColour(clr); - wxColourDialog dialog(nullptr, data); + wxColourDialog dialog(GUI::wxGetApp().GetTopWindow(), data); dialog.CenterOnParent(); if (dialog.ShowModal() == wxID_OK) return dialog.GetColourData().GetColour().GetAsString(wxC2S_HTML_SYNTAX).ToStdString(); From b1c791766ca03f721f3fdbe70f6c62577cc55263 Mon Sep 17 00:00:00 2001 From: rtyr <36745189+rtyr@users.noreply.github.com> Date: Tue, 2 Jan 2024 10:43:16 +0100 Subject: [PATCH 04/91] new Snapmaker resources --- .../Snapmaker A250 Dual QSKit_cover.png | Bin 0 -> 20874 bytes .../Snapmaker/Snapmaker A250 Dual_cover.png | Bin 0 -> 22830 bytes .../Snapmaker/Snapmaker A250 QSKit_cover.png | Bin 0 -> 20874 bytes .../Snapmaker A250 QSKit_texture.svg | 63 +++++++++++ .../profiles/Snapmaker/Snapmaker A250_bed.stl | Bin 0 -> 23484 bytes .../Snapmaker/Snapmaker A250_cover.png | Bin 0 -> 22830 bytes .../Snapmaker/Snapmaker A250_texture.svg | 59 ++++++++++ .../Snapmaker A350 Dual QSKit_cover.png | Bin 0 -> 26826 bytes .../Snapmaker/Snapmaker A350 Dual_cover.png | Bin 0 -> 23242 bytes .../Snapmaker/Snapmaker A350 QSKit_cover.png | Bin 0 -> 26826 bytes .../Snapmaker A350 QSKit_texture.svg | 107 ++++++++++++++++++ .../profiles/Snapmaker/Snapmaker A350_bed.stl | Bin 0 -> 23484 bytes .../Snapmaker/Snapmaker A350_cover.png | Bin 0 -> 23242 bytes .../Snapmaker/Snapmaker A350_texture.svg | 103 +++++++++++++++++ .../profiles/Snapmaker/Snapmaker J1_bed.stl | Bin 0 -> 67884 bytes .../profiles/Snapmaker/Snapmaker J1_cover.png | Bin 0 -> 21032 bytes .../Snapmaker/Snapmaker J1_texture.svg | 56 +++++++++ 17 files changed, 388 insertions(+) create mode 100644 resources/profiles/Snapmaker/Snapmaker A250 Dual QSKit_cover.png create mode 100644 resources/profiles/Snapmaker/Snapmaker A250 Dual_cover.png create mode 100644 resources/profiles/Snapmaker/Snapmaker A250 QSKit_cover.png create mode 100644 resources/profiles/Snapmaker/Snapmaker A250 QSKit_texture.svg create mode 100644 resources/profiles/Snapmaker/Snapmaker A250_bed.stl create mode 100644 resources/profiles/Snapmaker/Snapmaker A250_cover.png create mode 100644 resources/profiles/Snapmaker/Snapmaker A250_texture.svg create mode 100644 resources/profiles/Snapmaker/Snapmaker A350 Dual QSKit_cover.png create mode 100644 resources/profiles/Snapmaker/Snapmaker A350 Dual_cover.png create mode 100644 resources/profiles/Snapmaker/Snapmaker A350 QSKit_cover.png create mode 100644 resources/profiles/Snapmaker/Snapmaker A350 QSKit_texture.svg create mode 100644 resources/profiles/Snapmaker/Snapmaker A350_bed.stl create mode 100644 resources/profiles/Snapmaker/Snapmaker A350_cover.png create mode 100644 resources/profiles/Snapmaker/Snapmaker A350_texture.svg create mode 100644 resources/profiles/Snapmaker/Snapmaker J1_bed.stl create mode 100644 resources/profiles/Snapmaker/Snapmaker J1_cover.png create mode 100644 resources/profiles/Snapmaker/Snapmaker J1_texture.svg diff --git a/resources/profiles/Snapmaker/Snapmaker A250 Dual QSKit_cover.png b/resources/profiles/Snapmaker/Snapmaker A250 Dual QSKit_cover.png new file mode 100644 index 0000000000000000000000000000000000000000..d8b9d39ac7b52a8386330b0c74f048906755a0d0 GIT binary patch literal 20874 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 b)6)>ss#)S-e*FR9SOjT3)_YW`W{v(I8rACG literal 0 HcmV?d00001 diff --git a/resources/profiles/Snapmaker/Snapmaker A250 Dual_cover.png b/resources/profiles/Snapmaker/Snapmaker A250 Dual_cover.png new file mode 100644 index 0000000000000000000000000000000000000000..5325cafb31349eb99399ce0040cc5470218fb10c GIT binary patch literal 22830 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 b)6)>ss#)S-e*FR9SOjT3)_YW`W{v(I8rACG literal 0 HcmV?d00001 diff --git a/resources/profiles/Snapmaker/Snapmaker A250 QSKit_texture.svg b/resources/profiles/Snapmaker/Snapmaker A250 QSKit_texture.svg new file mode 100644 index 0000000000..a8c7c9cd5c --- /dev/null +++ b/resources/profiles/Snapmaker/Snapmaker A250 QSKit_texture.svg @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/profiles/Snapmaker/Snapmaker A250_bed.stl b/resources/profiles/Snapmaker/Snapmaker A250_bed.stl new file mode 100644 index 0000000000000000000000000000000000000000..9016f9c4f5db29f24b460df88fc74bd81d5d73f9 GIT binary patch literal 23484 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 literal 0 HcmV?d00001 diff --git a/resources/profiles/Snapmaker/Snapmaker A250_cover.png b/resources/profiles/Snapmaker/Snapmaker A250_cover.png new file mode 100644 index 0000000000000000000000000000000000000000..5325cafb31349eb99399ce0040cc5470218fb10c GIT binary patch literal 22830 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 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/profiles/Snapmaker/Snapmaker A350 Dual QSKit_cover.png b/resources/profiles/Snapmaker/Snapmaker A350 Dual QSKit_cover.png new file mode 100644 index 0000000000000000000000000000000000000000..fb801e0347ae3cea58a0e887012a2b7f1ff0e9fb GIT binary patch literal 26826 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%0D@y9r899>f% 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 literal 0 HcmV?d00001 diff --git a/resources/profiles/Snapmaker/Snapmaker A350 Dual_cover.png b/resources/profiles/Snapmaker/Snapmaker A350 Dual_cover.png new file mode 100644 index 0000000000000000000000000000000000000000..123b94e16cab7dee20b0dbe5be9fb87badf64ac0 GIT binary patch literal 23242 zcmeFZWmFwO(=NI0OTma;McmUuV5bwXdGLY(jWWWG`PzwOW z|Hx>4(tj-7ztevycn zUoj&o@qa{|t@ueb3~$9F0wRl*J_er~2m=KdHI1vpo+Z zqnn!>gBvS@oue5eGdDLkBNGcF3k&_H1ih1ot+Sy!y{*&N|E=Wz=n*q<`r&9{?`&ab zOZ-o-p^=@7Ge0TmKSTfB{`Ye_TbTY|OSVq`1thd@==SPN@-95jt0`Q=s=~k`(Eq>xe`*1t&_a+!x4GaM;z3)Q}Z z5tz(I_tyRVK5dW&Xh+C?kD{99=BnLWHCq>I>gwKKsi>rap@QErVt<}5*XF|#V}B?k zL$C;)@T1%NIIz_)*08MM&KT5%9F4P1>*;+C7D}no97DamR(TxDy4)z#UKqmIgU3Dv z!O^3YcDHO2(U7Vi>%MQ#D;GBh3OV8f%?qe2|?Og2ohEtTEHjK%K4(UTH2{MLdvPtkQjf zP1eVsn|X`B6_2Ezky`oE?RbuA)9N-A$;cl))-Fk%&%i~-HR>Pn`3|iiyIhD?Uw0wX z+wV=Jv5rr_!KZBCt*oq64Mt+M1NZH?GpD*yTDX?m*|2C4K9Qu$Ne1_JsqX z#D#Kw)|v1joWRFmXTN2NISGIt=F&jC394{oP283qI{BHB|ha;Z5X6`>T1s?m*Y=g6)XPlL9H$G)k2lR@$l z743&HjldEyax{)0LYTn}AhvC_va&)$2zA1+rSIttrJMzOaOMJsq>IQR5wYU)yq%RS zG}2-CVIk)-*;`UlvYT{!+n&bJ%jd8orpaC8r8r6e*HWA>_woK#h;Lz`d(GN@Uow6; zw=g@SXtxum0kazt0;T49no7g%DCWUWxIj)TBiDIFYq=`Nd1pYzw!?u6t)LMSB>wrEFPeT9f}#whcXuGJbd=WpY1^0eQtcWh%uGn5d|RIl1K_Z6Q7oDw6g4Iy8tmasUEN;iBs)(O}LvSMDAa&uDoh-lLiwJA#N?Ilg@uLGniPXO z+bY<>R!a*DP14mXS|%O8=PX!vgqf3UTk@J*Z)$%G(~zjp%-e6s1t`LH{DzsweF7@3 zyx8xef6EPx$c00KRmwy|gP5qXgb9OnhmAV8gk7nO_h&T3wSh7Z!_Nb}@8*WWaoRoY z)bo3I?8@usXG58oQ^}+dl$_`yS`W;{!CDeh2%R~2rBj7=Fantggly(gud}*lE@2F4yBG{|Paj}I8kS}Pt*2@7A zYei|Ss^?q1Mz(~tK^9|iD~w%_JH*;#7T=q+$-iJ4y_hd-^fDB$5okmD_tTR?I#`M> zP#Rr!*+e$U>^3ppK6Oyd6oDj=;23xzu zD5Ou9L-|1ty**H=-=S{0(l$K?QN4G5n55pG47CtNpB9bGzH%|k6<$Kfx`Vl||FGvV zc3*$a{m5p8T!j;Qj~W~t3^(7ddZ60^fw6m6ulc+rDhS}rhK%K=rKjI6BqbFH78exo z1)rSw;E>fYV*D0JPv472Rmuncu?MW~PhR6V?zOdfF0?v@;BtB*sgY8_Bd@F$BtvMOS5b(VNc4c>MW8$iYpF(VxO zdK{?iS(U=p6p)vf-$1xAL>?e3;g+S3`u$-F&)8(Q$p8xC&&La?OM~%y88?c=xw}Iw zGkZASzufMh@CSc}FM)Ngjum}*)qlNcyu8tWHiwY^1@+8rZ;q|&lK=-O9LR4ab`H)QmL-HHNv^WTkjuhD3ug*FWpDdxiS66c6#Y*A}Tzbdad3} z;ZK^tw;q35r{h$AsFEf-4SU&iUBMqi$mktquA%)$Qn!dTFjQ&kAMZYDs>TIvXN%es zhll2B`uf%Toi{PfZEZsqo)bzBn|{;BO8FAOm0FDv7a1_GUDfec2GD5aTW$0}dIJgZ zJ7LIf*vnf=5I_fP9r#^qs$&=&Zr%`de7{hx!Po_pW7--#FB~E-MyL$h%r!R??B{&h z;ykm#P~d9`(ZuL*pLjfNykfrMzPmfW-ZHqMy4DWP^=b>s;#lXr5fmJ5U$Os23J_lx zelD}i)}ukq5B^|&<4DYCBfP#nx!Jg0TwGKJy^}b@doR7bA>whk>w6l?Z`W-1--m=s z(uwFDX<5ER!t*PWIS4?o*a5g#1Bum+9SRS|DBTH+un z+L2KX2+uUDZ#Ac73CfMk@ar;|F$la^?QXN<|2RH5@stn~iy`3MK1RqmVG1IE))r@y z{o)enqm!^fwiD`=6BmXJ^p z5D@r#pI$q9Q06DiE!^0V^Qa;>_d``irseRxO<7Bcl!u%G^=)*qMup}TSC`C=xndxU ze{Lm!9zQ|N*&U?75ee>J$sDQb=Z5$K`uN`M`^Ff8OhgC~<027* zojS#>!)gZsHEj#1fJynFV_@(t@W3@!ta^Q&BP)rrkncZ*;`P)w;d;))=XW6c+v(0W zP_wm#f(e$5$c4LIlE^WJ6!wLH4V&G0gm`2|7=;~I)!RGc7|cr2Tc<;--j?96S9}N- z<91NExqR^`8xysN%|^p)BQK{$a7aki@XZNH0{+dOwwCYBt1pgUbE&daVOhm#3p8u1 zQku(_GAcxsDjO{_YkUx^FyUb1HW^lAbTqUg1|5kKR{30Nl|Gq}Ym?Sas4~CjEsQ^c zoczRr>Rd?<;WfdDgDo1N@8dQTfT^sajG;3x&xi}-PkRQ^uzLU}Mf!#-Y6J_bA8Sw$ zMEUi#VpQtFcZLNc$EAA=T2*O*@N>5@!!onjgdS`0vcfXDbYlw5*Xm>kP zGc#Vsgq;aG*OnP|(7rVWC1AVNZ{H2>&v}UNpm^{;mcF&pwjqQ~1t~Nb%$6xmDX|%R z3u}EFP3Zjhs}-|I3>x{|9R>>j!e+2kx4`+09%SGIM&xM-*)(h&h#VWjJ501@N$~A< zp1oz?!Fc>9eJkx!#g)2R7B*50Za9#vPDhITFns_P8TK!3XEM>&y-&vlvVe4O#xI@C z_^d2c)l@$rax#kA_@kL9FdIno53|mqC3H-Jd>RGSU$KJkL1QbmqCS_~p_ac79V|~% znJtf#@FwEo6z_&Qnq_5k)LiZwO}x3;+0_7h3WqzoGduC;f2SJkFWVv5FU@cj$GA); zdWcbgdz{pBRx_yhd|&~;8{Pk|CYLWENh0ssa|iBOQO>F;Ea82 zJZI=Fs)xiM^WXY#{s^4=W!a#CBozu~fW#j2B7{vw~-2T6Q5kolg!;}qQUCoU(&D6+1_fCe7xdTGBEocnl zOQeEJEuH&0mzPXf)zDDjCMVa}R|gMKOYf=}bQy_? z0bD0+)}%JqvfArW7x7}l%e4P!d32|AMml(Qu|oO`I?n$-Fkw4iX{*p;of=Ur?So7w z<8oKXlJKI|Mw+yxV5uCz020HEzq*LIcF$Jo4}v7c7Z6$Grro{m zNQ)k#0V#4hEW-@`W9s%b^R+G~UoOIEt4KA-KyS{Z_M-hFkcX=8<{l;Gl~})6E}BIQ ze&mNw2Lo}vW2%Z=PD#F%TUolgOr2hzZt6XqobbAy8uMxCzDCz$cKz8-ywp(DPKJ=6 zAypfQ@-ORI**$c1O4JDI6RcGmR=G&)X7&mfs6YnFF~>qfl=}X6dBNNgoJMDK_D<)DxH_&X(Vf-Z#%oF); z#ukYh6~M9KbzEA^(ivh^u+2^hM*RcO>uYGZJ%_Sve%PU|qHE(e*~B$hkb9|p8Ku&^ z?)eMXXBi7JMC$Qn>f{b|Gv%ds>g@* z=e6%vU-At2sUvhp9^)^SoIhM_WoUoe5i%Zy(GaTZYnZe!D#X8ovA)cRB0s$)d^`>d zQiwWtf=P6T*StnUm*ZkXsX$bc*%pjClQ1ktWFT%Oj(v8co(dsF7&qk z{ZlkF=TjG0w6PgilQFxPs$NGFv&r2!Gk`D5&26{eW4{YZ@vunNgsuHAQP3t;d?U#h z6skDRH-LoJZ5o%%itI>d*baEzBsZ)jQbJG=6g*0rAa5*v4kG^^abH|w|Cg|amKcJJ z@Za10gNOcbY675%1O3*$MGAwad5J~w`{o0^)rY%Q6AUhy!e+X7r*KI7oHF{tnf;kv zgN~y4mxfZ6iG(?{zk$etuF6MXOy{1Tz15Ao3nx!;NY}%zNRkiZAA~J#Y~c5O3Q97DQ>;wfc;VdIl(?>Pe zUxAOHuK}OR%G#cX${`ha-zvta+tVh@yiW1JET!&RPDZp9pa0KL?YJx7D!nLHN~7E%$L)ef~vtrV}lEOMzKls#r+yP7BbD7tA$*mrkRx&Rz2Ew$Yj0oW* zI8<)H$CpIZ%{#CXBsZTo{VjA|HrrSCW`!hX<_angBO{FFWmZMix$T|*Sl8vA)DJ#P zxVd)y5u>X=u^#rYNtpvH55;n{FMi+@kUCNTChf)C(j11&%siV4?AxpL`8`9qcIgljvMT@VOk3&gQ63U9G~-q z?AR?s$NK%98>t4iG*`&hwc<{0!S?=Jqf*x270AYYa=xxx27}K-ODh9- zKIgTgC2Zb!R%3VkjSY-~B#wZ#4TD7aYA~DQ!^2K4Zer?65;j>dASP=Q!AB1I;~uM$ zfkY%=bUHH1?BwL;MeGZ(qu?q_@kM2j<;p3YK3%K~t+lfw#8oA=9>hQG-3m9cxk=2( z(QS2XT}??TwtYLcA@!?ACC*0S7RgAB6C$#FF9MJM;C~5t7-v0C`e&&{{&pj71k$RRyOaKzJo*2Oj(u&#Igw!5D}Go-W`{=nVOcd*>7t;f;$!6 zN&~TX;GXbJ=tdZs?hg*UkO^q6)zva{SoQ-R{h9HsHb}X=P42?W1_5d4k#P#6BZpBg zTtfwuEqL|yKt(b`C_}jK+_DkvI5?d!l8kQ`R{`Bm zzV7Y?9g_AZGtU_2&_deaGz$xAeXy{mPysslLH4>(?KTuWyv~=z3zb$Htkk1BeZ_P0 zC9j4%C1Cc^;7?DczQVZ=pC7-9WOC4dc$t|Ogli%04H$(w5J$8S2IvQ%Bum!LFfYbEa{T0cm^=*9*}7eWH+27UZl11CTN?~%rY|HGMQ$RT_R!$ zqUbYCCh$R3l$54hUSHf{&6^{_BNI1*9@0hh@=pA)r2fS-H!=)z=M>2_6vptslk{=U z+isB9jRs&;gk~!ik2I9j)Cyw^Ou1TWR^7Hh-*vo~wRKgjdh)iTA|isEloO zsEE2a%C*}A3{H}9!Y<@)cg0-x8ocx=8Wj?>Y#ZAl!W9dPi0-%N>6OiqL3pcXr~Vuc z`#%wk40}$`BO?Cp2$D>o6xIpHWo6m+c}3sRm-J9%9%HxM_x1&nN??2;+;#Q^>kB4t zLHQ6jn%mV-K-SXI0yAdi|Db3H{AoxfsvQJxVZQ7?Q&aPN85Wl1Zsxz*IKC0w10Fm( zJ}VKyIm=wb{rA~@MQNc^Ltlxf@(DN+jC||rd;8Q!y;Z#quTW+}t@wrv<`xrq5ybx- z5o8sw!n$l0L6k~hbh_ES32EHKV*AmKEbkUNY zR%U;kQvPUjoqUy(mDNF}DUjZJ2VC0yq}RS5KRrEFWD9WzbtJ*|t>{(Yxv;allrE3a zGjn5}=k$_VW(ZZI!G=<5Syf@TG(5Q)06ep&R`?g3Zhh#=>D56{|gyl0#H3n4B9TQHZuAPG4W~xjcED{t(?Ps+$ zoF0w}k#J^#g>s_>s&7V zyC;)zGbnfa9nGCgz1$>rcE-$xXz=4BBP9>qZEI7{Sn~cLj5tQ3XE0l>l>OF;KY_+{ z9K7SZW`-To5dte|g%S$FbB;C*D!aF#t1cdbv5w~CNoIz% z=!k`y|Ku>9Ww=GHH^S$v)Wd}qjR+&1*q{t-w`9kl$KL?vZTPk{@n4=4r ztbotiM(>3*3(^H&#Ha6&1%n&h;@ysjUWBT$H+|iQIqKr)W(ofy=wc2D*MMhbP-vvN zR*g~D2X12CZXLE12KQnL&8H#}@{y?NqACBg+ivr{4hjaV(f_3^m0Gv#Pgw!D^4%_7 zGv1wfQ~v~|LnTH$_=h~Cx%2q-<8Fmp5bs1AyG`UC;;`8IV*?kn#vCv*Kd{sDLAkJS zcwi@xibsbSausprGzhY1x4SEyFB!q-yS;f*Y#t_bG~LsR<8$}@aX5uf^R|o)oo*M{ zG(!!?-AP@S_^$+@3x#(Wc9F<($=!T%ol-$_w5Fz1x!jE#v%nBo{gq=VSOji{pir~& zR6(wtOZG;mob7n;Ajyi=k^MV{xl;qmu&ZnE*B8IqIdI>e=KQ~*L)USv+UqMcnEsRO zyx1_iJ!a|%Zy(Kl3tPGnNa$Z0oEzQ0t9t@{q?&Nad)IU_ z3?TH$fb~$$C%-L!fos)8r;~w3)AeIX$WWO!hW_|uKqqc5XFyJeTFtH z`(HY#cSfWMR3r5k;?tFL{#4-a_CT=FZdAE2koEVN2|)cZohD+1R*3vP@>hdDa2lP=HGgg@DK;38S; zm_rwof0feB7s&288J_yk0@uH)gIFxiL{6`Tjd|tFMewiZI7091&35A+9)BH-jeTP_ zj1P3nA;*oFOPFNHJGmL!2oH<+=m!g|MMgf18+Q zR6SX;WBWpWF_@f3$NQ zXVBCW>}FL=`*+kSisxZK7-u*+!5A~lO{poPO4^?moLB>fk=(`gv%vpp@b{>PR(DsR z!7XB_z+6Jz+wUqQbXJ0aHkHzWosgtFE%Ko5~i_NE%As?HbAMs- zKL_)sBpVK@r4}EZPVd3r6OE)4@VG>z8~~4+jtU1oC=KL#&?;cf-HR0LATF~%UZ=Sv z74N8iOE99`$W=J1jZ8Q=DOQ}1&DIRjSk3EXzt(=Di1xJ4@sBX*!<4~`iR5W*4^zAs zQITPCr$7qUUh7Mw@`sjsMMy&X=`+pc4@A{{(tTi0l2T_qU=4UaAR#gvpd$mA*hI*e zjFs=R0JPk&>IhK~YU?n?(MFB{KQI>sbWLJ^5@H^_mz0EYK-Vic$2o4TMvLNpy%|$0 z6Uonm5-pz$A$kx~S%`u`f(sw!aDgi?d4GPw+85B(*M9Q?wFX>`)&j33x*<2Li)R=> zrr)V0$Mn7yi?LuIZwIP_*|n*U)!#1|%6rfnHsFbl$fi1H_2G!82TVtE46V64NT$&f*V6LA+h zdcfdXEIz}v#P9&OQH^_J7%mmY_~0HMj4h!i4%~^chT$gm5gnP_`wczt^us3?D=API z8TG68P5@Dl)SCPIQ_71G`L=_(+0xd7lx*w?KA4un?N8o!qY%W0@Ll;ODH#+9{cYIRE$KJ@7N)&6RSX@rqfa0cm%qsb$ z_^h!`@(!h0CFhD1UlMBOUb>+W5pwdvzqspJkPp+ZQ_z6-X(eiH@VZ`1sW)>x0dIFK zfGZb`E4~m5t^pxvwg)Cc7J`bKSx9IqT07(iBSmjffyu}Q&GNb2f)O&-(2pEJwrW_* zT-fvNX1-m=9<-y|j{*emz28bxbkL$Yheqi!O6Iy6{ixRXQuCZ(H@HtO42$xD7)jB* zsF%FEG^d>zRN3J^*6W9V5^AJg=QV%5v`=?l&e;*BI$Y?(n&Rt>Et^-HtgRBxl!!t7 z5`}L)EsLkDP~9B#$fBAaE4O_Jgn;|GURGUFf^d#OM5zK(Vd#=VWtz5JL6xi0QJj+# zN1G?_f@gU=0p0!Kcf~CIar5|Bkg;B;M+0D1;>->wDfo(H!oOw|gxoXXVzBoz z7}odt28Oo7LD#2soALDb1wjB|oZWXs%Xe!A0%g8_%m|pmc*%S3FXI>I4oJGNHn2IB z;C4S>Z@og)yTDxDb|Bpt8RCQv4GERzUVaDY*|zL9UD5)ex?xjAc0ZzaDPb<$Q8&SP zy*TmxJkEn#k@Nq0IPd#BboQ4tL|m>f_Iw7#^+^aNXpZK;+tm0Mb@k8K7nh!3@V83l z&VY=asi(F1J_p#EHAp=&I6&5g>kRE z?Z%tfH`}hqXpwW3+XL~S*8oUcJriWTKb#nSkCXhZ9

bZOX@vH?$X=MDVbOwk_vvkj!wMhjN+))nmjO1UU=7cj{R)D zu*7~-8u8geS7*1SjdO`j&<)eSzvAO!N{MAq8wf5s4YDP&QM>LQ9E93C<$a^m9`DgL z8n4;0khUm|fQbdfi4N}coF#Hww$hpvmp{%3*H<;A(z+`Tn*KIT_9WU{S2#%ug#hg9^mT+-)+@j4G=GKhfa`z5F0d*p zEL`~OOCW1~ZnM^uEckl)b;7s?Q0;MiQL#bQGF#rLLG*15&Th?|})K>^URfQ`TZ%DY5zEE>_f0(?9Zza1rt;c`qb9Y*T~j2X zg|k%=NMzyxo3LMU{XtRuQ$%=HlrT^>g%$#|Q;BV6Kl4LTlZAn@=lMJ-=?SKU4Ge()S6;qXamt-E&GD5>MFqI>yAUDo4CTlfGLnb4vgVaDYIiI zr~UVF3wJ-rL8YdvoKm}?C>#u%*FB3XEG?AU1)4I*O-o$JL6TXBdAV$uWstCF5=CL# z6?0qFDyy^pZFUZUW(#+NyCYZtGZu8aJ*%Hzmh+iTCai9gcS=@fU(_WsaeSf8Xr?zl zTy++W+a!xuj9?lWkJ~Qr8wsw`RWF!YAn+&E#B)q^WUw&BAw)t2*yXG!gaa?P%nZ^a z(lyoym~3EOAl{rH2N*3Cm!_)z#d%_S!fz0LUSJtbIsRd(DnrxLqxCF}7^)23SbC1K zNk+3%?NOGf1vMu)Jh!cdAi|s!4Kh-ysh>@(oWa1uV>%e^T~DJ-D&pY$ znPGJn5xpkm=aitSoQhTd68cr$CisxqbzKv6(mQ%p{@r^jfId6#C;)O#(7|Uq1M5IQ zS9j0ba(}`r27S5Grr*{{2wIt9W=)<8E9|`7tkm9dWUP$F8h^KgFn#q-LEvt zpG(lK_H#Bqb@g4GA?y1|;4&=Amb7#&joE=Z!fle#uVV(IyPoD#sskShTn2ojW6`cY zl8Dz7i>y>woEKPxDL!x|F)d8&1b9gqu`$;D!RezZ>~c)PpGmh^#~@DW;2N{yZ_7c( zK*7V70h^7gR?j?#8@c)QWx|z#XS;`tlBzYts@L|7PA|!5d~QeV-QCR}H_!O08|qX? z)d2hlw24Q#yUK_C(#pC-~%1C&WYox5_H zee6Zu!n2U!%D@pT*i^|E-#VSMbyNQpSGd0`NF1&=KB8CmZ;M6~`@=6zTw z-&(dwS0No$AbL+0E)kI+PEVG;p5FU)7Qa^)sAH0l`V<5IR|K2HnRgoyU8IeD*#QCF z%mDl%z(@C(c=2}`Qxur;Zy4CzWqz=8a=Jl-2t*75A?8kMjoB~5A|mQKp6s)mRSy_&EGI1i z%~e1lq(Rd7Bh9`Cs);mqY*$8*R05Qc7qM$WS)-MDNwxPLMRHO?5Pc@&YJ~hiVBk}c zEvOC=u;hF5#OyD5hyMFe&*Y-- zAlpk_c%a8X4F4SR2Odd`k<7yws|j0?4|fPfj|6w1!9gZc+d727bbr_ZZM)mWRIoR} zF#=-YwYl@?NSH%DqV-Bse`Z?z{w_=B+smDb!y3eFIb4ZQiHgW>5-M+Vnv)!Rw_%A4%@hjYaZ$=ZViI8a}ep^*{TQF!h4&hzOT~W-k#`s%_DBJ9TIYE2!5xwi2^=tc|Kaw{VaZJaekmNT6D-F9ux~{*cVcX z#U(>{UhiQR%sMK$0Qv~UD7L=7erN;gu#XHL8?EEX=8xfhB7xhPD~ei$tG{^w+{%&o z%*?X^VZ2(fRQ`vl=PB${=|>qVPYSpQrSfm=hU?fsHXphkhaPT(iB%~@eiFU7#5mBF z0Mp~aXi)}P1(JyWeh*ThBRd$&k=&m)7a8B@qhbxgs{wSzXdGTs(GOoA0_>fOh3XHX z;o3Slr?sLtdb`_@=wV<6tQ{ew>DXV+L{89MOOJ(P*o5N(J^B!N5F8{V zF~6i6zCO3{j8Mmwg6AE{2tsO>?%W9Pp}G*o-hgk-Gy{V^QdvyKXx)96s{LM;W9N9y zUg4T7BJW#Z2bItIQQV!`Y<^c@6AoR^Ma@3aS{kL$6&xXHDbHK+vEi2!Jo03!%fC@)h)7GA;f{Ps~ILyw>4t zqC90K4aA=SpiY9t!L!*}8wm`tj%l&o&X+=~ZdsYZx_X+0yFT%o_6};`~KKt{A|?$A@6_BgEbqEE)O&Iz$Mt zM!e6jWn#`cTmb()zp(5Wf}j}&Qve?4(0w{~`$YH`j!BCN0FJ^6t(|34X9fxoI8@E;l(730NKuUg62O0l z4JDMX%p*M#PKjHnq{J2Jpy8@P&e$c!6|Et$=Eq|oU1;d_Quy{ zQ!3ikDwW_xny;r%1;#(g!-gNaj4xPyyoQc-nWBk-fO&^kYX}fbcm&g@@g(r&G+}5- z)gCi+<4`?ZKpoBF$i0U7trvt6eLHveFz`p5@a*iY<`H3ToX`g={g>5?_q*fn3+cW~ zRCZNcY-yDK#-5+h)*h?Jc4T;qf~Fae--2`Xw1}?p2nK}(OfyKKrvw6&c#B#bAf_%x zN2L$J@`LkPqk9z9U1eR)7G=ou{SCg<(FmxP+@G%Iq9r7d>pLG)8lDDj+GI%>c&0qF zkM~9t*NJBujUlT1?nf4knhbdsf{MX#j}=sg|3asDvRIj)L4Esm1c0xZJhpJW z7pZ3Wj`~}a52_*t4vPYGM5Yeio%UlGi5ffOwU>znWf*+OkUrfaFuDrf7@Nd_iinKt$H7Sff|^B&ht08EvxuzfvPi+mC8)S&nvEKn?f$2u*JPQ7EPYra{^+a z-V7O^Urk9V-t%7J13G11j44`~75^`IT;aB-jRIc&sZEL4Eu0Is@@At|Y*N5#i|=vh4PGY+;E7#510 zlzOU{=EBQ)%B!`QFFFvOIB`2$b#R)RI?M6}hvM7Th@9v9I2A)F9T&1U( zfo#Kmnz=}~MEAUWk=$b(G7;U<9SggquDM7Q(i{0(K@~&iDzAXmceUPZr@vzAzPZ6S zF*MRI8wY{mi$-&R^7BZS_USAvBmFi{&LY>{WzC%-iV-m&pb7W|00IRkRJrsNkWl&K6 ztWjX0OOWVBj3g1l5lue-Iy^Gvm+DQCcafi|wMIcKkz9gcfr+V;;( zyu2?V>$<%Bif|cBi{%v+RU+0a@?bd4tfyWY@^n!IkLxtV+9i;BS=1iOwT~H&%;DmR zsD6o3eC@Nrj$d3PQs^-Kp$54stc&nM(~7P6bbC9IzuYU~aa4tV^cmG=&rys$;8;(Q z2=ep@?*F>q%+Tdl-q7RsD)sewfo+zP4h~1yV}t)wj&vV*p z5_K59X;G!mdLt1z1Z zw6i^dy}N685+h@kc#v*KgGLf>TzzfE0h$!&F@|hlzCA{#dl4R6>vt3K)~doNc7+rt z>cj+j1emL>H zkJNu{`OF00Y#xR>8;^Qx z1C52mGDDm(lGuWl*#CD#Qdk{V&xvGWTE=X$&8+z|%7PSdvt+ut`VK_wtMx0@Zt`9U z{TdQ0wb5pB!Uc26=A3T@!^vs0df4%D-mY3L0KOo{=_4K{Z&Z)s54mUOD!Ml7f{8(> z+MDW01}On2=;(%mEUB!Y)StNiem0(32s)4ubJdDK;(iXHM61>*IQkp2@j@PL+HiY&E=Ldw-ht ziZWWjwOzyVa?U()BE%**xlDEIlHejPsIsd1?3%fXDipK_P2>3D4!6K~E; z6pe)0$IUTT=!{ zf8(#yeqtwv#W(pOhF{JG$USzL7#L;JOM1ms9gbw6wr{g&VxG`N{SCVWyX9@^5$nEb zp5i7^Y-J!nXI))#qwoAB%JHTLQ=^PMr_Z5+A5TYoQB%R&m+z-$^{jPmCL2l`8a~Ll z!lul-Pom<3h*a%XhjGGN_dD%Clu$4FOPY;vM*z{4Oa0$kT?WIA zQ$TH>X+slU@Y`X9{cr1&_EDLS9Ob%>pqvB&zairiQQBnhi~U` z`hpr^ZGuhT^=F{hZn-i?PJ=<;Vwdf^(=BXbw1%Y*h|+99!E}CgFFXb(k6lmB6Lz_S zRfA`kglq7hj3~-XOcnzv!xnJ$GH{?7$jiu}4#rQzLco3NV1QgINT_!j=HMEyp^ZY5 zpZ><5h)v2udOhU)7;90>$2Y$|(lPr0W@77N~@DBAj5MD*e z*-dXs7dPpoJ3#yYuJwBFR>X)g-Gj(GOGKWe5 zrY>5yy&Owjj|~Zsyx`t#LlgBnSU0{&nV8%`1s;i29ZLi{^d>#r9%TDHgX=>WiGQ>0 z22A02ZVB~@&Sd+BL!-Xj6M=SCq${*A_zyd=qC!IJ9R7rWNLxSItFE+Ew>+dk_>caqP`kUVU^5??H_jx|sQI-WZ zUsWYHXB`iVXh~ZDsuNMdZQNOukC&LJS98$?2s zl#tON-5mqzl!lFxRFU=zNWyk4JYaNhbH=lOmg=hlR_TXkvZ z1HnrSWum*FQ(7l}q8Yh974Qp(?{XexB3 zpj11hxRD+G?4TTBxiU#d2*6m{I$~ncU+#`Ytvp)rt&w*5wp$*C>^dX;4i5 z#wOepz+lWa>bZ+`SHz7DIzJQ!GBAf87hGS@cUDjG_lP{G{-h73-tWWrpUzp9`m<)5 zZPGz|nX*-c_8j@v#F}DCMVm+e%pWp+$RTFMP?S=oj?M7&EO2x|{{EzQ0z!P-|2KMH zH#IMB4^`#DJNYQ%FG@niemBL6P}?T-bc<6H6nE7CdM_0M_OfLkA^#*Lsp-6=DErwo z&b=vhW|yBnw=}@+krhjx zTUv*+^7X<5A(|B= zk*C5t7o5rg?3MeTGt?|1k_J9Qdt3qc&gRyJLB|eavKe1`X5?;eQpz$ zbhsUOCQ3Rwvk5NOh_qI2=p68K4*V@R`kx=2voYP)&3sDeC9o_Q3j=&>lE_h5aiu<(oKznUwE(PgJSdDXm4Y zh-`!A_OkKTj0qh*`-bi@G9g>Qr^-az)cu1yKShdJDs01NMNY`U0erBKbhE6MQw^d( zblJ}9nDVD61o~HstteTL?pQR|G%HDNGFu1cBKY4q%WgRN1@{05s zcrqh0}Gyij5K?!{J7Gv`?FzcjeS;CV_J4EZ zDYEBibNWB@erhUKE!zAF{VQ9y-rY(Y#&2^6zqM&YL?=&Q!>1rp!gXw~H9a4+9-vEO za1ge}%9B`UU<9KOl^K^{J0aAFvBMr)teZ@EnuVlqq>I#Lk!VxDYUz=UD3)Fc@1t(g zkQ4F3E+VDzsQ7guyNzgY%6Wwy1>nB4UBh0p1G1q9HKKex63ZacgvJwz@G(EBUKR!PM@HkAb3G*CdU9cSoRAiYHVJvm&w_T3il0% z*S^*RX+>0x{=3@^8xNXJhg~AJ?9G^EWg+QO#csFOD{T^;j}CH*0|b73cXNSf!Wz74 z9|TFVxZ5*IV-3&!R^mu_GSKEv`&?XTlTa&?p0rnGuHbS1BXa+^e9_acjz%t9&n3QH zeW|0-K}^7M1EcI{F8Jv*CuLM)ZeJTz5f_))zSf9_F_0nnj41#LEWWF=jG?> z#1<%)GU|;Fl0cCqmzUXjle18uUSIkKs^t+4LYP9RjxDjCOTK^9`+n7i=KpF4%4UGr zK%e6gXZGuPHXEPPQPRd>#l89NKQ&OPB`}wU+{S}+4v9S>dDp(6wl4vLU{YAqggO;# zILc`W7V;Xo)XVuJVpRqS*(p#+2G!;0apl_79GDjI(L|U89p)A^V8d8lT3Q+!OUPVb zf`^#7dULhR5PqJGV{Z4#yQX+ws&4l?u**)fx-X*$>wi-{>YMy)1aM9+_kVOC+rJvt zc(^QfDCYrH$+6dXHXQ;t$Uz`qSlN~QW-II#cykK)(%VxvPLmyO`@`GnH$FJ?l?l!7 zwNahEkH`c#j1B)X`keqUU^h8OBk~N_Z(Z|=70LrIn3p+ zV^?CfTc=6}zWA-?R-D7gF@uB9QtjN#`|if8X{S08!+b3)a7)l5*uOW`TKEXUA;j=Q z&n%ABg#=_+CN7`y7n0>p77?5h&VFlJ7UI%b;nx1PzR80n3Z{1K?>EuYBhD`)DyhbK zf0i}o(CoBeV6x0vFY2>LCGN8)=JPYt$c0|c3M%+^NwXiPA;0fjqf!&nNK+K0Y3(=< z3TJ(a@&@ALW~cy{so>^G^%8B5I0ZYGcAmF9(y7|oC}xd!P#8t_k89^VU%HPrkGkul zlBd(SILD6V7LuTvxFn_PU)eCTfxm z!pqzO`YCM5M5^c+K(gTB_$^IAu*9eXC#U+Rc_a4b@_XdQz$<-YUqC45BI_ZFZ34t0 zEiocep~s!q7L33vmSGC!CVqY%3bEi)B!wvl(XP0RWDE9@g%Pdvz3EP!a$09ZLGI)a z!<(mGX=Py=SZVF<7gFn{JDPWTn3cboeSf)SMFEgUX5~4L=ZK7mgx-SiWHAoYk?i_U z=_c%;p&`-GBe-kQe~;HV3KDzu?iSk>KxI&|>2K_Hv-lAfqdz~tX0!A2Cw#&;niE?M zy*ZdFQA^5u@~|w@vAL|CoI%HLSnb(yeJyj6e>f*jX;!Nku07KA8AXPj46`;W$Zpkx z3Sn_LpAlVg)n2&*Z6@8_O?AXSok`8zl6k%5lNofNF774XI9ZdHq1zQu#rZ}-!*Gps z&%$XRq7l9)dTIY-4@FoENTf$L^n5#lOx&spJn(kk3SV^+lq{9|IRgL=2Z=ol+7*?(YSk=F0Nl_DEwqyy$~vYX#?L& z`&j*qg&-9?t)5rJ5{>`?!p$G*O3L0d<1$vV6eO2O1dz((>+*Tlr^;SZZ!dkujOW(6 zswm&a>hlir_mN=>k)hK_UgE@-yzUwX2)(#Dy1iJ5dU5h!&oKn|O*|q@2gSC?*A1s6 z*%CG1&gN3t&L3vFV;W5Qv#K=36CZG#`4#tu&U5N12~*wra4b)TVYxCTkDz!?V)07I zjbNxn^Rc$XvV%^G=qwB_A+A)DE|E+B%lQ#hsOhbX_xT9uyN*& zyOtgeL(6ja&@dLJatxRFA1hK7hY58KL2s+?NG8sYNLLC;D+>K=JR|Pft|W4CLz*Qs z;|$YY@Wf(HSQN_YuBQ_|V5^g<_t0V^z*l{E{g%I+L8FB8kfF%LPXCjgJ;EHuw}~Pp z>OpQl{%{dRT5K_hIgsJzLiJhTW`6X^ue#c^*_k(o@54P~8DqgVYJ%(q4+okXpT1)q z2vbujSGUl_v6G;7Xb7DDs1$|Jz)B+8n1he8p5j|gimxOdUa#b!>Hgrcmi%ZsLa+P( z&A(s-KX)-`5A>$I%BmON`SekAIt3p7yL-62Ue6!K96c`iLYX^E#=iQvjS~(lPSl3< z^}GX9Qj)4dbTYo8N24Z6V8(EK^){Ka)pW&2|K8v2vE*UTpqXygfKfs{g~?W@;~w`Y z)5!b}9TZl?E+{*8FQ(e|4@#p1dfV)O@>|>ZS2zvNlR=40JSL9uw@<@1%QSCSRe|0L zk5XK~Ci-I~i_qucB*zyjPg2>n-O2InGR3Nl>ms^zmL796rfRgx&C)#@VO($O=eE?i zAbFJUm$V#o9zQoBRKPFv+K|H-)VyZwjn8H;XA%g~Yamf_tisw|?*h7$`3pV)(QjC3 zYXsC#)-wasneAOr{b~ush<7%L%0fezGK2X;Ws;0zYLZ zcGC=s)nlSA>skrt`)uf5FE6j3)3zfmp z#LT2!=UutS#h}Jm>-2=+H>7T z4tIJ_%hvr0DGO(X#Z_k#=bMfYnj&iuAKj7^)pp6Hkwr)*auda#A~XH38;|+c?xp82 z29k#bP_0^Bd)r}Ec18?9RL3uiC?mf`v!|M|!I3F|bf7}1Suj+fSL)$Yij*A~BKbC4nzQG;)cG9qio4q}!YL9Rl+&)@q1<==Ui%Tr6|Ij{_m%4|K zJd1Ddh9F)LnX4M(!|w9dc$7;ZaxeIrLDpb@u9f!Eyj!QCH0jaO%GoDh=x!*?8=E3I zdNiXJ{H|SQj^Lk<_;b`$YJ=+fA}-GQG?8xY(yRCpFS@nG9D9YLN+?^{THU1a2cqed z;@SOBpJX%>A{#*#t`6VHk|-Z+>cC>SV2n)q-~N717^XU#L(?Pj)EU>t&~s_${+3(( zpdSIlOGXK#a+0xrs{N|(MlVoo0Mv-}qR6j3?_$z+lLYZuY}bVSa{^Mro;IdVe#^qz z?xp~Q8fiEV(V%OZl;g&OuC}rr<<`gL8xPI|6wcws44~6MzC5hAKr||w9%=w z4Ff~m577h6VaO#({3Qpv@{=%dBw2b39dSejzEg1U5BK7;c2c>1?<&wwoM!^_aA+d= z04_T5fL9U386x0-v(8~EHFl=e@HA$fmvW}VdCVRapIbXfR-1(++EffE8OuAP4@l|! zMq@cP-c@g3PtyREUYE?2VnVv~zWpQZcc@#_el5Jc0A|>PJl^OjlQq(-#bM(gs)T5$ z5^s$TyAuEYb3grcj80G4a(&m-LUkhPsg!Oay9CijAOGzt#>LC zXuejB5@kl@j$*Wnh!I^J&HFGoqHt~9P5v~e>py_z)(B>GlxM&n71B$;io`99C1+QI z9>@Zg{~fYj#)SQ_>Z@1vTk;qn;c#oUm2zwS^PHVS3e~%A55+R*7SFbdlC8D0|L#a= zgX=>^fClaHY{EkCGM~6UO<^aw=*bc`4|Q3+50Qk^%IlFeB=Vd#(FWgnO#zQ?-vSM?RHgPDDUlpQOo*3J@_uC*x$P|3bDtW7FjD zi5dR7xwS=!E2n#!Henw0UWb3!i|w}P26&56l{;unm*LVSb?1UZB1PW{(7B)y&)q!Q zuI8kZm)hFD$e$mSRO-h2U*M>r z>4{t!xc!R9&A~RY#1afWCukm8NM2e%WEg&e*P%!n_kRGySd;PpOF`a6aVis zRCit!z}P!WopYc}-x5&!w_LIrF)-5!^!y;iMnT^+kKa%b{-3ZHM)RrhlUb8J%aWxGJ6n&~beiyg9q5>1LTKKMFYtx*;oM z14dHDBf)yJUusu<14JdXTA9TB1x@lV!VsxD`CXjHpUiQwfK{v>$9oA2Z2=8=GLCQh zXC`F4f_4(ek&?<&pz#xf!>GcL?cl4-Foxw;JKkR(oxV7!Hm>cx(!Yd~XWjg0yW0Ny zrcEecw9TUPFL)a*Voe;2pF9pBy;jmTQ2klm%NaA@!&i5nW$L;RcY{ouP}^bSne_FC)srds-_ZH92*>-)ilOm~zNmX0&Ox4%HK zhTH+-x{B9bihvAqf85l0M@(qTql4Ct`Qt=zP95;|T19+bUDP7*k8nX9CD)J6fQx0Z z7!O0o-uaGm1Fx|?@nC11%O_Uu))J%d!y*^|YN6<(*eUT;bHzq~zfiZ<*e1H97qt^h z-drmdhRAE5+Q?7ZYs0;Y6)0Iex_#TU7F{ug_m~RPmnj*c5#pI+o25GYr`rC-xrKt) zqad^sd{YLBCm3x#85Y@Vw;`Ed>KwyIJJXZuRq`54iiqM`bv@U5n5BC3#*p#KQe6Qx zyh41@%}CRvv2|L&ps0s;U!zFiM3WeLP4=gRNnUhv1+V)%Dzam&#?a$+DJu2%XR~y8 zF$sjF#|#q(B?0<(rh02>Md7l2FP;GjLGv6m7B0-;!f{%AS`GwAN*w%m#A{w`xye<$ kMgRZ(KbXK|2i4^Rl}5)aL(iu@|0{IXP}NbXR)R(RABV*xjQ{`u literal 0 HcmV?d00001 diff --git a/resources/profiles/Snapmaker/Snapmaker A350 QSKit_cover.png b/resources/profiles/Snapmaker/Snapmaker A350 QSKit_cover.png new file mode 100644 index 0000000000000000000000000000000000000000..fb801e0347ae3cea58a0e887012a2b7f1ff0e9fb GIT binary patch literal 26826 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%0D@y9r899>f% zni20&KY=`HT5lE5ajE>#j~Y=f!P-$9SlYL@a*TK+xh!ct!V3~wTivqJ zBC#P`=*Q2>xHMw2m;Yw<@I)AYU7_>0@X_|{J)11Bug`Dx0=WB$Av~Xe|6USN05t%a zFFEPmtNB=zBe zgraYz`gX0)HJJocGyc3@F?wvV_VBC1Q94EbZjIFlk*VuY0$ufBET!d`=+_OkaKkBzV`qh8hsS=N?T3ufL@25e+-qELM(914DMa0Bp_v7z&!NW6K2-5U$6w6*e zm?8Pq3ErSvsbME1W>lia6qn8ixBq2Pg{6DcbV`eklWa8ZTvZMu4nK0DeiM%It9Qz? zLY}|lpC*LHn;mf8=m&|;KU(c--*OFL;Ty_r#8R4GH;OtHCJs2xl-`>qzYRCDVv~~> z-`+0R7@{VW^S|4K!NmoMq`!6NMJZPZCAt?X4?~twa2a&BX%OgYFoHOSY4jVzkk7lQW0gA2HI}-f zUYW(YiD~oNT|P?2t^=fSbb{KFrLLeZ{mG<^nq~ks{$|~Lvjb#K68Y5?g$vUKh`=4ARKe@R8ixY&Tw?mRZ+$z`&VtL#4^<7Dj^q_QCG8Rm@uYJI<_l7G_T}1^)abV(K$@1wa$BG&iCM^5 z{8!69GuJ{$gQV3GYYqg=DZgb$7?cZ#zlT=zHlfnjtM2 ziqjpUyBBU)YZWp&Ara~uJrF*xx!DWiit8^o6LdR7FuaOLnOcODogmSWT!IsGW`%n| zN_h>H#JjU|^>^w4cURhko0~u_n0ct~Snr|Fgd7eD<`ENKd)clCBZw~;7plxrY@S`a zau~DJ=oE(Hz!Kq$aKb;2tO^okf5DmJ0GEf0^|q228HwM%Y0ftp`zg4)^Zjm`5g8wf zI8bo1N&KEZyM%3{+bjM<2WYl(r-ZfPltlEp%Ol_2(YDW=LL{(Ih?ttXglEYtE5=sW z&JpnaY!#*SS_z);<)$Z6!6!2=YbBf~uZke1^3|hx5sdb2%c;kLaS72MVp;YkSEPKS z{{ZZAGm1{hUK*wJ^=ey1emd#fReckOn8EcMc7yzsG%t(|XlZphA*kBr(HD4P4if|DhTZs1Ed@PpB^ts!#ux%ovXBP)_53 zjh}RO_|;HZ;_HU?=bsd62uIbZ9={)PQQn&Sfj&e$FntjCk}5b%t_a(8M@2A!HV6=0 zmTe%?Fmdpxl5)*B+vm<&er=fs-+851@<0ACyid$whO2F)(8Amu=i81i%T;ZdiaUwJ zB`Wb@3y+COd%&>JIP<=!#nSCz3267~dye=elG{N^kkCPLxo&8>xq-rOYQF&P=hi2F zGz#<308vt0DN{;iMC? zSoa-z54$#6}?l+4BO zh-Lq!IhzJPajnli|3kFMj4s#8D9kr1>uomuOvz)ExphP77B>(LFYaXY+0zZSw)OM0 zRy-c;%P6p90Hn&)@vR#u1c7I8Dr~h7<63xv)&b zDI(!Bk;%Uh+v-Wur)b4RwdrzsgOm)D(`$t~!m-AoGV!E+UyO-pTf!r`J29qja#r!T zTag62-`GFDk5qgs(&KlC&>Yqx+=s47wd@q~5EK8g*05;uO(SShUG_{|PN_}yOMtTc zzH)L_%7+`bH|Tv`&aJP_vPFIrjAx}lx7}p%JyqkigViS!!HnIw zbOlYSic~&A*c)t-UC!hBm$$aOb1N<9^Es=2bAJXLyA2X{J-J=8(cyPQ90?@ zXdL`PC(&kTFfMLyh*%6Ox3E|hgv2Ui!g4&~&SxeJf30mSjr$xu*^y%W!CxL620b(_ zC*w4DuwIu4AQp65;R69hNmqBNq~k6R7KHzG-gC^?o|8KChEqrEz7@dUG}Vx(r(S|r zu`yrgVfFuh!^%YkXrl@JZiaM$(>H9cwvW+_q~%dtZ)+Z*-_qL4O37D7%3CIcmxTv_ z8(7^Gw|Uq{6Aztz!2Z6zOb{~9vY(#?#;{IuI;w$Q2^wvlkXI-Z9LfDcK?=^{Oz?|6 zZ%JK!dfcQAMHb!60~g!xWRwF*Zxjg9?7oKkK%tZ7{Chp&BizD(9q*p5d>+*aJ0&UQ zNXrB{?HOZ(&kPQ4NAINnLpca1{{qlhE~`^ka(26{?|Obr89o;m_q%GR9RE{-uwZcI zloh?0s~W$`1}&&Cb8zVD4swa51rzpf^$w?eujA$l#*+(HIoJIC44P}L(2VsdeRK&$ z&89x?xL#9|yhC&gy|7!L?V!OQ7y!T=oFI*2Myg&td}?pEjrj1n$*5CX zT(+sne)T|p0aNtFRYH`jBE?okdlqWT zW8DQjjQe*f#np_C&bt%qt30I$YJ2;bYMG28kSn=_XiGNBi@2hB+y%3T&C#d%d+9l?E z5{8WKY6hSQLAtcO*fk@Qxk&&O)8^gyS;H!5}9H50QdfWRZcCK&c zdK3&LepTZ+l6S!{Zv4XVvmnuVZ84CVONxEULNb@zH zBmodhOY!Tsr{Yds6KkX6ydM8(MZ9D<>j|mg*+h8Qw4i8LibKtCDq#n{N|I#@k87i7 z8!pOV2i4it&kD(U0$1jJ)taW04_J|wY!}R_8H<=W#iT9e*tmn3I%{9n{dw=1P4N5S zUyaZKJ2(%%f$(S`B)?Kjm#D2nxZc)0($V$jLxlNXcwRy2^bve5eQ_TR z4^n>LJe(q83kfb&QX}b6Ppq!P0Kn-Fd03eh%=*=#ygv~L3Jzqlb2o&&Ed^#s=Y?qm{=kK#GT?)S%y+_^RtFa(J1&EHMKLE;95;! z_63nbzMu_fzx+q;=y;zE7r4!w2nlIw0il*vumONdUu+JxixQB>j1YC-XCkJ0IaZ@p zpPg*14n~~wbq)KP3Nudm?v%m9{}j=WJLi&fp6R}YS&XR)u7`>_e_FBoJDMX-=*5;# zhy(;!NfJ%(rVlx(JS|SW_KR`dpzLviNlR&IC8Jg}6@fXs9$y@~Zhn*+)?TzDk3fzlHhFnTj&Hf*b;f`6mz-{eLC?Dil5qdMqBILa zdNQU0!C=u9bV|VqYAM_j)7nqNot8TsspxpG43xmCY6{R4?Kk^ADHok@}h%P zC`cnZ>NfOmD?tILx6mgB50;%^fTB`|AGHetX%?PVtwl6O}CK#K^`M!ip{?jR%Gg!NmxmB4j>N}oNdzH45f71ZdO zZez}7%kvOw`tKujZ@0y5Cm9y=UC^bI|BX1(`S8r%IW{)K73YKon~bB5(^SeBnhs?n zN-#<^LmrFYH|OW;F4a?CXT))txV{w#8LP@})irtIDci%|P{`r{gghlD&wlzK#M(l} z#>vV`NK9O;8=k7H&`2(q_V6Iqh?zqAS*fP7Ty*yYGBBS3y%7U$NrKG zM9>bu9xdv<(@IT_fflQs>{gSFk>@Qf^|BJ$-@}=HZnuw-xKWHBxggvKYPn!@D~m#< z$$yHzH}RkeuC=b{1>8*G>6;bO?RT!Fj$Jz~pF zJGdP|fpq>SJtQoTmTqot>MQ=|6ZTVL=i|m@tYu!|5tePLvr>a=d+Fk~RY&@oNy9(= zRk>z0&oyHgxu`g688wy9p4@|kRwrUWK*io0pZ|jCqp;D^6x9^bci>XKXkcOt?zfbG zG%8gdG=8Zns11yYyYCXTA{!A#u3xr@*_Z)$U_!6ajy>*mBjY}QA{LNP4<|7>K#-cC zM_x@u<97yc8l;<{(CL2CqOkYEo87dPfX$a4#-JKlB00-o z0=@kRXwXjk$20Q>HgaW_Ob%SaL+h1SCFDY>rd=y?+R1e*A`IZ~lap5kby5H@M z?699L4*c~3xFwkZ=kKqNuNS1fXKnqsAnKBj4OSRtHV37v(*6>hEBLB$=ZYb&Tu27} z;ib({w(5q*9m(fSt`-`Y=RG>JgtxlILH}nifE692n{1)OV*C9NT&Ke6aIMV3qNwKc zWS?C|9#aTEJz;Uqn_2^um2hsy`)`H?3dU2hQDCSP&L+fA%b^vJL>~`cVl5ltVUP)G z&;<7aA+WiXESg5o35Q0%1-1FdQ3)X$K7A_no=yJ|%TFpeOmDH~Lw!sOd1?)mE$Z;Q zRZ?7uXdWhVeqe~W532Kj$8><1b7(RS$pj`0!V-FdN9H4{~i5V*mzWoL*a1c91@if)O{p7Nei z@2>!#q9QD_M>tW&yzTq@DFyH($_%1IxJA+9w~X9D#8TZCi_@jf%Pp4Z-FD>8inId4 zoN`nG)(#Y~x@##n3+LXC&SO$k=Y2x3nR|@@LFk6r+tz4sxk!*C+H}hvM9m^DU3DF0FxsC=k2c zo>r%kKXU1R5~TGZq&SovM1xZ9zn-R!2n1WxNCGH`y6sHdU^xOw1nw13PjLZ$H+Q5Diws?cl@Z1*)b2!;jwPE( z$^XQ_b>2-N?>i|dtR+FWdpA8j{WrYggPm%VS&u)Ci1sHx3Sh_M)%W3`)UEHEnBHFr zjRQewHk&{jmvnax_{Pt8 z(UFnq#U7O)fG(KAyohMAgAWGg9-1$(|B`lHb75ZA7S!?5uX!hV|fDOiZ=RRhjO=-l(< z%>!>V$t-Dc6n9dxsh}|7mj>NXV&<$-+xBrzo#=5=zdfI;u(B+N zRlS6K`XkwR3n&_RUYCQ*%6cqtE*CG<(>tM?n8eOpFHOVA_zu94ajR$QV3Z4K^M9L} z*pb}iWT}qknj>CI<}!3){l#auTP(Uk9kR!&n092EVBG0CIu~|M6*KH#e|baVLJCpA zr~X%qwjj@wKLcNer2hs2jI)G=QO%A=mz&xZD+-}SH=NRgi)ww5*h7GLdb}uh5T4*!4E{x5 z^CCt%`9JeIbe^ZsSL>w{8p3rHVQ6?4D(PG(vm1J%eiyqTicD&x(Qg)vV;#wwuZgz8 zj23q^@RCqZL&r;9`_Cgf`2zX)^8$)`yA%DYB9L&DQ=f3)XA#2EV<6;HqV0?0EgyZf z^ui6h`@*%HoPwex2IYLC$FjgZb8eusXHs3{~re-Y##^CVAdkF@-KN?>F@Jy7uBFiO}9c<_> zC9lL#H-~XQ?(@Y>_WMCkT9Go9XaX92qW;*ha@l=k29sQxHz2(gCc#Uq?J4;4Ke0jYStZn;B!9j$uzJuRSU z;B2w#FB==HwXhM&*A^qrtBuZ&XhRL^lJ!SR9eVPQhksg-MAmYla>3Z~a$)qazl9MB zHGBv3XmO+faU5>|9wM^zh(tU+G?zY@5m1+RUT&iI3W8|Ow>e(xc!zYM%Dw2V=Uhom&Vn(w z8Y2{>ciF0;KaCofxIOM{oBAls8lzZxdx+5`Nz+O4R8f1tCFnYHp(N5sFnAiO7_5#T z2M|OS2=3P`Qd>3HCyY>5b)H5GgqKSQd?&Q&4p{ z|M|a9TI4FXY2PkV-_$9g!zW0AVm)DC>WcL4m{wcv#!Vv`5#`5Bfk0e{>G z!yi^0&GG&dBY-dYaB^+P+|+m4D^%*jdRiQ1J53>U@wTy33FV z$h;#`{;@9tn`V%SDr57#AYl_(!sHEr6B+f_xEz~Yvi7IS2rsJqcaA7bC{J22vP5Tx zkeD`vVd&ztouKMNYR@&E@+(){ypBT$mhrNrno$D%>%G!M$^W~s+YQ{OavJuU?KoH0 ztI=k5SU%b8D~!CReJykwF_Lw3BKG`nZtUE#{hwd{ejDLfG=?XBy#9%Qy;(joWy%Ht zq}MtjP~ES=Hs6)48vgfLbQ7Ub=(;gXT+1@0g`{Wi`A+S?Zq*+nS+|Hw6^15$ywy6x z?V8?kz%rw?k|*{ZD|Lp^Dy%OydMeL#It{r6I9i4N4 zuR`^yKxaz?s+*T*UQgYvBuW+M$cn@TC=P{?*Tsurhw?uffb$&n*iBc0Vl?+kEZSst zl(>Y=RQAD*|KA1uc+!&J41F-V=)QE<%8*HYPE1A?drK*H4D!X_b~#?V{ zZsKn|$HV0#gZa0u=<&k@_bXd+l8$d6O&D$-XiefN9q9uI%yr>XwZ<~D|*|{7)54@d7`762h%;iV2**_gLcejO;=BfPFeLFv5Z4D_x-uD zut*##7@aN~K6gtwj1H0e(4xMpH+gxg<~rd#OVHO^R;+CqXOlKh+$P)`EtBh`+2!+& zwqwmV3bF1`-S|@}v^7)j1}HydI4$Jf`EH@>X<&wqpKu&PuY$&sLiaeE`{WMtVG_Ld zy5v26zU(>?#QaT^RsCl;$t;ZabofmI0b-`UD^t8cZ`}mnj8FZIxyT1D#4Fk>@~eR{ zU3htduE(6YHVK2?fTkUAh9O3l?lL;y*L3 zSYX3(U~YGm^57z_i6Z@cW&w9y$6sKZX_z#MYTh?#yuS;285{rAHd~xY>$Ofp z;|zU~A7sBqWkj%5HTQ<_l2+7gl~GWoYw_vs-}_tlyR;f^3z!-NQ5OI(=ZUhbLs51= z;-oXyeoTAQ{ZVCdWg|Ol#Hy#X&!o$|FkqiKcd7pBP-hkDOeYs1eORba_0yxDXC4PM z+Zj4aQu|2;b;AVOu$p%jF5*&!yMiWDUi78Y`~sBYdhhg$a=|pH1DDtB3J<~C_m7~i zm2LF>m2{SVm+f`Ve6Ii92vaaW^%Ewd`-M45?T1e_#I0%^J1_Ay=|IF-(4)tAA@}l7 z0Y#OsOOJiO1RsGoVE0_UbE>T;8@ITo`DNc%>|)zAvNcMX5n6)hH@`n0pHLj&fP__7 z8H>c|YXWXF*_8eu4P%@QE_wm{#wbFZEy7Jw+Orb5`EcyBnDQ)^vBDY6GIePz1iupl^&J08xKk$!?mx!>QG&ac~!yH2HNA6x4Chn!gka2ch#YjEui|Mce|=;YIK=|T*qY5s)l?crnr$z zF^7x_TG%vese3Db=RyYBX?xg@mDH3vU#0Nod)t06?fm`NW@`#H@tfc>n5cD~C4;mE z0Gk#MVvU!7QRrPBIEvkD$e{IOD7@4{5EIh;^0IPa|AyUNv{It9J~Zp2ohfNNvO*ZgKP!B^$g zwL*GZDQ9)Ce+f42w|^y9!=mD#0muK^%J7iozcY{hca{f7N!e}}-D`;Zw+1;%=hq?@ z58mET2D71(%Vk(q{`n|nsknu86GP0LlQq(#P;D9Lu&o$W^Rn7xB(O2KA9tBBy>)f? z1%NpgBz?`A6(OD)*B`EXc!sN=PkFxc806=b7)nnNi9*sVr)RgQ8j3f|Dq=v8{l+ev zIok6w&T3|Z(J|=@GY$*y?#T^BZ=gqzGNM}XjCDXNiUiH6zPIYPDg4J>XnAoKTaa*< zvqMS!(pr`ArSRL6`tE5g;jz&+=P9Q^4m!?Tp$87BwIA%~2>r60XZM3XQTI6YDRY{T zYEbLRyN0O~>!6&b(kb1+AN<>|Sgj==11h3Kn7A-Qo(Kz_d0J34*A!Rg9VCHbF^ZX> y5KZ8_cAyx1+zbf9AfN}o(47CDO>U~YY2QX}pvQOANdNCcA4NGe*(zzX(EkJDr%ILp literal 0 HcmV?d00001 diff --git a/resources/profiles/Snapmaker/Snapmaker A350 QSKit_texture.svg b/resources/profiles/Snapmaker/Snapmaker A350 QSKit_texture.svg new file mode 100644 index 0000000000..75858e0454 --- /dev/null +++ b/resources/profiles/Snapmaker/Snapmaker A350 QSKit_texture.svg @@ -0,0 +1,107 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/profiles/Snapmaker/Snapmaker A350_bed.stl b/resources/profiles/Snapmaker/Snapmaker A350_bed.stl new file mode 100644 index 0000000000000000000000000000000000000000..761efa2fc55fa8b8b4759cf5f679bcbbeb28acef GIT binary patch literal 23484 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 an#FG-ql7B_s`3BYs^&V-JDk={KK(z~eyXDY literal 0 HcmV?d00001 diff --git a/resources/profiles/Snapmaker/Snapmaker A350_cover.png b/resources/profiles/Snapmaker/Snapmaker A350_cover.png new file mode 100644 index 0000000000000000000000000000000000000000..123b94e16cab7dee20b0dbe5be9fb87badf64ac0 GIT binary patch literal 23242 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 literal 0 HcmV?d00001 diff --git a/resources/profiles/Snapmaker/Snapmaker A350_texture.svg b/resources/profiles/Snapmaker/Snapmaker A350_texture.svg new file mode 100644 index 0000000000..df0770c819 --- /dev/null +++ b/resources/profiles/Snapmaker/Snapmaker A350_texture.svg @@ -0,0 +1,103 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/profiles/Snapmaker/Snapmaker J1_bed.stl b/resources/profiles/Snapmaker/Snapmaker J1_bed.stl new file mode 100644 index 0000000000000000000000000000000000000000..d20c38aaf7e2bd9e1d7ec70e8c95bb955ca0c7a2 GIT binary patch literal 67884 zcmbt-3$$fbb>)sR_$6W-A@~6)s$NwQR74;|<=yjm7wvqAMxyv(_@zT+BtiUOieSh= z3ZtC?R)`(NB#MAlprMVTF-ce5^WM9P?T=3s@B;{ffQ_l>Xnqf`FtfyW;IqVaDpKj(!nOb7mdevbQv}$49UiRC6(#etWH~;+Bwcowz@2g%l8i@R9 zfq*RKV7^%nN1Tv0Oc$^E25X||8u7zd-@g0!W8X5_{~_DDU;n{@)2%PaTFpV5q&v^M zcJ~)wynS-Ruc;kVw}a6&$G^Vjyp2PaJGw@=+3>C$8N21yR!wGoHIJk2rIO4JEsJ>sgPzjMNw zlWo7E^J?t#3cCB4*N9*K;zf&}K6m@%>8HQB(n{u4LDz_)muNM<`k?WPA90J0$8v6~ z<+UBR9+F0n`sr^^-g@n}?k_JnX#B`;-=datFGd#zwVbVGK1QeX`Q^Pv&p!0b$phay zz2aa`*NDO*cKpNkjpK9w?k2Uv+GwpzIfus@q0gcv)aME7+o0D z4%VId7@g9mo_o~jBgemT^3e-VuQ=FmHKMSH9pBq~)A;f`zovFrTkWW|lCc=wc1Y6k z_=Wp6j(_>T+@yAJFGd#zwS#qMK1Qb`HjKm;wSzg>Z#AN@h#d!8omowbhPV zD_Kn=Syg+mqFy72OE3PK+QGdTT^Q63)}8qnozl^Vo;i}arSpn8*rpm`EXtAEP2;;B z?6zoLl6FcrsvWgfk_kr02*?KSx@^<J`$;kgAr^~?wkLvy$iHx zrJiO^?V<{+{pWdA{}dSjElkR*4EkVB9^Dt7W!?OmIRi!>9LVLA8W`IeGI=@Fte zBDL9}20ESDo+i3}r(aEf3)MyDjP3i(6rusEm)mdjb9L{a5nghihjbV`<;N0gnl7t7@w zoHGuh1AJv!MiI=%=#*rQAC0wcRUh)JB5Ju@cVWD-4l(AIkrlywH5%&=Gv4Z5)QO7V zs-~`FrB1wr5U3Mo5P~L2vi^?7I>Z`et(e0q4wE#bRjod*7;8bcj zmCL;tU30Lt%*SY5Q4>TUtKkZV%=ThajR+R4;igif}MO-`7qf`^s@=f z61ALr@qE)7ZXz|@ZmZ#7ha%WoMr#d+@z9#u#y}A^HZy!FVVxuP(mK~(tO>7Xt>G}+ z^^C=4xFVR3(OSbHCi;0T*0v&8E=Rr+8736r6v2Fq)*24^L+!9Qs0fzJS)xQya#Zf|L$|PPrm!yKWR{TrS{gfOP>CYJ>08C1Cc*15aYaamlE?a+I!>Q zwh?`?tHzqBhBe~+zrX$HH@)pGldnJUC(W~Ecj!4{IkcLCHc9)gU3>I*w{4%C_zbmU z>~=7^=D6#r`(HX}`5Z6Qc8Dxl=h&^qN875&tgq&A)V%_orRBft5oEp^9T@elRjet+ z%s>z3IP|l3@7{j;_Q^w^GBf6|N$sf7%)y#iuNf~ye~fw5Q7Od??`!zhQ!d`~xyQYB zvi8<(%}b;TyH#e1jk#5_HM-_tO_;B?nm*HX6~Bzu;yoPEXU zVCZ|7`52wjmtMWsabMnmFPOmuF(={Sk+9oQmlp@yFHl?)XjR#LQ%b%@xY-_$E zb=yZIw!;qAozcMnJ6Lz-V{}TdIPIv(tImDp&|?PP6;-^7TCcY?6(>bENv5YR7#QcYn$X8M^+P7 z6;{+~Qj7khR2i^?b!T)izz)`(`52uN<`m`@<`r|WO*JA|B!5VSlxr&awp2^CO(`K0 zNJiL=Y;cKGmT#8Y2X<7t6IvPC%u{nPf^Euu9Z?<0a&v@ZZPS}1Dj+%_GO$+c1?J0n z795&uS8~M)JJ|BdBbu4_x#O%&giy;X1WQWDfszY%BM-7xa}ZgQatvwJ8yk!B$Q_bH zj@JCa?BbtXg_jXD1me2P#6_Bk%QS-8i|1QPh|&_Rk4B_6I~0+KuNtR>C@tf$i1Dy7 zPz0lE1Y)kN^AW9cMX)Bkn#*h-VYb^0R|NAhIwizIiHjqOiHcyk9QjIQ7*T{%1oJUE zCB!O;S!##HK}E1!&WR<8DhDGh`plqHLL8BJGNSCPy;v^i;F59FSC(ZI!F-HP32R)| z`pBw2WM@Uxa=Grp`jd4y!kAk|Rs{3aXv}n}$VOK0qE1ubqi%2aNmYUkyw(b~#6)P)uWK|#O8@*~YbI3^H zy7L;ov$k^72&{2g>pn}yQp2f*+>6o1p#Ri%Fdw5+LR66GFtQpB=LS9=#ikm8s36fn zXNk;=qLqwILDvY=tA%%E72&$GS}v7^U4yQ@plfg>@x<5QSZX-cimhdIZ8=-Ze2mr= zHIjU*D@s;T;b5C;1lu7o1J|9^4r}WO)>&|M2wbhPVE5uyNoMWls)DG^&=-Lj}o%tB8S#2aWoX#uBWQBumsu665 zR2FvKS-zDvRRDHf9la6PaaM0N+*oQjwWHFV(8i$uXbo357{NBxi0Vj|tDdg3MGZId znnCJ>q7{3A`Eu?6lT~D}cFk(IVtLJh+#xmGrG!w+*;i84ge25(BkX5b4Og_9gUFIJ zqYY`5uRF_8_Ci7?z&?Q0aKTQ!Djz1qbyNXX!(o=F<=l(so7Qk6oN-$X2RpK_$XZ4x z)NmLNt*LDc6k%gC!T=eAbEVQni1%jL*d zBE!ULxPq`1HG|Ii1LvK#2Y}eFy;v@1i4sMX!y>05Ec(o#wT4^7Iib~X$b;I8>*)8Tv|}aON$wC_ z&>1Ryq%FJuioliRZ{D3F&cE#6PU>DR2?*klw##CU+{S9o9N$0btmfk1`IhX1rgYag zHjQ^ZQzJEL(ntK#t=pQ1yy(_F8z1|^(fe-LG+zDwSJt4_d^EILecGFw3xB-2=Z`;k zPK5{!Q)l+6q-^=)ANlEn`j*$d+`gXWt;v-vQ*@U$dafp)|*fAZm-=21mNyRX%UZ#=zu>V-EiUh}u-%$p@@d5zBJ1o=GuYk6L+ zrSzVazTd*WYrnp&dCCiJU3|!EUO4$18S_2g|BA?c&q~N;Pow>+Uww14@T1kmH+=7$ z3c(!4t&(!4`Q#OUv=RHrtX17h$6OHLSkI2o-De39KHFu+FPQFPdC^_l@jX2K{4br} zH2?kPJ)hluPNkLE(L+E|{^YeTS{xwPX;j~zPwC*?hFqMB;Cr<3!ED5A$NAEyZ@zUo zuk+|tqccW1+K{zlh56!paEQf=upY=SKWW4Gx=#1>NfYQEd@0EqU&LC+I)BxV4jeCD zk+qtS28XQiMXYtKb4Jv14;+Vm$6WV&9~iPcda+i}KcXDYk+XM&!`i8v_0>F%x>ukx zgK@Myj~2cfjR;EKoo4Tt=K*0IiEE%~Q#)M!|OHG&m| zG5EO5tGv$L+Ww4@HNFRH9qas+KRR&w6d7|MLN42cwyg0zSnF8ljEM2bh~WMo&wcgA zA+4fUXqd-i9-=okkg>s?plHi1RD@+U9I<@Iy<8FyeU8Wz-b=@TIAj)fupU^6WK+rK#_k+_ zgskxnYu)nsRPwn-pZRELC2PFHTDN>&5NxevYSk*oF<377{NldlbuZU&!16WsF8n6u zi6-s^wAb@)9-E8^bl&Xc+d%8t<^yEuT*%pGz;z=S9OBEo;2PTDN>&5Zp^LwQ8GV z478Gbeo0@ex|fc*X}F#pp}Wr#jE&EBneoWyHrsiI??8=W-(&n`jdxh2jy8Qv>{jHm9>GuY_xoid}r%Cdevy=2w5dMD_?vMKFc_& zl||>CCeS_jG@tLmTDN>Ym3*#R%}0YnvhxPA0~u$=4&fmCP~{^!SOrixYE3kEnWUcO zWA`rPx_4)NMOqd1x>ukxgRgZS!Qj}jQll+@xOY)4`4|+f7+vbC8H8mS9~(lWX2)8$ zd|vDbxv8tsumo$w^7&M|884lqi zZdCb*4pspa4%Q0okThgRZ)~P97ksu`K1YQlTJa3u;WdhUkGYGQ9c$h4IqBTAn%CM@XGF*-QT-t}j@LKbsq^dXLy?L4FT(Z@fv_{d*7&d;5d!_I_f_)_}m$|=o; z>&_cZ54*5J1Yhb{Te+IP_LAn9!yn$f{QO&Xc6V(YA9VE1YI(H#cAWmI6Phco+^hNd zGk#^X_Y*daM`zxony|Hu4vv!_^{g$?YsX6TVlQ9>PyM48H9NN4G1~ESyDIMnI(5vQ z(tQs-vcaE!nm%mnV-MIk{Ej@dH1;S?%Cn zj1G?b9{P!0(Th3QCU9(Ccvf@wbid{mpSq&*RiIPH+!A+XEHEZ7KmQe*UwOzu<1-(E zDtyOEv{P4Wg|WbxU_9Qx=b-Tuj`)V!!MzwA99MmJ^Ooqv9BdQpfDNz(cCfyIP91a0 zeNVEQ@~S#`i$xr@BigB}wZdw`s=|u;&D%GO-@1Q3=j2|D4vw_XU+s)uy0#IuXZ$99 zlsTnyOXd~p8|c(AcS=}ISXEe2e1tWr&v$>}{X0kJ?t5zUjL$u7@?5dw4Pu9#N6pa+ z(P!sJKef2|;xn52-+mm zfsp*P2YCuPO4b3YK8-%86MUDVM#zeq_=;i#_mY)XwAFakSxnq1Gh<4z-P#&UiWg*k zT)9_AF>&fKk*y6$utVama`e3$z1RytNGzFnEMa|_Lt;$f*8I^~o9 z=BSQx)YNlSXr)=LplgokrR%Qn#rLp7VtePYo%Q8j67vhU=JO7D>bEX`7xMX(swHdp zwUV*usAiaY%@AJDDx;t)j>=ce$7s#9o#$HCmwQRgP`I@s>yW49&t_S7v^nkxAVBmvKS%pxJc3*)lrU`dX9=&qIs~y7|kD@=MR>}2+1o&lIGfua_!V} zZLBDcC6)&}&x0(B5t3_*q?BazCRAliy~>E_Q_gW@Y``IYns`2ES&WdHp-9pyW8zf? zABjjUcF<07Sy2-^kHV~81G|lfw9ER?c1pIQCUzc$S-ocGQCLOVi_yVh=TX*+Im#}M zaY%mZkf-cC3hO{QuXF6M znAq8Q6ylP~Vry-VnO2em5qCQ~k1F1cUhDfWe$rmW{2b_n+G&d#HXub9JPzS&{6nrX6WoZs`x5;l~|&DCD*DQtS@sgcd5uEhv<0} z>Nd5*)}YD_KGub0 zRkR9@)LAuX2#au?okt-q346I7rCta=L^#Pdh*zDR72yij48r1=ey?XN{BAg*4KOwevb{>U@tVdXr7)^@1ot;M&I~ZZ{*f=CVAxCv~9)--JM_6vme99l4 zokta|7-4zEIA8;8vGXWoNIk-GBT9fn@)Po)a2b9)(P=M_6t|RB%Xs zLO!3^c~sGg5tiqT1LKWxxAUmN!E&woFof+)$V$=ks4+zbYxnnFZD+z))Yw;)%o3c@ zi`=r8p>17J*!@tB=%uTu@WuC7wW!~ab+A5cKS9?4_p<#5TOZgNL}o))!%l(k&@+N1 zm3<$?M4U&BDYjd?Z-?zIc}&FKlCsO(Exrm#umk4>$WwjqMlbdP5Vj|yv4kyT4v8^^ zyX?auPx(Ha_+4|xIOpB6M`q)Jb12GD*y~d}LaVYnXb3w`Q;z7x9A&@65Vl9Av7Pk| zblK~(5yUwy@|2xNjj39)c3&%;(;`pN-mA)zHCQZ{wNlV!?-d-Cuc8;*gz>OFOV3fo zSIl91uVzQy=evAj=TT$7GAe7(+GP*fe1%;J{)uQ9eb{g6~(ax9JZh6IjYEF zgzZ_H9XJa{o}%4aJrdEU>?h0j;K2DN@)U9u%VLD>y&4D3g1s)`BN3^!%Al)f5B^4R?#AZ(h2=T=#~#@%zy6j@*WG_aV|Q9F>pk0qs3fKI zk56qLwsQOg9DFY)%jNrp<*5|XiV-ZA(J3we(t*u~5BRWh@QPx&e7|t2v|Em z?>xG>={LWv9K6n1F5fR)YsCoWV{}R)e2iG69T)App z-ao)vF@pJOG;?t6!)SaT9KZOPeGZZ}(&_rhd()P^qH?McJ0JCn7Y`vqu3S+rcIX`A975#peGSeaY~Asi&ut%%1{~%qlcoOAUi_3;N@whN z41CqNuf#%=6^L4rji7Sa7$^tJwOKMpD@L$fMwgkW95yqQgXP+6HxAZ{5zNQvvZ9p3 zX1H>&TwArqVXJlq!F-G^kzqu!L^)WlMIYm^=%XCAwiUq|GP*=K<*{;q~uv}TS zcuPsFkD?VLn2*sKuO_H}z#%KOTnA*i5`FLvm{{jUD@HIMqcxvTP{)BoB2Kwx%5v*j ziE7NXVg&Osy5`{Z!RVR;S#$Y{w_Rd+Q0K1Y!7`6|j+L3H^{&l~wE;x_9(fRRcLrhe zb&b|aZX*w3)pqa|qJi(1SY*&%W``kUHNm@zFw2#ldzr81a4>@T7+q$Ga+pVzgXP+o z&(Vqz%*W_5+m*w{Svgp)&0XWLSu%rQK1P>SJE0Y&94yz?pmCsPr4&IMux%|$%S}R5{AERX#N92PCzT&-bmdo$FtF>YT^D#Ol_zC_32VWmxx%`&A zS}R5{AEV_SdKqtwJ2?2t2+Os%-s)TVYONT-e2h*B^A_eE;C`aWdiV67Oz zd^MUm5NrK94x{nC|7L@{yXUUQqqgd>KI919p&aNMF}m`l$Y^sBAvb;(BCo+$e{930 z;IK8ZOsiJcqkV5XMYf_A;VYZrLkRu8tic(Ctvg=x+AibKfWv%cvf`c8{H9}hSJ+Qp zqUW^kD|(|fJZf^)Zzjn`P&xPx0hVjCWR6yhU=0~vW}Fdw5!q*jDQPUT>^JS%Ih7{MAcy5`{Z!RVSp*17J9`rMVspju(g&!4*zOBQ7v zs&{2(RCnVN0ujR`4IyN{mUq(Ee2@8=3Jw=C}r-94uF634Rg9 zI3(K?tz^^+g83M&>!Xnw?=ulsGn9kn%4{F|o5yRdWG)p1^D$c2`ABBGuP9tMP!5(W zs}{es6YHaBC2OJ}n2*sKuSSy3Ju={GhH|i6i9Tb02Y#)UtnGqeK1ORkAHlS(xde>&g5JJBn zM%a8+4qi8!2eHmO%Y$42ATlVz?9g_xToGouvU4x_)C{^rQAJq%&|WN;=UA;3BbblTH3!djM%Ns24r!lO zYPg>sBTvgM%NMIDtt{m~+Fprv?vCF0tgPfC_;o*T_tEH=KW%rWyy3>4$OOkqMi&nG zf3)Q}%LaevkM>&0zaZ%Cf>@G1iqO7oenRu7@=dX0#W`wj?VmxgoDh{43L0JgT^VS* zCKs*Dv12J~i+=et*SjlnOnBMT{)DLFv%1yRsu-wM8$ zKl#&U1dm#v`v~_Fpvt~9#}4@pcEG;;nQOTmb!+i&jR3C2lb*P%SnY^s+@U+3KmWXa zpY;bq-|1vWz|Ot=8F#WA0GYe~EPGm=bD+8*nzQV z@#O6^Kb4YJt*wY!!xQ8Vy_d=pPj~FQVQU<@$ln2=2u7_?U=-D`B%fEKemnk|P`kG}4($;+PfmInRz|HuK;)kS!eInayI zKO4aukd!}pJVM`#R-)angB&tD=26KqTAuTI+zpElyeGfA?KA&&^V)_n>}VVA73~<0 zT=T{ewtNZInMmfM442J;nq$shCz zzL13P^JngO6plc^S7P}d^6ql>E^DQuS#wO@~1AsyKR3aG9RNM7oU0F4URyBuX1H6u^mr7s2$c;J8G>Y8;p=S z!4yX{;}qQ)jeh>AeZ_ns31c(lEAAETz8#Wl@yv(XVQsae)=IK-gG%O_y*F-+BU%CY z^B<_lAW6|~1O9FK{T|*+`9c!xa9{oH4eTZNx{USZUeWH`A+;!;T~N8!Ry%5~WGos~O!uC>&(=7i z6|z77f%6@I3L@5rj)x(bL)#$JLFsjPi?4NYYSS>!bmGw z8x1O^`<}CSS?H^0ETtEt>+xV;F<(f69qy~6?p?f$_2pjC?%N^fY7%S9`LeXjS*kyk zA{-K{8dOZD-m)LgitLD<-BB-p3oW#gPpf}x1PYEo>wZA-Veab)wl-^6_5es*_b$%W z*ups+InErM;5sQ>*I0PKkx83 zvV=X7GBa#s#d7fdK(gj`nTcOG@`5YbyNrl7xDnS8ORl-<6NiVaC66B}mm@}g^8R?y zYU`WM{20p$bXn&%vJy-5Y4Yb^_)wF)5N-Li@}G~#TKL_yg6@ot-T>o>d)IsYzayZDqoHlD zZl7kYa3pk>I=Jl5K@)s@#lsDsm+gO}#n~t)AD@iZx+L@;(5ocmGN9N66A# zTjWYcoqFZ0d9XnaxmCQ&vI4ES*3j^k*P_TDAxmoplB-uBY|Qc8Hgd>+O8yABHG(DS zEVR{xmF2R)?(Jl4)K~ak=2U|m0&Fd-k3by+M0~Jvd8Mwb#PvFDFLBie++2k9T9JS8 z2P-%}x|1f%*t5bB?Ir(e8~<RC9Qwh9<1Ldcn|)sC8%bEW+cv%WZocj7D^mtR`2;TFGpEL_hmL+xYY? z_k6B49TPD>BRqBM9UlITG$ba3#Xz`(bUuJvZ_>bq@r$_d>=hYpf zhY{a<#Qlmm`FFqDF?tv=e()!Xc;e@OeTC7(h&a-&Fgm`^V{W68XNholc6MuZjwyGs z9PZK)6uGMyb7&=UwJpcc9zclh+6$KV&;tnZk0Rh*Mh|ny7$^cG$mn5&jI$z6l3Bv& zVFb@aM$bd&Y?K+U6|%%E_}!~zw0U(U{rHOVBk-uV`{;~t4&P}my^N31jHsgzqicj~ z1gsx%tvr_a_u#fqE3={D9Y||Slqecn+t1Zx-)Cp|2eUJLRim8*9PC}@W3=~oTW%0$ zk5|DF2wxdC+tW+0`jR4Y^kD=`$}D+(9J-W!lGlg(2YzETBhGyw_rm(9(L;!Ho_4ir zh4sPcVUAm-*C+z(gVDo?<;$b#prp6Ja?tCwEge07cQJ-e_z|NYjE=I zkDxR9GRL%+Niu|wdVeM|Up=q<{QNaPTs}PXtvTYnJ!T1*+QxP!)}Xt!=V*mpBJ38u z_7!iqGW2bmXxHel0vxP6^D$b_4RkN#vlnl92J6ecqTRQ{_LJ0(*jwsr<@-M0*k^Cr zDJou2%NbqlX#2imKK7fQf9Sr?$qRQ?zT#fd?%N?%xb1(Jz3@3&`Oe)A;fTGkwqe~( zlA>!nSa;@QblhLk_Z9bI?!qCBwvkF7`;chwt$dgBPi4&GNZUla?4-}JgLP*< zM#p|)D|46iZ9|MJ$VFc#5qs<;xh6e5R4v1ocqA%myv6MVDvD8EoU?%G^2@3 zeCA!v@bS;HGWYYbjJpNk_o&F~O6_OgIRO7S8j|?FjF45I>B-$N<$ev-s&%ax!E)pK zJRWR|?|7*u*pt)sCBulk;;AwqvqlXbv8`!QR-=Em$ zV-A+fX#3v$#t6yVw(F>s1=`xn&~p$hm(jxr$*;ES$oIY0e4!J3#c~;K-_OxXvVrXz z@;$;eU(LaC8ExOs;gCpeyN-OXbIn(Cuv|vl_j5QT4$6G>xTO1u+RM;^XfqS$Wgxg0 z^VM3_M|{r`b2lUb!E@ew)qEKd`9o2NyKTs7SLWY=4?g2)(W()w33L07a3H|$T9rzs zj8p7W|Gv}=VYyZ^r5BG=?C+kW=O4iy=raDs?e}GzA{AN4(yFh_N}g}|-JhsrJ|%Tx z$gL49DR$^ly~ggjR>);_@w$oq_CJuCnq{#jEGe#kpb8IJ^?Ky>Kde=t%Q`n-`E{JL z#PX1(=Ts%yaU6^5AAc_14Y@UfCB^lq<75Qms*IjNmZ)uUSG2-R^y@g!lUc&DSQD0% z=by|x%y#*BY{yLWHso@C^y^XRU&~^Iw`29q<6yZrti?Wxh;B`*R`vk&NUlY>7o(w# z+aWt1im?3>lgoCrE81JE^bZieXX$d$%iBQ9r**AlHzI2#wP>y35JGl56oFcl(Zd|F ztD*?hqKqC!$j*%-P>V8p7{R_`^bA7H&(`;!L_)msD@};`y=z6?shbw2pFHMvJrYsE z5so$jI9X<6a4#C%cA}&5@!}O}vtW~UFzCKI{QLpA;H1icZ zlq1Iv-_!MIu(Zm21)&@)m(g<(#(~-H9KPOqCaaEMj8xl1duf%|ro4%5V9Xg2ZP@#|SAS*l*`I%{a)hk5i8lNb zQ7NS%tr!t)aNKqMFLn1_`2yt#SvV4M>sUFY6(gdZ$1Tqj#1f9}HyyZnded*<>dDe- z&0#yjs#P3mn`kesGJ4n!Mnro(t=|8G&9WZx4v;>F_^A_rsaC<>Hql;MWpvrCow0)v z(OyrhKij@#`n_#k82jE?c>BVxaG>y**Mh}du4I%V`Qf-Pq> zBiMTOiMKI=z8{c%1%#hbV1L(r;(NV{knii7+GmRQf-K)L*I6=y$Q&|9$G%c!G>MPV zs*`CYYi;Zir$!GUBxZ=*961?XYsefD`^KID7(I-T7(Vv12}aLFz`YKx;NIG&oRUc;*aQnxo2$sYi22t3YcWG_-O&H2=~# zMk8ctb}nyaH zYXthm5v|)xFGkmPu(iw=k}&2&-sN7=?%N^fGO}`V<(=E*oU_=ZXDo||C(tkS)pH!` z1xXoQ+aYJ}eubl8qH z7}jQvSx*mpx8`s@*F|Q!jz{#u|Fa#qkIeT5M61>ja$c)PY$ug^F*@6kIpi!}d&Qk+ z?kh*kR(&|4_rtA(R_Nsj8}p)-oMC6J@=j`Q>%F`~hG%sRcdE!M?-kEFhP!|(lw z5d;Wx7)QQS5RQ(!I>J{O5%;R#NT6pBMXM+N=98zV?vu4b`+|FLH%(u|$H*_JUVY`u zWnJ^zdfJBVV6=(Xe`?E_kJ0sAFL4C3#{EZ9ITTEGy7UtI>w9?2TE<5wh|s3b`C5Z0;%t%L;Uk3>i&xx5d2T=#$$ycGZyx z`lEOL*V!S<+xmVdne~n)JM>*)!5)Y}lUB+TZ{=EAUApgp7eyqYOpwy$~f^=n`J!hg=#Bzv>jvua25Y8%!)zK=1_ zmHvM_`Np+V@6Yj^`50X+SFNrde|7E3-^!Vc(ZdM#52I@Y+Yv{G?0~Om1QUBP&^&_V zT`{Qb4tvMd;?eumqeorv<+W$ue80A9UxDK)n}=as*4#{2@#Ue^SIN_imOO-(v;Kye)`eA405WN1%OPfe(m1 zPker}-x>SPXvLav_K_=Q#~sq_8I2SXN7^RZORJoHhB+7!ZD=JQ%yw;sthR~v(kf@W zVXYVuZE*bQQSTeQe%l+BBV@Hrw3k-7`WV)V5zz+6&=VspH`iVH%zIcXMnv0urK(|_ zi>zg@opame`V%}xS;d*jz-r^qG$B>4pYbqbd4B#u1L-%dT8Rv6rz>X zaLZn+i?!uhqS_|biY;gK45DyI^&-~hid9B!*(+J*)A5-2EQup+6K$P|1+C)SOwx8z zEiHSk&U}on5v)6-YsAnqSllbx{aGS)$+FkDvL=?j%49F7R;a0ceVB#1K8m%BuI*rJ znXl%MH8|J1+$-Aa*&*>`+3V|CD~VT~$E!G^v7}he=wZtPtr5=9>uDuXROVPdv#2>F z?sgt`ZoO}ycs==ka|$;$W<|;XAo^BX*;Pb3kRcz5mF%+I~YBT;2F;78ew&) zdN+;?c^4x%G)n@#v>NUHm`nY!?3EtcUYFD(D78=LwND(;DnmS-X9=V05#(`ZzL1n> zN!wWs*M=;uuZmWT){1PdR)N;4&(N@3s=m&uSLN{Pj^(npu%l>&%Cg8}M6|&n)oW*U zdmFOcSEbS~v!~KZIb5qiYei;j(?$?+w}X1ICiL8($mN+|X@$DI$O^Qc;}{woa*i{x zbG0^P=~>a-wW4G0TH%bP$O^Qc-5DAja&|Yevs8ims>Km+>$x-WkybcYBUyn6G$hIS z`N+=CaRyls(bipq;|bpl(+?qI%K2zS4^;ob26s9D!yI zXeE1=c%Qy`kulzJ}eNZ_Gh~at`F)iPUx%Gqe?GE*LJY(%ombi zhg^@E>nrXR?QBO_6YP2=uGqnR!*&E(uP7QC(&hRfEY~ZeAuDsZ-`GB#fr2a72aBvg zXO6fAX_f@;54FWlrvCJ{~|8qVU;3s>d54Ikx?A7O;Y!5*S@gs@NPw^Bsz00IC( z@l`85KcDk^JZ6XV#)q%))#%!$+&gnf?h{L~Yrs22HD4AE0`!thX4mWZ8p{9zAi7>x zqvedg*rXix7hfgeJ+fLu?c8Qat%+p)wY(oN2QimJ&NJ<5R?TOf^`BZRIZF|rAx7~| zAza?gjAMm`JA&x475Z$8x}hlJ&fQ{WAqF{C^Cnf%h=98?`*r@d`B4F<9s(e`D~RtksMkNl`-ktp;X5GuXz$~}!a(b@NRNvjriaCOJ%{5?f#>5Y%q zxPHVdOPA!|=iYgiAj`N<(9StZ$HQ_|Un|yx(X~y?AwH1|nSGMmc{G{N`s+VBf<-Gv z&qcJb99iG*-iZo;b354~EPf2oaP~zgLi>z zz9Eh{^Q!rxKP=~6**G8MGrhjASQADwU(F$rY}v=0&rF%GM)3Y8qlXc(r^|bOMN#RJ1A_@vQd3l+o^mSwuV!zCcfUucuW!bG|@Nldp$}C+`>NiS-(hy_7xR z&(6c+XuC&&@HYC}o6NNrb3`vjI|Df6Nnd*>gLAk?`y3g??_}tshY<1`YcNsm481mJ8zs<&7f37IvZXJ)!jy8`V|HcGAebjr}$w6Wv z|E@%ZmfbYZE3g3&WP|$oms?nGcrV_wIu?8;AC?XRr#QmISTj zUHS`st+IxNPqgx!=w@eM`E!sMXMU2g_l%;0q!+&hpV5q9U(G(%=$bIX37}OxS;|kc z_B9kln^Arw%Vl(J6LZ9qto+n(pN~0ME~6zs+OxLMgE`_EXB>$qmS>*&Z3QKNG~d~C z+nUMj`RZCjWdK4x(QH#e0EDbxbZ7Jo zLSaDUw=LxOI{$fh^R8%w5B?8tx$ww|H#%grL?wG}zmH(c89jr@6g{oty$1Zo0^^vA zh_@~9dlc3~#5*AP?GA)!`@Z70R4^I}5l-GG60z3bk%8mkw}KE3e7271tt#SOuNfF^ z9IXNb5m~>F_HpVXqGqVkF|vI`)C^ncUEb?y6*a?FdSCc@2=*1DS*vVw){bW)+FmEr z-sPHs-;U0`7!3wQQp9%5SJsN#!H3>&{nUv&fyi;!GeAV`Iv#&v=`Svm-kl&NSNXee z@Kh|azK=OqfY8c*e?YF~@LPwt7gvBlFbB=60ge}MJ$IM=Rs-f}RZYemE5b}KfnpH2- zi{EpIcl<&#{f$6+ebPGxw_Bk>%$1HQr{wdjM@7 zf8J?Z`dTr9C1tN3_^9{pf(Q8Bk1V$yP3Zr!SDm}7uN5O$Qs%&T^f_2A&mQ!xVhQCa zL{5)ah^XGK5etKeh)O_2EMY{Q)grFc@oJ&UgVBrgRUNNtjzF*^Xcduxf5(F5a)tvU z;uXtc1WT&p75};h%iT)9@=?btmcEQz?sG6Aw>>7>oZ4lPK{+6c z)Byeg}wq7uwwQH!qmsU<6C@9QFF0 z@GiekgyrTplel-G)$}1pYK~%Aj9^JQM_qB@Cl-L@x16xt{Js?TF0_$&qGQgo7{QWq z{y6XTFW3nW@Vi%7Zhni4R~+!_Deu1SgMFD4-y9_lUFR});oU4Nzqy6w$_OeV#}a6Txr-5Gtr)?Qat^%b z#5{Mito%M1mMgPIIdV*dR#$xJuThCtS}}qpZdJCb01`7cZ=}mf(P(zgt5=97AkPe0_y+i1|L+HJO zq4!=7?{~iQoqK<|f5F{(l9@Go)~vne*=yFUnR)W#gR&y!J;r-@czBd=-@N*G2g~sA z@bO4V?l8thz12H_@AOeo9tXr}en90tRCafg%Q5#v9=Bm57`-3Je!5s&!4 za6G(s_)PzUf5hkfZyo|XJfsyK(SP&k+`<2#FaPuNKaemL|Nlx%CHNoivQ)zVgWoaV zUE6dgtapIS{*AU19v&~-f4=x`88R++qO`3(X(6;=N)Qt}IIoeZov|6O8{Gasz3?R6 zAa^L-3}M9T2Dhu!R4|GC2_z{}6~KeF$-O8$omQE{{~yBqmG@}&hN|BLhgMf>k@B>Da``2XW!{`XA( zi+VRz>3foV|D!hPdkhAP06aWdytl99KDps<*I9*|DZ1mltk=C%b4RCiKIZB^cpx7c zfyYp!9T?L0kKbfYKp=okvNotOkZfxYz>Km7`<@#k0g7&9NRG451GR4d0?hcE&5H#p z@B%1nNdlkIkdl!N>R`&9b1OHd{@s4vxlZZshTvwt=GvC0|L6@?i{m)#vN*>@^>mfa z{C$ze`hkX%^dZqb0%AXZS-I5zzxn^AjlD$0&kha_OX7B~1U~EEcVh>dE)lYvHMZ)z z&WbqniHrw=-toPtqb811<^ zmVej@cHS6i&4eYGt0YS@tS&twZ0_x)2$g9t>xm&-7v@WBW)MC=_SV-Ar(CUYxL$1y z+-ya4dR71?CDQQuNMs<7fD1ED14&iunF*HT?1q0~f0{Iy*omf0F?yCv&OYa{KJG}y zFAaD;_0e@Gg<$>XO|dV0at{;$ODsT1t-4G7-MeuwPb`ON0$yif zLLf>R+?L2b^dGCm)$q)OgCHJcf0^Twnbp}zkG)QgfM3)L29Lm&7hxm_HYldh4qV&) zM}ad_8rWWjn0P0MTRBP?G3p;WCmaz;>R(?2d$%TT?tS)^7kUu@09J!Y5e38Ht9}GP z<)}gw`{O#4iazm1|KF|XZsm=u^!~8TDvL)MlTP2$p*&U9&e1yf30(dS&xYqggd#}WZL7HBF976O6t4mB9oHeO z;H3EW`stU49>b6zSW?VYQNY9#SeE+)xl8MU;*=bf+VcD4_3z@MHWNik$}iYp3G+qn z*sQX(e+vl4C@4#xeCr^?Cm-l}hx)D+umi!YJ{MK8zkfI&eiy6`D4d%r_?DWZuk%K+zu#TguuV_pcS=GzDs9+V zjslTjT1lc<;Pe;a+WG580yCpM-GKDvR@Z6$X&uX;r9GNx2R4r3Tu{~AEUoTK5YuFS zr?T-I?6B0D4vo|rVQcM~n3$rK>>>4hGb|)IP4WmAPo%h(n9Bk*5%Bzo|9eNgZ|EDZq{ayipvZU&~4PEW(xv6`n z%TQx!eaU1>vvtxwR{ruLnrSNv3@mLpP5sFSrpH(8_$#Z&l%ftgP&NmnHF%b&x4X2b zC;ACbX`-CFRrRsMjK&~4+mCSFR9L9k1Asv1bS=grKRdUh7F#BHNsXxQTK zm~ISfF82p&ot-lHaN8dsB!9PTnb&)nx72&@c~TH&`K<)%Y{zyZkWeS+I z5JV?Sm3GsQD?^V*lqFB)L1xS&i`w+D_XEUw#Jd+p({ra=N?;~Q-xCgo9JBgbaHwI= zti`ueNi$`(g#DL}Vl{bO2G*0AA49PkAfv|{l7GS56E>-p!%L~YWZ!4hO@V--jxd(O zlkI6uedkg2I+72-Fk>#e!-uNRh7E$6_AXmwu3F-4q-Y&m-R1(}0stGFEFD#15@E-D z8q(Tr;hy54P~Yfb@@efx5R+{-3MeC8teym|L@YBr3VXj`e)+~k2$w!Qcx@z=I%-Fg zd*5N?t>X;u3Ys?QHtc3C%%AQejqV%)p@Im)WsCG(9M?FVkYaY0#R*Q9eY6l$*6FfV zaUR?mp#v({RG|tgy9^v`!p6Fk4_L9q*ICY%CeIILI4zTI zYub(cb}%9SCoD<1VfC{N_*)o2ppBmOI-N~>Ru^g!tExwRj%*ImqE|4vnM}FX2G>7o zb*Cq`2Mvj~uLc+=cgu4?RnO>Y+|pPCnmp6eRK+DD%eqpj0MteT!EuV+1J3%;5GogG z)2ltCOkVwA((We@q=2b^8`$5hVBvW}F{2cUS^VSmvEi+A_-DeC8c^}EbF%w6GpJY4 zL%JIC3P}4EQ-p41Tf<6X9jAIt2r|c8zO*G6y9v0SLY}ogPc^{z#+71jDp+iqdlY?2jjs_V& zxwVjE!r2Vo5nc1&>di}Ln|KXhSj`pa*ATcFyu@<@Y;_VI4`JNh$Hk8q-V)yav%4|R z7!NkiX|s84xty>m$ENVU*Ds%W4Ha--HwM5$!scJG{kPEPdUJ45duO#aAbXXiEUOKt zCw@p?P|ZFy?QykGf4M|e=qyA|a!;yqXBcAss{LlOpoSOH@r}+v%kQ?~_OgL*m@F;_ zb&UWY!Ng`i9loc1&-42qZ^ouRRY2vZkuOAzlDeS;;iN>89{ZK`$N5@?XwyBtfuV!E-HRY>s%UA7K6KZe8U?htE}qP6kH*^5z5Gr_l{XOM%e*2aJha z1h_t?M}(-(`!4I%>d_{jK1;1o$pYuVXS4IyvuoezyM`9*ZvNT%w*#B*g)K1`EKgv> zU2an8<6eegla6KBzVj(N8mw0jw@Qcq%1XlhcFcs^r~rR@B89g-czaCT7GA+7wCTFF zP>bJldJ{FLt0lk#9AC9hn^`W4H`1?`3Y}@GaIXM1##~JYi{n1mQ))Nra7A@{K6>l9C(bXTM3Es9IqtrK6{X-uQ<|y=`$c;UZla^8$ zhOMs11t{=yJ5D$#rF7&rg`ZfQT>MD6>Y_KZGGV6AqgU4!6{Ia~EmHe~yl(GNLcCp- zfX!sOV)izN3*mwN_*Re((!jyB+BhJkAMKib<9eL8_p+EbTge%;W&UP+zP;=fp9sxJ zaaw@{r>NHpyAMfaGlGMDg!U%ZqrIFr4J zb;{ZVuhUfg_}x;GalVqq-JdSCGp7AeJD0Mv#ZNm@VEBNM`Q&<=L;Aj8Uo8BUIZ%S{ zBnzTzH;fZl6^D878q{_xmY0WO?cXpsCEx8q1h|n@;qXwunB>2e<+&-JsBsG$rySl( z9DnKR)?SYyrH|4!E;b7bwf_iSStmQc{aXJvd{Sdv7$%@Br_YEAaGoP}jBIC}eWgdI zI)DTwO#rBp=NCvXq(g0k_TFh1MsZSJdp1Nh1}MvS#ElUff;dgy;Rt@3fh0&ilixZJ zyA5_RTx+9XR@G;B$7_+8uwK)KW8H>Fz;(mhW5e7#tLhVcELfsA>gUp+<(2~YoT_5U?$;+L%mUS3&P}0_W=Dneo5^T`tPK2+; zG&aVsEiFk#ucY6PBz~B+`1A*f$;LnbUl&G-_V8Pa>JQGo? z(lcBW7m}S8Oz8>hA4yiqyOqc^6G&9bH!W^&c1_xitX#UD$F@?D{I0t*?4fZdB8Bd- zV~K`CiQ;@KCg}ZjmqIvxArZHm_1q?$JSY8!D=wpe(c(V8yJ2{cH34mA741SL{!b_V zNPd4jyn6~gq%D}AjtAg3hom{7?|&84kOi6hDG#&Du;r^nAgK`iLvv!Uk@2wy`MRKl z` zg$Z}<5%?Lv4J;69EKwb-XxO;A;3b+hZEP7XagZkGzg+~rI96lOi!P~Y1@S=2zm1R$ zA(W|ijf%TA9jWTq{3s5a%m>~@3k=^+T_1Y>Jf%;P?r^A`a@kKifq=9jC|`2m>q^q1TeBw0?5ybUyoZ z0WzDGpa;v0t!!=vh1<+^A0@0Y^;=ju;Vg4=)QB1750U}xKM$gcp6!a8?nV!-5JIS6 z1|cq(p}IqqL^DG#*&b(0#Qb@`D^wIJ^r8fGxb_ZTHXYa@`CS0Q{3peQ;e2G#zu^8u zT62L5A(Psp3_i-Nf98NvKxo@6-{v6liOn;(MbUBuo#Olx=Z_M$=~0IZ8HbQJu16gX z-^rAAiB?OV~uyOC8o{Q1W1bx zn|`v|Os5gLK5+*vJMT5gaMxaT+SRT5kC6S2 zg8N#4S45Um(dS0iOq9X`>-FGaAoKcr!;6n=0}J6pa@6_G=hZ2f)$|#+OMEv^A-tZ` z1Q4t;mcQid$nz9D!^HUf2|mw7^5U;;Fd?W_tk4I)Cxoy9O`7MoTMBPAo(+3+oHNF;_m74nzS{@XaScfgHZR+Xk*R|TfOs>WNLT~pXAy%K?pY^qdhpX{s z=o%0c@5|cW5b6|0Tc{=XXzB*RkY%yGkelax-VWfohA;O3Ow2P){R849jR6@%m)Nki zf9)>Ylv$7u$_tqQ!G+U{@rL?~o`$O)OK$s~_3F2+FO{YT=gOX6xnsXGaV`*xZs{~_ zhT3_W>^%Mji2k~s^I$+pF;XVU9$zgG>vQW&TZw8>0Ft@KBK(vM+Y z!7hrIv*N!oX^|xMbCmfGW7rg-vP@GTgDUh3#6!^*LI>$maVe>X0@6$0GeX8@jhkg9hq9gCle9G&t@t8Evd4sG z@O08Yro6#!Gz&QAkrhCalsp?%h7SC2t?>ALwOoT9fpUB5#F zM+Y9?o?OZ$BI0kQ-clRh#(DqZ&Gn@Tnd9yCDW5KtR-Q9y$3q|HxaS~T8F}sS=Ziz( zKe~L7?(Jqm3p0j;Uxl8}`P1g|E9Z2sdk3zRu7^mJ--?I*J$MGf_W}@GIzpz#=6>=f zZuaaYT zh-{DsOasru$l0O_n;t74s%#>A5`5O+zo;nwP)z@)Vm9M2qcXB4xSPX?_fO5^4`cIAUCHrr!cRy^Im33W7Cb_GhWGzs?#V-JY>H| zzk*Jbpq2nn$al1z=S;8kcH)xpb<6kI_%Hvoa34)H-(H?nDoR0!R5GZWxd0$gx0J*rm7-)@{g?DS><1%Yet>f2M&|8+;;(g=UG4qOr0``(P`1(j~ zx?hV9`{*0Cfh(}jBDo>`@tucz!vl^Qf0RufdfioKgzRRvEVZ|`5N=fv7xt&2?|+Fu z6ECgHx}VO#%DD3Ijp-mOr)+hAB88iy+?!ox#nD9MrZ|*ZsrLz^Y4)Z>5Yl_=&r~`5 zt21I6wULe4;kt%2pMO+us8j`xx=a|=9d=q0+d&;G7^NH|a6zof$I8Q&kYAoc)f%L#=a1cVt6-Ty8$m!_C9hWNK$rCEI~Gn18Z zU^1oZY2%&dQC`3?Fc?~;=D4A(d(RkIZ45!u zC7IveTnkJM+r}vL_5=LN4%yI)EVW>4EdTd8;R=oy>ntvzj4_h=)#fk7(?8Vm_~J1V zzMjqIOyD-w5SCtDCxz(`N2#DQgQ-pA-`Q!eEhpWBs`bcvD>uA_d&U~TJuj2HHe~cM zT5!6ZVQVwS3%W2~jRq%IJJa7XQnVGA<&vAW%tRJQ_;|G4wbHVaeWMG1=cWT{P9L9f zx-;ZFc)TtRayk;R(IzxsU`{6-p6#i@L~uy(P-z$J`4_WlP)Az@3w!b^mlsFH$G-yo zA(8LQ>hhJZaMUwq+C&;Q!pjClmf5D8Ap@+u<{sYJL;8EMAbZgX)_8FTOpno%m0`;Q z6=^G8rQh}R_}{DF;J=g=hCS1{(YDp0Fog0O+DxWJ;M*aTn}Q9+M%FwRQ9Pq<(<&N5 zPL5E4#1R{pjDK5ST$MfbCrH7+oRmU`j1D~c|xx4j=L~~NB{Zgh~#3qu2|K_ zxfMB?U#XHO zI4~vaO3Jx9gudgml`osnpCucx*tA+;GIy39N!H@emsAKRHdR{pywi1Iy}%MsvRZ(C zj=o7e)qCx<>@Ub10)H}QOLTV9=CWRwN8!OIb}-l$2o^!>&6I`r&RT5e zfi&2B*4I!QGCS^NnCppxjVQ%RO_fa!Ni7rG=z!gbWH1$k$z}+>VF5e-wX0D$*ZkPuENy zRVH1{a_o@XD~5TQ?A#MIqQf-S$jCdPBFVE0~#NpDe!oXs05jQ^zi2iKbaNOfCQe?Db=h1k#(rB@l>iG^6V2 z?mUYX3BE}XlO+IiF?CcuN+*`6S%)}T+W3~Wn|}iz{x#aP4jhe`Rryrt(=s^W_>HC3 zO*sH(PX8%+BqXkarvwcjt)Ka2+SLS!-vmMEoiT~zHIf10pobxC_b~NpYACA6IJc{N z8@9+8xkW6$kbOO#@Y+fx7lplV`dP2LtWyjhS9Zy z_;I!4%As@7$5)sH)^aDBUDck!Y0(TV@N?iS{1vsd zXjfJ**6*`a(m&?pG6{T~iq+H7MHa{hJ8c?1fO+leo9un_jiOeT>aIC?>m`^9)3}l=1nA3iBb5Dbu%byRW)l%bmg^Ezjh%X&)2RWxlg}Ga9FT z_x`;8^2viLpyWZ~i%h$RiUxBNiOaRM#wt^a>@tn}R79TBYkFZBc*4sRFcgK)v{g|D z7cJ9A#W(J1=95;^>mw(k@u@xBL$>Y)9pa7!BSK)$f7_)V6-ne!Ti$*BN6Di`Wr#P< zPy76AB@LB(#RD{B>!T;rVh7VIsUW11sq6QWsCZsmBP(d2mJbo1d18_!QYM1JUA%^< zRu+$1jwHv8(z^&fdsC`lDYbL_xIO=@CQxQSE92((ZJ1}x5w%3d0GRN=F|L2POA+*P zxjBV{b~5dtEhWb{iIy5gdLdHch&HgLK!rlxFI2085#4y*^GNbq|AL) z7Ci3|`(z|TQsmj$aVUS7u&u5_6S9QYohwCkXpdRUaO>#cNe33U95ZPybS9*mj^-?B zirTf?d&s7uH0OEP=SPT|%9zf+P@tAUSdwGQ%Dr^5zFsNEFh367zn|U+CJ0)g(m(w} zf-fFE#ywz{jrsfXP{mpA5jyByeYQLlgxO-CK6w9Nk?y@><@QHaFk?mO>RW)`fE=3A zq)675R{6)@2)%NJF!E2)Z8QW{(L0~?gkgS|^TAiAHr*y&5df2LoRjjT2N8xAy<8Eq z%C;?#rx5zraB2)jwOxSnM9HN&bv-fqN2eUrc#Jnn6kjmK;h+$QJ?e}-|cYFDZ zaeaRht-_*^O5gGW*g?E6dl+P9-`Lu8J}QZJCtGAtY#$gc#w#7ua@03yntRA-Rxr#7 zud6Zvvt9MS`pnb6?Mk3U*#a>Kow%aGhYc@{2hdU*znubI@zNV*4fIeHvBMER=L+XKEuhN_Uv?&*i zXkl&7dRTQXA1}I;pI{cC`&1SsDaW))AR^kJdAxl5K=0IFRPINw`t$pK3e!3Fe}C8S zDm4oHQ&8EM?OTwzEZmY;qj66=IclS_*7Qio&4>j^EtOyc?`F~;+W1n%qcMv8`=oy7KzbhaHHje)f4IVE_n6)5 zEs@b+|7V22afJbg{XpvX=&89^u8|1&Zg4+BmYogpl{`9SR@4fZz9#V_AZ0{_*)}cAx(ijt zXH-4Y{j$9g<6pX&Vv}=M15kN%+El9-@mYuPl*1pf@!&q79b|>QU)W$r%64L{L=+V{ady_&yJl*ki68$Uh41V7>65_<6fW1^=+>mjcI*_Kay2F6ER|4ZkdNg z0>IF1&6P?LNU1kvZn++D5>@_owAl<#+0R9tp722~0Gd%gfe>+Ey)Yb2yeoPGJA%8f zHGg{{!JMAp7HN@`&^_%ICSr)mcWs2a2oH$}3Dz)ARUy{L?%r$U50p9I#*(DG_Fv0* zTVsLXr!J%&u&e%0Ac%db|A4DQUio5w^jxRhsoZu6qgNwgy)BC|GqX*iqWe@`^bW%B zF8;d=;vBIl(c;+kTz4?Fev7&T))+Td$?dO*O_Kz3xRYJtN{&ZL2x6j(va`5m^vy zoWu}0|C;=r{C)Ll%|`jJIF{6i6L%&r-TKXc3zdVo^N~Y8g}p!g=u*Xn#5vqpEM@>9 zOIN{g?kFQBZ!f=D`FOU7r*0K)&@L(E8m~1sNcJvEA@^qJ^^^VxN07-BG&N^9e@oHE z)E9jp>P$8M{#drs=v=l#z1D8E87U@1LcF1k8V=aVvk-@183vOW%s*H#L+PgJT%Wbc zP)0j{lcSQzu642e34B)cKCYr9-l9QZdabh(Bu?2VF>(Lw+#gtKsd-|Bg z-r5v!Nho6?MjjUcvW|8csi{I~L6;?1v6LINqwRW#g^^_TxFydjzpatZmAg#*kR)Zh zAUpK_GcH98g7IBtO+pTKX_bVeMO`Lh z_Heb_*>DKiox>i=lKfcyB6RAxO}SYQGiH|*UOPq6e~1sj8AY#f@eI}fb!h=Bn>8T= za6D%xL^6Is-XUXPp_HWq&ZIH6q|F6XAe)d`P1E-z+og!5h*%j~+{9?cVK$_R+~&$x zLr12AMu*r;C2{0swVcCcLfO+TgypXeX<=sI1%W5#9~jV$(+_b%Cs?K#Ay%hp>S?~{ zl!}Z#54#BYYg39ZJ)f~4Mp=jI-Ar@c`M#IRw%DswXeDk2*MiIow+4Ey^g3$|9DX`= z=)_lx`Rv}PF%63w`uQh`hP{sE{`h8?d(u(uVA`?6??z?l2)#$5*aTNpdHP}{MV>*J zjm4zhjEjH9gZfz4^^8~&*_A1Q7|tm*tl*!o2pnOQCzs_z5SOc)_-{ak#I~R@u8@-{ z5Y}zlYlSE=_+m!MVlHd=%*2ApXH{i^<}SY$a9GwWh_U>5 zQJfWp3gBHcN@{;XZcs+{^}v>Cy4#&s&> z`XEs(yrEG9{#P>|K+StIBx!kgSmv!84_SMo1-lllho5)ylUT?bB!JxO0Rf*H63wHX z&iI#$$-mK>2nlX2i1YoTwG3EgQ-Ds~Ez6?sCNyK#-;ZUv#(pt_??J05#G{?czKMS6 z?N}&ci`c=h+-G7>i4Y%k_zelL#GFmu@W#tsb?8fH>q8@u`ek%Ia&seM^;;xQvU+wZ zPAdPCep0pTdh!HZk<|7J(56B0e7m(ZxjV;>@zBxaqLwRD`CW%Not^jk14Y}7m#|ur z)h8WjuNQZIdU>>KcZ9SBWW_B^L0Z(&Yl&Q;-@(Qc{XTgNnNruo)5N+TZq*S?y*7osYO^h@fvE@~C$7_I^mc*5se=Nzh*rNbdtQ5far;|oVy zAuPSjxz@^UvVDGZG{-ll_trel{6ahNOT}VA!7uqyyyarUV+NRH&B4|ieTefYOF6}K zxK%ax#%Yqr>l=EZ$o-;!QzJXhi@zV_Z^utbE^OyOkvAum4L}7y=#1B*?A-R+2WAVs z_p+?1ZHTWV&;TRna+5{uvdsvu0q+<1g3&J)+SxcP+g09toMyI^zl<=X%$t)Pl2g&N z^8?^;@fg3XssCHWDh>h1k+xcqga%p==xthRudS5zV2mxrKh{EX8Z=(kAavo{);-ql z6o1D@PPmKSC~lGjh0=Y?lyF>XZLaosqaSuLDBo{T`5TJE|C7nZ_sH7f?V$#J^5cRh zQuhouf9(XQr34v=J(`~QX5`+kH1cl+PWKI4=))}>@J$*0d9XJ_eB3kCP)J?IwJ{Ps zoMzM%?*bqbQHqu2CSJz`-G@Ael#BOeLtOR+c)@}~@v(*l%hzt*4mSM>@&$$GqJzm@ zlADXlYi@}U))u#>aY2Q4Quy3D_KM&^C{3MH;#B3{AGvA9X?00?fnbU463KS=g&#M| z_qf*f0>!@WESSzZF{Yr&5z=(U*xBMdt1{ zPzg5Ns9mJNI@1Fv3zha?ji>H@ruaB7TB9n?(f1~VHj16XaU_u>A%14;fbraUg5uWU zn;zetd0UPY5M;4oDO$0tB^O=@?0Hy_#RG;*NY;|pTUW9zonEe_884-^mJT(Uz7t3 zme%c)^lH?>k~Zw(uo>qgQfxaReWdUGo!^zT#|sx!*FAZ4L338fw*4g{)Dxb8l-0;Wf=cS$d z)5y&APd`TUnn`vS2mb8OZGTd)Sb_>ZO-xK|Y&)ZCIBTP?TUSE7oD*$0!E8RQnB9DY zQ_w^-A3uoMhh1~S5|rFlH>x?8nyBhRYR^rXsUAtz=2<Q{xcH%Z_z)QX;PN9J1maJ zt@9u(lOtI56Yl&@jPGlZW8CcW;lcnt(OOQp1K6&6V11zmu{45pusy>*5|TeFDs$_Q zm{XNHSVIdyGM|B&QxxgP;&RAUVjf5wP1V-RQ;P}CNyL?>3V>sEAh>tH^PT!c% z&;BG64@k9G^@F`H0EJz71#`#ND0f@Ttjh_0svp{T?NWQzps-t$Zy@Jv8CJ~^*EC|)i7`~F#E}8bX$`TPgOqklTr|Im_CaXv> zBViN1#PK?b3%l%Pr~8a`;M{F&LdYc}dc=Vv=Ob+MS3@Py0ITV!9-W?Q=Z&SN1T}r5 zXUH96;erx8ZQpWYM%q*-+1WjJ?%&Tu-3hwL764p&r@-o zi5yLiXvwTWak}^pgwk=+y<{*YUzl`;vryrA6rE={*YyGRpWX-?O;*wYHcjEUx25K{ z=iawT-(7>+Ei=BKcKveHBtECEK6GDvn3Ebcv)731JcbiCQqn3CS+!akruwNsjO-rJ za%@On+Gfy~`@)>l$0lW)_Lhkv)V_Cl@zd79^2>0-UFbjmZK+*%73bOV@%Ex_CZWnX zkImLB>EoP@jod;MNx66RmeIhbMq}3nDpVQ~4R@T2ma$4i=%DJ-ZodYNNoADU#Gcpk zv{$|DGSx_BE1hm0R|TH=J`E#ZD7)LG&&*h|uI}>Ep!CnZ7K1^*zT5;DpNUM0WgF;7 zmndZYIy};$Ao?8gqy5v&V@G5VC~HAJbig?yB@gBu`zsS0?Le|Rf!RL=~VQS&)1*jJ*a}J;i9}y zU2}uhx>rfJTv$B+3n_#d*c(7xBbivJSd^S!+ffG}e}+vhe<6^HXFq{44t;z@i|om* z*j87g?g*p%B%Byw7`%Is08zNM+8NsF#G=@|q&V3KlBf zO!G{ACc;l*DL<$k_X}fjj(M`lg8OUDbzgI}lZ2WRBWV@hqxl)H&r@#Q%QaW^Sg)@JZaqDN zPXCj4N8mBe11hEr5c}23qIHL!h;|K@oWsc{Km~=Vvery778|4On%9cp?8GR2`m7)8 zy$AyWT#ayZ2^6;!D=Y2^CY>OXS@G-1H8}pOHT2qo2Ck<2s!jby!Io{H-iK(~VMn0_ zO8_tX#X9efo+6Z`3SretFDI6H_A6Eh=4cTbRD!~WXBt_$HIs--p#?$}Q$v0>-g*0` z0}K{8|L?O%%{%oLmw(f*rd@S+5tY!|u*W*4ySq=VX7-t^CBt{)R zW}P}y61b!k-2ur4X*+Boui9PUnW1HhltwAQ=owX z*}PYu*0P~G9;*~1IYM3^*~6HedwHbbpRE8KcbfTQZgRqp32moKVtQR}o_QtJJ(M;u zWZNOIEn)XjQN`+Wpu*uW2tW87bGPgCE1ff}YZOwMJ`O;d;6>%Gs3e z|B^&1ouA75g56jHc-<&z!(+Sc@`O?WVO!Y8#wI`spAmXOus?P83#rLPeh^IY*YImQ zCTzg*v-io%@y6nXvFu(Xy>G7EKIkd2Z@xJ!VxC@A4R_o)frY5@uJj3PpT@k69vCR~ z)E)U|v&)k<_igcj>RBr*gLo=oe=q2AYfI^PEv@DF8+&DocTk#Z zaLv4Z&?M6NC2t^$`{ zb9J3SU=J#pXUo>I<{;VU{v3yKS=|oiOF7!f=bA#a%C~JCk!61fbhRHBW@dW5=qD98 z(%;#6vsz`*mXzhP7TpP7l$2~<&vbi+3{vAw{jtvP&Z*Mkgs%~R1r)?Yh-aM38;-AU zw#J_pfiR0P`OzTnhAz*Lw&uTo@DN7ud|ILoJP|u=ciBXnivkxTbwhUJM;#PYw3TIAt$*BeZ z8$E76AaK&{Ls;3s^pLnuzgmdiTr{0o-^+xBxL zSp|zehe)%~25mCLu?+Js{)_R~2MKZcYg>~0$RvcRF<*J(L*&15{^YnPDJUu+l`=)> zrXL*+OEY7zW;8P-EL^bcc%VUx0YVn(-wi&!m!2Qa^isW*9H*2x` z5d}$R^!lb?((?>fqUD7{sc6y}dYF{&Hc~nk@!YC8#$?%_SOA|ZefuI{n9_|n0{ zO>mAKQxDgy$Hw6QvI`BCl|i9RBcTGq6#nb#(l7Z%gkfsRKqyf?Rz;hWn!X^9-kZv* z{_s<=GDHrD=g0>3`9LA1+%42Zgm|ZLuK=ENtW1V{qehLK#FU?QZU5-%h5TT*yF8gA zUY)eq%`->M8_xO+L~P8E7v}a)IUDgjw?4_$HEXJRTGfkJ3gVFT+HzZqq#|(W(PMiN z0Gr@c`YQ2~adI_r<*)}Msr-H_iBZRXg*D}5wNbnpWc0RW2xX=;W#ri4$Fd5RsomPz zD-0NdiFt20J|{t8B|mt-3!dH2xBGTK%<}NsTYuf;SzQ>E12(XX_l(eQNTav^eo(fB zU>_PB)T)sfE$807i5+?OLYQw@6)=ex9~-A~t~daW z@;pbWtx%ija4}SP=TPk8MU_nvxr?lD$o9 zF8GqkOUlQ`e%T&vi!Qg;U)s+4(K>5#i=DdTEm$A~00;f>N24K&r$@W2qk1sSmXDbk zLfHY4?I=`>U5i*KW|<&#W;7^78LjC7-3okQ)i41#=PNcTkVws))&#MI=5s|PM>aRC zBv-USBx4O)Now~)w_No`xJ|zv=Z_R46H&n|sV>4DSzK6_;Fnb5CP!myTN6{NSj5LV z2n0dg@RnJ&7Eo|wNoKbI+X&agBcl}0*`gP&(tol`U?|f|zL~Ttx1WO0ex3b! zuuhwMgIZ>oEN0|wTZjg8upHZoOsF;fA2&w6{n5bRC8AE5&G-Ff(#d~9o3;IDi5$1wcN6ueYX;%v<%|BTk@&bN1rS3 zv2B6iz4LzkPmRw>#3eM(eJZ?%(vGdS4B@)33;Uq)l;`~-P^A55C6l^-pZm`^g-T~@ zTwnQ8ng*2(>?6-42_@kDJ$PJN)vF`=Oz`KbkpM1wPq9}|CKbD)9_p$Ya=)KmYoInN znLV(-=*PZ90J%00=6>3)jy+8*q+W5ae&u=|7#GLqnKd=G#5Z~Dv{OSHJdGG;cAN)) zRodO>bj7bNF}Fw2)URdEbH?vs1N7K3(T&x^>M2z)jknhh_C3i+~5 z|8myx7hHKqD;L!X%_%v)fF}Bh7Neq0=#ET4oQ5OdRq2tyJFKM{bL)bTjCK}m+I@gD z^kC)qc)~X^{m&Ji6Uk^bof*~;*#LcxI%^Rj6O|bic7)GGb(fd8_Z;M(n60q(V87N{ zeUE#{{d#WZ^Iw9HKJNk=f-V%b3Pyr19mw10VMW)9lol()FtKL3znO4Tncf5s z5^{i`!^o}^fbgE7sKn7mi&ra`s*gPPBG;xjZl^52zc!kUG=2p@jrcq8-hW=y;mCJ= zxWsAMJX%0GLPq?)u$#1NauxGAYZ;7;&e4ZoIT1d!5GYrYI`duF?VYPTF~9zL*FWqN z3&AYJSHdpmN6DY>Bj|@TV7gK11V9K^5;PM2b@S=SB_BmN6VNXOz=e zSHfkH)cfz`9E)OwKtRPId7cVDpM}o#bR{xGmo5q11t0i2F6ACE!N&@dG3wC*P`ez! zz{hXc5vl3)wyUyQzqSl`-HmQ-8fLD=U1InS4U0zhmbi!M_Qk`aqCCK_b75ZZMgzU| zL;)>`?P~3EF$=n>{q=bKYagX7axI^jskErG;Rb5;3s6BRm7Wm7wNbQLhp0))u87di z5`li&j98dw^~^dfXW16;p!+)-n4pBx$LdbgT!xCmw$bc~gQl5Vbfq;wI}CYjs{iL# z=#c$Vq+tt*Z&1Zg!L4264XoIL{*WiUOQQ7fin|6(`2*)t{=eRPr2XrVL7(z5D1i6J;F&+}FQ{U7U@5NX>WVBgLh=!sheDjj{5Z8viJ~KM2E>!!@FXCj1aI0hzE=72~teMd_y? z6!|9yUv$~QU{!zKtrQfSAv&|+Yme)#R;J-MNB=M(|IXy$tt7$oeW3AvUopL8m-jWJ ziifnuN4e(5l!6S*SwZ^pD(;SDps(XV&Sz{7JELK$A)L7Ztb{-@r@KfG*ym;%8~JgZ z7LBpL@d{n-T0CcEDvV&H^&*mbxE5c!pIkC-iz0s<2gdSe&P7}7*BcjA$#Lp@`6dis zUR^898LayE+B|T_LyCQ|jC#5TDrt-I(pkuRA=f-!@uOFUcW3z8lDwYyAk{Jugi#@l ztD-4f5IK`_h8?t4!EQB%dm%^GB_by@iQ84jS1#6>#Ht>g%Aewi^^2(cUVi zXd5%1{Wbe|`LP3XLTE)(r)MZk)ykyULpoFZp{|T$m|{HyJ5L;!Bx?#C)i4#$Wylht zbk1ffOzl4Cm|?ZVACEtuA1}`6_Hvk;&|%C?FL7RmNtI#?Jsxc5?ogHXurRHn&-1-i z?^|~KwR~==x;8bW{#$2(`b$X2txuF)E>)9;gCFcJ>jF_c zl!d8D=PR~=8(xo6yW<%ItwdVv89llntqhVD{=b536U58ZQcq*=zsMP* zdhA{A$bd*Aaz_WL5BYK1P5S&nW>-!>DC>q4`o)e`EN$=kxf|otxb?&)U*B*C--#Pf z`c~LDE&D7|=*9v^P^P2!!z(V9#QKkMX?rnxGQp2eLrQ9V27@Urd#w9D(krg~ki%=) z6$oCl+e{ugx-Z&EiQ}mi3%rT^4_yjMPN=75Rr~4^*<|Cj=HG7=1t(mniM+!Ckvq7p zknXY|A;k{wDL}yrkJqHh&RE;s2vh+z@veSVD+${WsZqz})MNy3rA0Awx5=8kH<(I; zUf$!&E9OBi6275lEr%pPi7c}Pob@8QRI2!Ndl0U{9ER?9a~ZvBwSis=){%|Vro@FeR7wTci&&1PVRlWnxeTTWV$)A zTU?R|Q;>3*o*f%YhgO;8y$y=4R@GkP{8ptcL)1)F1xSL$rD{nR<|k7P){|QUM zk6@lfg#2SGN1Htn{?Qw>Cg0|DNF<3XWc>P0oKR0Hu5H}|@pCV|7hYvle#W8cW|j;Z zPkviQjAM~o-yEy6l-o0cKq2mNx;*i0Sny*J`^{!`kx@$M4 z$v^tsK+bZ4uhB{m2W{Fac1hh`)z@7Rh6rsl zw{M?u%Sr7EYI19_=6)JHD#hY_=eN8z^~O&x%Vf9GQ$y#j7P@i(K{$1(aEr_)`v`*&#W$KA4o`j?b&#UC!S_1; zT9KoSV6=gf>i!aQb=t}$VwRIJjz!N!&_OKW*2&r7>Yn7j1>igN9H~jg&|#ETr^_Q2 zX2rH|l{Q5_&|=T|xq=$O#7S|}_0>EhFQ%gY=XZ}L;|*vbJt~v;>}fS=Dwu;(jHZi6 zbd5zz6ZCtqqX@YrhugVt1I2F(o)QzV5;HMcYRs`Xu}^vi(SC>I7E$?ub5N()ql~E^ z{mk#YjW175(gFtK;x*xWVoEJ6A>CdgX=B2@f%bdl0N+*kmPP?oPA#?Bvzk_i& zS?b(x{M>@vOr{%kNssr!0}>X!c};~xc$U2KFl(ze`L92Eie}f_<{Y&CRf?72;xpiz z{jZaMn19*85`ZJxO+_i`&C7G8H95M~#BlsT%;yaLyGLH;*Q+fK=%k{5r`#h5u7?R) zQhhW6xe1--O!$rnib0uP3n7z0b=tbx!S??$xc|EguYke-l+nF6<&*JWH0(cJ;$wCA KqkL7%5B~!I6P!>0 literal 0 HcmV?d00001 diff --git a/resources/profiles/Snapmaker/Snapmaker J1_texture.svg b/resources/profiles/Snapmaker/Snapmaker J1_texture.svg new file mode 100644 index 0000000000..de7fdbbd7e --- /dev/null +++ b/resources/profiles/Snapmaker/Snapmaker J1_texture.svg @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 33b13b937c5470c1c70ea34793607b844f42bb76 Mon Sep 17 00:00:00 2001 From: rtyr <36745189+rtyr@users.noreply.github.com> Date: Tue, 2 Jan 2024 10:44:24 +0100 Subject: [PATCH 05/91] Sync with PrusaSlicer-settings. Added new printers. --- resources/profiles/Snapmaker.idx | 3 + resources/profiles/Snapmaker.ini | 3297 ++++++++++++++++++++++++++---- 2 files changed, 2881 insertions(+), 419 deletions(-) diff --git a/resources/profiles/Snapmaker.idx b/resources/profiles/Snapmaker.idx index 03488b17c5..089ae26861 100644 --- a/resources/profiles/Snapmaker.idx +++ b/resources/profiles/Snapmaker.idx @@ -1,2 +1,5 @@ +min_slic3r_version = 2.6.0 +1.1.0 Add more Snapmaker printers. min_slic3r_version = 2.4.1 +1.0.1 Fix for leading zeroes. 1.0.0 Initial Snapmaker bundle diff --git a/resources/profiles/Snapmaker.ini b/resources/profiles/Snapmaker.ini index 68e32910b1..33d8991287 100644 --- a/resources/profiles/Snapmaker.ini +++ b/resources/profiles/Snapmaker.ini @@ -1,473 +1,2932 @@ -# Snapmaker profiles - -# Based on the profiles from: https://github.com/nivekmai/snapmaker-prusa by nivekmai, WilliamBosacker, mrworf - +# Author: https://github.com/macdylan +# Update: 2023/12/15 [vendor] -# Vendor name will be shown by the Config Wizard. name = Snapmaker -# Configuration version of this file. Config file will only be installed, if the config_version differs. -# This means, the server may force the Slic3r configuration to be downgraded. -config_version = 1.0.0 -# Where to get the updates from? +config_version = 1.1.0 config_update_url = https://files.prusa3d.com/wp-content/uploads/repository/PrusaSlicer-settings-master/live/Snapmaker/ -# The printer models will be shown by the Configuration Wizard in this order, -[printer_model:A250] +[printer_model:Snapmaker J1] +name = Snapmaker J1 +variants = 0.4;0.2;0.6;0.8 +technology = FFF +family = Snapmaker +bed_model = Snapmaker J1_bed.stl +bed_texture = Snapmaker J1_texture.svg +thumbnail = Snapmaker J1_cover.png + +[printer_model:Snapmaker A250] name = Snapmaker A250 -variants = 0.4 +variants = 0.4;0.2;0.6;0.8 technology = FFF -bed_model = A250_bed.stl -bed_texture = A250_texture.svg -default_materials = Generic PLA @Snapmaker; Generic PETG @Snapmaker +family = Snapmaker +bed_model = Snapmaker A250_bed.stl +bed_texture = Snapmaker A250_texture.svg +thumbnail = Snapmaker A250_cover.png -[printer_model:A350] +[printer_model:Snapmaker A350] name = Snapmaker A350 -variants = 0.4 +variants = 0.4;0.2;0.6;0.8 technology = FFF -bed_model = A350_bed.stl -bed_texture = A350_texture.svg -default_materials = Generic PLA @Snapmaker; Generic PETG @Snapmaker +family = Snapmaker +bed_model = Snapmaker A350_bed.stl +bed_texture = Snapmaker A350_texture.svg +thumbnail = Snapmaker A350_cover.png -[print:*common*] -avoid_crossing_perimeters = 1 -avoid_crossing_perimeters_max_detour = 0 -bottom_fill_pattern = monotonic -bottom_solid_layers = 4 -bottom_solid_min_thickness = 0 -bridge_acceleration = 0 -bridge_angle = 0 -bridge_flow_ratio = 1 -bridge_speed = 60 -brim_separation = 0 -brim_type = outer_only -brim_width = 0 -clip_multipart_objects = 1 -complete_objects = 0 -default_acceleration = 0 -dont_support_bridges = 1 -draft_shield = disabled -elefant_foot_compensation = 0.1 -ensure_vertical_shell_thickness = 1 -external_perimeter_extrusion_width = 0.45 -external_perimeter_speed = 50% -external_perimeters_first = 0 -extra_perimeters = 0 -extruder_clearance_height = 25 -extruder_clearance_radius = 75 -extrusion_width = 0.45 -fill_angle = 45 -fill_density = 20% -fill_pattern = gyroid -first_layer_acceleration = 0 -first_layer_acceleration_over_raft = 0 -first_layer_extrusion_width = 0.45 -first_layer_height = 0.2 -first_layer_speed = 15 -first_layer_speed_over_raft = 30 -fuzzy_skin = none -fuzzy_skin_point_dist = 0.8 -fuzzy_skin_thickness = 0.3 -gap_fill_enabled = 1 -gap_fill_speed = 20 -gcode_comments = 0 -gcode_label_objects = 0 -gcode_resolution = 0.0125 -gcode_substitutions = -infill_acceleration = 0 -infill_anchor = 600% -infill_anchor_max = 50 -infill_every_layers = 1 -infill_extruder = 1 -infill_extrusion_width = 0.45 -infill_first = 0 -infill_only_where_needed = 0 -infill_overlap = 25% -infill_speed = 100 -inherits = -interface_shells = 0 -ironing = 0 -ironing_flowrate = 15% -ironing_spacing = 0.25 -ironing_speed = 15 -ironing_type = top +[printer_model:Snapmaker A250 Dual] +name = Snapmaker A250 Dual +variants = 0.4;0.2;0.6;0.8 +technology = FFF +family = Snapmaker +bed_model = Snapmaker A250_bed.stl +bed_texture = Snapmaker A250_texture.svg +thumbnail = Snapmaker A250 Dual_cover.png + +[printer_model:Snapmaker A350 Dual] +name = Snapmaker A350 Dual +variants = 0.4;0.2;0.6;0.8 +technology = FFF +family = Snapmaker +bed_model = Snapmaker A350_bed.stl +bed_texture = Snapmaker A350_texture.svg +thumbnail = Snapmaker A350 Dual_cover.png + +[printer_model:Snapmaker A250 QSKit] +name = Snapmaker A250 QSKit +variants = 0.4;0.2;0.6;0.8 +technology = FFF +family = Snapmaker +bed_model = Snapmaker A250_bed.stl +bed_texture = Snapmaker A250 QSKit_texture.svg +thumbnail = Snapmaker A250 QSKit_cover.png + +[printer_model:Snapmaker A350 QSKit] +name = Snapmaker A350 QSKit +variants = 0.4;0.2;0.6;0.8 +technology = FFF +family = Snapmaker +bed_model = Snapmaker A350_bed.stl +bed_texture = Snapmaker A350 QSKit_texture.svg +thumbnail = Snapmaker A350 QSKit_cover.png + +[printer_model:Snapmaker A250 Dual QSKit] +name = Snapmaker A250 Dual QSKit +variants = 0.4;0.2;0.6;0.8 +technology = FFF +family = Snapmaker +bed_model = Snapmaker A250_bed.stl +bed_texture = Snapmaker A250 QSKit_texture.svg +thumbnail = Snapmaker A250 Dual QSKit_cover.png + +[printer_model:Snapmaker A350 Dual QSKit] +name = Snapmaker A350 Dual QSKit +variants = 0.4;0.2;0.6;0.8 +technology = FFF +family = Snapmaker +bed_model = Snapmaker A350_bed.stl +bed_texture = Snapmaker A350 QSKit_texture.svg +thumbnail = Snapmaker A350 Dual QSKit_cover.png + +[print:*fdm_process_common*] +adaptive_layer_height = 0 layer_height = 0.2 -max_print_speed = 100 -max_volumetric_speed = 0 -min_skirt_length = 4 -mmu_segmented_region_max_width = 0 -notes = -only_retract_when_crossing_perimeters = 0 -ooze_prevention = 0 -output_filename_format = {input_filename_base}_{layer_height}mm_{filament_type[0]}_{printer_model}_{print_time}.gcode -overhangs = 0 -perimeter_acceleration = 0 -perimeter_extruder = 1 -perimeter_extrusion_width = 0.45 -perimeter_speed = 60 -perimeters = 2 -post_process = -print_settings_id = -raft_contact_distance = 0.1 -raft_expansion = 1.5 -raft_first_layer_density = 90% -raft_first_layer_expansion = 3 -raft_layers = 0 -resolution = 0 -seam_position = nearest -single_extruder_multi_material_priming = 1 -skirt_distance = 5 -skirt_height = 1 -skirts = 3 +seam_position = aligned +seam_gap = 15% +role_based_wipe_speed = 1 +wipe_speed = 80% +wipe_on_loops = 1 slice_closing_radius = 0.049 -slicing_mode = regular -small_perimeter_speed = 25% -solid_infill_below_area = 0 -solid_infill_every_layers = 0 -solid_infill_extruder = 1 -solid_infill_extrusion_width = 0.45 -solid_infill_speed = 80% -spiral_vase = 0 -standby_temperature_delta = -5 -support_material = 0 -support_material_angle = 0 -support_material_auto = 1 -support_material_bottom_contact_distance = 0 -support_material_bottom_interface_layers = -1 -support_material_buildplate_only = 0 -support_material_closing_radius = 2 -support_material_contact_distance = 0.15 -support_material_enforce_layers = 0 -support_material_extruder = 0 -support_material_extrusion_width = 0.38 -support_material_interface_contact_loops = 0 -support_material_interface_extruder = 0 -support_material_interface_layers = 2 -support_material_interface_pattern = rectilinear -support_material_interface_spacing = 0.2 -support_material_interface_speed = 100% -support_material_pattern = rectilinear -support_material_spacing = 2 -support_material_speed = 60 -support_material_style = grid -support_material_synchronize_layers = 0 -support_material_threshold = 45 -support_material_with_sheath = 0 -support_material_xy_spacing = 60% +resolution = 0.012 +arc_fitting = disabled +xy_contour_compensation = 0 +elefant_foot_compensation = 0.1 +precise_outer_wall = 1 +ironing_spacing = 0.15 +wall_transition_angle = 10 +wall_transition_filter_deviation = 25% +wall_transition_length = 100% +wall_distribution_count = 1 +min_bead_width = 85% +min_feature_size = 25% +bridge_density = 100% thick_bridges = 1 -thin_walls = 0 -threads = 8 -top_fill_pattern = monotonic -top_infill_extrusion_width = 0.4 -top_solid_infill_speed = 60% -top_solid_layers = 4 -top_solid_min_thickness = 0 -travel_speed = 150 -travel_speed_z = 0 -wipe_tower = 0 -wipe_tower_bridging = 10 -wipe_tower_brim_width = 2 +top_solid_infill_flow_ratio = 1 +bottom_solid_infill_flow_ratio = 1 +only_one_wall_top = 0 +only_one_wall_first_layer = 0 +max_travel_detour_distance = 0 wipe_tower_no_sparse_layers = 0 -wipe_tower_rotation_angle = 0 -wipe_tower_width = 60 -wipe_tower_x = 170 -wipe_tower_y = 140 -xy_size_compensation = 0 -compatible_printers_condition = nozzle_diameter[0]==0.4 - -[print:0.10mm HIGHDETAIL @SnapmakerA350] -inherits = *common* -layer_height = 0.1 -bottom_solid_layers = 7 -top_solid_layers = 8 +draft_shield = disabled +independent_support_layer_height = 1 +interface_shells = 0 +max_bridge_length = 10 +print_flow_ratio = 1 +top_surface_pattern = monotonicline +bottom_surface_pattern = monotonic +filter_out_gap_fill = 0 +infill_wall_overlap = 15% +infill_direction = 45 +bridge_angle = 0 +minimum_sparse_infill_area = 15 +infill_combination = 0 +detect_narrow_internal_solid_infill = 1 +ensure_vertical_shell_thickness = 1 +internal_bridge_support_thickness = 0.8 +initial_layer_infill_speed = 50 +initial_layer_travel_speed = 80% +ironing_speed = 50 +overhang_speed_classic = 0 +bridge_speed = 50 +travel_speed = 120 +default_acceleration = 2000 +bridge_acceleration = 1000 +travel_acceleration = 2000 +default_jerk = 0 +infill_jerk = 4 +initial_layer_jerk = 4 +inner_wall_jerk = 4 +outer_wall_jerk = 2 +top_surface_jerk = 2 +travel_jerk = 4 +support_type = normal(auto) +support_critical_regions_only = 1 +raft_layers = 0 +raft_contact_distance = 0.1 +raft_expansion = 2 +raft_first_layer_density = 90% +tree_support_wall_count = 2 +tree_support_adaptive_layer_height = 1 +tree_support_auto_brim = 1 +tree_support_brim_width = 3 +tree_support_with_infill = 0 +support_angle = 0 +support_bottom_interface_spacing = 0.12 +support_interface_loop_pattern = 0 +support_expansion = 1 +support_object_xy_distance = 0.9 +skirt_distance = 2 +skirt_height = 1 +brim_type = no_brim +brim_width = 5 +prime_volume = 7.3 +wipe_tower_cone_angle = 40 +flush_into_infill = 0 +flush_into_support = 1 +flush_into_objects = 0 +slicing_mode = regular +print_sequence = by layer +fuzzy_skin = none +fuzzy_skin_thickness = 0.3 +reduce_infill_retraction = 1 +gcode_comments = 0 +gcode_add_line_number = 0 +gcode_label_objects = 0 +post_process = +enforce_support_layers = 0 +exclude_object = 1 +standby_temperature_delta = -45 +timelapse_type = 0 +single_extruder_multi_material_priming = 0 +gap_fill_enabled = 0 +first_layer_height = 0.3 +perimeters = 3 +top_solid_layers = 4 top_solid_min_thickness = 0.8 -bottom_solid_min_thickness = 0.8 -bridge_speed = 40 -infill_speed = 50 -perimeter_speed = 40 -support_material_speed = 40 -max_print_speed = 50 -skirt_distance = 10 -first_layer_speed = 25% -compatible_printers_condition = nozzle_diameter[0]==0.4 and printer_model=="A350" - -[print:0.16mm OPTIMAL @SnapmakerA350] -inherits = *common* -layer_height = 0.16 -top_solid_layers = 6 -bottom_solid_layers = 6 -first_layer_speed = 25% -max_print_speed = 60 -compatible_printers_condition = nozzle_diameter[0]==0.4 and printer_model=="A350" - -[print:0.20mm NORMAL @SnapmakerA350] -inherits = *common* -compatible_printers_condition = nozzle_diameter[0]==0.4 and printer_model=="A350" - -[print:0.20mm FAST @SnapmakerA350] -inherits = 0.20mm NORMAL @SnapmakerA350 -bridge_speed = 80 -gap_fill_speed = 30 -infill_speed = 120 -ironing_speed = 20 +bottom_solid_layers = 3 +bottom_solid_min_thickness = 0 +avoid_crossing_perimeters = 1 +overhangs = 1 +perimeter_generator = arachne +fill_density = 15% +fill_pattern = grid +extrusion_width = 0.42 +first_layer_extrusion_width = 0.5 +perimeter_extrusion_width = 0.42 +external_perimeter_extrusion_width = 0.45 +top_infill_extrusion_width = 0.42 +infill_extrusion_width = 0.45 +solid_infill_extrusion_width = 0.42 +support_material_extrusion_width = 0.42 +xy_size_compensation = 0 +ironing_flowrate = 10% +bridge_flow_ratio = 0.95 +thin_walls = 0 +first_layer_speed = 50 +external_perimeter_speed = 70 perimeter_speed = 80 +infill_speed = 85 +solid_infill_speed = 100 +top_solid_infill_speed = 100 +gap_fill_speed = 100 support_material_speed = 80 -compatible_printers_condition = nozzle_diameter[0]==0.4 and printer_model=="A350" +support_material_interface_speed = 50 +enable_dynamic_overhang_speeds = 1 +overhang_speed_0 = 35 +overhang_speed_1 = 25 +overhang_speed_2 = 15 +overhang_speed_3 = 10 +external_perimeter_acceleration = 1000 +perimeter_acceleration = 2000 +infill_acceleration = 2000 +solid_infill_acceleration = 2000 +first_layer_acceleration = 500 +top_solid_infill_acceleration = 1000 +support_material = 0 +support_material_style = snug +support_material_buildplate_only = 1 +support_material_extruder = 0 +support_material_interface_extruder = 0 +support_material_contact_distance = 0 +support_material_bottom_contact_distance = 0.12 +support_material_pattern = rectilinear +support_material_spacing = 2.5 +support_material_threshold = 30 +support_material_interface_layers = 2 +support_material_bottom_interface_layers = 3 +support_material_interface_pattern = auto +support_material_interface_spacing = 0.12 +support_tree_branch_distance = 5 +support_tree_branch_diameter = 5 +support_tree_branch_diameter_angle = 30 +dont_support_bridges = 1 +skirts = 0 +brim_separation = 0.1 +wipe_tower = 1 +wipe_tower_width = 25 +wipe_tower_brim_width = 5 +spiral_vase = 0 +fuzzy_skin_point_dist = 0.8 +output_filename_format = {input_filename_base}_{layer_height}mm_{print_time}.gcode -[print:0.08mm DETAIL @SnapmakerA250] -inherits = 0.20mm NORMAL @SnapmakerA250 +[print:*fdm_process_idex*] +inherits = *fdm_process_common* +arc_fitting = emit_center +initial_layer_infill_speed = 75 +ironing_speed = 30 +travel_speed = 350 +default_acceleration = 10000 +bridge_acceleration = 2000 +travel_acceleration = 12000 +infill_jerk = 9 +initial_layer_jerk = 9 +inner_wall_jerk = 9 +outer_wall_jerk = 9 +top_surface_jerk = 9 +travel_jerk = 10 +raft_expansion = 2 +brim_type = no_brim +small_perimeter_threshold = 0 +support_material_synchronize_layers = 1 +first_layer_height = 0.2 +perimeters = 3 +top_solid_layers = 4 +top_solid_min_thickness = 0.8 +bottom_solid_layers = 3 +bottom_solid_min_thickness = 0 +avoid_crossing_perimeters = 1 +overhangs = 1 +perimeter_generator = arachne +fill_density = 15% +fill_pattern = grid +extrusion_width = 0.42 +first_layer_extrusion_width = 0.5 +perimeter_extrusion_width = 0.42 +external_perimeter_extrusion_width = 0.45 +top_infill_extrusion_width = 0.42 +infill_extrusion_width = 0.45 +solid_infill_extrusion_width = 0.42 +support_material_extrusion_width = 0.42 +xy_size_compensation = 0 +ironing_flowrate = 10% +bridge_flow_ratio = 0.95 +thin_walls = 0 +first_layer_speed = 50 +external_perimeter_speed = 100 +perimeter_speed = 250 +infill_speed = 150 +solid_infill_speed = 180 +top_solid_infill_speed = 100 +gap_fill_speed = 150 +support_material_speed = 100 +support_material_interface_speed = 50 +enable_dynamic_overhang_speeds = 1 +overhang_speed_0 = 35 +overhang_speed_1 = 25 +overhang_speed_2 = 15 +overhang_speed_3 = 10 +external_perimeter_acceleration = 5000 +perimeter_acceleration = 10000 +infill_acceleration = 10000 +solid_infill_acceleration = 10000 +first_layer_acceleration = 500 +top_solid_infill_acceleration = 2000 +support_material = 0 +support_material_style = snug +support_material_buildplate_only = 1 +support_material_extruder = 1 +support_material_interface_extruder = 2 +support_material_contact_distance = 0 +support_material_bottom_contact_distance = 0 +support_material_pattern = rectilinear +support_material_spacing = 2.5 +support_material_threshold = 30 +support_material_interface_layers = 3 +support_material_bottom_interface_layers = 3 +support_material_interface_pattern = rectilinear +support_material_interface_spacing = 0.12 +support_tree_branch_distance = 5 +support_tree_branch_diameter = 5 +support_tree_branch_diameter_angle = 30 +dont_support_bridges = 1 +skirts = 0 +brim_separation = 0.1 +wipe_tower = 1 +wipe_tower_width = 25 +wipe_tower_brim_width = 5 +spiral_vase = 0 +fuzzy_skin_point_dist = 0.8 +output_filename_format = {input_filename_base}_{layer_height}mm_{print_time}_J1.gcode + +[print:0.06 Standard @Snapmaker (0.2 nozzle)] +inherits = *fdm_process_common* +compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350 QSKit" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A250 Dual") and (nozzle_diameter[0]=="0.2") +layer_height = 0.06 +ironing_speed = 30 +travel_speed = 110 +first_layer_height = 0.1 +perimeters = 4 +top_solid_layers = 7 +bottom_solid_layers = 5 +extrusion_width = 0.22 +first_layer_extrusion_width = 0.25 +perimeter_extrusion_width = 0.22 +external_perimeter_extrusion_width = 0.22 +top_infill_extrusion_width = 0.22 +infill_extrusion_width = 0.22 +solid_infill_extrusion_width = 0.22 +support_material_extrusion_width = 0.22 +bridge_flow_ratio = 1 +first_layer_speed = 40 +external_perimeter_speed = 100 +perimeter_speed = 120 +solid_infill_speed = 120 +gap_fill_speed = 85 +support_material_speed = 100 +support_material_interface_speed = 40 +overhang_speed_0 = 60 +overhang_speed_1 = 30 +overhang_speed_2 = 10 +overhang_speed_3 = 10 + +[print:0.06 Standard @Snapmaker J1 (0.2 nozzle)] +inherits = *fdm_process_idex* +compatible_printers_condition = (printer_model=="Snapmaker J1") and (nozzle_diameter[0]=="0.2") +layer_height = 0.06 +initial_layer_infill_speed = 70 +first_layer_height = 0.1 +perimeters = 4 +top_solid_layers = 7 +bottom_solid_layers = 5 +extrusion_width = 0.22 +first_layer_extrusion_width = 0.25 +perimeter_extrusion_width = 0.22 +external_perimeter_extrusion_width = 0.22 +top_infill_extrusion_width = 0.22 +infill_extrusion_width = 0.22 +solid_infill_extrusion_width = 0.22 +support_material_extrusion_width = 0.22 +bridge_flow_ratio = 1 +first_layer_speed = 40 +perimeter_speed = 200 +infill_speed = 100 +solid_infill_speed = 200 +top_solid_infill_speed = 150 +gap_fill_speed = 120 +support_material_interface_speed = 40 +overhang_speed_0 = 60 +overhang_speed_1 = 30 +overhang_speed_2 = 10 + +[print:0.08 Extra Fine @Snapmaker (0.4 nozzle)] +inherits = *fdm_process_common* +compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350 QSKit" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A250 Dual") and (nozzle_diameter[0]=="0.4") +elefant_foot_compensation = 0.15 layer_height = 0.08 -infill_speed = 40 -external_perimeter_speed = 10 -perimeter_speed = 15 -top_solid_infill_speed = 20 -travel_speed = 70 -first_layer_extrusion_width = 0.45 -perimeter_extrusion_width = 0.4 -external_perimeter_extrusion_width = 0.4 -infill_extrusion_width = 0.4 -solid_infill_extrusion_width = 0.4 -top_infill_extrusion_width = 0.4 +initial_layer_infill_speed = 65 +ironing_speed = 30 +travel_speed = 110 +first_layer_height = 0.1 +top_solid_layers = 9 +bottom_solid_layers = 7 +ironing_flowrate = 8% +bridge_flow_ratio = 1 +first_layer_speed = 50 +external_perimeter_speed = 70 +perimeter_speed = 120 +infill_speed = 90 +solid_infill_speed = 120 +top_solid_infill_speed = 70 +gap_fill_speed = 85 +support_material_speed = 100 +support_material_interface_speed = 50 +overhang_speed_0 = 55 +overhang_speed_1 = 30 +overhang_speed_2 = 10 +overhang_speed_3 = 10 +support_material_threshold = 15 -[print:0.20mm NORMAL @SnapmakerA250] -inherits = *common* -compatible_printers_condition = nozzle_diameter[0]==0.4 and printer_model=="A250" -first_layer_speed = 15 -gap_fill_speed = 15 -infill_speed = 50 -perimeter_speed = 25 -small_perimeter_speed = 20 -external_perimeter_speed = 15 -support_material_speed = 25 -top_solid_infill_speed = 25 -travel_speed = 80 -max_print_speed = 80 -skirt_distance = 3 -min_skirt_length = 25 +[print:0.08 Extra Fine @Snapmaker J1 (0.4 nozzle)] +inherits = *fdm_process_idex* +compatible_printers_condition = (printer_model=="Snapmaker J1") and (nozzle_diameter[0]=="0.4") +elefant_foot_compensation = 0.15 +layer_height = 0.08 +initial_layer_infill_speed = 65 +first_layer_height = 0.1 +top_solid_layers = 9 +bottom_solid_layers = 7 +ironing_flowrate = 8% +bridge_flow_ratio = 1 +perimeter_speed = 230 +infill_speed = 120 +solid_infill_speed = 230 +gap_fill_speed = 160 +overhang_speed_0 = 60 +overhang_speed_1 = 30 +overhang_speed_2 = 10 +support_material_threshold = 15 -[print:0.24mm FAST @SnapmakerA250] -inherits = 0.20mm NORMAL @SnapmakerA250 +[print:0.10 Standard @Snapmaker (0.2 nozzle)] +inherits = *fdm_process_common* +compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350 QSKit" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A250 Dual") and (nozzle_diameter[0]=="0.2") +layer_height = 0.1 +initial_layer_infill_speed = 70 +ironing_speed = 30 +travel_speed = 110 +first_layer_height = 0.1 +perimeters = 4 +top_solid_layers = 7 +bottom_solid_layers = 5 +extrusion_width = 0.22 +first_layer_extrusion_width = 0.25 +perimeter_extrusion_width = 0.22 +external_perimeter_extrusion_width = 0.22 +top_infill_extrusion_width = 0.22 +infill_extrusion_width = 0.22 +solid_infill_extrusion_width = 0.22 +support_material_extrusion_width = 0.22 +bridge_flow_ratio = 1 +first_layer_speed = 40 +external_perimeter_speed = 100 +perimeter_speed = 120 +infill_speed = 100 +solid_infill_speed = 120 +top_solid_infill_speed = 100 +gap_fill_speed = 85 +support_material_speed = 100 +support_material_interface_speed = 40 +overhang_speed_0 = 60 +overhang_speed_1 = 30 +overhang_speed_2 = 10 +overhang_speed_3 = 10 + +[print:0.10 Standard @Snapmaker J1 (0.2 nozzle)] +inherits = *fdm_process_idex* +compatible_printers_condition = (printer_model=="Snapmaker J1") and (nozzle_diameter[0]=="0.2") +layer_height = 0.1 +initial_layer_infill_speed = 70 +first_layer_height = 0.1 +perimeters = 4 +top_solid_layers = 7 +bottom_solid_layers = 5 +extrusion_width = 0.22 +first_layer_extrusion_width = 0.25 +perimeter_extrusion_width = 0.22 +external_perimeter_extrusion_width = 0.22 +top_infill_extrusion_width = 0.22 +infill_extrusion_width = 0.22 +solid_infill_extrusion_width = 0.22 +support_material_extrusion_width = 0.22 +bridge_flow_ratio = 1 +first_layer_speed = 40 +perimeter_speed = 200 +infill_speed = 100 +solid_infill_speed = 200 +top_solid_infill_speed = 150 +gap_fill_speed = 120 +support_material_interface_speed = 40 +overhang_speed_0 = 60 +overhang_speed_1 = 30 +overhang_speed_2 = 10 + +[print:0.12 Fine @Snapmaker (0.4 nozzle)] +inherits = *fdm_process_common* +compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350 QSKit" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A250 Dual") and (nozzle_diameter[0]=="0.4") +layer_height = 0.12 +elefant_foot_compensation = 0.15 +initial_layer_infill_speed = 65 +ironing_speed = 30 +first_layer_height = 0.2 +top_solid_layers = 5 +top_solid_min_thickness = 0.6 +bottom_solid_layers = 5 +bridge_flow_ratio = 1 +first_layer_speed = 50 +external_perimeter_speed = 75 +perimeter_speed = 120 +infill_speed = 90 +solid_infill_speed = 120 +top_solid_infill_speed = 70 +gap_fill_speed = 85 +support_material_speed = 100 +support_material_interface_speed = 50 +overhang_speed_0 = 55 +overhang_speed_1 = 30 +overhang_speed_2 = 10 +overhang_speed_3 = 10 +support_material_threshold = 20 + +[print:0.12 Fine @Snapmaker J1 (0.4 nozzle)] +inherits = *fdm_process_idex* +compatible_printers_condition = (printer_model=="Snapmaker J1") and (nozzle_diameter[0]=="0.4") +layer_height = 0.12 +elefant_foot_compensation = 0.15 +initial_layer_infill_speed = 60 +top_solid_layers = 5 +top_solid_min_thickness = 0.6 +bottom_solid_layers = 5 +bridge_flow_ratio = 1 +perimeter_speed = 230 +infill_speed = 120 +solid_infill_speed = 230 +top_solid_infill_speed = 120 +gap_fill_speed = 160 +overhang_speed_0 = 60 +overhang_speed_1 = 30 +overhang_speed_2 = 10 +support_material_threshold = 20 + +[print:0.14 Standard @Snapmaker (0.2 nozzle)] +inherits = *fdm_process_common* +compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350 QSKit" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A250 Dual") and (nozzle_diameter[0]=="0.2") +layer_height = 0.14 +initial_layer_infill_speed = 70 +ironing_speed = 30 +first_layer_height = 0.2 +perimeters = 4 +top_solid_layers = 7 +bottom_solid_layers = 5 +extrusion_width = 0.22 +first_layer_extrusion_width = 0.25 +perimeter_extrusion_width = 0.22 +external_perimeter_extrusion_width = 0.22 +top_infill_extrusion_width = 0.22 +infill_extrusion_width = 0.22 +solid_infill_extrusion_width = 0.22 +support_material_extrusion_width = 0.22 +bridge_flow_ratio = 1 +first_layer_speed = 40 +external_perimeter_speed = 100 +perimeter_speed = 120 +infill_speed = 100 +solid_infill_speed = 120 +top_solid_infill_speed = 100 +gap_fill_speed = 85 +support_material_speed = 100 +support_material_interface_speed = 40 +overhang_speed_0 = 60 +overhang_speed_1 = 30 +overhang_speed_2 = 10 +overhang_speed_3 = 10 + +[print:0.14 Standard @Snapmaker J1 (0.2 nozzle)] +inherits = *fdm_process_idex* +compatible_printers_condition = (printer_model=="Snapmaker J1") and (nozzle_diameter[0]=="0.2") +layer_height = 0.14 +initial_layer_infill_speed = 70 +perimeters = 4 +top_solid_layers = 7 +bottom_solid_layers = 5 +extrusion_width = 0.22 +first_layer_extrusion_width = 0.25 +perimeter_extrusion_width = 0.22 +external_perimeter_extrusion_width = 0.22 +top_infill_extrusion_width = 0.22 +infill_extrusion_width = 0.22 +solid_infill_extrusion_width = 0.22 +support_material_extrusion_width = 0.22 +bridge_flow_ratio = 1 +first_layer_speed = 40 +perimeter_speed = 200 +infill_speed = 100 +solid_infill_speed = 200 +top_solid_infill_speed = 150 +gap_fill_speed = 120 +support_material_interface_speed = 40 +overhang_speed_0 = 60 +overhang_speed_1 = 30 +overhang_speed_2 = 10 + +[print:0.16 Optimal @Snapmaker (0.4 nozzle)] +inherits = *fdm_process_common* +compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350 QSKit" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A250 Dual") and (nozzle_diameter[0]=="0.4") +layer_height = 0.16 +elefant_foot_compensation = 0.15 +initial_layer_infill_speed = 65 +infill_wall_overlap = 20% +ironing_speed = 30 +first_layer_height = 0.2 +top_solid_layers = 4 +top_solid_min_thickness = 0.6 +bottom_solid_layers = 4 +bridge_flow_ratio = 1 +first_layer_speed = 50 +external_perimeter_speed = 80 +perimeter_speed = 100 +infill_speed = 95 +top_solid_infill_speed = 70 +gap_fill_speed = 85 +support_material_speed = 100 +overhang_speed_0 = 55 +overhang_speed_1 = 30 +overhang_speed_2 = 10 +overhang_speed_3 = 10 +support_material_threshold = 25 + +[print:0.16 Optimal @Snapmaker J1 (0.4 nozzle)] +inherits = *fdm_process_idex* +compatible_printers_condition = (printer_model=="Snapmaker J1") and (nozzle_diameter[0]=="0.4") +layer_height = 0.16 +elefant_foot_compensation = 0.15 +initial_layer_infill_speed = 60 +top_solid_min_thickness = 0.6 +bottom_solid_layers = 4 +bridge_flow_ratio = 1 +external_perimeter_speed = 80 +perimeter_speed = 200 +infill_speed = 140 +solid_infill_speed = 200 +top_solid_infill_speed = 80 +gap_fill_speed = 160 +overhang_speed_0 = 60 +overhang_speed_1 = 30 +overhang_speed_2 = 10 +support_material_threshold = 25 + +[print:0.18 Standard @Snapmaker (0.6 nozzle)] +inherits = *fdm_process_common* +compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350 QSKit" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A250 Dual") and (nozzle_diameter[0]=="0.6") +layer_height = 0.18 +initial_layer_infill_speed = 55 +ironing_speed = 30 +first_layer_height = 0.2 +perimeters = 2 +top_solid_layers = 3 +extrusion_width = 0.62 +first_layer_extrusion_width = 0.62 +perimeter_extrusion_width = 0.62 +external_perimeter_extrusion_width = 0.62 +top_infill_extrusion_width = 0.62 +infill_extrusion_width = 0.62 +solid_infill_extrusion_width = 0.62 +support_material_extrusion_width = 0.62 +bridge_flow_ratio = 1 +first_layer_speed = 35 +external_perimeter_speed = 90 +perimeter_speed = 90 +infill_speed = 100 +solid_infill_speed = 100 +top_solid_infill_speed = 100 +gap_fill_speed = 50 +support_material_speed = 100 +support_material_interface_speed = 35 +overhang_speed_0 = 0 +overhang_speed_1 = 50 +overhang_speed_2 = 15 +overhang_speed_3 = 10 + +[print:0.18 Standard @Snapmaker J1 (0.6 nozzle)] +inherits = *fdm_process_idex* +compatible_printers_condition = (printer_model=="Snapmaker J1") and (nozzle_diameter[0]=="0.6") +layer_height = 0.18 +initial_layer_infill_speed = 55 +perimeters = 2 +extrusion_width = 0.62 +first_layer_extrusion_width = 0.62 +perimeter_extrusion_width = 0.62 +external_perimeter_extrusion_width = 0.62 +top_infill_extrusion_width = 0.62 +infill_extrusion_width = 0.62 +solid_infill_extrusion_width = 0.62 +support_material_extrusion_width = 0.62 +bridge_flow_ratio = 1 +first_layer_speed = 35 +external_perimeter_speed = 120 +perimeter_speed = 150 +infill_speed = 100 +solid_infill_speed = 150 +top_solid_infill_speed = 150 +gap_fill_speed = 50 +support_material_interface_speed = 35 +overhang_speed_0 = 0 +overhang_speed_1 = 50 + +[print:0.20 Standard @Snapmaker (0.4 nozzle)] +inherits = *fdm_process_common* +compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350 QSKit" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A250 Dual") and (nozzle_diameter[0]=="0.4") +elefant_foot_compensation = 0.15 +initial_layer_infill_speed = 60 +ironing_speed = 30 +top_solid_layers = 4 +top_solid_min_thickness = 0.8 +first_layer_speed = 50 +external_perimeter_speed = 70 +perimeter_speed = 90 +infill_speed = 95 +solid_infill_speed = 100 +top_solid_infill_speed = 70 +gap_fill_speed = 85 +support_material_speed = 100 +enable_dynamic_overhang_speeds = 1 +overhang_speed_0 = 40 +overhang_speed_1 = 20 +overhang_speed_2 = 10 +overhang_speed_3 = 10 + +[print:0.20 Standard @Snapmaker J1 (0.4 nozzle)] +inherits = *fdm_process_idex* +compatible_printers_condition = (printer_model=="Snapmaker J1") and (nozzle_diameter[0]=="0.4") +elefant_foot_compensation = 0.15 +external_perimeter_speed = 140 +perimeter_speed = 240 +infill_speed = 300 +solid_infill_speed = 240 +top_solid_infill_speed = 140 +gap_fill_speed = 240 +overhang_speed_0 = 60 +overhang_speed_1 = 30 +overhang_speed_2 = 10 + +[print:0.20 Strength @Snapmaker (0.4 nozzle)] +inherits = *fdm_process_common* +compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350 QSKit" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A250 Dual") and (nozzle_diameter[0]=="0.4") +elefant_foot_compensation = 0.15 +initial_layer_infill_speed = 65 +infill_wall_overlap = 25% +ironing_speed = 30 +perimeters = 6 +top_solid_layers = 4 +top_solid_min_thickness = 0.8 +fill_density = 25% +first_layer_speed = 50 +external_perimeter_speed = 90 +perimeter_speed = 100 +infill_speed = 95 +solid_infill_speed = 100 +top_solid_infill_speed = 70 +gap_fill_speed = 85 +support_material_speed = 100 +support_material_interface_speed = 50 +overhang_speed_0 = 55 +overhang_speed_1 = 30 +overhang_speed_2 = 10 +overhang_speed_3 = 10 + +[print:0.20 Strength @Snapmaker J1 (0.4 nozzle)] +inherits = *fdm_process_idex* +compatible_printers_condition = (printer_model=="Snapmaker J1") and (nozzle_diameter[0]=="0.4") +elefant_foot_compensation = 0.15 +initial_layer_infill_speed = 65 +perimeters = 6 +fill_density = 25% +external_perimeter_speed = 120 +perimeter_speed = 200 +infill_speed = 160 +solid_infill_speed = 200 +top_solid_infill_speed = 120 +gap_fill_speed = 160 +overhang_speed_0 = 60 +overhang_speed_1 = 30 +overhang_speed_2 = 10 + +[print:0.24 Draft @Snapmaker (0.4 nozzle)] +inherits = *fdm_process_common* +compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350 QSKit" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A250 Dual") and (nozzle_diameter[0]=="0.4") layer_height = 0.24 -infill_speed = 60 -external_perimeter_speed = 20 -top_solid_infill_speed = 30 +elefant_foot_compensation = 0.15 +initial_layer_infill_speed = 65 +ironing_speed = 30 +top_solid_layers = 3 +top_solid_min_thickness = 0.6 +top_infill_extrusion_width = 0.45 +first_layer_speed = 50 +external_perimeter_speed = 90 +perimeter_speed = 100 +infill_speed = 100 +solid_infill_speed = 100 +top_solid_infill_speed = 70 +gap_fill_speed = 85 +support_material_speed = 100 +support_material_interface_speed = 50 +overhang_speed_0 = 55 +overhang_speed_1 = 30 +overhang_speed_2 = 10 +overhang_speed_3 = 10 +support_material_threshold = 35 -[filament:*common*] -bed_temperature = 60 -bridge_fan_speed = 100 -compatible_printers = -compatible_printers_condition = -compatible_prints = -compatible_prints_condition = -cooling = 1 -disable_fan_first_layers = 3 -end_filament_gcode = "; Filament-specific end gcode \n;END gcode for filament\n" -extrusion_multiplier = 1 -fan_always_on = 1 -fan_below_layer_time = 60 -filament_colour = #29B2B2 -filament_cooling_final_speed = 3.4 -filament_cooling_initial_speed = 2.2 -filament_cooling_moves = 4 +[print:0.24 Draft @Snapmaker J1 (0.4 nozzle)] +inherits = *fdm_process_idex* +compatible_printers_condition = (printer_model=="Snapmaker J1") and (nozzle_diameter[0]=="0.4") +layer_height = 0.24 +elefant_foot_compensation = 0.15 +initial_layer_infill_speed = 65 +top_solid_layers = 3 +top_solid_min_thickness = 0.6 +top_infill_extrusion_width = 0.45 +perimeter_speed = 190 +infill_speed = 160 +solid_infill_speed = 190 +top_solid_infill_speed = 160 +gap_fill_speed = 160 +overhang_speed_0 = 60 +overhang_speed_1 = 30 +overhang_speed_2 = 10 +support_material_threshold = 35 + +[print:0.25 Benchy @Snapmaker J1 (0.4 nozzle)] +inherits = *fdm_process_idex* +compatible_printers_condition = (printer_model=="Snapmaker J1") and (nozzle_diameter[0]=="0.4") +elefant_foot_compensation = 0.15 +initial_layer_infill_speed = 60 +ensure_vertical_shell_thickness = 0 +seam_position = nearest +only_one_wall_top = 1 +only_one_wall_first_layer = 1 +resolution = 0.05 +minimum_sparse_infill_area = 0 +infill_combination = 1 +bridge_acceleration = 3000 +bridge_speed = 180 +default_acceleration = 15000 +small_perimeter_speed = 200 +travel_acceleration = 28000 +first_layer_height = 0.25 +perimeters = 2 +top_solid_min_thickness = 0.5 +avoid_crossing_perimeters = 0 +overhangs = 0 +perimeter_generator = classic +fill_density = 10% +extrusion_width = 0.5 +perimeter_extrusion_width = 0.5 +external_perimeter_extrusion_width = 0.5 +top_infill_extrusion_width = 0.5 +infill_extrusion_width = 0.5 +solid_infill_extrusion_width = 0.5 +support_material_extrusion_width = 0.5 +external_perimeter_speed = 180 +perimeter_speed = 280 +infill_speed = 200 +solid_infill_speed = 280 +top_solid_infill_speed = 200 +gap_fill_speed = 280 +enable_dynamic_overhang_speeds = 0 +overhang_speed_0 = 150 +overhang_speed_1 = 20 +overhang_speed_2 = 10 +external_perimeter_acceleration = 3000 +perimeter_acceleration = 15000 +infill_acceleration = 15000 +solid_infill_acceleration = 20000 +top_solid_infill_acceleration = 8000 +output_filename_format = J1Benchy_{print_time}.gcode + +[print:0.24 Standard @Snapmaker (0.6 nozzle)] +inherits = *fdm_process_common* +compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350 QSKit" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A250 Dual") and (nozzle_diameter[0]=="0.6") +layer_height = 0.24 +initial_layer_infill_speed = 55 +ironing_speed = 30 +perimeters = 2 +top_solid_layers = 3 +extrusion_width = 0.62 +first_layer_extrusion_width = 0.62 +perimeter_extrusion_width = 0.62 +external_perimeter_extrusion_width = 0.62 +top_infill_extrusion_width = 0.62 +infill_extrusion_width = 0.62 +solid_infill_extrusion_width = 0.62 +support_material_extrusion_width = 0.62 +first_layer_speed = 35 +external_perimeter_speed = 90 +perimeter_speed = 85 +infill_speed = 100 +solid_infill_speed = 100 +top_solid_infill_speed = 100 +gap_fill_speed = 50 +support_material_speed = 100 +support_material_interface_speed = 35 +overhang_speed_0 = 0 +overhang_speed_1 = 50 +overhang_speed_2 = 15 +overhang_speed_3 = 10 + +[print:0.24 Standard @Snapmaker J1 (0.6 nozzle)] +inherits = *fdm_process_idex* +compatible_printers_condition = (printer_model=="Snapmaker J1") and (nozzle_diameter[0]=="0.6") +layer_height = 0.24 +initial_layer_infill_speed = 55 +perimeters = 2 +top_solid_layers = 3 +extrusion_width = 0.62 +first_layer_extrusion_width = 0.62 +perimeter_extrusion_width = 0.62 +external_perimeter_extrusion_width = 0.62 +top_infill_extrusion_width = 0.62 +infill_extrusion_width = 0.62 +solid_infill_extrusion_width = 0.62 +support_material_extrusion_width = 0.62 +first_layer_speed = 35 +external_perimeter_speed = 120 +perimeter_speed = 150 +infill_speed = 100 +solid_infill_speed = 150 +top_solid_infill_speed = 150 +gap_fill_speed = 50 +support_material_interface_speed = 35 +overhang_speed_0 = 0 +overhang_speed_1 = 50 + +[print:0.24 Standard @Snapmaker (0.8 nozzle)] +inherits = *fdm_process_common* +compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350 QSKit" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A250 Dual") and (nozzle_diameter[0]=="0.8") +layer_height = 0.24 +top_surface_pattern = monotonic +initial_layer_infill_speed = 55 +ironing_speed = 30 +first_layer_height = 0.3 +perimeters = 2 +top_solid_layers = 3 +extrusion_width = 0.82 +first_layer_extrusion_width = 0.82 +perimeter_extrusion_width = 0.82 +external_perimeter_extrusion_width = 0.82 +top_infill_extrusion_width = 0.82 +infill_extrusion_width = 0.82 +solid_infill_extrusion_width = 0.82 +support_material_extrusion_width = 0.82 +first_layer_speed = 35 +external_perimeter_speed = 90 +perimeter_speed = 85 +infill_speed = 100 +solid_infill_speed = 100 +top_solid_infill_speed = 100 +gap_fill_speed = 50 +support_material_speed = 100 +support_material_interface_speed = 35 +overhang_speed_0 = 0 +overhang_speed_1 = 50 +overhang_speed_2 = 25 +overhang_speed_3 = 5 + +[print:0.24 Standard @Snapmaker J1 (0.8 nozzle)] +inherits = *fdm_process_idex* +compatible_printers_condition = (printer_model=="Snapmaker J1") and (nozzle_diameter[0]=="0.8") +layer_height = 0.24 +top_surface_pattern = monotonic +initial_layer_infill_speed = 55 +first_layer_height = 0.3 +perimeters = 2 +top_solid_layers = 3 +extrusion_width = 0.82 +first_layer_extrusion_width = 0.82 +perimeter_extrusion_width = 0.82 +external_perimeter_extrusion_width = 0.82 +top_infill_extrusion_width = 0.82 +infill_extrusion_width = 0.82 +solid_infill_extrusion_width = 0.82 +support_material_extrusion_width = 0.82 +first_layer_speed = 35 +external_perimeter_speed = 120 +perimeter_speed = 150 +infill_speed = 100 +solid_infill_speed = 150 +top_solid_infill_speed = 150 +gap_fill_speed = 50 +support_material_interface_speed = 35 +overhang_speed_0 = 0 +overhang_speed_1 = 50 +overhang_speed_2 = 25 +overhang_speed_3 = 5 + +[print:0.28 Extra Draft @Snapmaker (0.4 nozzle)] +inherits = *fdm_process_common* +compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350 QSKit" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A250 Dual") and (nozzle_diameter[0]=="0.4") +layer_height = 0.28 +elefant_foot_compensation = 0.15 +initial_layer_infill_speed = 65 +ironing_speed = 30 +top_solid_layers = 3 +top_solid_min_thickness = 0.6 +top_infill_extrusion_width = 0.45 +first_layer_speed = 50 +external_perimeter_speed = 85 +perimeter_speed = 95 +infill_speed = 95 +solid_infill_speed = 95 +top_solid_infill_speed = 70 +gap_fill_speed = 85 +support_material_speed = 100 +support_material_interface_speed = 50 +overhang_speed_0 = 55 +overhang_speed_1 = 30 +overhang_speed_2 = 10 +overhang_speed_3 = 10 +support_material_threshold = 40 + +[print:0.28 Extra Draft @Snapmaker J1 (0.4 nozzle)] +inherits = *fdm_process_idex* +compatible_printers_condition = (printer_model=="Snapmaker J1") and (nozzle_diameter[0]=="0.4") +layer_height = 0.28 +elefant_foot_compensation = 0.15 +initial_layer_infill_speed = 65 +top_solid_layers = 3 +top_solid_min_thickness = 0.6 +top_infill_extrusion_width = 0.45 +perimeter_speed = 180 +infill_speed = 160 +top_solid_infill_speed = 150 +gap_fill_speed = 160 +overhang_speed_0 = 60 +overhang_speed_1 = 30 +overhang_speed_2 = 10 +support_material_threshold = 40 + +[print:0.30 Standard @Snapmaker (0.6 nozzle)] +inherits = *fdm_process_common* +compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350 QSKit" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A250 Dual") and (nozzle_diameter[0]=="0.6") +layer_height = 0.3 +bridge_speed = 30 +initial_layer_infill_speed = 55 +ironing_speed = 30 +top_solid_layers = 3 +extrusion_width = 0.62 +first_layer_extrusion_width = 0.62 +perimeter_extrusion_width = 0.62 +external_perimeter_extrusion_width = 0.62 +top_infill_extrusion_width = 0.62 +infill_extrusion_width = 0.62 +solid_infill_extrusion_width = 0.62 +support_material_extrusion_width = 0.62 +first_layer_speed = 35 +external_perimeter_speed = 75 +perimeter_speed = 85 +infill_speed = 100 +solid_infill_speed = 85 +top_solid_infill_speed = 100 +gap_fill_speed = 50 +support_material_speed = 100 +support_material_interface_speed = 35 +overhang_speed_0 = 0 +overhang_speed_1 = 50 +overhang_speed_2 = 15 +overhang_speed_3 = 10 + +[print:0.30 Standard @Snapmaker J1 (0.6 nozzle)] +inherits = *fdm_process_idex* +compatible_printers_condition = (printer_model=="Snapmaker J1") and (nozzle_diameter[0]=="0.6") +layer_height = 0.3 +bridge_speed = 30 +initial_layer_infill_speed = 55 +top_solid_layers = 3 +extrusion_width = 0.62 +first_layer_extrusion_width = 0.62 +perimeter_extrusion_width = 0.62 +external_perimeter_extrusion_width = 0.62 +top_infill_extrusion_width = 0.62 +infill_extrusion_width = 0.62 +solid_infill_extrusion_width = 0.62 +support_material_extrusion_width = 0.62 +first_layer_speed = 35 +external_perimeter_speed = 120 +perimeter_speed = 150 +infill_speed = 100 +solid_infill_speed = 150 +top_solid_infill_speed = 150 +gap_fill_speed = 50 +support_material_interface_speed = 35 +overhang_speed_0 = 0 +overhang_speed_1 = 50 + +[print:0.30 Strength @Snapmaker (0.6 nozzle)] +inherits = *fdm_process_common* +compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350 QSKit" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A250 Dual") and (nozzle_diameter[0]=="0.6") +layer_height = 0.3 +bridge_speed = 30 +initial_layer_infill_speed = 55 +ironing_speed = 30 +perimeters = 6 +top_solid_layers = 3 +fill_density = 25% +extrusion_width = 0.62 +first_layer_extrusion_width = 0.62 +perimeter_extrusion_width = 0.62 +external_perimeter_extrusion_width = 0.62 +top_infill_extrusion_width = 0.62 +infill_extrusion_width = 0.62 +solid_infill_extrusion_width = 0.62 +support_material_extrusion_width = 0.62 +first_layer_speed = 35 +external_perimeter_speed = 75 +perimeter_speed = 85 +infill_speed = 100 +solid_infill_speed = 85 +top_solid_infill_speed = 100 +gap_fill_speed = 50 +support_material_speed = 100 +support_material_interface_speed = 35 +overhang_speed_0 = 0 +overhang_speed_1 = 50 +overhang_speed_2 = 15 +overhang_speed_3 = 10 + +[print:0.30 Strength @Snapmaker J1 (0.6 nozzle)] +inherits = *fdm_process_idex* +compatible_printers_condition = (printer_model=="Snapmaker J1") and (nozzle_diameter[0]=="0.6") +layer_height = 0.3 +bridge_speed = 30 +initial_layer_infill_speed = 55 +perimeters = 6 +top_solid_layers = 3 +fill_density = 25% +extrusion_width = 0.62 +first_layer_extrusion_width = 0.62 +perimeter_extrusion_width = 0.62 +external_perimeter_extrusion_width = 0.62 +top_infill_extrusion_width = 0.62 +infill_extrusion_width = 0.62 +solid_infill_extrusion_width = 0.62 +support_material_extrusion_width = 0.62 +first_layer_speed = 35 +external_perimeter_speed = 120 +perimeter_speed = 150 +infill_speed = 100 +solid_infill_speed = 150 +top_solid_infill_speed = 150 +gap_fill_speed = 50 +support_material_interface_speed = 35 +overhang_speed_0 = 0 +overhang_speed_1 = 50 + +[print:0.32 Standard @Snapmaker (0.8 nozzle)] +inherits = *fdm_process_common* +compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350 QSKit" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A250 Dual") and (nozzle_diameter[0]=="0.8") +layer_height = 0.32 +bridge_speed = 30 +top_surface_pattern = monotonic +initial_layer_infill_speed = 55 +ironing_speed = 30 +perimeters = 2 +top_solid_layers = 3 +extrusion_width = 0.82 +first_layer_extrusion_width = 0.82 +perimeter_extrusion_width = 0.82 +external_perimeter_extrusion_width = 0.82 +top_infill_extrusion_width = 0.82 +infill_extrusion_width = 0.82 +solid_infill_extrusion_width = 0.82 +support_material_extrusion_width = 0.82 +first_layer_speed = 35 +external_perimeter_speed = 75 +perimeter_speed = 85 +infill_speed = 100 +solid_infill_speed = 85 +top_solid_infill_speed = 100 +gap_fill_speed = 50 +support_material_speed = 100 +support_material_interface_speed = 35 +overhang_speed_0 = 0 +overhang_speed_1 = 50 +overhang_speed_2 = 25 +overhang_speed_3 = 5 + +[print:0.32 Standard @Snapmaker J1 (0.8 nozzle)] +inherits = *fdm_process_idex* +compatible_printers_condition = (printer_model=="Snapmaker J1") and (nozzle_diameter[0]=="0.8") +layer_height = 0.32 +bridge_speed = 30 +top_surface_pattern = monotonic +initial_layer_infill_speed = 55 +perimeters = 2 +top_solid_layers = 3 +extrusion_width = 0.82 +first_layer_extrusion_width = 0.82 +perimeter_extrusion_width = 0.82 +external_perimeter_extrusion_width = 0.82 +top_infill_extrusion_width = 0.82 +infill_extrusion_width = 0.82 +solid_infill_extrusion_width = 0.82 +support_material_extrusion_width = 0.82 +first_layer_speed = 35 +external_perimeter_speed = 120 +perimeter_speed = 150 +infill_speed = 100 +solid_infill_speed = 150 +top_solid_infill_speed = 150 +gap_fill_speed = 50 +support_material_interface_speed = 35 +overhang_speed_0 = 0 +overhang_speed_1 = 50 +overhang_speed_2 = 25 +overhang_speed_3 = 5 + +[print:0.34 Standard @Snapmaker (0.6 nozzle)] +inherits = *fdm_process_common* +compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350 QSKit" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A250 Dual") and (nozzle_diameter[0]=="0.6") +layer_height = 0.34 +bridge_speed = 30 +top_surface_pattern = monotonic +initial_layer_infill_speed = 55 +ironing_speed = 30 +travel_speed = 110 +perimeters = 2 +top_solid_layers = 3 +extrusion_width = 0.82 +first_layer_extrusion_width = 0.82 +perimeter_extrusion_width = 0.82 +external_perimeter_extrusion_width = 0.82 +top_infill_extrusion_width = 0.82 +infill_extrusion_width = 0.82 +solid_infill_extrusion_width = 0.82 +support_material_extrusion_width = 0.82 +first_layer_speed = 35 +external_perimeter_speed = 75 +perimeter_speed = 85 +infill_speed = 100 +solid_infill_speed = 85 +top_solid_infill_speed = 100 +gap_fill_speed = 50 +support_material_speed = 100 +support_material_interface_speed = 35 +overhang_speed_0 = 0 +overhang_speed_1 = 50 +overhang_speed_2 = 15 +overhang_speed_3 = 10 + +[print:0.34 Standard @Snapmaker J1 (0.6 nozzle)] +inherits = *fdm_process_idex* +compatible_printers_condition = (printer_model=="Snapmaker J1") and (nozzle_diameter[0]=="0.6") +layer_height = 0.34 +bridge_speed = 30 +top_surface_pattern = monotonic +initial_layer_infill_speed = 55 +perimeters = 2 +top_solid_layers = 3 +extrusion_width = 0.82 +first_layer_extrusion_width = 0.82 +perimeter_extrusion_width = 0.82 +external_perimeter_extrusion_width = 0.82 +top_infill_extrusion_width = 0.82 +infill_extrusion_width = 0.82 +solid_infill_extrusion_width = 0.82 +support_material_extrusion_width = 0.82 +first_layer_speed = 35 +external_perimeter_speed = 120 +perimeter_speed = 150 +infill_speed = 100 +solid_infill_speed = 150 +top_solid_infill_speed = 150 +gap_fill_speed = 50 +support_material_interface_speed = 35 +overhang_speed_0 = 0 +overhang_speed_1 = 50 + +[print:0.36 Standard @Snapmaker (0.8 nozzle)] +inherits = *fdm_process_common* +compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350 QSKit" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A250 Dual") and (nozzle_diameter[0]=="0.8") +layer_height = 0.36 +bridge_speed = 30 +top_surface_pattern = monotonic +initial_layer_infill_speed = 55 +ironing_speed = 30 +perimeters = 2 +top_solid_layers = 3 +extrusion_width = 0.82 +first_layer_extrusion_width = 0.82 +perimeter_extrusion_width = 0.82 +external_perimeter_extrusion_width = 0.82 +top_infill_extrusion_width = 0.82 +infill_extrusion_width = 0.82 +solid_infill_extrusion_width = 0.82 +support_material_extrusion_width = 0.82 +first_layer_speed = 35 +external_perimeter_speed = 75 +perimeter_speed = 85 +infill_speed = 100 +solid_infill_speed = 85 +top_solid_infill_speed = 100 +gap_fill_speed = 50 +support_material_speed = 100 +support_material_interface_speed = 35 +overhang_speed_0 = 0 +overhang_speed_1 = 50 +overhang_speed_2 = 25 +overhang_speed_3 = 5 + +[print:0.36 Standard @Snapmaker J1 (0.8 nozzle)] +inherits = *fdm_process_idex* +compatible_printers_condition = (printer_model=="Snapmaker J1") and (nozzle_diameter[0]=="0.8") +layer_height = 0.36 +bridge_speed = 30 +top_surface_pattern = monotonic +initial_layer_infill_speed = 55 +perimeters = 2 +top_solid_layers = 3 +extrusion_width = 0.82 +first_layer_extrusion_width = 0.82 +perimeter_extrusion_width = 0.82 +external_perimeter_extrusion_width = 0.82 +top_infill_extrusion_width = 0.82 +infill_extrusion_width = 0.82 +solid_infill_extrusion_width = 0.82 +support_material_extrusion_width = 0.82 +first_layer_speed = 35 +external_perimeter_speed = 120 +perimeter_speed = 150 +infill_speed = 100 +solid_infill_speed = 150 +top_solid_infill_speed = 150 +gap_fill_speed = 50 +support_material_interface_speed = 35 +overhang_speed_0 = 0 +overhang_speed_1 = 50 +overhang_speed_2 = 25 +overhang_speed_3 = 5 + +[print:0.38 Standard @Snapmaker (0.6 nozzle)] +inherits = *fdm_process_common* +compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350 QSKit" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A250 Dual") and (nozzle_diameter[0]=="0.6") +layer_height = 0.38 +bridge_speed = 30 +top_surface_pattern = monotonic +initial_layer_infill_speed = 55 +ironing_speed = 30 +perimeters = 2 +top_solid_layers = 3 +extrusion_width = 0.82 +first_layer_extrusion_width = 0.82 +perimeter_extrusion_width = 0.82 +external_perimeter_extrusion_width = 0.82 +top_infill_extrusion_width = 0.82 +infill_extrusion_width = 0.82 +solid_infill_extrusion_width = 0.82 +support_material_extrusion_width = 0.82 +first_layer_speed = 35 +external_perimeter_speed = 75 +perimeter_speed = 85 +infill_speed = 100 +solid_infill_speed = 85 +top_solid_infill_speed = 100 +gap_fill_speed = 50 +support_material_speed = 100 +support_material_interface_speed = 35 +overhang_speed_0 = 0 +overhang_speed_1 = 50 +overhang_speed_2 = 15 +overhang_speed_3 = 10 + +[print:0.38 Standard @Snapmaker J1 (0.6 nozzle)] +inherits = *fdm_process_idex* +compatible_printers_condition = (printer_model=="Snapmaker J1") and (nozzle_diameter[0]=="0.6") +layer_height = 0.38 +bridge_speed = 30 +top_surface_pattern = monotonic +initial_layer_infill_speed = 55 +perimeters = 2 +top_solid_layers = 3 +extrusion_width = 0.82 +first_layer_extrusion_width = 0.82 +perimeter_extrusion_width = 0.82 +external_perimeter_extrusion_width = 0.82 +top_infill_extrusion_width = 0.82 +infill_extrusion_width = 0.82 +solid_infill_extrusion_width = 0.82 +support_material_extrusion_width = 0.82 +first_layer_speed = 35 +external_perimeter_speed = 120 +perimeter_speed = 150 +infill_speed = 100 +solid_infill_speed = 150 +top_solid_infill_speed = 150 +gap_fill_speed = 50 +support_material_interface_speed = 35 +overhang_speed_0 = 0 +overhang_speed_1 = 50 + +[print:0.40 Standard @Snapmaker (0.8 nozzle)] +inherits = *fdm_process_common* +compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350 QSKit" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A250 Dual") and (nozzle_diameter[0]=="0.8") +layer_height = 0.4 +bridge_speed = 30 +top_surface_pattern = monotonic +initial_layer_infill_speed = 55 +ironing_speed = 30 +top_solid_layers = 3 +extrusion_width = 0.82 +first_layer_extrusion_width = 0.82 +perimeter_extrusion_width = 0.82 +external_perimeter_extrusion_width = 0.82 +top_infill_extrusion_width = 0.82 +infill_extrusion_width = 0.82 +solid_infill_extrusion_width = 0.82 +support_material_extrusion_width = 0.82 +first_layer_speed = 35 +external_perimeter_speed = 75 +perimeter_speed = 85 +infill_speed = 100 +solid_infill_speed = 85 +top_solid_infill_speed = 100 +gap_fill_speed = 50 +support_material_speed = 100 +support_material_interface_speed = 35 +overhang_speed_0 = 0 +overhang_speed_1 = 50 +overhang_speed_2 = 25 +overhang_speed_3 = 5 + +[print:0.40 Standard @Snapmaker J1 (0.8 nozzle)] +inherits = *fdm_process_idex* +compatible_printers_condition = (printer_model=="Snapmaker J1") and (nozzle_diameter[0]=="0.8") +layer_height = 0.4 +bridge_speed = 30 +top_surface_pattern = monotonic +initial_layer_infill_speed = 55 +top_solid_layers = 3 +extrusion_width = 0.82 +first_layer_extrusion_width = 0.82 +perimeter_extrusion_width = 0.82 +external_perimeter_extrusion_width = 0.82 +top_infill_extrusion_width = 0.82 +infill_extrusion_width = 0.82 +solid_infill_extrusion_width = 0.82 +support_material_extrusion_width = 0.82 +first_layer_speed = 35 +external_perimeter_speed = 120 +perimeter_speed = 150 +infill_speed = 100 +solid_infill_speed = 150 +top_solid_infill_speed = 150 +gap_fill_speed = 50 +support_material_interface_speed = 35 +overhang_speed_0 = 0 +overhang_speed_1 = 50 +overhang_speed_2 = 25 +overhang_speed_3 = 5 + +[print:0.42 Draft @Snapmaker (0.6 nozzle)] +inherits = *fdm_process_common* +compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350 QSKit" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A250 Dual") and (nozzle_diameter[0]=="0.6") +layer_height = 0.42 +bridge_speed = 30 +initial_layer_infill_speed = 55 +ironing_speed = 30 +perimeters = 2 +top_solid_layers = 3 +extrusion_width = 0.62 +first_layer_extrusion_width = 0.62 +perimeter_extrusion_width = 0.62 +external_perimeter_extrusion_width = 0.62 +top_infill_extrusion_width = 0.62 +infill_extrusion_width = 0.62 +solid_infill_extrusion_width = 0.62 +support_material_extrusion_width = 0.62 +first_layer_speed = 35 +external_perimeter_speed = 75 +perimeter_speed = 85 +infill_speed = 100 +solid_infill_speed = 85 +top_solid_infill_speed = 100 +gap_fill_speed = 50 +support_material_speed = 100 +support_material_interface_speed = 35 +overhang_speed_0 = 0 +overhang_speed_1 = 50 +overhang_speed_2 = 15 +overhang_speed_3 = 10 + +[print:0.42 Draft @Snapmaker J1 (0.6 nozzle)] +inherits = *fdm_process_idex* +compatible_printers_condition = (printer_model=="Snapmaker J1") and (nozzle_diameter[0]=="0.6") +layer_height = 0.42 +bridge_speed = 30 +initial_layer_infill_speed = 55 +perimeters = 2 +top_solid_layers = 3 +extrusion_width = 0.62 +first_layer_extrusion_width = 0.62 +perimeter_extrusion_width = 0.62 +external_perimeter_extrusion_width = 0.62 +top_infill_extrusion_width = 0.62 +infill_extrusion_width = 0.62 +solid_infill_extrusion_width = 0.62 +support_material_extrusion_width = 0.62 +first_layer_speed = 35 +external_perimeter_speed = 120 +perimeter_speed = 150 +infill_speed = 100 +solid_infill_speed = 150 +top_solid_infill_speed = 150 +gap_fill_speed = 50 +support_material_interface_speed = 35 +overhang_speed_0 = 0 +overhang_speed_1 = 50 + +[print:0.48 Draft @Snapmaker (0.8 nozzle)] +inherits = *fdm_process_common* +compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350 QSKit" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A250 Dual") and (nozzle_diameter[0]=="0.8") +layer_height = 0.48 +bridge_speed = 30 +top_surface_pattern = monotonic +initial_layer_infill_speed = 55 +ironing_speed = 30 +first_layer_height = 0.4 +perimeters = 2 +top_solid_layers = 3 +extrusion_width = 0.82 +first_layer_extrusion_width = 0.82 +perimeter_extrusion_width = 0.82 +external_perimeter_extrusion_width = 0.82 +top_infill_extrusion_width = 0.82 +infill_extrusion_width = 0.82 +solid_infill_extrusion_width = 0.82 +support_material_extrusion_width = 0.82 +first_layer_speed = 35 +external_perimeter_speed = 75 +perimeter_speed = 85 +infill_speed = 100 +solid_infill_speed = 85 +top_solid_infill_speed = 100 +gap_fill_speed = 50 +support_material_speed = 100 +support_material_interface_speed = 35 +overhang_speed_0 = 0 +overhang_speed_1 = 50 +overhang_speed_2 = 25 +overhang_speed_3 = 5 + +[print:0.48 Draft @Snapmaker J1 (0.8 nozzle)] +inherits = *fdm_process_idex* +compatible_printers_condition = (printer_model=="Snapmaker J1") and (nozzle_diameter[0]=="0.8") +layer_height = 0.48 +bridge_speed = 30 +top_surface_pattern = monotonic +initial_layer_infill_speed = 55 +first_layer_height = 0.4 +perimeters = 2 +top_solid_layers = 3 +extrusion_width = 0.82 +first_layer_extrusion_width = 0.82 +perimeter_extrusion_width = 0.82 +external_perimeter_extrusion_width = 0.82 +top_infill_extrusion_width = 0.82 +infill_extrusion_width = 0.82 +solid_infill_extrusion_width = 0.82 +support_material_extrusion_width = 0.82 +first_layer_speed = 35 +external_perimeter_speed = 120 +perimeter_speed = 150 +infill_speed = 100 +solid_infill_speed = 150 +top_solid_infill_speed = 150 +gap_fill_speed = 50 +support_material_interface_speed = 35 +overhang_speed_0 = 0 +overhang_speed_1 = 50 +overhang_speed_2 = 25 +overhang_speed_3 = 5 + +[filament:*fdm_filament_common*] +filament_vendor = Snapmaker +filament_soluble = 0 +filament_settings_id = +bed_type = Hot Plate +overhang_fan_threshold = 95% filament_cost = 0 filament_density = 0 -filament_deretract_speed = nil filament_diameter = 1.75 -filament_load_time = 0 -filament_loading_speed = 28 -filament_loading_speed_start = 3 filament_max_volumetric_speed = 0 -filament_minimal_purge_on_wipe_tower = 15 -filament_notes = "" -filament_ramming_parameters = "120 100 6.6 6.8 7.2 7.6 7.9 8.2 8.7 9.4 9.9 10.0| 0.05 6.6 0.45 6.8 0.95 7.8 1.45 8.3 1.95 9.7 2.45 10 2.95 7.6 3.45 7.6 3.95 7.6 4.45 7.6 4.95 7.6" -filament_retract_before_travel = nil +filament_minimal_purge_on_wipe_tower = 3 filament_retract_before_wipe = nil -filament_retract_layer_change = nil -filament_retract_length = nil -filament_retract_lift = nil -filament_retract_lift_above = nil -filament_retract_lift_below = nil filament_retract_restart_extra = nil -filament_retract_speed = nil -filament_settings_id = "" -filament_soluble = 0 -filament_spool_weight = 0 -filament_toolchange_delay = 0 -filament_type = PLA -filament_unload_time = 0 -filament_unloading_speed = 90 -filament_unloading_speed_start = 100 filament_wipe = nil -first_layer_bed_temperature = 60 -first_layer_temperature = 210 +filament_wipe_distance = nil +filament_loading_speed_start = 3 +filament_loading_speed = 25 +filament_unloading_speed_start = 3 +filament_unloading_speed = 25 +filament_load_time = 0 +filament_unload_time = 0 +filament_toolchange_delay = 0 +filament_cooling_moves = 4 +filament_cooling_initial_speed = 2.2 +filament_cooling_final_speed = 3.4 +filament_multitool_ramming = 0 +filament_multitool_ramming_volume = 0 full_fan_speed_layer = 0 -inherits = -max_fan_speed = 100 +enable_pressure_advance = 0 +bed_temperature = 60 +first_layer_bed_temperature = 60 +temperature = 200 +first_layer_temperature = 200 +idle_temperature = 140 +filament_retract_length = nil +filament_retract_speed = nil +filament_deretract_speed = nil +filament_retract_lift = nil +filament_retract_before_travel = nil +start_filament_gcode = "M900 K0.04 ;override pressure advance value" +end_filament_gcode = +filament_retract_layer_change = nil +fan_always_on = 0 +cooling = 1 min_fan_speed = 35 -min_print_speed = 10 -slowdown_below_layer_time = 5 -start_filament_gcode = "; Filament gcode\n" -temperature = 210 - -[filament:*PLA*] -inherits = *common* - -[filament:*PETG*] -inherits = *common* -first_layer_bed_temperature = 80 -bed_temperature = 75 -first_layer_temperature = 245 -temperature = 245 -filament_density = 1.27 -disable_fan_first_layers = 3 -min_fan_speed = 20 -max_fan_speed = 50 -fan_below_layer_time = 20 -min_print_speed = 20 -filament_max_volumetric_speed = 8 -filament_type = PETG - -[filament:Generic PLA @Snapmaker] -inherits = *PLA* -filament_vendor = Generic - -[filament:Generic PETG @Snapmaker] -inherits = *PETG* -filament_vendor = Generic - -[filament:Snapmaker PLA @Snapmaker] -inherits = *PLA* -filament_vendor = Snapmaker - -[filament:Overture PLA @Snapmaker] -inherits = *PLA* -filament_vendor = Overture -bed_temperature = 50 -first_layer_temperature = 205 -temperature = 205 -filament_density = 1.24 -disable_fan_first_layers = 1 -min_fan_speed = 100 -max_fan_speed = 100 -full_fan_speed_layer = 3 -fan_below_layer_time = 100 -min_print_speed = 15 -filament_max_volumetric_speed = 0 - -[filament:MatterHackers Build Translucent @Snapmaker] -inherits = *PETG* -filament_vendor = MatterHackers - -[filament:MatterHackers Build White @Snapmaker] -inherits = MatterHackers Build Translucent @Snapmaker -bed_temperature = 65 -first_layer_bed_temperature = 70 -first_layer_temperature = 260 -temperature = 255 -filament_density = 1.28 -disable_fan_first_layers = 3 -full_fan_speed_layer = 5 -min_fan_speed = 40 max_fan_speed = 100 +bridge_fan_speed = 100 +disable_fan_first_layers = 2 +slowdown_below_layer_time = 8 fan_below_layer_time = 60 min_print_speed = 10 +extrusion_multiplier = 1 -[filament:Overture TPU @Snapmaker] -inherits = *common* -filament_vendor = Overture -filament_type = FLEX +[filament:*fdm_filament_abs*] +inherits = *fdm_filament_common* +overhang_fan_threshold = 25% +filament_cost = 50 +filament_density = 1.04 +filament_max_volumetric_speed = 16 +enable_pressure_advance = 1 +filament_type = ABS +filament_notes = "eSUN ABS+\nSunlu ABS+\n" +bed_temperature = 90 +first_layer_bed_temperature = 90 +temperature = 260 +first_layer_temperature = 260 +idle_temperature = 189 +filament_retract_length = 0.6 +filament_retract_speed = nil +filament_deretract_speed = nil +filament_retract_lift = 0.7 +filament_retract_before_travel = nil +start_filament_gcode = "M900 K0.015 ;override pressure advance value" +end_filament_gcode = +filament_retract_layer_change = nil +fan_always_on = 1 +cooling = 1 +min_fan_speed = 15 +max_fan_speed = 80 +bridge_fan_speed = 80 +disable_fan_first_layers = 3 +slowdown_below_layer_time = 3 +fan_below_layer_time = 30 +min_print_speed = 20 +extrusion_multiplier = 0.93 +filament_colour = #682D35 + +[filament:*fdm_filament_asa*] +inherits = *fdm_filament_common* +overhang_fan_threshold = 25% +filament_cost = 80 +filament_density = 1.04 +filament_max_volumetric_speed = 7.6 +enable_pressure_advance = 1 +filament_type = ASA +bed_temperature = 90 +first_layer_bed_temperature = 90 +temperature = 255 +first_layer_temperature = 255 +idle_temperature = 182 +filament_retract_length = 0.6 +filament_retract_speed = nil +filament_deretract_speed = nil +filament_retract_lift = 0.7 +filament_retract_before_travel = nil +start_filament_gcode = "M900 K0.04 ;override pressure advance value" +end_filament_gcode = +filament_retract_layer_change = nil +fan_always_on = 1 +cooling = 1 +min_fan_speed = 10 +max_fan_speed = 35 +bridge_fan_speed = 80 +disable_fan_first_layers = 4 +slowdown_below_layer_time = 5 +fan_below_layer_time = 20 +min_print_speed = 20 +extrusion_multiplier = 0.94 +filament_colour = #F35887 + +[filament:*fdm_filament_pa*] +inherits = *fdm_filament_common* +overhang_fan_threshold = 0% +filament_cost = 150 +filament_density = 1.09 +filament_max_volumetric_speed = 8 +full_fan_speed_layer = 3 +filament_type = PA-CF +filament_notes = "!! It needs to be dried before use.\n" +bed_temperature = 90 +first_layer_bed_temperature = 85 +temperature = 250 +first_layer_temperature = 255 +idle_temperature = 203 +filament_retract_length = 2 +filament_retract_speed = 36 +filament_deretract_speed = nil +filament_retract_lift = nil +filament_retract_before_travel = 0 +start_filament_gcode = "M900 K0.04 ;override pressure advance value" +end_filament_gcode = +filament_retract_layer_change = nil +fan_always_on = 1 +cooling = 1 +min_fan_speed = 30 +max_fan_speed = 65 +bridge_fan_speed = 60 +disable_fan_first_layers = 3 +slowdown_below_layer_time = 20 +fan_below_layer_time = 20 +min_print_speed = 15 +extrusion_multiplier = 1 +filament_colour = #3D3C39 + +[filament:*fdm_filament_petg*] +inherits = *fdm_filament_common* +overhang_fan_threshold = 25% +filament_cost = 30 +filament_density = 1.27 +filament_max_volumetric_speed = 10 +enable_pressure_advance = 1 +filament_type = PETG +bed_temperature = 70 +first_layer_bed_temperature = 70 +temperature = 245 +first_layer_temperature = 255 +idle_temperature = 160 +filament_retract_length = 1.8 +filament_retract_speed = nil +filament_deretract_speed = nil +filament_retract_lift = nil +filament_retract_before_travel = 0 +start_filament_gcode = "M900 K0.04 ;override pressure advance value" +end_filament_gcode = +filament_retract_layer_change = nil +fan_always_on = 1 +cooling = 1 +min_fan_speed = 40 +max_fan_speed = 90 +bridge_fan_speed = 90 +disable_fan_first_layers = 2 +slowdown_below_layer_time = 8 +fan_below_layer_time = 30 +min_print_speed = 20 +extrusion_multiplier = 0.95 +filament_colour = #DF6734 + +[filament:*fdm_filament_pet*] +inherits = *fdm_filament_common* +overhang_fan_threshold = 25% +filament_cost = 8 +filament_density = 1.29 +filament_max_volumetric_speed = 6 +enable_pressure_advance = 1 +filament_type = PET +filament_notes = "JiaNong PET 1.63x1.75mm" +bed_temperature = 65 +first_layer_bed_temperature = 60 +temperature = 278 +first_layer_temperature = 275 +idle_temperature = 230 +filament_retract_length = nil +filament_retract_speed = nil +filament_deretract_speed = nil +filament_retract_lift = nil +filament_retract_before_travel = nil +start_filament_gcode = "M900 K0.022 ;override pressure advance value" +end_filament_gcode = +filament_retract_layer_change = nil +fan_always_on = 1 +cooling = 1 +min_fan_speed = 0 +max_fan_speed = 40 +bridge_fan_speed = 60 +disable_fan_first_layers = 2 +slowdown_below_layer_time = 2 +fan_below_layer_time = 7 +min_print_speed = 50 +extrusion_multiplier = 1 +filament_colour = #FFFFFF + +[filament:*fdm_filament_pla*] +inherits = *fdm_filament_common* +overhang_fan_threshold = 0% +filament_cost = 60 +filament_density = 1.24 +filament_max_volumetric_speed = 14 +enable_pressure_advance = 1 +filament_type = PLA +additional_cooling_fan_speed = 70 +bed_temperature = 60 +first_layer_bed_temperature = 60 +temperature = 210 first_layer_temperature = 220 -temperature = 220 -filament_density = 1.22 -disable_fan_first_layers = 1 +idle_temperature = 154 +filament_retract_length = 1.2 +filament_retract_speed = nil +filament_deretract_speed = nil +filament_retract_lift = nil +filament_retract_before_travel = nil +start_filament_gcode = "M900 K0.04 ;override pressure advance value" +end_filament_gcode = +filament_retract_layer_change = nil +fan_always_on = 1 +cooling = 1 min_fan_speed = 100 max_fan_speed = 100 +bridge_fan_speed = 100 +disable_fan_first_layers = 1 +slowdown_below_layer_time = 8 fan_below_layer_time = 100 min_print_speed = 15 -filament_retract_speed = 40 -filament_deretract_speed = 25 -filament_retract_length = 1.8 -filament_max_volumetric_speed = 3 +extrusion_multiplier = 0.98 +filament_colour = #F8C827 -# Common printer preset -[printer:*common*] -bed_shape = 0x0,320x0,320x350,0x350 -color_change_gcode = M600 -cooling_tube_length = 5 -cooling_tube_retraction = 91.5 -default_filament_profile = "" -default_print_profile = -end_gcode = ;End GCode begin\nM104 S0 ;extruder heater off\nM140 S0 ;heated bed heater off\nG90 ;absolute positioning\nG92 E0\nG1 E-2 F300 ;retract the filament a bit before lifting the nozzle, to release some of the pressure\nG28 X0 Y0 ; home\nM84 ;steppers off\nM107 ;fan off\nM82 ;absolute extrusion mode\n;End GCode end +[filament:*fdm_filament_pla_eco*] +inherits = *fdm_filament_pla* +temperature = 200 +first_layer_temperature = 205 +filament_colour = #D5DDDC + +[filament:*fdm_filament_pva*] +inherits = *fdm_filament_common* +overhang_fan_threshold = 50% +filament_cost = 120 +filament_density = 1.37 +filament_max_volumetric_speed = 2.4 +filament_type = PVA +additional_cooling_fan_speed = 50 +bed_temperature = 50 +first_layer_bed_temperature = 50 +temperature = 215 +first_layer_temperature = 215 +idle_temperature = 150 +filament_retract_length = 2 +filament_retract_speed = 28 +filament_deretract_speed = 15 +filament_retract_lift = nil +filament_retract_before_travel = nil +start_filament_gcode = "M900 K0.04 ;override pressure advance value" +end_filament_gcode = +filament_retract_layer_change = nil +fan_always_on = 1 +cooling = 1 +min_fan_speed = 35 +max_fan_speed = 100 +bridge_fan_speed = 100 +disable_fan_first_layers = 2 +slowdown_below_layer_time = 7 +fan_below_layer_time = 100 +min_print_speed = 20 +extrusion_multiplier = 1 +filament_colour = #D9DFE3 + +[filament:*fdm_filament_tpu*] +inherits = *fdm_filament_common* +filament_cost = 80 +filament_density = 1.24 +filament_max_volumetric_speed = 2.8 +filament_type = TPU +additional_cooling_fan_speed = 70 +filament_notes = "!! It needs to be dried before use.\nSunlu TPU 95A\n" +bed_temperature = 40 +first_layer_bed_temperature = 40 +temperature = 240 +first_layer_temperature = 240 +idle_temperature = 138 +filament_retract_length = 0.6 +filament_retract_speed = 20 +filament_deretract_speed = 20 +filament_retract_lift = 0 +filament_retract_before_travel = nil +start_filament_gcode = "M900 K0.04 ;override pressure advance value" +end_filament_gcode = +filament_retract_layer_change = 0 +fan_always_on = 1 +cooling = 0 +min_fan_speed = 70 +max_fan_speed = 70 +bridge_fan_speed = 70 +disable_fan_first_layers = 1 +slowdown_below_layer_time = 8 +fan_below_layer_time = 100 +min_print_speed = 10 +extrusion_multiplier = 1 +filament_colour = #302730 + +[filament:*Snapmaker ABS @base*] +inherits = *fdm_filament_abs* + +[filament:Snapmaker ABS] +inherits = *Snapmaker ABS @base* +compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350 QSKit" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A250 Dual") and (nozzle_diameter[0]=="0.6" or nozzle_diameter[0]=="0.8" or nozzle_diameter[0]=="0.4") + +[filament:Snapmaker ABS @0.2 nozzle] +inherits = *Snapmaker ABS @base* +compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350 QSKit" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A250 Dual") and (nozzle_diameter[0]=="0.2") +filament_max_volumetric_speed = 2 + +[filament:*Snapmaker ASA @base*] +inherits = *fdm_filament_asa* + +[filament:Snapmaker ASA] +inherits = *Snapmaker ASA @base* +compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350 QSKit" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A250 Dual") and (nozzle_diameter[0]=="0.6" or nozzle_diameter[0]=="0.8" or nozzle_diameter[0]=="0.4") + +[filament:Snapmaker ASA @0.2 nozzle] +inherits = *Snapmaker ASA @base* +compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350 QSKit" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A250 Dual") and (nozzle_diameter[0]=="0.2") +filament_max_volumetric_speed = 2 + +[filament:*Snapmaker PA-CF @base*] +inherits = *fdm_filament_pa* + +[filament:Snapmaker PA-CF] +inherits = *Snapmaker PA-CF @base* +compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350 QSKit" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A250 Dual") and (nozzle_diameter[0]=="0.6" or nozzle_diameter[0]=="0.8" or nozzle_diameter[0]=="0.4") + +[filament:*Snapmaker PETG @base*] +inherits = *fdm_filament_petg* + +[filament:Snapmaker PETG] +inherits = *Snapmaker PETG @base* +compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350 QSKit" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A250 Dual") and (nozzle_diameter[0]=="0.6" or nozzle_diameter[0]=="0.8" or nozzle_diameter[0]=="0.4") + +[filament:Snapmaker PETG @0.2 nozzle] +inherits = *Snapmaker PETG @base* +compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350 QSKit" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A250 Dual") and (nozzle_diameter[0]=="0.2") +filament_max_volumetric_speed = 1 + +[filament:*Snapmaker PET @base*] +inherits = *fdm_filament_pet* + +[filament:Snapmaker PET] +inherits = *Snapmaker PET @base* +compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350 QSKit" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A250 Dual") and (nozzle_diameter[0]=="0.6" or nozzle_diameter[0]=="0.8" or nozzle_diameter[0]=="0.4") + +[filament:Snapmaker PET @Dual] +inherits = *Snapmaker PET @base* +compatible_printers_condition = (printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A250 Dual") and (nozzle_diameter[0]=="0.6" or nozzle_diameter[0]=="0.8" or nozzle_diameter[0]=="0.4") +min_fan_speed = 20 +max_fan_speed = 55 +bridge_fan_speed = 40 + +[filament:*Snapmaker PETG-CF @base*] +inherits = *fdm_filament_petg* +filament_cost = 40 +filament_density = 1.25 +enable_pressure_advance = 0 +filament_type = PETG-CF +idle_temperature = 178 +filament_retract_length = nil +filament_retract_before_travel = nil +fan_always_on = 0 +min_fan_speed = 0 +max_fan_speed = 30 +slowdown_below_layer_time = 6 +fan_below_layer_time = 20 +min_print_speed = 10 +filament_colour = #3D3C39 + +[filament:Snapmaker PETG-CF] +inherits = *Snapmaker PETG-CF @base* +compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350 QSKit" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A250 Dual") and (nozzle_diameter[0]=="0.6" or nozzle_diameter[0]=="0.8" or nozzle_diameter[0]=="0.4") + +[filament:*Snapmaker PLA Eco @base*] +inherits = *fdm_filament_pla_eco* + +[filament:Snapmaker PLA Eco] +inherits = *Snapmaker PLA Eco @base* +compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A250 Dual") and (nozzle_diameter[0]=="0.2" or nozzle_diameter[0]=="0.6" or nozzle_diameter[0]=="0.8" or nozzle_diameter[0]=="0.4") + +[filament:*Snapmaker PLA @base*] +inherits = *fdm_filament_pla* + +[filament:Snapmaker PLA] +inherits = *Snapmaker PLA @base* +compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350 QSKit" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A250 Dual") and (nozzle_diameter[0]=="0.2" or nozzle_diameter[0]=="0.6" or nozzle_diameter[0]=="0.8" or nozzle_diameter[0]=="0.4") + +[filament:*Snapmaker PLA-CF @base*] +inherits = *fdm_filament_pla* +filament_max_volumetric_speed = 12 +filament_type = PLA-CF +additional_cooling_fan_speed = 0 +idle_temperature = 150 +slowdown_below_layer_time = 7 +extrusion_multiplier = 0.95 +filament_colour = #3D3C39 + +[filament:Snapmaker PLA-CF] +inherits = *Snapmaker PLA-CF @base* +compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350 QSKit" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A250 Dual") and (nozzle_diameter[0]=="0.6" or nozzle_diameter[0]=="0.8" or nozzle_diameter[0]=="0.4") + +[filament:*Snapmaker PLA Silk @base*] +inherits = *fdm_filament_pla* +filament_cost = 70 +filament_max_volumetric_speed = 7.5 +first_layer_bed_temperature = 65 +filament_retract_length = 0.5 +filament_colour = #CF942B + +[filament:Snapmaker PLA Silk] +inherits = *Snapmaker PLA Silk @base* +compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350 QSKit" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A250 Dual") and (nozzle_diameter[0]=="0.6" or nozzle_diameter[0]=="0.8" or nozzle_diameter[0]=="0.4") + +[filament:Snapmaker PLA Silk @0.2 nozzle] +inherits = *Snapmaker PLA Silk @base* +compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350 QSKit" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A250 Dual") and (nozzle_diameter[0]=="0.2") +filament_max_volumetric_speed = 2 + +[filament:*PolyLite PLA @base*] +inherits = *fdm_filament_pla* +filament_cost = 90 +filament_max_volumetric_speed = 15 +extrusion_multiplier = 0.95 +filament_colour = #8269AC + +[filament:PolyLite PLA] +inherits = *PolyLite PLA @base* +compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350 QSKit" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A250 Dual") and (nozzle_diameter[0]=="0.6" or nozzle_diameter[0]=="0.8" or nozzle_diameter[0]=="0.4") + +[filament:PolyLite PLA @0.2 nozzle] +inherits = *PolyLite PLA @base* +compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350 QSKit" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A250 Dual") and (nozzle_diameter[0]=="0.2") +filament_max_volumetric_speed = 1 + +[filament:*PolyTerra PLA @base*] +inherits = *fdm_filament_pla* +filament_cost = 80 +filament_density = 1.31 +filament_max_volumetric_speed = 18 +filament_colour = #73CEC8 + +[filament:PolyTerra PLA] +inherits = *PolyTerra PLA @base* +compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350 QSKit" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A250 Dual") and (nozzle_diameter[0]=="0.6" or nozzle_diameter[0]=="0.8" or nozzle_diameter[0]=="0.4") + +[filament:PolyTerra PLA @0.2 nozzle] +inherits = *PolyTerra PLA @base* +compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350 QSKit" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A250 Dual") and (nozzle_diameter[0]=="0.2") +filament_max_volumetric_speed = 1 + +[filament:*Snapmaker PVA @base*] +inherits = *fdm_filament_pva* + +[filament:Snapmaker PVA] +inherits = *Snapmaker PVA @base* +compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350 QSKit" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A250 Dual") and (nozzle_diameter[0]=="0.6" or nozzle_diameter[0]=="0.8" or nozzle_diameter[0]=="0.4") + +[filament:Snapmaker PVA @0.2 nozzle] +inherits = *Snapmaker PVA @base* +compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350 QSKit" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A250 Dual") and (nozzle_diameter[0]=="0.2") +filament_max_volumetric_speed = 1.2 + +[filament:*Snapmaker TPU @base*] +inherits = *fdm_filament_tpu* + +[filament:Snapmaker TPU] +inherits = *Snapmaker TPU @base* +compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350 QSKit" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A250 Dual") and (nozzle_diameter[0]=="0.6" or nozzle_diameter[0]=="0.8" or nozzle_diameter[0]=="0.4") + +[filament:Snapmaker TPE] +inherits = *Snapmaker TPU @base* +compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350 QSKit" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A250 Dual") and (nozzle_diameter[0]=="0.6" or nozzle_diameter[0]=="0.8" or nozzle_diameter[0]=="0.4") +filament_density = 1.22 +filament_max_volumetric_speed = 7.2 +filament_notes = "eSUN eLastic TPE-83A\n" +bed_temperature = 45 +first_layer_bed_temperature = 45 +min_fan_speed = 100 +max_fan_speed = 100 +bridge_fan_speed = 100 +filament_colour = #383737 + +[filament:*Snapmaker J1 ABS @base*] +inherits = *fdm_filament_abs* +filament_max_volumetric_speed = 18 +max_fan_speed = 29 +bridge_fan_speed = 29 +extrusion_multiplier = 0.95 +start_filament_gcode = "M900 K0.02 ;override pressure advance value" + +[filament:Snapmaker J1 ABS] +inherits = *Snapmaker J1 ABS @base* +compatible_printers_condition = (printer_model=="Snapmaker J1") and (nozzle_diameter[0]=="0.6" or nozzle_diameter[0]=="0.4") + +[filament:Snapmaker J1 ABS @0.2 nozzle] +inherits = *Snapmaker J1 ABS @base* +compatible_printers_condition = (printer_model=="Snapmaker J1") and (nozzle_diameter[0]=="0.2") + +[filament:Snapmaker J1 ABS @0.8 nozzle] +inherits = *Snapmaker J1 ABS @base* +compatible_printers_condition = (printer_model=="Snapmaker J1") and (nozzle_diameter[0]=="0.8") +filament_max_volumetric_speed = 22 +min_print_speed = 10 + +[filament:*Snapmaker J1 ASA @base*] +inherits = *fdm_filament_asa* +min_fan_speed = 0 +max_fan_speed = 20 +bridge_fan_speed = 20 + +[filament:Snapmaker J1 ASA] +inherits = *Snapmaker J1 ASA @base* +compatible_printers_condition = (printer_model=="Snapmaker J1") and (nozzle_diameter[0]=="0.6" or nozzle_diameter[0]=="0.8" or nozzle_diameter[0]=="0.4") + +[filament:Snapmaker J1 ASA @0.2 nozzle] +inherits = *Snapmaker J1 ASA @base* +compatible_printers_condition = (printer_model=="Snapmaker J1") and (nozzle_diameter[0]=="0.2") + +[filament:*Snapmaker J1 PA-CF @base*] +inherits = *fdm_filament_pa* +min_fan_speed = 29 +max_fan_speed = 55 +bridge_fan_speed = 55 +extrusion_multiplier = 0.96 + +[filament:Snapmaker J1 PA-CF] +inherits = *Snapmaker J1 PA-CF @base* +compatible_printers_condition = (printer_model=="Snapmaker J1") and (nozzle_diameter[0]=="0.6" or nozzle_diameter[0]=="0.8" or nozzle_diameter[0]=="0.4") + +[filament:*Snapmaker J1 PETG @base*] +inherits = *fdm_filament_petg* +filament_density = 1.25 +filament_max_volumetric_speed = 14 +temperature = 255 +idle_temperature = 178 +filament_retract_speed = 35 +min_fan_speed = 10 +max_fan_speed = 40 + +[filament:Snapmaker J1 PETG] +inherits = *Snapmaker J1 PETG @base* +compatible_printers_condition = (printer_model=="Snapmaker J1") and (nozzle_diameter[0]=="0.6" or nozzle_diameter[0]=="0.4") + +[filament:Snapmaker J1 PETG @0.2 nozzle] +inherits = *Snapmaker J1 PETG @base* +compatible_printers_condition = (printer_model=="Snapmaker J1") and (nozzle_diameter[0]=="0.2") +filament_max_volumetric_speed = 1.2 + +[filament:Snapmaker J1 PETG @0.8 nozzle] +inherits = *Snapmaker J1 PETG @base* +compatible_printers_condition = (printer_model=="Snapmaker J1") and (nozzle_diameter[0]=="0.8") +filament_max_volumetric_speed = 16 +min_fan_speed = 20 +max_fan_speed = 60 + +[filament:*Snapmaker J1 PET @base*] +inherits = *fdm_filament_pet* +filament_max_volumetric_speed = 6.8 +min_fan_speed = 26 +max_fan_speed = 50 +bridge_fan_speed = 40 +min_print_speed = 35 + +[filament:Snapmaker J1 PET] +inherits = *Snapmaker J1 PET @base* +compatible_printers_condition = (printer_model=="Snapmaker J1") and (nozzle_diameter[0]=="0.6" or nozzle_diameter[0]=="0.8" or nozzle_diameter[0]=="0.4") + +[filament:*Snapmaker J1 PETG-CF @base*] +inherits = *fdm_filament_petg* +filament_cost = 40 +filament_density = 1.25 +filament_max_volumetric_speed = 14 +enable_pressure_advance = 0 +filament_type = PETG-CF +temperature = 255 +idle_temperature = 178 +filament_retract_length = nil +filament_retract_before_travel = nil +fan_always_on = 0 +min_fan_speed = 0 +max_fan_speed = 30 +slowdown_below_layer_time = 6 +fan_below_layer_time = 20 +min_print_speed = 10 +filament_colour = #3D3C39 + +[filament:Snapmaker J1 PETG-CF] +inherits = *Snapmaker J1 PETG-CF @base* +compatible_printers_condition = (printer_model=="Snapmaker J1") and (nozzle_diameter[0]=="0.6" or nozzle_diameter[0]=="0.8" or nozzle_diameter[0]=="0.4") + +[filament:*Snapmaker J1 PLA Eco @base*] +inherits = *fdm_filament_pla_eco* +filament_density = 1.26 +filament_max_volumetric_speed = 12 + +[filament:Snapmaker J1 PLA Eco] +inherits = *Snapmaker J1 PLA Eco @base* +compatible_printers_condition = (printer_model=="Snapmaker J1") and (nozzle_diameter[0]=="0.6" or nozzle_diameter[0]=="0.4") + +[filament:Snapmaker J1 PLA Eco @0.2 nozzle] +inherits = *Snapmaker J1 PLA Eco @base* +compatible_printers_condition = (printer_model=="Snapmaker J1") and (nozzle_diameter[0]=="0.2") +filament_max_volumetric_speed = 2 + +[filament:Snapmaker J1 PLA Eco @0.8 nozzle] +inherits = *Snapmaker J1 PLA Eco @base* +compatible_printers_condition = (printer_model=="Snapmaker J1") and (nozzle_diameter[0]=="0.8") +min_print_speed = 20 + +[filament:*Snapmaker J1 PLA @base*] +inherits = *fdm_filament_pla* +temperature = 220 +filament_retract_length = nil + +[filament:Snapmaker J1 PLA] +inherits = *Snapmaker J1 PLA @base* +compatible_printers_condition = (printer_model=="Snapmaker J1") and (nozzle_diameter[0]=="0.2" or nozzle_diameter[0]=="0.6" or nozzle_diameter[0]=="0.8" or nozzle_diameter[0]=="0.4") + +[filament:*Snapmaker J1 PLA Matte @base*] +inherits = *fdm_filament_pla* +filament_density = 1.32 +filament_max_volumetric_speed = 19 +first_layer_temperature = 215 +filament_colour = #EAC3C3 + +[filament:Snapmaker J1 PLA Matte] +inherits = *Snapmaker J1 PLA Matte @base* +compatible_printers_condition = (printer_model=="Snapmaker J1") and (nozzle_diameter[0]=="0.6" or nozzle_diameter[0]=="0.4") + +[filament:Snapmaker J1 PLA Matte @0.2 nozzle] +inherits = *Snapmaker J1 PLA Matte @base* +compatible_printers_condition = (printer_model=="Snapmaker J1") and (nozzle_diameter[0]=="0.2") +filament_max_volumetric_speed = 2 + +[filament:Snapmaker J1 PLA Matte @0.8 nozzle] +inherits = *Snapmaker J1 PLA Matte @base* +compatible_printers_condition = (printer_model=="Snapmaker J1") and (nozzle_diameter[0]=="0.8") +filament_max_volumetric_speed = 22 +min_print_speed = 20 + +[filament:*Snapmaker J1 PLA Metal @base*] +inherits = *fdm_filament_pla* +filament_cost = 90 +filament_density = 1.25 +filament_max_volumetric_speed = 16 +temperature = 220 +filament_colour = #767A7E + +[filament:Snapmaker J1 PLA Metal] +inherits = *Snapmaker J1 PLA Metal @base* +compatible_printers_condition = (printer_model=="Snapmaker J1") and (nozzle_diameter[0]=="0.6" or nozzle_diameter[0]=="0.8" or nozzle_diameter[0]=="0.4") + +[filament:Snapmaker J1 PLA Metal @0.2 nozzle] +inherits = *Snapmaker J1 PLA Metal @base* +compatible_printers_condition = (printer_model=="Snapmaker J1") and (nozzle_diameter[0]=="0.2") +filament_max_volumetric_speed = 2 + +[filament:*Snapmaker J1 PLA-CF @base*] +inherits = *fdm_filament_pla* +filament_density = 1.22 +filament_max_volumetric_speed = 15 +filament_type = PLA-CF +additional_cooling_fan_speed = 0 +bed_temperature = 55 +first_layer_bed_temperature = 55 +temperature = 230 +first_layer_temperature = 230 +idle_temperature = 150 +filament_colour = #3D3C39 + +[filament:Snapmaker J1 PLA-CF] +inherits = *Snapmaker J1 PLA-CF @base* +compatible_printers_condition = (printer_model=="Snapmaker J1") and (nozzle_diameter[0]=="0.6" or nozzle_diameter[0]=="0.4") + +[filament:Snapmaker J1 PLA-CF @0.8 nozzle] +inherits = *Snapmaker J1 PLA-CF @base* +compatible_printers_condition = (printer_model=="Snapmaker J1") and (nozzle_diameter[0]=="0.8") +filament_max_volumetric_speed = 18 + +[filament:*Snapmaker J1 PLA Silk @base*] +inherits = *fdm_filament_pla* +filament_cost = 70 +filament_density = 1.32 +filament_max_volumetric_speed = 12 +first_layer_bed_temperature = 65 +temperature = 230 +first_layer_temperature = 230 +filament_retract_length = 0.5 +filament_colour = #CF942B + +[filament:Snapmaker J1 PLA Silk] +inherits = *Snapmaker J1 PLA Silk @base* +compatible_printers_condition = (printer_model=="Snapmaker J1") and (nozzle_diameter[0]=="0.6" or nozzle_diameter[0]=="0.8" or nozzle_diameter[0]=="0.4") + +[filament:Snapmaker J1 PLA Silk @0.2 nozzle] +inherits = *Snapmaker J1 PLA Silk @base* +compatible_printers_condition = (printer_model=="Snapmaker J1") and (nozzle_diameter[0]=="0.2") +filament_max_volumetric_speed = 2 + +[filament:PolyLite J1 PLA] +inherits = *PolyLite PLA @base* +compatible_printers_condition = (printer_model=="Snapmaker J1") and (nozzle_diameter[0]=="0.6" or nozzle_diameter[0]=="0.8" or nozzle_diameter[0]=="0.4") + +[filament:PolyLite J1 PLA @0.2 nozzle] +inherits = PolyLite PLA @0.2 nozzle +compatible_printers_condition = (printer_model=="Snapmaker J1") and (nozzle_diameter[0]=="0.2") + +[filament:PolyTerra J1 PLA] +inherits = *PolyTerra PLA @base* +compatible_printers_condition = (printer_model=="Snapmaker J1") and (nozzle_diameter[0]=="0.6" or nozzle_diameter[0]=="0.8" or nozzle_diameter[0]=="0.4") + +[filament:PolyTerra J1 PLA @0.2 nozzle] +inherits = PolyTerra PLA @0.2 nozzle +compatible_printers_condition = (printer_model=="Snapmaker J1") and (nozzle_diameter[0]=="0.2") + +[filament:*Snapmaker J1 PVA @base*] +inherits = *fdm_filament_pva* +slowdown_below_layer_time = 8 + +[filament:Snapmaker J1 PVA] +inherits = *Snapmaker J1 PVA @base* +compatible_printers_condition = (printer_model=="Snapmaker J1") and (nozzle_diameter[0]=="0.6" or nozzle_diameter[0]=="0.8" or nozzle_diameter[0]=="0.4") + +[filament:Snapmaker J1 PVA @0.2 nozzle] +inherits = *Snapmaker J1 PVA @base* +compatible_printers_condition = (printer_model=="Snapmaker J1") and (nozzle_diameter[0]=="0.2") +filament_max_volumetric_speed = 1.2 +temperature = 220 +first_layer_temperature = 220 + +[filament:*Snapmaker J1 TPU @base*] +inherits = *fdm_filament_tpu* + +[filament:Snapmaker J1 TPU] +inherits = *Snapmaker J1 TPU @base* +compatible_printers_condition = (printer_model=="Snapmaker J1") and (nozzle_diameter[0]=="0.6" or nozzle_diameter[0]=="0.8" or nozzle_diameter[0]=="0.4") + +[filament:Snapmaker J1 TPU High-Flow] +inherits = *Snapmaker J1 TPU @base* +compatible_printers_condition = (printer_model=="Snapmaker J1") and (nozzle_diameter[0]=="0.6" or nozzle_diameter[0]=="0.8" or nozzle_diameter[0]=="0.4") +filament_max_volumetric_speed = 7.6 +filament_notes = "!! It needs to be dried before use.\nSnapmaker TPU 95A High-Flow\n" +filament_retract_length = 0.8 +filament_retract_speed = nil +filament_deretract_speed = nil +extrusion_multiplier = 0.983 + +[filament:Snapmaker J1 TPE] +inherits = *Snapmaker J1 TPU @base* +compatible_printers_condition = (printer_model=="Snapmaker J1") and (nozzle_diameter[0]=="0.6" or nozzle_diameter[0]=="0.8" or nozzle_diameter[0]=="0.4") +filament_density = 1.22 +filament_max_volumetric_speed = 7.2 +filament_notes = "eSUN eLastic TPE-83A\n" +bed_temperature = 45 +first_layer_bed_temperature = 45 +min_fan_speed = 65 +max_fan_speed = 65 +bridge_fan_speed = 65 +extrusion_multiplier = 1.1 +filament_colour = #383737 + +[printer:*fdm_common*] +gcode_flavor = marlin2 +pause_gcode = M600 ;pause print +nozzle_type = hardened_steel +use_relative_e_distances = 1 +silent_mode = 0 +auxiliary_fan = 0 +remaining_times = 1 +single_extruder_multi_material = 0 +purge_in_prime_tower = 0 +enable_filament_ramming = 0 +nozzle_volume = 0 +cooling_tube_retraction = 0 +cooling_tube_length = 8 +parking_pos_retraction = 0 extra_loading_move = -2 -extruder_colour = "" -extruder_offset = 0x0 -gcode_flavor = marlin high_current_on_filament_swap = 0 -machine_limits_usage = time_estimate_only -machine_max_acceleration_e = 10000 +wipe = 0 +wipe_distance = 1 +retract_when_changing_layer = 1 +retract_before_wipe = 0% +fan_speedup_overhangs = 1 +name = *fdm_common* +retract_length = 0.8 +retract_speed = 45 +deretract_speed = 45 +retract_before_travel = 1 +retract_lift = 0.4 + +[printer:*fdm_linear2*] +inherits = *fdm_common* +wipe = 1 +wipe_distance = 2 +name = *fdm_linear2* +extruder_clearance_height_to_rod = 25 +extruder_clearance_height_to_lid = 90 +machine_max_acceleration_x = 1000 +machine_max_acceleration_y = 1000 +machine_max_acceleration_z = 500 +machine_max_acceleration_e = 3000 +machine_max_acceleration_travel = 1000 machine_max_acceleration_extruding = 1000 -machine_max_acceleration_retracting = 1000 -machine_max_acceleration_travel = 1500 -machine_max_acceleration_x = 3000 -machine_max_acceleration_y = 3000 -machine_max_acceleration_z = 100 -machine_max_feedrate_e = 25 +machine_max_acceleration_retracting = 2000 +machine_max_jerk_x = 1 +machine_max_jerk_y = 1 +machine_max_jerk_z = 1 +machine_max_jerk_e = 3 +thumbnails = 300x150 +retract_length_toolchange = 2 +default_filament_profile = Snapmaker PLA machine_max_feedrate_x = 150 machine_max_feedrate_y = 150 -machine_max_feedrate_z = 50 +machine_max_feedrate_z = 40 +machine_max_feedrate_e = 45 + +[printer:*fdm_linear2_dual*] +inherits = *fdm_linear2* +name = *fdm_linear2_dual* +extruder_clearance_height_to_rod = 45 +extruder_clearance_height_to_lid = 133 +machine_max_acceleration_retracting = 1000 +retract_length_toolchange = 8,8 +default_filament_profile = Snapmaker PLA,Snapmaker PETG +machine_max_feedrate_e = 35 +retract_speed = 35,35 +deretract_speed = 35,35 + +[printer:*fdm_idex*] +inherits = *fdm_common* +wipe = 1 +wipe_distance = 2 +name = *fdm_idex* +extruder_clearance_height_to_rod = 36 +extruder_clearance_height_to_lid = 90 +printer_notes = PRINTER_MODEL_SNAPMAKER_J1\n +fan_speedup_time = 0.2 +machine_max_acceleration_x = 11000 +machine_max_acceleration_y = 11000 +machine_max_acceleration_z = 100 +machine_max_acceleration_e = 6000 +machine_max_acceleration_travel = 11000 +machine_max_acceleration_extruding = 11000 +machine_max_acceleration_retracting = 5000 +machine_max_jerk_x = 8 +machine_max_jerk_y = 8 +machine_max_jerk_z = 3 machine_max_jerk_e = 2.5 -machine_max_jerk_x = 10 -machine_max_jerk_y = 10 -machine_max_jerk_z = 0.2 -machine_min_extruding_rate = 0 -machine_min_travel_rate = 0 -max_layer_height = 0.3 +retract_length_toolchange = 2,2 +bed_exclude_area = 312x0,324x0,324x200,312x200 +thumbnails = 300x300 +extruder_offset = 0x0,0x0 +default_filament_profile = Snapmaker J1 PLA,Snapmaker J1 PETG +start_gcode = ; Model: Snapmaker J1 ({nozzle_diameter[0]}/{nozzle_diameter[1]})\n; Update: 20231019\n; Maintained by https://github.com/macdylan/3dp-configs\n; Printer : [printer_preset]\n; Profile : [print_preset]\n; Plate : [physical_printer_preset]\n; --- initial_extruder: [initial_extruder]\n; --- has_wipe_tower: [has_wipe_tower]\n; --- total_toolchanges: [total_toolchanges]\n; --- T0: {is_extruder_used[0]}\n; --- T1: {is_extruder_used[1]}\n\nM201 X[machine_max_acceleration_x] Y[machine_max_acceleration_y] Z[machine_max_acceleration_z] E[machine_max_acceleration_e]\nM203 X[machine_max_feedrate_x] Y[machine_max_feedrate_y] Z[machine_max_feedrate_z] E[machine_max_feedrate_e]\nM204 P[machine_max_acceleration_extruding] R[machine_max_acceleration_retracting] T[machine_max_acceleration_travel]\nM205 X[machine_max_jerk_x] Y[machine_max_jerk_y] Z[machine_max_jerk_z] E[machine_max_jerk_e]\n\nT[initial_extruder]\n\nM205 V20 ;Junction Deviation (mm)\n\n{if physical_printer_preset =~/.*IDEXDupl.*/ || physical_printer_preset =~/.*IDEXCopy.*/ }\n M605 S2 X162 R0 ;IDEX Duplication\n{elsif physical_printer_preset =~/.*IDEXMirr.*/}\n M605 S3 ;IDEX Mirror\n{elsif physical_printer_preset =~/.*IDEXBack.*/}\n M605 S4 ;IDEX Backup\n{endif}\n\nM140 S{first_layer_bed_temperature[initial_extruder]}\n\n; you can clean the nozzle\n{if is_extruder_used[0]}M104 T0 S165{endif}\n{if is_extruder_used[1]}M104 T1 S165{endif}\nM204 S100\nG28\n\nG0 Z100.0\n{if is_extruder_used[0]}\n T0\n G0 X{if 0 == 0}80{else}240{endif} Y0 F7980.0\n {endif}\n{if is_extruder_used[1]}\n T1\n G0 X{if 1 == 0}80{else}240{endif} Y0 F7980.0\n {endif}\n\nM190 R{first_layer_bed_temperature[initial_extruder]}\n{if 1==1}; LED\n M355 S1 P64\n G4 P100\n M355 S1 P128\n G4 P100\n M355 S1 P64\n G4 P200\n M355 S1 P255\n G4 P100\n{endif}\nG28 X Y\n\nM83\n\n{if is_extruder_used[0]}M104 T0 S{max(250, min(290, first_layer_temperature[0] + 15))}{endif}\n{if is_extruder_used[1]}M104 T1 S{max(250, min(290, first_layer_temperature[1] + 15))}{endif}\n\n{if is_extruder_used[0] and initial_extruder != 0}\n T0\nG0 Z20 F240.0\nG0 X{if 0 == 0}-7{else}331{endif} F7980.0\nG0 Y0\n\nM109 S{max(250, min(290, first_layer_temperature[0] + 15))} C2 W1; common flush temp\nG0 E50 F80.0\n\nM106 S{min(255, (max_fan_speed[0] + 10) * 2.55)}\nM104 S{first_layer_temperature[0] + 5}\n\nG0 E50 F200\n\nG0 E-0.5 F200\nM107\n\nG28 X\n\nG0 Z1.0 F240.0\n\nM109 S{first_layer_temperature[0]} C3 W1\nG1 X{if 0 == 0}142.0{else}182.0{endif} F7980.0\nG1 Z0.3 F240.0\nG1 E4 F200\nG1 X{if 0 == 0}10{else}314{endif} E9.47915 F7980.0\nG1 Y11 E0.68599\nG1 X{if 0 == 0}10.5{else}313.5{endif}\nG1 E0.4\nG1 Y0.8 E0.6361\nG1 X{if 0 == 0}19.5{else}304.5{endif} E0.59245\nG1 E-0.5 F200\nG92 E0\n\n M104 S{is_nil(idle_temperature[0]) ? temperature[0] + standby_temperature_delta : idle_temperature[0]}\n{endif}\n{if is_extruder_used[1] and initial_extruder != 1}\n T1\nG0 Z20 F240.0\nG0 X{if 1 == 0}-7{else}331{endif} F7980.0\nG0 Y0\n\nM109 S{max(250, min(290, first_layer_temperature[1] + 15))} C2 W1; common flush temp\nG0 E50 F80.0\n\nM106 S{min(255, (max_fan_speed[1] + 10) * 2.55)}\nM104 S{first_layer_temperature[1] + 5}\n\nG0 E50 F200\n\nG0 E-0.5 F200\nM107\n\nG28 X\n\nG0 Z1.0 F240.0\n\nM109 S{first_layer_temperature[1]} C3 W1\nG1 X{if 1 == 0}142.0{else}182.0{endif} F7980.0\nG1 Z0.3 F240.0\nG1 E4 F200\nG1 X{if 1 == 0}10{else}314{endif} E9.47915 F7980.0\nG1 Y11 E0.68599\nG1 X{if 1 == 0}10.5{else}313.5{endif}\nG1 E0.4\nG1 Y0.8 E0.6361\nG1 X{if 1 == 0}19.5{else}304.5{endif} E0.59245\nG1 E-0.5 F200\nG92 E0\n\n M104 S{is_nil(idle_temperature[1]) ? temperature[1] + standby_temperature_delta : idle_temperature[1]}\n{endif}\n\nT[initial_extruder]\nG0 Z20 F240.0\nG0 X{if initial_extruder == 0}-7{else}331{endif} F7980.0\nG0 Y0\n\nM109 S{max(250, min(290, first_layer_temperature[initial_extruder] + 15))} C2 W1; common flush temp\nG0 E50 F80.0\n\nM106 S{min(255, (max_fan_speed[initial_extruder] + 10) * 2.55)}\nM104 S{first_layer_temperature[initial_extruder] + 5}\n\nG0 E50 F200\n\nG0 E-0.5 F200\nM107\n\nG28 X\n\nG0 Z1.0 F240.0\n\nM109 S{first_layer_temperature[initial_extruder]} C3 W1\nG1 X{if initial_extruder == 0}142.0{else}182.0{endif} F7980.0\nG1 Z0.3 F240.0\nG1 E4 F200\nG1 X{if initial_extruder == 0}10{else}314{endif} E9.47915 F7980.0\nG1 Y11 E0.68599\nG1 X{if initial_extruder == 0}10.5{else}313.5{endif}\nG1 E0.4\nG1 Y0.8 E0.6361\nG1 X{if initial_extruder == 0}19.5{else}304.5{endif} E0.59245\nG1 E-0.5 F200\nG92 E0\n\n; ready [physical_printer_preset] +end_gcode = G92 E0\n\nG0 Z{max_layer_z + 0.5} F600\n; retract the filament to make it easier to replace\nG0 E-40 F200\nG28\n\n {if is_extruder_used[0]}M104 T0 S0{endif}\n {if is_extruder_used[1]}M104 T1 S0{endif}\nM140 S0\nM107\nM220 S100\nM84\n\n;\n; DON'T REMOVE these lines if you're using the smfix (https://github.com/macdylan/SMFix)\n; min_x = [first_layer_print_min_0]\n; min_y = [first_layer_print_min_1]\n; max_x = [first_layer_print_max_0]\n; max_y = [first_layer_print_max_1]\n; max_z = [max_layer_z]\n; total_layer_number = [layer_num]\n; +toolchange_gcode = ;***** Update: 20230730\n{if current_extruder != next_extruder }\n; Change T[current_extruder] -> T[next_extruder] (layer [layer_num]\n; layer\nT{next_extruder}\n\nM107 P[current_extruder] ;fan off T[current_extruder]\nM104 T[current_extruder] S{is_nil(idle_temperature[current_extruder]) ? temperature[current_extruder] + standby_temperature_delta : idle_temperature[current_extruder]} ;standby T[current_extruder]\n\n{if layer_num == 1 &&\n ((filament_type[current_extruder] == "PLA" || filament_type[current_extruder] == "TPU")\n || (filament_type[next_extruder] == "PLA" || filament_type[next_extruder] == "TPU"))\n}\n; set bed temp: {filament_type[current_extruder]}({bed_temperature[current_extruder]}) -> {filament_type[next_extruder]}({bed_temperature[next_extruder]})\nM140 S{min(bed_temperature[current_extruder], bed_temperature[next_extruder])}\n{endif}\n\nM2000 S200 V[travel_speed] A[travel_acceleration] ;quick switch extruders, S:200 mode/V:speed/A:acceleration\nM109 T[next_extruder] S{layer_num < 1 ? first_layer_temperature[next_extruder] : temperature[next_extruder]} C3 W1 ;wait T{next_extruder}\n{if layer_num >= disable_fan_first_layers[next_extruder]}\n M106 P[next_extruder] S{min_fan_speed[next_extruder] * 255.0 / 100.0} ; restore fan speed for T[next_extruder]\n{endif}\n\n{if layer_z <= (first_layer_height + 0.001)}\n M204 S[first_layer_acceleration] ;first layer accel\n{elsif default_acceleration > 0}\n M204 S[default_acceleration] ;default accel\n{endif}\n\n{endif} +before_layer_gcode = ; layer_num: [layer_num]\nG92 E0 +bed_shape = 0x0,324x0,324x200,0x200 +max_print_height = 200 +machine_max_feedrate_x = 350 +machine_max_feedrate_y = 350 +machine_max_feedrate_z = 10 +machine_max_feedrate_e = 40 +retract_speed = 30,30 +deretract_speed = 30,30 + +[printer:*fdm_a250*] +inherits = *fdm_linear2* +name = *fdm_a250* +printer_notes = PRINTER_MODEL_SNAPMAKER_A250\n +start_gcode = ; Model: Snapmaker A250\n; Update: 20231019\n; Maintained by https://github.com/macdylan/3dp-configs\n; Printer : [printer_preset]\n; Profile : [print_preset]\n; Plate : [physical_printer_preset]\n\nM201 X[machine_max_acceleration_x] Y[machine_max_acceleration_y] Z[machine_max_acceleration_z] E[machine_max_acceleration_e]\nM203 X[machine_max_feedrate_x] Y[machine_max_feedrate_y] Z[machine_max_feedrate_z] E[machine_max_feedrate_e]\nM204 P[machine_max_acceleration_extruding] R[machine_max_acceleration_retracting] T[machine_max_acceleration_travel]\nM205 X[machine_max_jerk_x] Y[machine_max_jerk_y] Z[machine_max_jerk_z] E[machine_max_jerk_e]\n\nT[initial_extruder]\n\nM140 S{first_layer_bed_temperature[initial_extruder]}\n\n; you can clean the nozzle\nM104 S165\nM204 S100\nG28\nG0 Z156 F960.0\nG0 Y125.0 F3420.0\nG0 X115.0\n\nM190 R{first_layer_bed_temperature[initial_extruder]}\n\nG28\nG0 X0\nG0 Z0.2 F960.0\nG0 Y0 F3420.0\nG0 X230\nG0 Y250\nG0 X0\nG0 Y0\n\nM83\n\nT[initial_extruder]\nG0 Z20 F960.0\nG0 X{if initial_extruder == 0}-10{else}240{endif} F3420.0\nG0 Y0\n\nM109 S{max(250, min(290, first_layer_temperature[initial_extruder] + 15))} C2 W1; common flush temp\nG0 E35 F80.0\n\nM106 S{min(255, (max_fan_speed[initial_extruder] + 10) * 2.55)}\nM104 S{first_layer_temperature[initial_extruder] + 5}\n\nG0 E35 F200\n\nG0 E-0.5 F200\nM107\n\nG0 Z0.1 F960.0\nG0 X{if initial_extruder == 0}10{else}220{endif} F3420.0\nG0 X{if initial_extruder == 0}-10{else}240{endif}\n\nG0 Z1.0 F960.0\n\nM109 S{first_layer_temperature[initial_extruder]} C3 W1\nG1 X{if initial_extruder == 0}105.0{else}125.0{endif} F3420.0\nG1 Z0.3 F960.0\nG1 E4 F200\nG1 X{if initial_extruder == 0}0{else}230{endif} E6.54809 F3420.0\nG1 Y11 E0.68599\nG1 X{if initial_extruder == 0}0.5{else}229.5{endif}\nG1 E0.4\nG1 Y0.8 E0.6361\nG1 X{if initial_extruder == 0}9.5{else}220.5{endif} E0.59245\nG1 E-0.5 F200\nG92 E0\n\n; ready [physical_printer_preset] +end_gcode = G92 E0\n\nG0 Z{max_layer_z + 0.5} F600\n; retract the filament to make it easier to replace\nG0 E-25 F200\nG28\n\n M104 S0\nM140 S0\nM107\nM220 S100\nM84\n\n;\n; DON'T REMOVE these lines if you're using the smfix (https://github.com/macdylan/SMFix)\n; min_x = [first_layer_print_min_0]\n; min_y = [first_layer_print_min_1]\n; max_x = [first_layer_print_max_0]\n; max_y = [first_layer_print_max_1]\n; max_z = [max_layer_z]\n; total_layer_number = [layer_num]\n; +before_layer_gcode = ; layer_num: [layer_num]\nG92 E0 +bed_shape = 0x0,230x0,230x250,0x250 +max_print_height = 235 + +[printer:*fdm_a350*] +inherits = *fdm_linear2* +name = *fdm_a350* +printer_notes = PRINTER_MODEL_SNAPMAKER_A350\n +start_gcode = ; Model: Snapmaker A350\n; Update: 20231019\n; Maintained by https://github.com/macdylan/3dp-configs\n; Printer : [printer_preset]\n; Profile : [print_preset]\n; Plate : [physical_printer_preset]\n\nM201 X[machine_max_acceleration_x] Y[machine_max_acceleration_y] Z[machine_max_acceleration_z] E[machine_max_acceleration_e]\nM203 X[machine_max_feedrate_x] Y[machine_max_feedrate_y] Z[machine_max_feedrate_z] E[machine_max_feedrate_e]\nM204 P[machine_max_acceleration_extruding] R[machine_max_acceleration_retracting] T[machine_max_acceleration_travel]\nM205 X[machine_max_jerk_x] Y[machine_max_jerk_y] Z[machine_max_jerk_z] E[machine_max_jerk_e]\n\nT[initial_extruder]\n\nM140 S{first_layer_bed_temperature[initial_extruder]}\n\n; you can clean the nozzle\nM104 S165\nM204 S100\nG28\nG0 Z220 F960.0\nG0 Y175.0 F3420.0\nG0 X160.0\n\nM190 R{first_layer_bed_temperature[initial_extruder]}\n\nG28\nG0 X0\nG0 Z0.2 F960.0\nG0 Y0 F3420.0\nG0 X320\nG0 Y350\nG0 X0\nG0 Y0\n\nM83\n\nT[initial_extruder]\nG0 Z20 F960.0\nG0 X{if initial_extruder == 0}-10{else}330{endif} F3420.0\nG0 Y0\n\nM109 S{max(250, min(290, first_layer_temperature[initial_extruder] + 15))} C2 W1; common flush temp\nG0 E35 F80.0\n\nM106 S{min(255, (max_fan_speed[initial_extruder] + 10) * 2.55)}\nM104 S{first_layer_temperature[initial_extruder] + 5}\n\nG0 E35 F200\n\nG0 E-0.5 F200\nM107\n\nG0 Z0.1 F960.0\nG0 X{if initial_extruder == 0}10{else}310{endif} F3420.0\nG0 X{if initial_extruder == 0}-10{else}330{endif}\n\nG0 Z1.0 F960.0\n\nM109 S{first_layer_temperature[initial_extruder]} C3 W1\nG1 X{if initial_extruder == 0}150.0{else}170.0{endif} F3420.0\nG1 Z0.3 F960.0\nG1 E4 F200\nG1 X{if initial_extruder == 0}0{else}320{endif} E9.35442 F3420.0\nG1 Y11 E0.68599\nG1 X{if initial_extruder == 0}0.5{else}319.5{endif}\nG1 E0.4\nG1 Y0.8 E0.6361\nG1 X{if initial_extruder == 0}9.5{else}310.5{endif} E0.59245\nG1 E-0.5 F200\nG92 E0\n\n; ready [physical_printer_preset] +end_gcode = G92 E0\n\nG0 Z{max_layer_z + 0.5} F600\n; retract the filament to make it easier to replace\nG0 E-25 F200\nG28\n\n M104 S0\nM140 S0\nM107\nM220 S100\nM84\n\n;\n; DON'T REMOVE these lines if you're using the smfix (https://github.com/macdylan/SMFix)\n; min_x = [first_layer_print_min_0]\n; min_y = [first_layer_print_min_1]\n; max_x = [first_layer_print_max_0]\n; max_y = [first_layer_print_max_1]\n; max_z = [max_layer_z]\n; total_layer_number = [layer_num]\n; +before_layer_gcode = ; layer_num: [layer_num]\nG92 E0 +bed_shape = 0x0,320x0,320x350,0x350 max_print_height = 330 + +[printer:*fdm_a250_dual*] +inherits = *fdm_linear2_dual* +name = *fdm_a250_dual* +printer_notes = PRINTER_MODEL_SNAPMAKER_A250_DUAL\n +start_gcode = ; Model: Snapmaker A250 Dual ({nozzle_diameter[0]}/{nozzle_diameter[1]})\n; Update: 20231019\n; Maintained by https://github.com/macdylan/3dp-configs\n; Printer : [printer_preset]\n; Profile : [print_preset]\n; Plate : [physical_printer_preset]\n; --- initial_extruder: [initial_extruder]\n; --- has_wipe_tower: [has_wipe_tower]\n; --- total_toolchanges: [total_toolchanges]\n; --- T0: {is_extruder_used[0]}\n; --- T1: {is_extruder_used[1]}\n\nM201 X[machine_max_acceleration_x] Y[machine_max_acceleration_y] Z[machine_max_acceleration_z] E[machine_max_acceleration_e]\nM203 X[machine_max_feedrate_x] Y[machine_max_feedrate_y] Z[machine_max_feedrate_z] E[machine_max_feedrate_e]\nM204 P[machine_max_acceleration_extruding] R[machine_max_acceleration_retracting] T[machine_max_acceleration_travel]\nM205 X[machine_max_jerk_x] Y[machine_max_jerk_y] Z[machine_max_jerk_z] E[machine_max_jerk_e]\n\nT[initial_extruder]\n\nM140 S{first_layer_bed_temperature[initial_extruder]}\n\n; you can clean the nozzle\n{if is_extruder_used[0]}M104 T0 S165{endif}\n{if is_extruder_used[1]}M104 T1 S165{endif}\nM204 S100\nG28\nG0 Z136 F960.0\nG0 Y125.0 F3420.0\nG0 X115.0\n\nM190 R{first_layer_bed_temperature[initial_extruder]}\n\nG28\nG0 X0\nG0 Z0.2 F960.0\nG0 Y0 F3420.0\nG0 X230\nG0 Y250\nG0 X0\nG0 Y0\n\nM83\n\n{if is_extruder_used[0]}M104 T0 S{max(250, min(290, first_layer_temperature[0] + 15))}{endif}\n{if is_extruder_used[1]}M104 T1 S{max(250, min(290, first_layer_temperature[1] + 15))}{endif}\n\n{if is_extruder_used[0] and initial_extruder != 0}\n T0\nG0 Z20 F960.0\nG0 X{if 0 == 0}-10{else}240{endif} F3420.0\nG0 Y0\n\nM109 S{max(250, min(290, first_layer_temperature[0] + 15))} C2 W1; common flush temp\nG0 E45 F80.0\n\nM106 S{min(255, (max_fan_speed[0] + 10) * 2.55)}\nM104 S{first_layer_temperature[0] + 5}\n\nG0 E45 F200\n\nG0 E-0.5 F200\nM107\n\nG0 Z0.1 F960.0\nG0 X{if 0 == 0}10{else}220{endif} F3420.0\nG0 X{if 0 == 0}-10{else}240{endif}\n\nG0 Z1.0 F960.0\n\nM109 S{first_layer_temperature[0]} C3 W1\nG1 X{if 0 == 0}105.0{else}125.0{endif} F3420.0\nG1 Z0.3 F960.0\nG1 E4 F200\nG1 X{if 0 == 0}0{else}230{endif} E6.54809 F3420.0\nG1 Y11 E0.68599\nG1 X{if 0 == 0}0.5{else}229.5{endif}\nG1 E0.4\nG1 Y0.8 E0.6361\nG1 X{if 0 == 0}9.5{else}220.5{endif} E0.59245\nG1 E-0.5 F200\nG92 E0\n\n M104 S{is_nil(idle_temperature[0]) ? temperature[0] + standby_temperature_delta : idle_temperature[0]}\n{endif}\n{if is_extruder_used[1] and initial_extruder != 1}\n T1\nG0 Z20 F960.0\nG0 X{if 1 == 0}-10{else}240{endif} F3420.0\nG0 Y0\n\nM109 S{max(250, min(290, first_layer_temperature[1] + 15))} C2 W1; common flush temp\nG0 E45 F80.0\n\nM106 S{min(255, (max_fan_speed[1] + 10) * 2.55)}\nM104 S{first_layer_temperature[1] + 5}\n\nG0 E45 F200\n\nG0 E-0.5 F200\nM107\n\nG0 Z0.1 F960.0\nG0 X{if 1 == 0}10{else}220{endif} F3420.0\nG0 X{if 1 == 0}-10{else}240{endif}\n\nG0 Z1.0 F960.0\n\nM109 S{first_layer_temperature[1]} C3 W1\nG1 X{if 1 == 0}105.0{else}125.0{endif} F3420.0\nG1 Z0.3 F960.0\nG1 E4 F200\nG1 X{if 1 == 0}0{else}230{endif} E6.54809 F3420.0\nG1 Y11 E0.68599\nG1 X{if 1 == 0}0.5{else}229.5{endif}\nG1 E0.4\nG1 Y0.8 E0.6361\nG1 X{if 1 == 0}9.5{else}220.5{endif} E0.59245\nG1 E-0.5 F200\nG92 E0\n\n M104 S{is_nil(idle_temperature[1]) ? temperature[1] + standby_temperature_delta : idle_temperature[1]}\n{endif}\n\nT[initial_extruder]\nG0 Z20 F960.0\nG0 X{if initial_extruder == 0}-10{else}240{endif} F3420.0\nG0 Y0\n\nM109 S{max(250, min(290, first_layer_temperature[initial_extruder] + 15))} C2 W1; common flush temp\nG0 E45 F80.0\n\nM106 S{min(255, (max_fan_speed[initial_extruder] + 10) * 2.55)}\nM104 S{first_layer_temperature[initial_extruder] + 5}\n\nG0 E45 F200\n\nG0 E-0.5 F200\nM107\n\nG0 Z0.1 F960.0\nG0 X{if initial_extruder == 0}10{else}220{endif} F3420.0\nG0 X{if initial_extruder == 0}-10{else}240{endif}\n\nG0 Z1.0 F960.0\n\nM109 S{first_layer_temperature[initial_extruder]} C3 W1\nG1 X{if initial_extruder == 0}105.0{else}125.0{endif} F3420.0\nG1 Z0.3 F960.0\nG1 E4 F200\nG1 X{if initial_extruder == 0}0{else}230{endif} E6.54809 F3420.0\nG1 Y11 E0.68599\nG1 X{if initial_extruder == 0}0.5{else}229.5{endif}\nG1 E0.4\nG1 Y0.8 E0.6361\nG1 X{if initial_extruder == 0}9.5{else}220.5{endif} E0.59245\nG1 E-0.5 F200\nG92 E0\n\n; ready [physical_printer_preset] +end_gcode = G92 E0\n\nG0 Z{max_layer_z + 0.5} F600\n; retract the filament to make it easier to replace\nG0 E-35 F200\nG28\n\n {if is_extruder_used[0]}M104 T0 S0{endif}\n {if is_extruder_used[1]}M104 T1 S0{endif}\nM140 S0\nM107\nM220 S100\nM84\n\n;\n; DON'T REMOVE these lines if you're using the smfix (https://github.com/macdylan/SMFix)\n; min_x = [first_layer_print_min_0]\n; min_y = [first_layer_print_min_1]\n; max_x = [first_layer_print_max_0]\n; max_y = [first_layer_print_max_1]\n; max_z = [max_layer_z]\n; total_layer_number = [layer_num]\n; +toolchange_gcode = ;***** Update: 20231010\n{if current_extruder != next_extruder }\n; Change T[current_extruder] -> T[next_extruder] (layer [layer_num]\n; layer\nT{next_extruder}\n\nM107 P[current_extruder] ;fan off T[current_extruder]\nM104 T[current_extruder] S{is_nil(idle_temperature[current_extruder]) ? temperature[current_extruder] + standby_temperature_delta : idle_temperature[current_extruder]} ;standby T[current_extruder]\n\n{if layer_num == 1 &&\n ((filament_type[current_extruder] == "PLA" || filament_type[current_extruder] == "TPU")\n || (filament_type[next_extruder] == "PLA" || filament_type[next_extruder] == "TPU"))\n}\n; set bed temp: {filament_type[current_extruder]}({bed_temperature[current_extruder]}) -> {filament_type[next_extruder]}({bed_temperature[next_extruder]})\nM140 S{min(bed_temperature[current_extruder], bed_temperature[next_extruder])}\n{endif}\n\nM109 T[next_extruder] S{layer_num < 1 ? first_layer_temperature[next_extruder] : temperature[next_extruder]} C3 W1 ;wait T{next_extruder}\n{if layer_num >= disable_fan_first_layers[next_extruder]}\n M106 P[next_extruder] S{min_fan_speed[next_extruder] * 255.0 / 100.0} ; restore fan speed for T[next_extruder]\n{endif}\n\n{if layer_z <= (first_layer_height + 0.001)}\n M204 S[first_layer_acceleration] ;first layer accel\n{elsif default_acceleration > 0}\n M204 S[default_acceleration] ;default accel\n{endif}\n\n{endif} +before_layer_gcode = ; layer_num: [layer_num]\nG92 E0 +bed_shape = 0x0,230x0,230x250,0x250 +max_print_height = 205 + +[printer:*fdm_a350_dual*] +inherits = *fdm_linear2_dual* +name = *fdm_a350_dual* +printer_notes = PRINTER_MODEL_SNAPMAKER_A350_DUAL\n +start_gcode = ; Model: Snapmaker A350 Dual ({nozzle_diameter[0]}/{nozzle_diameter[1]})\n; Update: 20231019\n; Maintained by https://github.com/macdylan/3dp-configs\n; Printer : [printer_preset]\n; Profile : [print_preset]\n; Plate : [physical_printer_preset]\n; --- initial_extruder: [initial_extruder]\n; --- has_wipe_tower: [has_wipe_tower]\n; --- total_toolchanges: [total_toolchanges]\n; --- T0: {is_extruder_used[0]}\n; --- T1: {is_extruder_used[1]}\n\nM201 X[machine_max_acceleration_x] Y[machine_max_acceleration_y] Z[machine_max_acceleration_z] E[machine_max_acceleration_e]\nM203 X[machine_max_feedrate_x] Y[machine_max_feedrate_y] Z[machine_max_feedrate_z] E[machine_max_feedrate_e]\nM204 P[machine_max_acceleration_extruding] R[machine_max_acceleration_retracting] T[machine_max_acceleration_travel]\nM205 X[machine_max_jerk_x] Y[machine_max_jerk_y] Z[machine_max_jerk_z] E[machine_max_jerk_e]\n\nT[initial_extruder]\n\nM140 S{first_layer_bed_temperature[initial_extruder]}\n\n; you can clean the nozzle\n{if is_extruder_used[0]}M104 T0 S165{endif}\n{if is_extruder_used[1]}M104 T1 S165{endif}\nM204 S100\nG28\nG0 Z193 F960.0\nG0 Y175.0 F3420.0\nG0 X160.0\n\nM190 R{first_layer_bed_temperature[initial_extruder]}\n\nG28\nG0 X0\nG0 Z0.2 F960.0\nG0 Y0 F3420.0\nG0 X320\nG0 Y350\nG0 X0\nG0 Y0\n\nM83\n\n{if is_extruder_used[0]}M104 T0 S{max(250, min(290, first_layer_temperature[0] + 15))}{endif}\n{if is_extruder_used[1]}M104 T1 S{max(250, min(290, first_layer_temperature[1] + 15))}{endif}\n\n{if is_extruder_used[0] and initial_extruder != 0}\n T0\nG0 Z20 F960.0\nG0 X{if 0 == 0}-10{else}330{endif} F3420.0\nG0 Y0\n\nM109 S{max(250, min(290, first_layer_temperature[0] + 15))} C2 W1; common flush temp\nG0 E45 F80.0\n\nM106 S{min(255, (max_fan_speed[0] + 10) * 2.55)}\nM104 S{first_layer_temperature[0] + 5}\n\nG0 E45 F200\n\nG0 E-0.5 F200\nM107\n\nG0 Z0.1 F960.0\nG0 X{if 0 == 0}10{else}310{endif} F3420.0\nG0 X{if 0 == 0}-10{else}330{endif}\n\nG0 Z1.0 F960.0\n\nM109 S{first_layer_temperature[0]} C3 W1\nG1 X{if 0 == 0}150.0{else}170.0{endif} F3420.0\nG1 Z0.3 F960.0\nG1 E4 F200\nG1 X{if 0 == 0}0{else}320{endif} E9.35442 F3420.0\nG1 Y11 E0.68599\nG1 X{if 0 == 0}0.5{else}319.5{endif}\nG1 E0.4\nG1 Y0.8 E0.6361\nG1 X{if 0 == 0}9.5{else}310.5{endif} E0.59245\nG1 E-0.5 F200\nG92 E0\n\n M104 S{is_nil(idle_temperature[0]) ? temperature[0] + standby_temperature_delta : idle_temperature[0]}\n{endif}\n{if is_extruder_used[1] and initial_extruder != 1}\n T1\nG0 Z20 F960.0\nG0 X{if 1 == 0}-10{else}330{endif} F3420.0\nG0 Y0\n\nM109 S{max(250, min(290, first_layer_temperature[1] + 15))} C2 W1; common flush temp\nG0 E45 F80.0\n\nM106 S{min(255, (max_fan_speed[1] + 10) * 2.55)}\nM104 S{first_layer_temperature[1] + 5}\n\nG0 E45 F200\n\nG0 E-0.5 F200\nM107\n\nG0 Z0.1 F960.0\nG0 X{if 1 == 0}10{else}310{endif} F3420.0\nG0 X{if 1 == 0}-10{else}330{endif}\n\nG0 Z1.0 F960.0\n\nM109 S{first_layer_temperature[1]} C3 W1\nG1 X{if 1 == 0}150.0{else}170.0{endif} F3420.0\nG1 Z0.3 F960.0\nG1 E4 F200\nG1 X{if 1 == 0}0{else}320{endif} E9.35442 F3420.0\nG1 Y11 E0.68599\nG1 X{if 1 == 0}0.5{else}319.5{endif}\nG1 E0.4\nG1 Y0.8 E0.6361\nG1 X{if 1 == 0}9.5{else}310.5{endif} E0.59245\nG1 E-0.5 F200\nG92 E0\n\n M104 S{is_nil(idle_temperature[1]) ? temperature[1] + standby_temperature_delta : idle_temperature[1]}\n{endif}\n\nT[initial_extruder]\nG0 Z20 F960.0\nG0 X{if initial_extruder == 0}-10{else}330{endif} F3420.0\nG0 Y0\n\nM109 S{max(250, min(290, first_layer_temperature[initial_extruder] + 15))} C2 W1; common flush temp\nG0 E45 F80.0\n\nM106 S{min(255, (max_fan_speed[initial_extruder] + 10) * 2.55)}\nM104 S{first_layer_temperature[initial_extruder] + 5}\n\nG0 E45 F200\n\nG0 E-0.5 F200\nM107\n\nG0 Z0.1 F960.0\nG0 X{if initial_extruder == 0}10{else}310{endif} F3420.0\nG0 X{if initial_extruder == 0}-10{else}330{endif}\n\nG0 Z1.0 F960.0\n\nM109 S{first_layer_temperature[initial_extruder]} C3 W1\nG1 X{if initial_extruder == 0}150.0{else}170.0{endif} F3420.0\nG1 Z0.3 F960.0\nG1 E4 F200\nG1 X{if initial_extruder == 0}0{else}320{endif} E9.35442 F3420.0\nG1 Y11 E0.68599\nG1 X{if initial_extruder == 0}0.5{else}319.5{endif}\nG1 E0.4\nG1 Y0.8 E0.6361\nG1 X{if initial_extruder == 0}9.5{else}310.5{endif} E0.59245\nG1 E-0.5 F200\nG92 E0\n\n; ready [physical_printer_preset] +end_gcode = G92 E0\n\nG0 Z{max_layer_z + 0.5} F600\n; retract the filament to make it easier to replace\nG0 E-35 F200\nG28\n\n {if is_extruder_used[0]}M104 T0 S0{endif}\n {if is_extruder_used[1]}M104 T1 S0{endif}\nM140 S0\nM107\nM220 S100\nM84\n\n;\n; DON'T REMOVE these lines if you're using the smfix (https://github.com/macdylan/SMFix)\n; min_x = [first_layer_print_min_0]\n; min_y = [first_layer_print_min_1]\n; max_x = [first_layer_print_max_0]\n; max_y = [first_layer_print_max_1]\n; max_z = [max_layer_z]\n; total_layer_number = [layer_num]\n; +toolchange_gcode = ;***** Update: 20231010\n{if current_extruder != next_extruder }\n; Change T[current_extruder] -> T[next_extruder] (layer [layer_num]\n; layer\nT{next_extruder}\n\nM107 P[current_extruder] ;fan off T[current_extruder]\nM104 T[current_extruder] S{is_nil(idle_temperature[current_extruder]) ? temperature[current_extruder] + standby_temperature_delta : idle_temperature[current_extruder]} ;standby T[current_extruder]\n\n{if layer_num == 1 &&\n ((filament_type[current_extruder] == "PLA" || filament_type[current_extruder] == "TPU")\n || (filament_type[next_extruder] == "PLA" || filament_type[next_extruder] == "TPU"))\n}\n; set bed temp: {filament_type[current_extruder]}({bed_temperature[current_extruder]}) -> {filament_type[next_extruder]}({bed_temperature[next_extruder]})\nM140 S{min(bed_temperature[current_extruder], bed_temperature[next_extruder])}\n{endif}\n\nM109 T[next_extruder] S{layer_num < 1 ? first_layer_temperature[next_extruder] : temperature[next_extruder]} C3 W1 ;wait T{next_extruder}\n{if layer_num >= disable_fan_first_layers[next_extruder]}\n M106 P[next_extruder] S{min_fan_speed[next_extruder] * 255.0 / 100.0} ; restore fan speed for T[next_extruder]\n{endif}\n\n{if layer_z <= (first_layer_height + 0.001)}\n M204 S[first_layer_acceleration] ;first layer accel\n{elsif default_acceleration > 0}\n M204 S[default_acceleration] ;default accel\n{endif}\n\n{endif} +before_layer_gcode = ; layer_num: [layer_num]\nG92 E0 +bed_shape = 0x0,320x0,320x350,0x350 +max_print_height = 290 + +[printer:*fdm_a250_qs*] +inherits = *fdm_a250* +name = *fdm_a250_qs* +printer_notes = PRINTER_MODEL_SNAPMAKER_A250\nPRINTER_MODEL_SNAPMAKER_A250_QUICKSWAPKIT\n +bed_exclude_area = 0x235,230x235,230x250,0x250 +max_print_height = 220 + +[printer:*fdm_a350_qs*] +inherits = *fdm_a350* +name = *fdm_a350_qs* +printer_notes = PRINTER_MODEL_SNAPMAKER_A350\nPRINTER_MODEL_SNAPMAKER_A350_QUICKSWAPKIT\n +bed_exclude_area = 0x335,320x335,320x350,0x350 +max_print_height = 315 + +[printer:*fdm_a250_dual_qs*] +inherits = *fdm_a250_dual* +name = *fdm_a250_dual_qs* +printer_notes = PRINTER_MODEL_SNAPMAKER_A250_DUAL\nPRINTER_MODEL_SNAPMAKER_A250_DUAL_QUICKSWAPKIT\n +bed_exclude_area = 0x235,230x235,230x250,0x250 + +[printer:*fdm_a350_dual_qs*] +inherits = *fdm_a350_dual* +name = *fdm_a350_dual_qs* +printer_notes = PRINTER_MODEL_SNAPMAKER_A350_DUAL\nPRINTER_MODEL_SNAPMAKER_A350_DUAL_QUICKSWAPKIT\n +bed_exclude_area = 0x335,320x335,320x350,0x350 +max_print_height = 300 + +[printer:Snapmaker J1 (0.2 nozzle)] +name = Snapmaker J1 (0.2 nozzle) +printer_model = Snapmaker J1 +default_print_profile = 0.14 Standard @Snapmaker J1 (0.2 nozzle) +printer_variant = 0.2 +max_layer_height = 0.14 +min_layer_height = 0.06 +nozzle_diameter = 0.2,0.2 +inherits = *fdm_idex* + +[printer:Snapmaker J1 (0.4 nozzle)] +name = Snapmaker J1 (0.4 nozzle) +printer_model = Snapmaker J1 +default_print_profile = 0.16 Optimal @Snapmaker J1 (0.4 nozzle) +printer_variant = 0.4 +max_layer_height = 0.28 +min_layer_height = 0.08 +nozzle_diameter = 0.4,0.4 +inherits = *fdm_idex* + +[printer:Snapmaker J1 (0.6 nozzle)] +name = Snapmaker J1 (0.6 nozzle) +printer_model = Snapmaker J1 +default_print_profile = 0.18 Standard @Snapmaker J1 (0.6 nozzle) +printer_variant = 0.6 +max_layer_height = 0.42 +min_layer_height = 0.18 +nozzle_diameter = 0.6,0.6 +inherits = *fdm_idex* + +[printer:Snapmaker J1 (0.8 nozzle)] +name = Snapmaker J1 (0.8 nozzle) +printer_model = Snapmaker J1 +default_print_profile = 0.24 Standard @Snapmaker J1 (0.8 nozzle) +printer_variant = 0.8 +max_layer_height = 0.48 +min_layer_height = 0.24 +nozzle_diameter = 0.8,0.8 +inherits = *fdm_idex* + +[printer:Snapmaker A250 (0.2 nozzle)] +name = Snapmaker A250 (0.2 nozzle) +printer_model = Snapmaker A250 +default_print_profile = 0.14 Standard @Snapmaker (0.2 nozzle) +printer_variant = 0.2 +max_layer_height = 0.14 +min_layer_height = 0.06 +nozzle_diameter = 0.2 +inherits = *fdm_a250* + +[printer:Snapmaker A250 (0.4 nozzle)] +name = Snapmaker A250 (0.4 nozzle) +printer_model = Snapmaker A250 +default_print_profile = 0.16 Optimal @Snapmaker (0.4 nozzle) +printer_variant = 0.4 +max_layer_height = 0.28 min_layer_height = 0.08 nozzle_diameter = 0.4 -parking_pos_retraction = 92 -pause_print_gcode = -printer_technology = FFF -remaining_times = 0 -retract_before_travel = 2 -retract_before_wipe = 0% -retract_layer_change = 1 -retract_length = 3 -retract_length_toolchange = 10 -retract_lift = 0 -retract_lift_above = 0 -retract_lift_below = 328 -retract_restart_extra = 0 -retract_restart_extra_toolchange = 0 -retract_speed = 60 -deretract_speed = 40 -silent_mode = 0 -single_extruder_multi_material = 0 -start_gcode = M82 ;absolute extrusion mode\n;Start GCode begin\nM140 S[first_layer_bed_temperature] ;Start warming Bed\nM104 S[first_layer_temperature] ;Start warming Nozzle\nG28 ; home all axes\nG90 ;absolute positioning\nG1 X-10 Y-10 F3000\nG1 Z0 F1800\nM190 S[first_layer_bed_temperature] ;Wait For Bed Temperature\nM109 S[first_layer_temperature] ;Wait for Hotend Temperature\nG92 E0\nG1 E20 F200 ; Prime extrude for wipe\nG92 E0 -thumbnails = 16x16,220x124 -use_firmware_retraction = 0 -use_relative_e_distances = 0 -use_volumetric_e = 0 -variable_layer_height = 1 -wipe = 0 -z_offset = 0 +inherits = *fdm_a250* -[printer:Snapmaker A350] -inherits = *common* -printer_model = A350 -printer_variant = 0.4 -default_filament_profile = Generic PLA @Snapmaker -default_print_profile = 0.20mm NORMAL @SnapmakerA350 +[printer:Snapmaker A250 (0.6 nozzle)] +name = Snapmaker A250 (0.6 nozzle) +printer_model = Snapmaker A250 +default_print_profile = 0.18 Standard @Snapmaker (0.6 nozzle) +printer_variant = 0.6 +max_layer_height = 0.42 +min_layer_height = 0.18 +nozzle_diameter = 0.6 +inherits = *fdm_a250* -[printer:Snapmaker A250] -inherits = *common* -printer_model = A250 +[printer:Snapmaker A250 (0.8 nozzle)] +name = Snapmaker A250 (0.8 nozzle) +printer_model = Snapmaker A250 +default_print_profile = 0.24 Standard @Snapmaker (0.8 nozzle) +printer_variant = 0.8 +max_layer_height = 0.48 +min_layer_height = 0.24 +nozzle_diameter = 0.8 +inherits = *fdm_a250* + +[printer:Snapmaker A350 (0.2 nozzle)] +name = Snapmaker A350 (0.2 nozzle) +printer_model = Snapmaker A350 +default_print_profile = 0.14 Standard @Snapmaker (0.2 nozzle) +printer_variant = 0.2 +max_layer_height = 0.14 +min_layer_height = 0.06 +nozzle_diameter = 0.2 +inherits = *fdm_a350* + +[printer:Snapmaker A350 (0.4 nozzle)] +name = Snapmaker A350 (0.4 nozzle) +printer_model = Snapmaker A350 +default_print_profile = 0.16 Optimal @Snapmaker (0.4 nozzle) printer_variant = 0.4 -bed_shape = 0x0,230x0,230x250,0x250 -thumbnails = -variable_layer_height = 0 -retract_lift_below = 0 -max_print_height = 235 -start_gcode = M82 ;absolute extrusion mode\n;Start GCode begin\nM140 S[first_layer_bed_temperature] ;Start Warming Bed\nM104 S160 ;Preheat Nozzle\nG28 ; home all axes\nG90 ;absolute positioning\nG1 X-10 Y-10 F3000\nG1 Z0 F1800\nG1 Z5 F5000 ; lift nozzle\nM190 S[first_layer_bed_temperature] ;Wait For Bed Temperature\nM109 S[first_layer_temperature] ;Wait for Hotend Temperature\nG92 E0\nG1 E10 F200\nG1 E-2 F300\nG92 E0\n;Start GCode end\nG1 F3600 E-2 -end_gcode = M140 S0\n;End GCode begin\nM104 S0 ;extruder heater off\nM140 S0 ;heated bed heater off (if you have it)\nG90 ;absolute positioning\nG92 E0\nG1 E-2 F300 ;retract the filament a bit before lifting the nozzle, to release some of the pressure\nG1 Z330 E-1 F80 ;move Z up a bit and retract filament even more\nG1 X0 F3000 ;move X to min endstops, so the head is out of the way\nG1 Y250 F3000 ;so the head is out of the way and Plate is moved forward\nM84 ;steppers off\n;End GCode end\nM82 ;absolute extrusion mode\nM104 S0\nM107\n;End of Gcode -default_filament_profile = Generic PLA @Snapmaker -default_print_profile = 0.20mm NORMAL @SnapmakerA250 +max_layer_height = 0.28 +min_layer_height = 0.08 +nozzle_diameter = 0.4 +inherits = *fdm_a350* + +[printer:Snapmaker A350 (0.6 nozzle)] +name = Snapmaker A350 (0.6 nozzle) +printer_model = Snapmaker A350 +default_print_profile = 0.18 Standard @Snapmaker (0.6 nozzle) +printer_variant = 0.6 +max_layer_height = 0.42 +min_layer_height = 0.18 +nozzle_diameter = 0.6 +inherits = *fdm_a350* + +[printer:Snapmaker A350 (0.8 nozzle)] +name = Snapmaker A350 (0.8 nozzle) +printer_model = Snapmaker A350 +default_print_profile = 0.24 Standard @Snapmaker (0.8 nozzle) +printer_variant = 0.8 +max_layer_height = 0.48 +min_layer_height = 0.24 +nozzle_diameter = 0.8 +inherits = *fdm_a350* + +[printer:Snapmaker A250 Dual (0.2 nozzle)] +name = Snapmaker A250 Dual (0.2 nozzle) +printer_model = Snapmaker A250 Dual +default_print_profile = 0.14 Standard @Snapmaker (0.2 nozzle) +printer_variant = 0.2 +max_layer_height = 0.14 +min_layer_height = 0.06 +nozzle_diameter = 0.2,0.2 +inherits = *fdm_a250_dual* + +[printer:Snapmaker A250 Dual (0.4 nozzle)] +name = Snapmaker A250 Dual (0.4 nozzle) +printer_model = Snapmaker A250 Dual +default_print_profile = 0.16 Optimal @Snapmaker (0.4 nozzle) +printer_variant = 0.4 +max_layer_height = 0.28 +min_layer_height = 0.08 +nozzle_diameter = 0.4,0.4 +inherits = *fdm_a250_dual* + +[printer:Snapmaker A250 Dual (0.6 nozzle)] +name = Snapmaker A250 Dual (0.6 nozzle) +printer_model = Snapmaker A250 Dual +default_print_profile = 0.18 Standard @Snapmaker (0.6 nozzle) +printer_variant = 0.6 +max_layer_height = 0.42 +min_layer_height = 0.18 +nozzle_diameter = 0.6,0.6 +inherits = *fdm_a250_dual* + +[printer:Snapmaker A250 Dual (0.8 nozzle)] +name = Snapmaker A250 Dual (0.8 nozzle) +printer_model = Snapmaker A250 Dual +default_print_profile = 0.24 Standard @Snapmaker (0.8 nozzle) +printer_variant = 0.8 +max_layer_height = 0.48 +min_layer_height = 0.24 +nozzle_diameter = 0.8,0.8 +inherits = *fdm_a250_dual* + +[printer:Snapmaker A350 Dual (0.2 nozzle)] +name = Snapmaker A350 Dual (0.2 nozzle) +printer_model = Snapmaker A350 Dual +default_print_profile = 0.14 Standard @Snapmaker (0.2 nozzle) +printer_variant = 0.2 +max_layer_height = 0.14 +min_layer_height = 0.06 +nozzle_diameter = 0.2,0.2 +inherits = *fdm_a350_dual* + +[printer:Snapmaker A350 Dual (0.4 nozzle)] +name = Snapmaker A350 Dual (0.4 nozzle) +printer_model = Snapmaker A350 Dual +default_print_profile = 0.16 Optimal @Snapmaker (0.4 nozzle) +printer_variant = 0.4 +max_layer_height = 0.28 +min_layer_height = 0.08 +nozzle_diameter = 0.4,0.4 +inherits = *fdm_a350_dual* + +[printer:Snapmaker A350 Dual (0.6 nozzle)] +name = Snapmaker A350 Dual (0.6 nozzle) +printer_model = Snapmaker A350 Dual +default_print_profile = 0.18 Standard @Snapmaker (0.6 nozzle) +printer_variant = 0.6 +max_layer_height = 0.42 +min_layer_height = 0.18 +nozzle_diameter = 0.6,0.6 +inherits = *fdm_a350_dual* + +[printer:Snapmaker A350 Dual (0.8 nozzle)] +name = Snapmaker A350 Dual (0.8 nozzle) +printer_model = Snapmaker A350 Dual +default_print_profile = 0.24 Standard @Snapmaker (0.8 nozzle) +printer_variant = 0.8 +max_layer_height = 0.48 +min_layer_height = 0.24 +nozzle_diameter = 0.8,0.8 +inherits = *fdm_a350_dual* + +[printer:Snapmaker A250 QSKit (0.2 nozzle)] +name = Snapmaker A250 QSKit (0.2 nozzle) +printer_model = Snapmaker A250 QSKit +default_print_profile = 0.14 Standard @Snapmaker (0.2 nozzle) +printer_variant = 0.2 +max_layer_height = 0.14 +min_layer_height = 0.06 +nozzle_diameter = 0.2 +inherits = *fdm_a250_qs* + +[printer:Snapmaker A250 QSKit (0.4 nozzle)] +name = Snapmaker A250 QSKit (0.4 nozzle) +printer_model = Snapmaker A250 QSKit +default_print_profile = 0.16 Optimal @Snapmaker (0.4 nozzle) +printer_variant = 0.4 +max_layer_height = 0.28 +min_layer_height = 0.08 +nozzle_diameter = 0.4 +inherits = *fdm_a250_qs* + +[printer:Snapmaker A250 QSKit (0.6 nozzle)] +name = Snapmaker A250 QSKit (0.6 nozzle) +printer_model = Snapmaker A250 QSKit +default_print_profile = 0.18 Standard @Snapmaker (0.6 nozzle) +printer_variant = 0.6 +max_layer_height = 0.42 +min_layer_height = 0.18 +nozzle_diameter = 0.6 +inherits = *fdm_a250_qs* + +[printer:Snapmaker A250 QSKit (0.8 nozzle)] +name = Snapmaker A250 QSKit (0.8 nozzle) +printer_model = Snapmaker A250 QSKit +default_print_profile = 0.24 Standard @Snapmaker (0.8 nozzle) +printer_variant = 0.8 +max_layer_height = 0.48 +min_layer_height = 0.24 +nozzle_diameter = 0.8 +inherits = *fdm_a250_qs* + +[printer:Snapmaker A350 QSKit (0.2 nozzle)] +name = Snapmaker A350 QSKit (0.2 nozzle) +printer_model = Snapmaker A350 QSKit +default_print_profile = 0.14 Standard @Snapmaker (0.2 nozzle) +printer_variant = 0.2 +max_layer_height = 0.14 +min_layer_height = 0.06 +nozzle_diameter = 0.2 +inherits = *fdm_a350_qs* + +[printer:Snapmaker A350 QSKit (0.4 nozzle)] +name = Snapmaker A350 QSKit (0.4 nozzle) +printer_model = Snapmaker A350 QSKit +default_print_profile = 0.16 Optimal @Snapmaker (0.4 nozzle) +printer_variant = 0.4 +max_layer_height = 0.28 +min_layer_height = 0.08 +nozzle_diameter = 0.4 +inherits = *fdm_a350_qs* + +[printer:Snapmaker A350 QSKit (0.6 nozzle)] +name = Snapmaker A350 QSKit (0.6 nozzle) +printer_model = Snapmaker A350 QSKit +default_print_profile = 0.18 Standard @Snapmaker (0.6 nozzle) +printer_variant = 0.6 +max_layer_height = 0.42 +min_layer_height = 0.18 +nozzle_diameter = 0.6 +inherits = *fdm_a350_qs* + +[printer:Snapmaker A350 QSKit (0.8 nozzle)] +name = Snapmaker A350 QSKit (0.8 nozzle) +printer_model = Snapmaker A350 QSKit +default_print_profile = 0.24 Standard @Snapmaker (0.8 nozzle) +printer_variant = 0.8 +max_layer_height = 0.48 +min_layer_height = 0.24 +nozzle_diameter = 0.8 +inherits = *fdm_a350_qs* + +[printer:Snapmaker A250 Dual QSKit (0.2 nozzle)] +name = Snapmaker A250 Dual QSKit (0.2 nozzle) +printer_model = Snapmaker A250 Dual QSKit +default_print_profile = 0.14 Standard @Snapmaker (0.2 nozzle) +printer_variant = 0.2 +max_layer_height = 0.14 +min_layer_height = 0.06 +nozzle_diameter = 0.2,0.2 +inherits = *fdm_a250_dual_qs* + +[printer:Snapmaker A250 Dual QSKit (0.4 nozzle)] +name = Snapmaker A250 Dual QSKit (0.4 nozzle) +printer_model = Snapmaker A250 Dual QSKit +default_print_profile = 0.16 Optimal @Snapmaker (0.4 nozzle) +printer_variant = 0.4 +max_layer_height = 0.28 +min_layer_height = 0.08 +nozzle_diameter = 0.4,0.4 +inherits = *fdm_a250_dual_qs* + +[printer:Snapmaker A250 Dual QSKit (0.6 nozzle)] +name = Snapmaker A250 Dual QSKit (0.6 nozzle) +printer_model = Snapmaker A250 Dual QSKit +default_print_profile = 0.18 Standard @Snapmaker (0.6 nozzle) +printer_variant = 0.6 +max_layer_height = 0.42 +min_layer_height = 0.18 +nozzle_diameter = 0.6,0.6 +inherits = *fdm_a250_dual_qs* + +[printer:Snapmaker A250 Dual QSKit (0.8 nozzle)] +name = Snapmaker A250 Dual QSKit (0.8 nozzle) +printer_model = Snapmaker A250 Dual QSKit +default_print_profile = 0.24 Standard @Snapmaker (0.8 nozzle) +printer_variant = 0.8 +max_layer_height = 0.48 +min_layer_height = 0.24 +nozzle_diameter = 0.8,0.8 +inherits = *fdm_a250_dual_qs* + +[printer:Snapmaker A350 Dual QSKit (0.2 nozzle)] +name = Snapmaker A350 Dual QSKit (0.2 nozzle) +printer_model = Snapmaker A350 Dual QSKit +default_print_profile = 0.14 Standard @Snapmaker (0.2 nozzle) +printer_variant = 0.2 +max_layer_height = 0.14 +min_layer_height = 0.06 +nozzle_diameter = 0.2,0.2 +inherits = *fdm_a350_dual_qs* + +[printer:Snapmaker A350 Dual QSKit (0.4 nozzle)] +name = Snapmaker A350 Dual QSKit (0.4 nozzle) +printer_model = Snapmaker A350 Dual QSKit +default_print_profile = 0.16 Optimal @Snapmaker (0.4 nozzle) +printer_variant = 0.4 +max_layer_height = 0.28 +min_layer_height = 0.08 +nozzle_diameter = 0.4,0.4 +inherits = *fdm_a350_dual_qs* + +[printer:Snapmaker A350 Dual QSKit (0.6 nozzle)] +name = Snapmaker A350 Dual QSKit (0.6 nozzle) +printer_model = Snapmaker A350 Dual QSKit +default_print_profile = 0.18 Standard @Snapmaker (0.6 nozzle) +printer_variant = 0.6 +max_layer_height = 0.42 +min_layer_height = 0.18 +nozzle_diameter = 0.6,0.6 +inherits = *fdm_a350_dual_qs* + +[printer:Snapmaker A350 Dual QSKit (0.8 nozzle)] +name = Snapmaker A350 Dual QSKit (0.8 nozzle) +printer_model = Snapmaker A350 Dual QSKit +default_print_profile = 0.24 Standard @Snapmaker (0.8 nozzle) +printer_variant = 0.8 +max_layer_height = 0.48 +min_layer_height = 0.24 +nozzle_diameter = 0.8,0.8 +inherits = *fdm_a350_dual_qs* + From 9a3c831020a3b836f32e3e655efc8a9c9ad1f4dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hejl?= Date: Tue, 2 Jan 2024 13:19:02 +0100 Subject: [PATCH 06/91] SPE-2075: Fixed crash during thumbnail generation for SLA printers. --- src/slic3r/GUI/GLCanvas3D.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 28f55f5b3b..bba3c602fa 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -4905,8 +4905,9 @@ void GLCanvas3D::_render_thumbnail_internal(ThumbnailData& thumbnail_data, const camera.apply_projection(volumes_box, near_z, far_z); - const ModelObjectPtrs &model_objects = GUI::wxGetApp().model().objects; - std::vector extruders_colors = get_extruders_colors(); + const ModelObjectPtrs &model_objects = GUI::wxGetApp().model().objects; + std::vector extruders_colors = get_extruders_colors(); + const bool is_enabled_painted_thumbnail = !model_objects.empty() && !extruders_colors.empty(); if (thumbnail_params.transparent_background) glsafe(::glClearColor(0.0f, 0.0f, 0.0f, 0.0f)); @@ -4921,8 +4922,7 @@ void GLCanvas3D::_render_thumbnail_internal(ThumbnailData& thumbnail_data, const for (GLVolume *vol : visible_volumes) { const int obj_idx = vol->object_idx(); const int vol_idx = vol->volume_idx(); - const bool render_as_painted = (obj_idx >= 0 && vol_idx >= 0) ? - !model_objects[obj_idx]->volumes[vol_idx]->mmu_segmentation_facets.empty() : false; + const bool render_as_painted = is_enabled_painted_thumbnail && obj_idx >= 0 && vol_idx >= 0 && !model_objects[obj_idx]->volumes[vol_idx]->mmu_segmentation_facets.empty(); GLShaderProgram* shader = wxGetApp().get_shader(render_as_painted ? "mm_gouraud" : "gouraud_light"); if (shader == nullptr) continue; @@ -4955,7 +4955,7 @@ void GLCanvas3D::_render_thumbnail_internal(ThumbnailData& thumbnail_data, const glsafe(::glFrontFace(GL_CW)); if (render_as_painted) { - const ModelVolume& model_volume = *model_objects[obj_idx]->volumes[vol_idx]; + const ModelVolume& model_volume = *model_objects[obj_idx]->volumes[vol_idx]; const size_t extruder_idx = get_extruder_color_idx(model_volume, extruders_count); TriangleSelectorMmGui ts(model_volume.mesh(), extruders_colors, extruders_colors[extruder_idx]); ts.deserialize(model_volume.mmu_segmentation_facets.get_data(), true); From b82aa37bf566dd1872cc350b69f7f7aaca393374 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Tue, 2 Jan 2024 16:01:14 +0100 Subject: [PATCH 07/91] Fixed build when building without GUI --- src/PrusaSlicer.cpp | 23 +++++++++++++++++------ tests/CMakeLists.txt | 7 ++++++- 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/src/PrusaSlicer.cpp b/src/PrusaSlicer.cpp index 1517729ba0..a07256fd7b 100644 --- a/src/PrusaSlicer.cpp +++ b/src/PrusaSlicer.cpp @@ -130,12 +130,6 @@ int CLI::run(int argc, char **argv) // On Unix systems, the prusa-slicer binary may be symlinked to give the application a different meaning. boost::algorithm::iends_with(boost::filesystem::path(argv[0]).filename().string(), "gcodeviewer"); #endif // _WIN32 -#if ENABLE_GL_CORE_PROFILE - std::pair opengl_version = { 0, 0 }; -#if ENABLE_OPENGL_DEBUG_OPTION - bool opengl_debug = false; -#endif // ENABLE_OPENGL_DEBUG_OPTION -#endif // ENABLE_GL_CORE_PROFILE const std::vector &load_configs = m_config.option("load", true)->values; const ForwardCompatibilitySubstitutionRule config_substitution_rule = m_config.option>("config_compatibility", true)->value; @@ -174,7 +168,13 @@ int CLI::run(int argc, char **argv) m_print_config.apply(config); } +#ifdef SLIC3R_GUI #if ENABLE_GL_CORE_PROFILE + std::pair opengl_version = { 0, 0 }; +#if ENABLE_OPENGL_DEBUG_OPTION + bool opengl_debug = false; +#endif // ENABLE_OPENGL_DEBUG_OPTION + // search for special keys into command line parameters auto it = std::find(m_actions.begin(), m_actions.end(), "gcodeviewer"); if (it != m_actions.end()) { @@ -222,6 +222,17 @@ int CLI::run(int argc, char **argv) } } #endif // ENABLE_GL_CORE_PROFILE +#else // SLIC3R_GUI + // If there is no GUI, we shall ignore the parameters. Remove them from the list. + for (const std::string& s : { "opengl-version", "opengl-debug", "gcodeviewer" }) { + auto it = std::find(m_actions.cbegin(), m_actions.cend(), s); + if (it != m_actions.end()) { + boost::nowide::cerr << "Parameter '" << s << "' is ignored, this PrusaSlicer build is CLI only." << std::endl; + m_actions.erase(it); + } + } +#endif + // Read input file(s) if any. for (const std::string& file : m_input_files) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index f00a2eb7ee..82027558cc 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -24,8 +24,13 @@ set_property(GLOBAL PROPERTY USE_FOLDERS ON) add_subdirectory(arrange) add_subdirectory(thumbnails) add_subdirectory(libslic3r) -add_subdirectory(slic3rutils) add_subdirectory(fff_print) add_subdirectory(sla_print) add_subdirectory(cpp17 EXCLUDE_FROM_ALL) # does not have to be built all the time + +if (SLIC3R_GUI) + add_subdirectory(slic3rutils) +endif() + + # add_subdirectory(example) From 1cb156c815e138d3fb23718bcec75872949fd215 Mon Sep 17 00:00:00 2001 From: Filip Sykala - NTB T15p Date: Wed, 3 Jan 2024 08:47:11 +0100 Subject: [PATCH 08/91] Apply rotation angle given by style for new text object Turn off feature 'use_surface' for new text object --- src/slic3r/GUI/Jobs/EmbossJob.cpp | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/Jobs/EmbossJob.cpp b/src/slic3r/GUI/Jobs/EmbossJob.cpp index 2bd85054ba..32b0effbd7 100644 --- a/src/slic3r/GUI/Jobs/EmbossJob.cpp +++ b/src/slic3r/GUI/Jobs/EmbossJob.cpp @@ -102,6 +102,9 @@ struct DataCreateObject // Define which gizmo open on the success GLGizmosManager::EType gizmo; + + // additionl rotation around Z axe, given by style settings + std::optional angle = {}; }; ///

@@ -330,6 +333,12 @@ void CreateObjectJob::process(Ctl &ctl) offset -= m_result.center(); Transform3d::TranslationType tt(offset.x(), offset.y(), offset.z()); m_transformation = Transform3d(tt); + + // rotate around Z by style settings + if (m_input.angle.has_value()) { + std::optional distance; // new object ignore surface distance from style settings + apply_transformation(m_input.angle, distance, m_transformation); + } } void CreateObjectJob::finalize(bool canceled, std::exception_ptr &eptr) @@ -1485,8 +1494,14 @@ bool start_create_object_job(const CreateVolumeParams &input, DataBasePtr emboss { const Pointfs &bed_shape = input.build_volume.bed_shape(); auto gizmo_type = static_cast(input.gizmo); - DataCreateObject data{std::move(emboss_data), coor, input.camera, bed_shape, gizmo_type}; - auto job = std::make_unique(std::move(data)); + DataCreateObject data{std::move(emboss_data), coor, input.camera, bed_shape, gizmo_type, input.angle}; + + // Fix: adding text on print bed with style containing use_surface + if (data.base->shape.projection.use_surface) + // Til the print bed is flat using surface for Object is useless + data.base->shape.projection.use_surface = false; + + auto job = std::make_unique(std::move(data)); return queue_job(input.worker, std::move(job)); } From 285cb02d74bcc63c850c5ebf73167c495b33360c Mon Sep 17 00:00:00 2001 From: rtyr <36745189+rtyr@users.noreply.github.com> Date: Wed, 3 Jan 2024 14:10:25 +0100 Subject: [PATCH 09/91] Fixed overhang speeds. Fixed branch diameter angle for organic supports. --- resources/profiles/Snapmaker.idx | 1 + resources/profiles/Snapmaker.ini | 497 +++++++++++++++---------------- 2 files changed, 248 insertions(+), 250 deletions(-) diff --git a/resources/profiles/Snapmaker.idx b/resources/profiles/Snapmaker.idx index 089ae26861..12c79a6ba8 100644 --- a/resources/profiles/Snapmaker.idx +++ b/resources/profiles/Snapmaker.idx @@ -1,4 +1,5 @@ min_slic3r_version = 2.6.0 +1.1.1 Fixed overhang speeds. Fixed branch diameter angle for organic supports. 1.1.0 Add more Snapmaker printers. min_slic3r_version = 2.4.1 1.0.1 Fix for leading zeroes. diff --git a/resources/profiles/Snapmaker.ini b/resources/profiles/Snapmaker.ini index 33d8991287..22ab6602d0 100644 --- a/resources/profiles/Snapmaker.ini +++ b/resources/profiles/Snapmaker.ini @@ -1,8 +1,8 @@ # Author: https://github.com/macdylan -# Update: 2023/12/15 +# Update: 2024/01/03 [vendor] name = Snapmaker -config_version = 1.1.0 +config_version = 1.1.1 config_update_url = https://files.prusa3d.com/wp-content/uploads/repository/PrusaSlicer-settings-master/live/Snapmaker/ [printer_model:Snapmaker J1] @@ -96,7 +96,6 @@ wipe_speed = 80% wipe_on_loops = 1 slice_closing_radius = 0.049 resolution = 0.012 -arc_fitting = disabled xy_contour_compensation = 0 elefant_foot_compensation = 0.1 precise_outer_wall = 1 @@ -188,6 +187,7 @@ timelapse_type = 0 single_extruder_multi_material_priming = 0 gap_fill_enabled = 0 first_layer_height = 0.3 +arc_fitting = disabled perimeters = 3 top_solid_layers = 4 top_solid_min_thickness = 0.8 @@ -220,10 +220,10 @@ gap_fill_speed = 100 support_material_speed = 80 support_material_interface_speed = 50 enable_dynamic_overhang_speeds = 1 -overhang_speed_0 = 35 -overhang_speed_1 = 25 -overhang_speed_2 = 15 -overhang_speed_3 = 10 +overhang_speed_3 = 35 +overhang_speed_2 = 25 +overhang_speed_1 = 15 +overhang_speed_0 = 10 external_perimeter_acceleration = 1000 perimeter_acceleration = 2000 infill_acceleration = 2000 @@ -246,7 +246,7 @@ support_material_interface_pattern = auto support_material_interface_spacing = 0.12 support_tree_branch_distance = 5 support_tree_branch_diameter = 5 -support_tree_branch_diameter_angle = 30 +support_tree_branch_diameter_angle = 15 dont_support_bridges = 1 skirts = 0 brim_separation = 0.1 @@ -259,7 +259,6 @@ output_filename_format = {input_filename_base}_{layer_height}mm_{print_time}.gco [print:*fdm_process_idex*] inherits = *fdm_process_common* -arc_fitting = emit_center initial_layer_infill_speed = 75 ironing_speed = 30 travel_speed = 350 @@ -277,6 +276,7 @@ brim_type = no_brim small_perimeter_threshold = 0 support_material_synchronize_layers = 1 first_layer_height = 0.2 +arc_fitting = emit_center perimeters = 3 top_solid_layers = 4 top_solid_min_thickness = 0.8 @@ -309,12 +309,12 @@ gap_fill_speed = 150 support_material_speed = 100 support_material_interface_speed = 50 enable_dynamic_overhang_speeds = 1 -overhang_speed_0 = 35 -overhang_speed_1 = 25 -overhang_speed_2 = 15 -overhang_speed_3 = 10 -external_perimeter_acceleration = 5000 -perimeter_acceleration = 10000 +overhang_speed_3 = 35 +overhang_speed_2 = 25 +overhang_speed_1 = 15 +overhang_speed_0 = 10 +external_perimeter_acceleration = 2500 +perimeter_acceleration = 5000 infill_acceleration = 10000 solid_infill_acceleration = 10000 first_layer_acceleration = 500 @@ -335,7 +335,7 @@ support_material_interface_pattern = rectilinear support_material_interface_spacing = 0.12 support_tree_branch_distance = 5 support_tree_branch_diameter = 5 -support_tree_branch_diameter_angle = 30 +support_tree_branch_diameter_angle = 15 dont_support_bridges = 1 skirts = 0 brim_separation = 0.1 @@ -348,7 +348,7 @@ output_filename_format = {input_filename_base}_{layer_height}mm_{print_time}_J1. [print:0.06 Standard @Snapmaker (0.2 nozzle)] inherits = *fdm_process_common* -compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350 QSKit" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A250 Dual") and (nozzle_diameter[0]=="0.2") +compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A250 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A350 QSKit") and (nozzle_diameter[0]=="0.2") layer_height = 0.06 ironing_speed = 30 travel_speed = 110 @@ -372,10 +372,10 @@ solid_infill_speed = 120 gap_fill_speed = 85 support_material_speed = 100 support_material_interface_speed = 40 -overhang_speed_0 = 60 -overhang_speed_1 = 30 -overhang_speed_2 = 10 -overhang_speed_3 = 10 +overhang_speed_3 = 60 +overhang_speed_2 = 30 +overhang_speed_1 = 10 +overhang_speed_0 = 10 [print:0.06 Standard @Snapmaker J1 (0.2 nozzle)] inherits = *fdm_process_idex* @@ -402,13 +402,13 @@ solid_infill_speed = 200 top_solid_infill_speed = 150 gap_fill_speed = 120 support_material_interface_speed = 40 -overhang_speed_0 = 60 -overhang_speed_1 = 30 -overhang_speed_2 = 10 +overhang_speed_3 = 60 +overhang_speed_2 = 30 +overhang_speed_1 = 10 [print:0.08 Extra Fine @Snapmaker (0.4 nozzle)] inherits = *fdm_process_common* -compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350 QSKit" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A250 Dual") and (nozzle_diameter[0]=="0.4") +compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A250 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A350 QSKit") and (nozzle_diameter[0]=="0.4") elefant_foot_compensation = 0.15 layer_height = 0.08 initial_layer_infill_speed = 65 @@ -428,10 +428,10 @@ top_solid_infill_speed = 70 gap_fill_speed = 85 support_material_speed = 100 support_material_interface_speed = 50 -overhang_speed_0 = 55 -overhang_speed_1 = 30 -overhang_speed_2 = 10 -overhang_speed_3 = 10 +overhang_speed_3 = 55 +overhang_speed_2 = 30 +overhang_speed_1 = 10 +overhang_speed_0 = 10 support_material_threshold = 15 [print:0.08 Extra Fine @Snapmaker J1 (0.4 nozzle)] @@ -449,14 +449,14 @@ perimeter_speed = 230 infill_speed = 120 solid_infill_speed = 230 gap_fill_speed = 160 -overhang_speed_0 = 60 -overhang_speed_1 = 30 -overhang_speed_2 = 10 +overhang_speed_3 = 60 +overhang_speed_2 = 30 +overhang_speed_1 = 10 support_material_threshold = 15 [print:0.10 Standard @Snapmaker (0.2 nozzle)] inherits = *fdm_process_common* -compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350 QSKit" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A250 Dual") and (nozzle_diameter[0]=="0.2") +compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A250 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A350 QSKit") and (nozzle_diameter[0]=="0.2") layer_height = 0.1 initial_layer_infill_speed = 70 ironing_speed = 30 @@ -483,10 +483,10 @@ top_solid_infill_speed = 100 gap_fill_speed = 85 support_material_speed = 100 support_material_interface_speed = 40 -overhang_speed_0 = 60 -overhang_speed_1 = 30 -overhang_speed_2 = 10 -overhang_speed_3 = 10 +overhang_speed_3 = 60 +overhang_speed_2 = 30 +overhang_speed_1 = 10 +overhang_speed_0 = 10 [print:0.10 Standard @Snapmaker J1 (0.2 nozzle)] inherits = *fdm_process_idex* @@ -513,13 +513,13 @@ solid_infill_speed = 200 top_solid_infill_speed = 150 gap_fill_speed = 120 support_material_interface_speed = 40 -overhang_speed_0 = 60 -overhang_speed_1 = 30 -overhang_speed_2 = 10 +overhang_speed_3 = 60 +overhang_speed_2 = 30 +overhang_speed_1 = 10 [print:0.12 Fine @Snapmaker (0.4 nozzle)] inherits = *fdm_process_common* -compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350 QSKit" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A250 Dual") and (nozzle_diameter[0]=="0.4") +compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A250 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A350 QSKit") and (nozzle_diameter[0]=="0.4") layer_height = 0.12 elefant_foot_compensation = 0.15 initial_layer_infill_speed = 65 @@ -538,10 +538,10 @@ top_solid_infill_speed = 70 gap_fill_speed = 85 support_material_speed = 100 support_material_interface_speed = 50 -overhang_speed_0 = 55 -overhang_speed_1 = 30 -overhang_speed_2 = 10 -overhang_speed_3 = 10 +overhang_speed_3 = 55 +overhang_speed_2 = 30 +overhang_speed_1 = 10 +overhang_speed_0 = 10 support_material_threshold = 20 [print:0.12 Fine @Snapmaker J1 (0.4 nozzle)] @@ -559,14 +559,14 @@ infill_speed = 120 solid_infill_speed = 230 top_solid_infill_speed = 120 gap_fill_speed = 160 -overhang_speed_0 = 60 -overhang_speed_1 = 30 -overhang_speed_2 = 10 +overhang_speed_3 = 60 +overhang_speed_2 = 30 +overhang_speed_1 = 10 support_material_threshold = 20 [print:0.14 Standard @Snapmaker (0.2 nozzle)] inherits = *fdm_process_common* -compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350 QSKit" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A250 Dual") and (nozzle_diameter[0]=="0.2") +compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A250 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A350 QSKit") and (nozzle_diameter[0]=="0.2") layer_height = 0.14 initial_layer_infill_speed = 70 ironing_speed = 30 @@ -592,10 +592,10 @@ top_solid_infill_speed = 100 gap_fill_speed = 85 support_material_speed = 100 support_material_interface_speed = 40 -overhang_speed_0 = 60 -overhang_speed_1 = 30 -overhang_speed_2 = 10 -overhang_speed_3 = 10 +overhang_speed_3 = 60 +overhang_speed_2 = 30 +overhang_speed_1 = 10 +overhang_speed_0 = 10 [print:0.14 Standard @Snapmaker J1 (0.2 nozzle)] inherits = *fdm_process_idex* @@ -621,13 +621,13 @@ solid_infill_speed = 200 top_solid_infill_speed = 150 gap_fill_speed = 120 support_material_interface_speed = 40 -overhang_speed_0 = 60 -overhang_speed_1 = 30 -overhang_speed_2 = 10 +overhang_speed_3 = 60 +overhang_speed_2 = 30 +overhang_speed_1 = 10 [print:0.16 Optimal @Snapmaker (0.4 nozzle)] inherits = *fdm_process_common* -compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350 QSKit" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A250 Dual") and (nozzle_diameter[0]=="0.4") +compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A250 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A350 QSKit") and (nozzle_diameter[0]=="0.4") layer_height = 0.16 elefant_foot_compensation = 0.15 initial_layer_infill_speed = 65 @@ -645,10 +645,10 @@ infill_speed = 95 top_solid_infill_speed = 70 gap_fill_speed = 85 support_material_speed = 100 -overhang_speed_0 = 55 -overhang_speed_1 = 30 -overhang_speed_2 = 10 -overhang_speed_3 = 10 +overhang_speed_3 = 55 +overhang_speed_2 = 30 +overhang_speed_1 = 10 +overhang_speed_0 = 10 support_material_threshold = 25 [print:0.16 Optimal @Snapmaker J1 (0.4 nozzle)] @@ -666,14 +666,14 @@ infill_speed = 140 solid_infill_speed = 200 top_solid_infill_speed = 80 gap_fill_speed = 160 -overhang_speed_0 = 60 -overhang_speed_1 = 30 -overhang_speed_2 = 10 +overhang_speed_3 = 60 +overhang_speed_2 = 30 +overhang_speed_1 = 10 support_material_threshold = 25 [print:0.18 Standard @Snapmaker (0.6 nozzle)] inherits = *fdm_process_common* -compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350 QSKit" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A250 Dual") and (nozzle_diameter[0]=="0.6") +compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A250 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A350 QSKit") and (nozzle_diameter[0]=="0.6") layer_height = 0.18 initial_layer_infill_speed = 55 ironing_speed = 30 @@ -698,10 +698,10 @@ top_solid_infill_speed = 100 gap_fill_speed = 50 support_material_speed = 100 support_material_interface_speed = 35 -overhang_speed_0 = 0 -overhang_speed_1 = 50 -overhang_speed_2 = 15 -overhang_speed_3 = 10 +overhang_speed_3 = 0 +overhang_speed_2 = 50 +overhang_speed_1 = 15 +overhang_speed_0 = 10 [print:0.18 Standard @Snapmaker J1 (0.6 nozzle)] inherits = *fdm_process_idex* @@ -726,12 +726,12 @@ solid_infill_speed = 150 top_solid_infill_speed = 150 gap_fill_speed = 50 support_material_interface_speed = 35 -overhang_speed_0 = 0 -overhang_speed_1 = 50 +overhang_speed_3 = 0 +overhang_speed_2 = 50 [print:0.20 Standard @Snapmaker (0.4 nozzle)] inherits = *fdm_process_common* -compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350 QSKit" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A250 Dual") and (nozzle_diameter[0]=="0.4") +compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A250 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A350 QSKit") and (nozzle_diameter[0]=="0.4") elefant_foot_compensation = 0.15 initial_layer_infill_speed = 60 ironing_speed = 30 @@ -746,10 +746,10 @@ top_solid_infill_speed = 70 gap_fill_speed = 85 support_material_speed = 100 enable_dynamic_overhang_speeds = 1 -overhang_speed_0 = 40 -overhang_speed_1 = 20 -overhang_speed_2 = 10 -overhang_speed_3 = 10 +overhang_speed_3 = 40 +overhang_speed_2 = 20 +overhang_speed_1 = 10 +overhang_speed_0 = 10 [print:0.20 Standard @Snapmaker J1 (0.4 nozzle)] inherits = *fdm_process_idex* @@ -761,13 +761,13 @@ infill_speed = 300 solid_infill_speed = 240 top_solid_infill_speed = 140 gap_fill_speed = 240 -overhang_speed_0 = 60 -overhang_speed_1 = 30 -overhang_speed_2 = 10 +overhang_speed_3 = 60 +overhang_speed_2 = 30 +overhang_speed_1 = 10 [print:0.20 Strength @Snapmaker (0.4 nozzle)] inherits = *fdm_process_common* -compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350 QSKit" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A250 Dual") and (nozzle_diameter[0]=="0.4") +compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A250 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A350 QSKit") and (nozzle_diameter[0]=="0.4") elefant_foot_compensation = 0.15 initial_layer_infill_speed = 65 infill_wall_overlap = 25% @@ -785,10 +785,10 @@ top_solid_infill_speed = 70 gap_fill_speed = 85 support_material_speed = 100 support_material_interface_speed = 50 -overhang_speed_0 = 55 -overhang_speed_1 = 30 -overhang_speed_2 = 10 -overhang_speed_3 = 10 +overhang_speed_3 = 55 +overhang_speed_2 = 30 +overhang_speed_1 = 10 +overhang_speed_0 = 10 [print:0.20 Strength @Snapmaker J1 (0.4 nozzle)] inherits = *fdm_process_idex* @@ -803,13 +803,13 @@ infill_speed = 160 solid_infill_speed = 200 top_solid_infill_speed = 120 gap_fill_speed = 160 -overhang_speed_0 = 60 -overhang_speed_1 = 30 -overhang_speed_2 = 10 +overhang_speed_3 = 60 +overhang_speed_2 = 30 +overhang_speed_1 = 10 [print:0.24 Draft @Snapmaker (0.4 nozzle)] inherits = *fdm_process_common* -compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350 QSKit" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A250 Dual") and (nozzle_diameter[0]=="0.4") +compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A250 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A350 QSKit") and (nozzle_diameter[0]=="0.4") layer_height = 0.24 elefant_foot_compensation = 0.15 initial_layer_infill_speed = 65 @@ -826,10 +826,10 @@ top_solid_infill_speed = 70 gap_fill_speed = 85 support_material_speed = 100 support_material_interface_speed = 50 -overhang_speed_0 = 55 -overhang_speed_1 = 30 -overhang_speed_2 = 10 -overhang_speed_3 = 10 +overhang_speed_3 = 55 +overhang_speed_2 = 30 +overhang_speed_1 = 10 +overhang_speed_0 = 10 support_material_threshold = 35 [print:0.24 Draft @Snapmaker J1 (0.4 nozzle)] @@ -846,9 +846,9 @@ infill_speed = 160 solid_infill_speed = 190 top_solid_infill_speed = 160 gap_fill_speed = 160 -overhang_speed_0 = 60 -overhang_speed_1 = 30 -overhang_speed_2 = 10 +overhang_speed_3 = 60 +overhang_speed_2 = 30 +overhang_speed_1 = 10 support_material_threshold = 35 [print:0.25 Benchy @Snapmaker J1 (0.4 nozzle)] @@ -860,9 +860,9 @@ ensure_vertical_shell_thickness = 0 seam_position = nearest only_one_wall_top = 1 only_one_wall_first_layer = 1 -resolution = 0.05 minimum_sparse_infill_area = 0 infill_combination = 1 +infill_direction = 90 bridge_acceleration = 3000 bridge_speed = 180 default_acceleration = 15000 @@ -870,18 +870,15 @@ small_perimeter_speed = 200 travel_acceleration = 28000 first_layer_height = 0.25 perimeters = 2 -top_solid_min_thickness = 0.5 +top_solid_layers = 3 +top_solid_min_thickness = 0.42 avoid_crossing_perimeters = 0 overhangs = 0 perimeter_generator = classic fill_density = 10% -extrusion_width = 0.5 -perimeter_extrusion_width = 0.5 -external_perimeter_extrusion_width = 0.5 -top_infill_extrusion_width = 0.5 -infill_extrusion_width = 0.5 -solid_infill_extrusion_width = 0.5 -support_material_extrusion_width = 0.5 +fill_pattern = alignedrectilinear +external_perimeter_extrusion_width = 0.42 +infill_extrusion_width = 0.42 external_perimeter_speed = 180 perimeter_speed = 280 infill_speed = 200 @@ -889,9 +886,9 @@ solid_infill_speed = 280 top_solid_infill_speed = 200 gap_fill_speed = 280 enable_dynamic_overhang_speeds = 0 -overhang_speed_0 = 150 -overhang_speed_1 = 20 -overhang_speed_2 = 10 +overhang_speed_3 = 150 +overhang_speed_2 = 20 +overhang_speed_1 = 10 external_perimeter_acceleration = 3000 perimeter_acceleration = 15000 infill_acceleration = 15000 @@ -901,7 +898,7 @@ output_filename_format = J1Benchy_{print_time}.gcode [print:0.24 Standard @Snapmaker (0.6 nozzle)] inherits = *fdm_process_common* -compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350 QSKit" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A250 Dual") and (nozzle_diameter[0]=="0.6") +compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A250 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A350 QSKit") and (nozzle_diameter[0]=="0.6") layer_height = 0.24 initial_layer_infill_speed = 55 ironing_speed = 30 @@ -924,10 +921,10 @@ top_solid_infill_speed = 100 gap_fill_speed = 50 support_material_speed = 100 support_material_interface_speed = 35 -overhang_speed_0 = 0 -overhang_speed_1 = 50 -overhang_speed_2 = 15 -overhang_speed_3 = 10 +overhang_speed_3 = 0 +overhang_speed_2 = 50 +overhang_speed_1 = 15 +overhang_speed_0 = 10 [print:0.24 Standard @Snapmaker J1 (0.6 nozzle)] inherits = *fdm_process_idex* @@ -952,12 +949,12 @@ solid_infill_speed = 150 top_solid_infill_speed = 150 gap_fill_speed = 50 support_material_interface_speed = 35 -overhang_speed_0 = 0 -overhang_speed_1 = 50 +overhang_speed_3 = 0 +overhang_speed_2 = 50 [print:0.24 Standard @Snapmaker (0.8 nozzle)] inherits = *fdm_process_common* -compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350 QSKit" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A250 Dual") and (nozzle_diameter[0]=="0.8") +compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A250 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A350 QSKit") and (nozzle_diameter[0]=="0.8") layer_height = 0.24 top_surface_pattern = monotonic initial_layer_infill_speed = 55 @@ -982,10 +979,10 @@ top_solid_infill_speed = 100 gap_fill_speed = 50 support_material_speed = 100 support_material_interface_speed = 35 -overhang_speed_0 = 0 -overhang_speed_1 = 50 -overhang_speed_2 = 25 -overhang_speed_3 = 5 +overhang_speed_3 = 0 +overhang_speed_2 = 50 +overhang_speed_1 = 25 +overhang_speed_0 = 5 [print:0.24 Standard @Snapmaker J1 (0.8 nozzle)] inherits = *fdm_process_idex* @@ -1012,14 +1009,14 @@ solid_infill_speed = 150 top_solid_infill_speed = 150 gap_fill_speed = 50 support_material_interface_speed = 35 -overhang_speed_0 = 0 -overhang_speed_1 = 50 -overhang_speed_2 = 25 -overhang_speed_3 = 5 +overhang_speed_3 = 0 +overhang_speed_2 = 50 +overhang_speed_1 = 25 +overhang_speed_0 = 5 [print:0.28 Extra Draft @Snapmaker (0.4 nozzle)] inherits = *fdm_process_common* -compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350 QSKit" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A250 Dual") and (nozzle_diameter[0]=="0.4") +compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A250 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A350 QSKit") and (nozzle_diameter[0]=="0.4") layer_height = 0.28 elefant_foot_compensation = 0.15 initial_layer_infill_speed = 65 @@ -1036,10 +1033,10 @@ top_solid_infill_speed = 70 gap_fill_speed = 85 support_material_speed = 100 support_material_interface_speed = 50 -overhang_speed_0 = 55 -overhang_speed_1 = 30 -overhang_speed_2 = 10 -overhang_speed_3 = 10 +overhang_speed_3 = 55 +overhang_speed_2 = 30 +overhang_speed_1 = 10 +overhang_speed_0 = 10 support_material_threshold = 40 [print:0.28 Extra Draft @Snapmaker J1 (0.4 nozzle)] @@ -1055,14 +1052,14 @@ perimeter_speed = 180 infill_speed = 160 top_solid_infill_speed = 150 gap_fill_speed = 160 -overhang_speed_0 = 60 -overhang_speed_1 = 30 -overhang_speed_2 = 10 +overhang_speed_3 = 60 +overhang_speed_2 = 30 +overhang_speed_1 = 10 support_material_threshold = 40 [print:0.30 Standard @Snapmaker (0.6 nozzle)] inherits = *fdm_process_common* -compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350 QSKit" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A250 Dual") and (nozzle_diameter[0]=="0.6") +compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A250 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A350 QSKit") and (nozzle_diameter[0]=="0.6") layer_height = 0.3 bridge_speed = 30 initial_layer_infill_speed = 55 @@ -1085,10 +1082,10 @@ top_solid_infill_speed = 100 gap_fill_speed = 50 support_material_speed = 100 support_material_interface_speed = 35 -overhang_speed_0 = 0 -overhang_speed_1 = 50 -overhang_speed_2 = 15 -overhang_speed_3 = 10 +overhang_speed_3 = 0 +overhang_speed_2 = 50 +overhang_speed_1 = 15 +overhang_speed_0 = 10 [print:0.30 Standard @Snapmaker J1 (0.6 nozzle)] inherits = *fdm_process_idex* @@ -1113,12 +1110,12 @@ solid_infill_speed = 150 top_solid_infill_speed = 150 gap_fill_speed = 50 support_material_interface_speed = 35 -overhang_speed_0 = 0 -overhang_speed_1 = 50 +overhang_speed_3 = 0 +overhang_speed_2 = 50 [print:0.30 Strength @Snapmaker (0.6 nozzle)] inherits = *fdm_process_common* -compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350 QSKit" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A250 Dual") and (nozzle_diameter[0]=="0.6") +compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A250 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A350 QSKit") and (nozzle_diameter[0]=="0.6") layer_height = 0.3 bridge_speed = 30 initial_layer_infill_speed = 55 @@ -1143,10 +1140,10 @@ top_solid_infill_speed = 100 gap_fill_speed = 50 support_material_speed = 100 support_material_interface_speed = 35 -overhang_speed_0 = 0 -overhang_speed_1 = 50 -overhang_speed_2 = 15 -overhang_speed_3 = 10 +overhang_speed_3 = 0 +overhang_speed_2 = 50 +overhang_speed_1 = 15 +overhang_speed_0 = 10 [print:0.30 Strength @Snapmaker J1 (0.6 nozzle)] inherits = *fdm_process_idex* @@ -1173,12 +1170,12 @@ solid_infill_speed = 150 top_solid_infill_speed = 150 gap_fill_speed = 50 support_material_interface_speed = 35 -overhang_speed_0 = 0 -overhang_speed_1 = 50 +overhang_speed_3 = 0 +overhang_speed_2 = 50 [print:0.32 Standard @Snapmaker (0.8 nozzle)] inherits = *fdm_process_common* -compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350 QSKit" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A250 Dual") and (nozzle_diameter[0]=="0.8") +compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A250 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A350 QSKit") and (nozzle_diameter[0]=="0.8") layer_height = 0.32 bridge_speed = 30 top_surface_pattern = monotonic @@ -1203,10 +1200,10 @@ top_solid_infill_speed = 100 gap_fill_speed = 50 support_material_speed = 100 support_material_interface_speed = 35 -overhang_speed_0 = 0 -overhang_speed_1 = 50 -overhang_speed_2 = 25 -overhang_speed_3 = 5 +overhang_speed_3 = 0 +overhang_speed_2 = 50 +overhang_speed_1 = 25 +overhang_speed_0 = 5 [print:0.32 Standard @Snapmaker J1 (0.8 nozzle)] inherits = *fdm_process_idex* @@ -1233,14 +1230,14 @@ solid_infill_speed = 150 top_solid_infill_speed = 150 gap_fill_speed = 50 support_material_interface_speed = 35 -overhang_speed_0 = 0 -overhang_speed_1 = 50 -overhang_speed_2 = 25 -overhang_speed_3 = 5 +overhang_speed_3 = 0 +overhang_speed_2 = 50 +overhang_speed_1 = 25 +overhang_speed_0 = 5 [print:0.34 Standard @Snapmaker (0.6 nozzle)] inherits = *fdm_process_common* -compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350 QSKit" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A250 Dual") and (nozzle_diameter[0]=="0.6") +compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A250 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A350 QSKit") and (nozzle_diameter[0]=="0.6") layer_height = 0.34 bridge_speed = 30 top_surface_pattern = monotonic @@ -1266,10 +1263,10 @@ top_solid_infill_speed = 100 gap_fill_speed = 50 support_material_speed = 100 support_material_interface_speed = 35 -overhang_speed_0 = 0 -overhang_speed_1 = 50 -overhang_speed_2 = 15 -overhang_speed_3 = 10 +overhang_speed_3 = 0 +overhang_speed_2 = 50 +overhang_speed_1 = 15 +overhang_speed_0 = 10 [print:0.34 Standard @Snapmaker J1 (0.6 nozzle)] inherits = *fdm_process_idex* @@ -1296,12 +1293,12 @@ solid_infill_speed = 150 top_solid_infill_speed = 150 gap_fill_speed = 50 support_material_interface_speed = 35 -overhang_speed_0 = 0 -overhang_speed_1 = 50 +overhang_speed_3 = 0 +overhang_speed_2 = 50 [print:0.36 Standard @Snapmaker (0.8 nozzle)] inherits = *fdm_process_common* -compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350 QSKit" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A250 Dual") and (nozzle_diameter[0]=="0.8") +compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A250 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A350 QSKit") and (nozzle_diameter[0]=="0.8") layer_height = 0.36 bridge_speed = 30 top_surface_pattern = monotonic @@ -1326,10 +1323,10 @@ top_solid_infill_speed = 100 gap_fill_speed = 50 support_material_speed = 100 support_material_interface_speed = 35 -overhang_speed_0 = 0 -overhang_speed_1 = 50 -overhang_speed_2 = 25 -overhang_speed_3 = 5 +overhang_speed_3 = 0 +overhang_speed_2 = 50 +overhang_speed_1 = 25 +overhang_speed_0 = 5 [print:0.36 Standard @Snapmaker J1 (0.8 nozzle)] inherits = *fdm_process_idex* @@ -1356,14 +1353,14 @@ solid_infill_speed = 150 top_solid_infill_speed = 150 gap_fill_speed = 50 support_material_interface_speed = 35 -overhang_speed_0 = 0 -overhang_speed_1 = 50 -overhang_speed_2 = 25 -overhang_speed_3 = 5 +overhang_speed_3 = 0 +overhang_speed_2 = 50 +overhang_speed_1 = 25 +overhang_speed_0 = 5 [print:0.38 Standard @Snapmaker (0.6 nozzle)] inherits = *fdm_process_common* -compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350 QSKit" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A250 Dual") and (nozzle_diameter[0]=="0.6") +compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A250 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A350 QSKit") and (nozzle_diameter[0]=="0.6") layer_height = 0.38 bridge_speed = 30 top_surface_pattern = monotonic @@ -1388,10 +1385,10 @@ top_solid_infill_speed = 100 gap_fill_speed = 50 support_material_speed = 100 support_material_interface_speed = 35 -overhang_speed_0 = 0 -overhang_speed_1 = 50 -overhang_speed_2 = 15 -overhang_speed_3 = 10 +overhang_speed_3 = 0 +overhang_speed_2 = 50 +overhang_speed_1 = 15 +overhang_speed_0 = 10 [print:0.38 Standard @Snapmaker J1 (0.6 nozzle)] inherits = *fdm_process_idex* @@ -1418,12 +1415,12 @@ solid_infill_speed = 150 top_solid_infill_speed = 150 gap_fill_speed = 50 support_material_interface_speed = 35 -overhang_speed_0 = 0 -overhang_speed_1 = 50 +overhang_speed_3 = 0 +overhang_speed_2 = 50 [print:0.40 Standard @Snapmaker (0.8 nozzle)] inherits = *fdm_process_common* -compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350 QSKit" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A250 Dual") and (nozzle_diameter[0]=="0.8") +compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A250 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A350 QSKit") and (nozzle_diameter[0]=="0.8") layer_height = 0.4 bridge_speed = 30 top_surface_pattern = monotonic @@ -1447,10 +1444,10 @@ top_solid_infill_speed = 100 gap_fill_speed = 50 support_material_speed = 100 support_material_interface_speed = 35 -overhang_speed_0 = 0 -overhang_speed_1 = 50 -overhang_speed_2 = 25 -overhang_speed_3 = 5 +overhang_speed_3 = 0 +overhang_speed_2 = 50 +overhang_speed_1 = 25 +overhang_speed_0 = 5 [print:0.40 Standard @Snapmaker J1 (0.8 nozzle)] inherits = *fdm_process_idex* @@ -1476,14 +1473,14 @@ solid_infill_speed = 150 top_solid_infill_speed = 150 gap_fill_speed = 50 support_material_interface_speed = 35 -overhang_speed_0 = 0 -overhang_speed_1 = 50 -overhang_speed_2 = 25 -overhang_speed_3 = 5 +overhang_speed_3 = 0 +overhang_speed_2 = 50 +overhang_speed_1 = 25 +overhang_speed_0 = 5 [print:0.42 Draft @Snapmaker (0.6 nozzle)] inherits = *fdm_process_common* -compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350 QSKit" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A250 Dual") and (nozzle_diameter[0]=="0.6") +compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A250 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A350 QSKit") and (nozzle_diameter[0]=="0.6") layer_height = 0.42 bridge_speed = 30 initial_layer_infill_speed = 55 @@ -1507,10 +1504,10 @@ top_solid_infill_speed = 100 gap_fill_speed = 50 support_material_speed = 100 support_material_interface_speed = 35 -overhang_speed_0 = 0 -overhang_speed_1 = 50 -overhang_speed_2 = 15 -overhang_speed_3 = 10 +overhang_speed_3 = 0 +overhang_speed_2 = 50 +overhang_speed_1 = 15 +overhang_speed_0 = 10 [print:0.42 Draft @Snapmaker J1 (0.6 nozzle)] inherits = *fdm_process_idex* @@ -1536,12 +1533,12 @@ solid_infill_speed = 150 top_solid_infill_speed = 150 gap_fill_speed = 50 support_material_interface_speed = 35 -overhang_speed_0 = 0 -overhang_speed_1 = 50 +overhang_speed_3 = 0 +overhang_speed_2 = 50 [print:0.48 Draft @Snapmaker (0.8 nozzle)] inherits = *fdm_process_common* -compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350 QSKit" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A250 Dual") and (nozzle_diameter[0]=="0.8") +compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A250 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A350 QSKit") and (nozzle_diameter[0]=="0.8") layer_height = 0.48 bridge_speed = 30 top_surface_pattern = monotonic @@ -1567,10 +1564,10 @@ top_solid_infill_speed = 100 gap_fill_speed = 50 support_material_speed = 100 support_material_interface_speed = 35 -overhang_speed_0 = 0 -overhang_speed_1 = 50 -overhang_speed_2 = 25 -overhang_speed_3 = 5 +overhang_speed_3 = 0 +overhang_speed_2 = 50 +overhang_speed_1 = 25 +overhang_speed_0 = 5 [print:0.48 Draft @Snapmaker J1 (0.8 nozzle)] inherits = *fdm_process_idex* @@ -1598,10 +1595,10 @@ solid_infill_speed = 150 top_solid_infill_speed = 150 gap_fill_speed = 50 support_material_interface_speed = 35 -overhang_speed_0 = 0 -overhang_speed_1 = 50 -overhang_speed_2 = 25 -overhang_speed_3 = 5 +overhang_speed_3 = 0 +overhang_speed_2 = 50 +overhang_speed_1 = 25 +overhang_speed_0 = 5 [filament:*fdm_filament_common*] filament_vendor = Snapmaker @@ -1625,7 +1622,7 @@ filament_unloading_speed = 25 filament_load_time = 0 filament_unload_time = 0 filament_toolchange_delay = 0 -filament_cooling_moves = 4 +filament_cooling_moves = 0 filament_cooling_initial_speed = 2.2 filament_cooling_final_speed = 3.4 filament_multitool_ramming = 0 @@ -1935,11 +1932,11 @@ inherits = *fdm_filament_abs* [filament:Snapmaker ABS] inherits = *Snapmaker ABS @base* -compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350 QSKit" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A250 Dual") and (nozzle_diameter[0]=="0.6" or nozzle_diameter[0]=="0.8" or nozzle_diameter[0]=="0.4") +compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A250 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A350 QSKit") and (nozzle_diameter[0]=="0.4" or nozzle_diameter[0]=="0.6" or nozzle_diameter[0]=="0.8") [filament:Snapmaker ABS @0.2 nozzle] inherits = *Snapmaker ABS @base* -compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350 QSKit" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A250 Dual") and (nozzle_diameter[0]=="0.2") +compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A250 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A350 QSKit") and (nozzle_diameter[0]=="0.2") filament_max_volumetric_speed = 2 [filament:*Snapmaker ASA @base*] @@ -1947,11 +1944,11 @@ inherits = *fdm_filament_asa* [filament:Snapmaker ASA] inherits = *Snapmaker ASA @base* -compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350 QSKit" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A250 Dual") and (nozzle_diameter[0]=="0.6" or nozzle_diameter[0]=="0.8" or nozzle_diameter[0]=="0.4") +compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A250 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A350 QSKit") and (nozzle_diameter[0]=="0.4" or nozzle_diameter[0]=="0.6" or nozzle_diameter[0]=="0.8") [filament:Snapmaker ASA @0.2 nozzle] inherits = *Snapmaker ASA @base* -compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350 QSKit" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A250 Dual") and (nozzle_diameter[0]=="0.2") +compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A250 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A350 QSKit") and (nozzle_diameter[0]=="0.2") filament_max_volumetric_speed = 2 [filament:*Snapmaker PA-CF @base*] @@ -1959,18 +1956,18 @@ inherits = *fdm_filament_pa* [filament:Snapmaker PA-CF] inherits = *Snapmaker PA-CF @base* -compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350 QSKit" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A250 Dual") and (nozzle_diameter[0]=="0.6" or nozzle_diameter[0]=="0.8" or nozzle_diameter[0]=="0.4") +compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A250 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A350 QSKit") and (nozzle_diameter[0]=="0.4" or nozzle_diameter[0]=="0.6" or nozzle_diameter[0]=="0.8") [filament:*Snapmaker PETG @base*] inherits = *fdm_filament_petg* [filament:Snapmaker PETG] inherits = *Snapmaker PETG @base* -compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350 QSKit" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A250 Dual") and (nozzle_diameter[0]=="0.6" or nozzle_diameter[0]=="0.8" or nozzle_diameter[0]=="0.4") +compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A250 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A350 QSKit") and (nozzle_diameter[0]=="0.4" or nozzle_diameter[0]=="0.6" or nozzle_diameter[0]=="0.8") [filament:Snapmaker PETG @0.2 nozzle] inherits = *Snapmaker PETG @base* -compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350 QSKit" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A250 Dual") and (nozzle_diameter[0]=="0.2") +compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A250 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A350 QSKit") and (nozzle_diameter[0]=="0.2") filament_max_volumetric_speed = 1 [filament:*Snapmaker PET @base*] @@ -1978,11 +1975,11 @@ inherits = *fdm_filament_pet* [filament:Snapmaker PET] inherits = *Snapmaker PET @base* -compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350 QSKit" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A250 Dual") and (nozzle_diameter[0]=="0.6" or nozzle_diameter[0]=="0.8" or nozzle_diameter[0]=="0.4") +compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A250 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A350 QSKit") and (nozzle_diameter[0]=="0.4" or nozzle_diameter[0]=="0.6" or nozzle_diameter[0]=="0.8") [filament:Snapmaker PET @Dual] inherits = *Snapmaker PET @base* -compatible_printers_condition = (printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A250 Dual") and (nozzle_diameter[0]=="0.6" or nozzle_diameter[0]=="0.8" or nozzle_diameter[0]=="0.4") +compatible_printers_condition = (printer_model=="Snapmaker A250 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A350 Dual QSKit") and (nozzle_diameter[0]=="0.4" or nozzle_diameter[0]=="0.6" or nozzle_diameter[0]=="0.8") min_fan_speed = 20 max_fan_speed = 55 bridge_fan_speed = 40 @@ -2006,21 +2003,21 @@ filament_colour = #3D3C39 [filament:Snapmaker PETG-CF] inherits = *Snapmaker PETG-CF @base* -compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350 QSKit" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A250 Dual") and (nozzle_diameter[0]=="0.6" or nozzle_diameter[0]=="0.8" or nozzle_diameter[0]=="0.4") +compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A250 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A350 QSKit") and (nozzle_diameter[0]=="0.4" or nozzle_diameter[0]=="0.6" or nozzle_diameter[0]=="0.8") [filament:*Snapmaker PLA Eco @base*] inherits = *fdm_filament_pla_eco* [filament:Snapmaker PLA Eco] inherits = *Snapmaker PLA Eco @base* -compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A250 Dual") and (nozzle_diameter[0]=="0.2" or nozzle_diameter[0]=="0.6" or nozzle_diameter[0]=="0.8" or nozzle_diameter[0]=="0.4") +compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A250 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A350 Dual QSKit") and (nozzle_diameter[0]=="0.2" or nozzle_diameter[0]=="0.4" or nozzle_diameter[0]=="0.6" or nozzle_diameter[0]=="0.8") [filament:*Snapmaker PLA @base*] inherits = *fdm_filament_pla* [filament:Snapmaker PLA] inherits = *Snapmaker PLA @base* -compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350 QSKit" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A250 Dual") and (nozzle_diameter[0]=="0.2" or nozzle_diameter[0]=="0.6" or nozzle_diameter[0]=="0.8" or nozzle_diameter[0]=="0.4") +compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A250 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A350 QSKit") and (nozzle_diameter[0]=="0.2" or nozzle_diameter[0]=="0.4" or nozzle_diameter[0]=="0.6" or nozzle_diameter[0]=="0.8") [filament:*Snapmaker PLA-CF @base*] inherits = *fdm_filament_pla* @@ -2034,7 +2031,7 @@ filament_colour = #3D3C39 [filament:Snapmaker PLA-CF] inherits = *Snapmaker PLA-CF @base* -compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350 QSKit" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A250 Dual") and (nozzle_diameter[0]=="0.6" or nozzle_diameter[0]=="0.8" or nozzle_diameter[0]=="0.4") +compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A250 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A350 QSKit") and (nozzle_diameter[0]=="0.4" or nozzle_diameter[0]=="0.6" or nozzle_diameter[0]=="0.8") [filament:*Snapmaker PLA Silk @base*] inherits = *fdm_filament_pla* @@ -2046,11 +2043,11 @@ filament_colour = #CF942B [filament:Snapmaker PLA Silk] inherits = *Snapmaker PLA Silk @base* -compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350 QSKit" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A250 Dual") and (nozzle_diameter[0]=="0.6" or nozzle_diameter[0]=="0.8" or nozzle_diameter[0]=="0.4") +compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A250 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A350 QSKit") and (nozzle_diameter[0]=="0.4" or nozzle_diameter[0]=="0.6" or nozzle_diameter[0]=="0.8") [filament:Snapmaker PLA Silk @0.2 nozzle] inherits = *Snapmaker PLA Silk @base* -compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350 QSKit" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A250 Dual") and (nozzle_diameter[0]=="0.2") +compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A250 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A350 QSKit") and (nozzle_diameter[0]=="0.2") filament_max_volumetric_speed = 2 [filament:*PolyLite PLA @base*] @@ -2062,11 +2059,11 @@ filament_colour = #8269AC [filament:PolyLite PLA] inherits = *PolyLite PLA @base* -compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350 QSKit" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A250 Dual") and (nozzle_diameter[0]=="0.6" or nozzle_diameter[0]=="0.8" or nozzle_diameter[0]=="0.4") +compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A250 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A350 QSKit") and (nozzle_diameter[0]=="0.4" or nozzle_diameter[0]=="0.6" or nozzle_diameter[0]=="0.8") [filament:PolyLite PLA @0.2 nozzle] inherits = *PolyLite PLA @base* -compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350 QSKit" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A250 Dual") and (nozzle_diameter[0]=="0.2") +compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A250 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A350 QSKit") and (nozzle_diameter[0]=="0.2") filament_max_volumetric_speed = 1 [filament:*PolyTerra PLA @base*] @@ -2078,11 +2075,11 @@ filament_colour = #73CEC8 [filament:PolyTerra PLA] inherits = *PolyTerra PLA @base* -compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350 QSKit" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A250 Dual") and (nozzle_diameter[0]=="0.6" or nozzle_diameter[0]=="0.8" or nozzle_diameter[0]=="0.4") +compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A250 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A350 QSKit") and (nozzle_diameter[0]=="0.4" or nozzle_diameter[0]=="0.6" or nozzle_diameter[0]=="0.8") [filament:PolyTerra PLA @0.2 nozzle] inherits = *PolyTerra PLA @base* -compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350 QSKit" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A250 Dual") and (nozzle_diameter[0]=="0.2") +compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A250 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A350 QSKit") and (nozzle_diameter[0]=="0.2") filament_max_volumetric_speed = 1 [filament:*Snapmaker PVA @base*] @@ -2090,11 +2087,11 @@ inherits = *fdm_filament_pva* [filament:Snapmaker PVA] inherits = *Snapmaker PVA @base* -compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350 QSKit" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A250 Dual") and (nozzle_diameter[0]=="0.6" or nozzle_diameter[0]=="0.8" or nozzle_diameter[0]=="0.4") +compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A250 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A350 QSKit") and (nozzle_diameter[0]=="0.4" or nozzle_diameter[0]=="0.6" or nozzle_diameter[0]=="0.8") [filament:Snapmaker PVA @0.2 nozzle] inherits = *Snapmaker PVA @base* -compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350 QSKit" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A250 Dual") and (nozzle_diameter[0]=="0.2") +compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A250 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A350 QSKit") and (nozzle_diameter[0]=="0.2") filament_max_volumetric_speed = 1.2 [filament:*Snapmaker TPU @base*] @@ -2102,11 +2099,11 @@ inherits = *fdm_filament_tpu* [filament:Snapmaker TPU] inherits = *Snapmaker TPU @base* -compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350 QSKit" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A250 Dual") and (nozzle_diameter[0]=="0.6" or nozzle_diameter[0]=="0.8" or nozzle_diameter[0]=="0.4") +compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A250 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A350 QSKit") and (nozzle_diameter[0]=="0.4" or nozzle_diameter[0]=="0.6" or nozzle_diameter[0]=="0.8") [filament:Snapmaker TPE] inherits = *Snapmaker TPU @base* -compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350 QSKit" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A250 Dual") and (nozzle_diameter[0]=="0.6" or nozzle_diameter[0]=="0.8" or nozzle_diameter[0]=="0.4") +compatible_printers_condition = (printer_model=="Snapmaker A250" or printer_model=="Snapmaker A250 Dual" or printer_model=="Snapmaker A250 Dual QSKit" or printer_model=="Snapmaker A250 QSKit" or printer_model=="Snapmaker A350" or printer_model=="Snapmaker A350 Dual" or printer_model=="Snapmaker A350 Dual QSKit" or printer_model=="Snapmaker A350 QSKit") and (nozzle_diameter[0]=="0.4" or nozzle_diameter[0]=="0.6" or nozzle_diameter[0]=="0.8") filament_density = 1.22 filament_max_volumetric_speed = 7.2 filament_notes = "eSUN eLastic TPE-83A\n" @@ -2127,7 +2124,7 @@ start_filament_gcode = "M900 K0.02 ;override pressure advance value" [filament:Snapmaker J1 ABS] inherits = *Snapmaker J1 ABS @base* -compatible_printers_condition = (printer_model=="Snapmaker J1") and (nozzle_diameter[0]=="0.6" or nozzle_diameter[0]=="0.4") +compatible_printers_condition = (printer_model=="Snapmaker J1") and (nozzle_diameter[0]=="0.4" or nozzle_diameter[0]=="0.6") [filament:Snapmaker J1 ABS @0.2 nozzle] inherits = *Snapmaker J1 ABS @base* @@ -2147,7 +2144,7 @@ bridge_fan_speed = 20 [filament:Snapmaker J1 ASA] inherits = *Snapmaker J1 ASA @base* -compatible_printers_condition = (printer_model=="Snapmaker J1") and (nozzle_diameter[0]=="0.6" or nozzle_diameter[0]=="0.8" or nozzle_diameter[0]=="0.4") +compatible_printers_condition = (printer_model=="Snapmaker J1") and (nozzle_diameter[0]=="0.4" or nozzle_diameter[0]=="0.6" or nozzle_diameter[0]=="0.8") [filament:Snapmaker J1 ASA @0.2 nozzle] inherits = *Snapmaker J1 ASA @base* @@ -2162,7 +2159,7 @@ extrusion_multiplier = 0.96 [filament:Snapmaker J1 PA-CF] inherits = *Snapmaker J1 PA-CF @base* -compatible_printers_condition = (printer_model=="Snapmaker J1") and (nozzle_diameter[0]=="0.6" or nozzle_diameter[0]=="0.8" or nozzle_diameter[0]=="0.4") +compatible_printers_condition = (printer_model=="Snapmaker J1") and (nozzle_diameter[0]=="0.4" or nozzle_diameter[0]=="0.6" or nozzle_diameter[0]=="0.8") [filament:*Snapmaker J1 PETG @base*] inherits = *fdm_filament_petg* @@ -2176,7 +2173,7 @@ max_fan_speed = 40 [filament:Snapmaker J1 PETG] inherits = *Snapmaker J1 PETG @base* -compatible_printers_condition = (printer_model=="Snapmaker J1") and (nozzle_diameter[0]=="0.6" or nozzle_diameter[0]=="0.4") +compatible_printers_condition = (printer_model=="Snapmaker J1") and (nozzle_diameter[0]=="0.4" or nozzle_diameter[0]=="0.6") [filament:Snapmaker J1 PETG @0.2 nozzle] inherits = *Snapmaker J1 PETG @base* @@ -2200,7 +2197,7 @@ min_print_speed = 35 [filament:Snapmaker J1 PET] inherits = *Snapmaker J1 PET @base* -compatible_printers_condition = (printer_model=="Snapmaker J1") and (nozzle_diameter[0]=="0.6" or nozzle_diameter[0]=="0.8" or nozzle_diameter[0]=="0.4") +compatible_printers_condition = (printer_model=="Snapmaker J1") and (nozzle_diameter[0]=="0.4" or nozzle_diameter[0]=="0.6" or nozzle_diameter[0]=="0.8") [filament:*Snapmaker J1 PETG-CF @base*] inherits = *fdm_filament_petg* @@ -2223,7 +2220,7 @@ filament_colour = #3D3C39 [filament:Snapmaker J1 PETG-CF] inherits = *Snapmaker J1 PETG-CF @base* -compatible_printers_condition = (printer_model=="Snapmaker J1") and (nozzle_diameter[0]=="0.6" or nozzle_diameter[0]=="0.8" or nozzle_diameter[0]=="0.4") +compatible_printers_condition = (printer_model=="Snapmaker J1") and (nozzle_diameter[0]=="0.4" or nozzle_diameter[0]=="0.6" or nozzle_diameter[0]=="0.8") [filament:*Snapmaker J1 PLA Eco @base*] inherits = *fdm_filament_pla_eco* @@ -2232,7 +2229,7 @@ filament_max_volumetric_speed = 12 [filament:Snapmaker J1 PLA Eco] inherits = *Snapmaker J1 PLA Eco @base* -compatible_printers_condition = (printer_model=="Snapmaker J1") and (nozzle_diameter[0]=="0.6" or nozzle_diameter[0]=="0.4") +compatible_printers_condition = (printer_model=="Snapmaker J1") and (nozzle_diameter[0]=="0.4" or nozzle_diameter[0]=="0.6") [filament:Snapmaker J1 PLA Eco @0.2 nozzle] inherits = *Snapmaker J1 PLA Eco @base* @@ -2251,7 +2248,7 @@ filament_retract_length = nil [filament:Snapmaker J1 PLA] inherits = *Snapmaker J1 PLA @base* -compatible_printers_condition = (printer_model=="Snapmaker J1") and (nozzle_diameter[0]=="0.2" or nozzle_diameter[0]=="0.6" or nozzle_diameter[0]=="0.8" or nozzle_diameter[0]=="0.4") +compatible_printers_condition = (printer_model=="Snapmaker J1") and (nozzle_diameter[0]=="0.2" or nozzle_diameter[0]=="0.4" or nozzle_diameter[0]=="0.6" or nozzle_diameter[0]=="0.8") [filament:*Snapmaker J1 PLA Matte @base*] inherits = *fdm_filament_pla* @@ -2262,7 +2259,7 @@ filament_colour = #EAC3C3 [filament:Snapmaker J1 PLA Matte] inherits = *Snapmaker J1 PLA Matte @base* -compatible_printers_condition = (printer_model=="Snapmaker J1") and (nozzle_diameter[0]=="0.6" or nozzle_diameter[0]=="0.4") +compatible_printers_condition = (printer_model=="Snapmaker J1") and (nozzle_diameter[0]=="0.4" or nozzle_diameter[0]=="0.6") [filament:Snapmaker J1 PLA Matte @0.2 nozzle] inherits = *Snapmaker J1 PLA Matte @base* @@ -2285,7 +2282,7 @@ filament_colour = #767A7E [filament:Snapmaker J1 PLA Metal] inherits = *Snapmaker J1 PLA Metal @base* -compatible_printers_condition = (printer_model=="Snapmaker J1") and (nozzle_diameter[0]=="0.6" or nozzle_diameter[0]=="0.8" or nozzle_diameter[0]=="0.4") +compatible_printers_condition = (printer_model=="Snapmaker J1") and (nozzle_diameter[0]=="0.4" or nozzle_diameter[0]=="0.6" or nozzle_diameter[0]=="0.8") [filament:Snapmaker J1 PLA Metal @0.2 nozzle] inherits = *Snapmaker J1 PLA Metal @base* @@ -2307,7 +2304,7 @@ filament_colour = #3D3C39 [filament:Snapmaker J1 PLA-CF] inherits = *Snapmaker J1 PLA-CF @base* -compatible_printers_condition = (printer_model=="Snapmaker J1") and (nozzle_diameter[0]=="0.6" or nozzle_diameter[0]=="0.4") +compatible_printers_condition = (printer_model=="Snapmaker J1") and (nozzle_diameter[0]=="0.4" or nozzle_diameter[0]=="0.6") [filament:Snapmaker J1 PLA-CF @0.8 nozzle] inherits = *Snapmaker J1 PLA-CF @base* @@ -2327,7 +2324,7 @@ filament_colour = #CF942B [filament:Snapmaker J1 PLA Silk] inherits = *Snapmaker J1 PLA Silk @base* -compatible_printers_condition = (printer_model=="Snapmaker J1") and (nozzle_diameter[0]=="0.6" or nozzle_diameter[0]=="0.8" or nozzle_diameter[0]=="0.4") +compatible_printers_condition = (printer_model=="Snapmaker J1") and (nozzle_diameter[0]=="0.4" or nozzle_diameter[0]=="0.6" or nozzle_diameter[0]=="0.8") [filament:Snapmaker J1 PLA Silk @0.2 nozzle] inherits = *Snapmaker J1 PLA Silk @base* @@ -2336,7 +2333,7 @@ filament_max_volumetric_speed = 2 [filament:PolyLite J1 PLA] inherits = *PolyLite PLA @base* -compatible_printers_condition = (printer_model=="Snapmaker J1") and (nozzle_diameter[0]=="0.6" or nozzle_diameter[0]=="0.8" or nozzle_diameter[0]=="0.4") +compatible_printers_condition = (printer_model=="Snapmaker J1") and (nozzle_diameter[0]=="0.4" or nozzle_diameter[0]=="0.6" or nozzle_diameter[0]=="0.8") [filament:PolyLite J1 PLA @0.2 nozzle] inherits = PolyLite PLA @0.2 nozzle @@ -2344,7 +2341,7 @@ compatible_printers_condition = (printer_model=="Snapmaker J1") and (nozzle_diam [filament:PolyTerra J1 PLA] inherits = *PolyTerra PLA @base* -compatible_printers_condition = (printer_model=="Snapmaker J1") and (nozzle_diameter[0]=="0.6" or nozzle_diameter[0]=="0.8" or nozzle_diameter[0]=="0.4") +compatible_printers_condition = (printer_model=="Snapmaker J1") and (nozzle_diameter[0]=="0.4" or nozzle_diameter[0]=="0.6" or nozzle_diameter[0]=="0.8") [filament:PolyTerra J1 PLA @0.2 nozzle] inherits = PolyTerra PLA @0.2 nozzle @@ -2356,7 +2353,7 @@ slowdown_below_layer_time = 8 [filament:Snapmaker J1 PVA] inherits = *Snapmaker J1 PVA @base* -compatible_printers_condition = (printer_model=="Snapmaker J1") and (nozzle_diameter[0]=="0.6" or nozzle_diameter[0]=="0.8" or nozzle_diameter[0]=="0.4") +compatible_printers_condition = (printer_model=="Snapmaker J1") and (nozzle_diameter[0]=="0.4" or nozzle_diameter[0]=="0.6" or nozzle_diameter[0]=="0.8") [filament:Snapmaker J1 PVA @0.2 nozzle] inherits = *Snapmaker J1 PVA @base* @@ -2370,11 +2367,11 @@ inherits = *fdm_filament_tpu* [filament:Snapmaker J1 TPU] inherits = *Snapmaker J1 TPU @base* -compatible_printers_condition = (printer_model=="Snapmaker J1") and (nozzle_diameter[0]=="0.6" or nozzle_diameter[0]=="0.8" or nozzle_diameter[0]=="0.4") +compatible_printers_condition = (printer_model=="Snapmaker J1") and (nozzle_diameter[0]=="0.4" or nozzle_diameter[0]=="0.6" or nozzle_diameter[0]=="0.8") [filament:Snapmaker J1 TPU High-Flow] inherits = *Snapmaker J1 TPU @base* -compatible_printers_condition = (printer_model=="Snapmaker J1") and (nozzle_diameter[0]=="0.6" or nozzle_diameter[0]=="0.8" or nozzle_diameter[0]=="0.4") +compatible_printers_condition = (printer_model=="Snapmaker J1") and (nozzle_diameter[0]=="0.4" or nozzle_diameter[0]=="0.6" or nozzle_diameter[0]=="0.8") filament_max_volumetric_speed = 7.6 filament_notes = "!! It needs to be dried before use.\nSnapmaker TPU 95A High-Flow\n" filament_retract_length = 0.8 @@ -2384,7 +2381,7 @@ extrusion_multiplier = 0.983 [filament:Snapmaker J1 TPE] inherits = *Snapmaker J1 TPU @base* -compatible_printers_condition = (printer_model=="Snapmaker J1") and (nozzle_diameter[0]=="0.6" or nozzle_diameter[0]=="0.8" or nozzle_diameter[0]=="0.4") +compatible_printers_condition = (printer_model=="Snapmaker J1") and (nozzle_diameter[0]=="0.4" or nozzle_diameter[0]=="0.6" or nozzle_diameter[0]=="0.8") filament_density = 1.22 filament_max_volumetric_speed = 7.2 filament_notes = "eSUN eLastic TPE-83A\n" @@ -2409,7 +2406,7 @@ purge_in_prime_tower = 0 enable_filament_ramming = 0 nozzle_volume = 0 cooling_tube_retraction = 0 -cooling_tube_length = 8 +cooling_tube_length = 0 parking_pos_retraction = 0 extra_loading_move = -2 high_current_on_filament_swap = 0 @@ -2489,7 +2486,7 @@ thumbnails = 300x300 extruder_offset = 0x0,0x0 default_filament_profile = Snapmaker J1 PLA,Snapmaker J1 PETG start_gcode = ; Model: Snapmaker J1 ({nozzle_diameter[0]}/{nozzle_diameter[1]})\n; Update: 20231019\n; Maintained by https://github.com/macdylan/3dp-configs\n; Printer : [printer_preset]\n; Profile : [print_preset]\n; Plate : [physical_printer_preset]\n; --- initial_extruder: [initial_extruder]\n; --- has_wipe_tower: [has_wipe_tower]\n; --- total_toolchanges: [total_toolchanges]\n; --- T0: {is_extruder_used[0]}\n; --- T1: {is_extruder_used[1]}\n\nM201 X[machine_max_acceleration_x] Y[machine_max_acceleration_y] Z[machine_max_acceleration_z] E[machine_max_acceleration_e]\nM203 X[machine_max_feedrate_x] Y[machine_max_feedrate_y] Z[machine_max_feedrate_z] E[machine_max_feedrate_e]\nM204 P[machine_max_acceleration_extruding] R[machine_max_acceleration_retracting] T[machine_max_acceleration_travel]\nM205 X[machine_max_jerk_x] Y[machine_max_jerk_y] Z[machine_max_jerk_z] E[machine_max_jerk_e]\n\nT[initial_extruder]\n\nM205 V20 ;Junction Deviation (mm)\n\n{if physical_printer_preset =~/.*IDEXDupl.*/ || physical_printer_preset =~/.*IDEXCopy.*/ }\n M605 S2 X162 R0 ;IDEX Duplication\n{elsif physical_printer_preset =~/.*IDEXMirr.*/}\n M605 S3 ;IDEX Mirror\n{elsif physical_printer_preset =~/.*IDEXBack.*/}\n M605 S4 ;IDEX Backup\n{endif}\n\nM140 S{first_layer_bed_temperature[initial_extruder]}\n\n; you can clean the nozzle\n{if is_extruder_used[0]}M104 T0 S165{endif}\n{if is_extruder_used[1]}M104 T1 S165{endif}\nM204 S100\nG28\n\nG0 Z100.0\n{if is_extruder_used[0]}\n T0\n G0 X{if 0 == 0}80{else}240{endif} Y0 F7980.0\n {endif}\n{if is_extruder_used[1]}\n T1\n G0 X{if 1 == 0}80{else}240{endif} Y0 F7980.0\n {endif}\n\nM190 R{first_layer_bed_temperature[initial_extruder]}\n{if 1==1}; LED\n M355 S1 P64\n G4 P100\n M355 S1 P128\n G4 P100\n M355 S1 P64\n G4 P200\n M355 S1 P255\n G4 P100\n{endif}\nG28 X Y\n\nM83\n\n{if is_extruder_used[0]}M104 T0 S{max(250, min(290, first_layer_temperature[0] + 15))}{endif}\n{if is_extruder_used[1]}M104 T1 S{max(250, min(290, first_layer_temperature[1] + 15))}{endif}\n\n{if is_extruder_used[0] and initial_extruder != 0}\n T0\nG0 Z20 F240.0\nG0 X{if 0 == 0}-7{else}331{endif} F7980.0\nG0 Y0\n\nM109 S{max(250, min(290, first_layer_temperature[0] + 15))} C2 W1; common flush temp\nG0 E50 F80.0\n\nM106 S{min(255, (max_fan_speed[0] + 10) * 2.55)}\nM104 S{first_layer_temperature[0] + 5}\n\nG0 E50 F200\n\nG0 E-0.5 F200\nM107\n\nG28 X\n\nG0 Z1.0 F240.0\n\nM109 S{first_layer_temperature[0]} C3 W1\nG1 X{if 0 == 0}142.0{else}182.0{endif} F7980.0\nG1 Z0.3 F240.0\nG1 E4 F200\nG1 X{if 0 == 0}10{else}314{endif} E9.47915 F7980.0\nG1 Y11 E0.68599\nG1 X{if 0 == 0}10.5{else}313.5{endif}\nG1 E0.4\nG1 Y0.8 E0.6361\nG1 X{if 0 == 0}19.5{else}304.5{endif} E0.59245\nG1 E-0.5 F200\nG92 E0\n\n M104 S{is_nil(idle_temperature[0]) ? temperature[0] + standby_temperature_delta : idle_temperature[0]}\n{endif}\n{if is_extruder_used[1] and initial_extruder != 1}\n T1\nG0 Z20 F240.0\nG0 X{if 1 == 0}-7{else}331{endif} F7980.0\nG0 Y0\n\nM109 S{max(250, min(290, first_layer_temperature[1] + 15))} C2 W1; common flush temp\nG0 E50 F80.0\n\nM106 S{min(255, (max_fan_speed[1] + 10) * 2.55)}\nM104 S{first_layer_temperature[1] + 5}\n\nG0 E50 F200\n\nG0 E-0.5 F200\nM107\n\nG28 X\n\nG0 Z1.0 F240.0\n\nM109 S{first_layer_temperature[1]} C3 W1\nG1 X{if 1 == 0}142.0{else}182.0{endif} F7980.0\nG1 Z0.3 F240.0\nG1 E4 F200\nG1 X{if 1 == 0}10{else}314{endif} E9.47915 F7980.0\nG1 Y11 E0.68599\nG1 X{if 1 == 0}10.5{else}313.5{endif}\nG1 E0.4\nG1 Y0.8 E0.6361\nG1 X{if 1 == 0}19.5{else}304.5{endif} E0.59245\nG1 E-0.5 F200\nG92 E0\n\n M104 S{is_nil(idle_temperature[1]) ? temperature[1] + standby_temperature_delta : idle_temperature[1]}\n{endif}\n\nT[initial_extruder]\nG0 Z20 F240.0\nG0 X{if initial_extruder == 0}-7{else}331{endif} F7980.0\nG0 Y0\n\nM109 S{max(250, min(290, first_layer_temperature[initial_extruder] + 15))} C2 W1; common flush temp\nG0 E50 F80.0\n\nM106 S{min(255, (max_fan_speed[initial_extruder] + 10) * 2.55)}\nM104 S{first_layer_temperature[initial_extruder] + 5}\n\nG0 E50 F200\n\nG0 E-0.5 F200\nM107\n\nG28 X\n\nG0 Z1.0 F240.0\n\nM109 S{first_layer_temperature[initial_extruder]} C3 W1\nG1 X{if initial_extruder == 0}142.0{else}182.0{endif} F7980.0\nG1 Z0.3 F240.0\nG1 E4 F200\nG1 X{if initial_extruder == 0}10{else}314{endif} E9.47915 F7980.0\nG1 Y11 E0.68599\nG1 X{if initial_extruder == 0}10.5{else}313.5{endif}\nG1 E0.4\nG1 Y0.8 E0.6361\nG1 X{if initial_extruder == 0}19.5{else}304.5{endif} E0.59245\nG1 E-0.5 F200\nG92 E0\n\n; ready [physical_printer_preset] -end_gcode = G92 E0\n\nG0 Z{max_layer_z + 0.5} F600\n; retract the filament to make it easier to replace\nG0 E-40 F200\nG28\n\n {if is_extruder_used[0]}M104 T0 S0{endif}\n {if is_extruder_used[1]}M104 T1 S0{endif}\nM140 S0\nM107\nM220 S100\nM84\n\n;\n; DON'T REMOVE these lines if you're using the smfix (https://github.com/macdylan/SMFix)\n; min_x = [first_layer_print_min_0]\n; min_y = [first_layer_print_min_1]\n; max_x = [first_layer_print_max_0]\n; max_y = [first_layer_print_max_1]\n; max_z = [max_layer_z]\n; total_layer_number = [layer_num]\n; +end_gcode = G92 E0\n\nG0 Z{max_layer_z + 2.0} F600\n; retract the filament to make it easier to replace\nG0 E-40 F200\nG28\n\n {if is_extruder_used[0]}M104 T0 S0{endif}\n {if is_extruder_used[1]}M104 T1 S0{endif}\nM140 S0\nM107\nM220 S100\nM84\n\n;\n; DON'T REMOVE these lines if you're using the smfix (https://github.com/macdylan/SMFix)\n; min_x = [first_layer_print_min_0]\n; min_y = [first_layer_print_min_1]\n; max_x = [first_layer_print_max_0]\n; max_y = [first_layer_print_max_1]\n; max_z = [max_layer_z]\n; total_layer_number = [layer_num]\n; toolchange_gcode = ;***** Update: 20230730\n{if current_extruder != next_extruder }\n; Change T[current_extruder] -> T[next_extruder] (layer [layer_num]\n; layer\nT{next_extruder}\n\nM107 P[current_extruder] ;fan off T[current_extruder]\nM104 T[current_extruder] S{is_nil(idle_temperature[current_extruder]) ? temperature[current_extruder] + standby_temperature_delta : idle_temperature[current_extruder]} ;standby T[current_extruder]\n\n{if layer_num == 1 &&\n ((filament_type[current_extruder] == "PLA" || filament_type[current_extruder] == "TPU")\n || (filament_type[next_extruder] == "PLA" || filament_type[next_extruder] == "TPU"))\n}\n; set bed temp: {filament_type[current_extruder]}({bed_temperature[current_extruder]}) -> {filament_type[next_extruder]}({bed_temperature[next_extruder]})\nM140 S{min(bed_temperature[current_extruder], bed_temperature[next_extruder])}\n{endif}\n\nM2000 S200 V[travel_speed] A[travel_acceleration] ;quick switch extruders, S:200 mode/V:speed/A:acceleration\nM109 T[next_extruder] S{layer_num < 1 ? first_layer_temperature[next_extruder] : temperature[next_extruder]} C3 W1 ;wait T{next_extruder}\n{if layer_num >= disable_fan_first_layers[next_extruder]}\n M106 P[next_extruder] S{min_fan_speed[next_extruder] * 255.0 / 100.0} ; restore fan speed for T[next_extruder]\n{endif}\n\n{if layer_z <= (first_layer_height + 0.001)}\n M204 S[first_layer_acceleration] ;first layer accel\n{elsif default_acceleration > 0}\n M204 S[default_acceleration] ;default accel\n{endif}\n\n{endif} before_layer_gcode = ; layer_num: [layer_num]\nG92 E0 bed_shape = 0x0,324x0,324x200,0x200 @@ -2506,7 +2503,7 @@ inherits = *fdm_linear2* name = *fdm_a250* printer_notes = PRINTER_MODEL_SNAPMAKER_A250\n start_gcode = ; Model: Snapmaker A250\n; Update: 20231019\n; Maintained by https://github.com/macdylan/3dp-configs\n; Printer : [printer_preset]\n; Profile : [print_preset]\n; Plate : [physical_printer_preset]\n\nM201 X[machine_max_acceleration_x] Y[machine_max_acceleration_y] Z[machine_max_acceleration_z] E[machine_max_acceleration_e]\nM203 X[machine_max_feedrate_x] Y[machine_max_feedrate_y] Z[machine_max_feedrate_z] E[machine_max_feedrate_e]\nM204 P[machine_max_acceleration_extruding] R[machine_max_acceleration_retracting] T[machine_max_acceleration_travel]\nM205 X[machine_max_jerk_x] Y[machine_max_jerk_y] Z[machine_max_jerk_z] E[machine_max_jerk_e]\n\nT[initial_extruder]\n\nM140 S{first_layer_bed_temperature[initial_extruder]}\n\n; you can clean the nozzle\nM104 S165\nM204 S100\nG28\nG0 Z156 F960.0\nG0 Y125.0 F3420.0\nG0 X115.0\n\nM190 R{first_layer_bed_temperature[initial_extruder]}\n\nG28\nG0 X0\nG0 Z0.2 F960.0\nG0 Y0 F3420.0\nG0 X230\nG0 Y250\nG0 X0\nG0 Y0\n\nM83\n\nT[initial_extruder]\nG0 Z20 F960.0\nG0 X{if initial_extruder == 0}-10{else}240{endif} F3420.0\nG0 Y0\n\nM109 S{max(250, min(290, first_layer_temperature[initial_extruder] + 15))} C2 W1; common flush temp\nG0 E35 F80.0\n\nM106 S{min(255, (max_fan_speed[initial_extruder] + 10) * 2.55)}\nM104 S{first_layer_temperature[initial_extruder] + 5}\n\nG0 E35 F200\n\nG0 E-0.5 F200\nM107\n\nG0 Z0.1 F960.0\nG0 X{if initial_extruder == 0}10{else}220{endif} F3420.0\nG0 X{if initial_extruder == 0}-10{else}240{endif}\n\nG0 Z1.0 F960.0\n\nM109 S{first_layer_temperature[initial_extruder]} C3 W1\nG1 X{if initial_extruder == 0}105.0{else}125.0{endif} F3420.0\nG1 Z0.3 F960.0\nG1 E4 F200\nG1 X{if initial_extruder == 0}0{else}230{endif} E6.54809 F3420.0\nG1 Y11 E0.68599\nG1 X{if initial_extruder == 0}0.5{else}229.5{endif}\nG1 E0.4\nG1 Y0.8 E0.6361\nG1 X{if initial_extruder == 0}9.5{else}220.5{endif} E0.59245\nG1 E-0.5 F200\nG92 E0\n\n; ready [physical_printer_preset] -end_gcode = G92 E0\n\nG0 Z{max_layer_z + 0.5} F600\n; retract the filament to make it easier to replace\nG0 E-25 F200\nG28\n\n M104 S0\nM140 S0\nM107\nM220 S100\nM84\n\n;\n; DON'T REMOVE these lines if you're using the smfix (https://github.com/macdylan/SMFix)\n; min_x = [first_layer_print_min_0]\n; min_y = [first_layer_print_min_1]\n; max_x = [first_layer_print_max_0]\n; max_y = [first_layer_print_max_1]\n; max_z = [max_layer_z]\n; total_layer_number = [layer_num]\n; +end_gcode = G92 E0\n\nG0 Z{max_layer_z + 2.0} F600\n; retract the filament to make it easier to replace\nG0 E-25 F200\nG28\n\n M104 S0\nM140 S0\nM107\nM220 S100\nM84\n\n;\n; DON'T REMOVE these lines if you're using the smfix (https://github.com/macdylan/SMFix)\n; min_x = [first_layer_print_min_0]\n; min_y = [first_layer_print_min_1]\n; max_x = [first_layer_print_max_0]\n; max_y = [first_layer_print_max_1]\n; max_z = [max_layer_z]\n; total_layer_number = [layer_num]\n; before_layer_gcode = ; layer_num: [layer_num]\nG92 E0 bed_shape = 0x0,230x0,230x250,0x250 max_print_height = 235 @@ -2516,7 +2513,7 @@ inherits = *fdm_linear2* name = *fdm_a350* printer_notes = PRINTER_MODEL_SNAPMAKER_A350\n start_gcode = ; Model: Snapmaker A350\n; Update: 20231019\n; Maintained by https://github.com/macdylan/3dp-configs\n; Printer : [printer_preset]\n; Profile : [print_preset]\n; Plate : [physical_printer_preset]\n\nM201 X[machine_max_acceleration_x] Y[machine_max_acceleration_y] Z[machine_max_acceleration_z] E[machine_max_acceleration_e]\nM203 X[machine_max_feedrate_x] Y[machine_max_feedrate_y] Z[machine_max_feedrate_z] E[machine_max_feedrate_e]\nM204 P[machine_max_acceleration_extruding] R[machine_max_acceleration_retracting] T[machine_max_acceleration_travel]\nM205 X[machine_max_jerk_x] Y[machine_max_jerk_y] Z[machine_max_jerk_z] E[machine_max_jerk_e]\n\nT[initial_extruder]\n\nM140 S{first_layer_bed_temperature[initial_extruder]}\n\n; you can clean the nozzle\nM104 S165\nM204 S100\nG28\nG0 Z220 F960.0\nG0 Y175.0 F3420.0\nG0 X160.0\n\nM190 R{first_layer_bed_temperature[initial_extruder]}\n\nG28\nG0 X0\nG0 Z0.2 F960.0\nG0 Y0 F3420.0\nG0 X320\nG0 Y350\nG0 X0\nG0 Y0\n\nM83\n\nT[initial_extruder]\nG0 Z20 F960.0\nG0 X{if initial_extruder == 0}-10{else}330{endif} F3420.0\nG0 Y0\n\nM109 S{max(250, min(290, first_layer_temperature[initial_extruder] + 15))} C2 W1; common flush temp\nG0 E35 F80.0\n\nM106 S{min(255, (max_fan_speed[initial_extruder] + 10) * 2.55)}\nM104 S{first_layer_temperature[initial_extruder] + 5}\n\nG0 E35 F200\n\nG0 E-0.5 F200\nM107\n\nG0 Z0.1 F960.0\nG0 X{if initial_extruder == 0}10{else}310{endif} F3420.0\nG0 X{if initial_extruder == 0}-10{else}330{endif}\n\nG0 Z1.0 F960.0\n\nM109 S{first_layer_temperature[initial_extruder]} C3 W1\nG1 X{if initial_extruder == 0}150.0{else}170.0{endif} F3420.0\nG1 Z0.3 F960.0\nG1 E4 F200\nG1 X{if initial_extruder == 0}0{else}320{endif} E9.35442 F3420.0\nG1 Y11 E0.68599\nG1 X{if initial_extruder == 0}0.5{else}319.5{endif}\nG1 E0.4\nG1 Y0.8 E0.6361\nG1 X{if initial_extruder == 0}9.5{else}310.5{endif} E0.59245\nG1 E-0.5 F200\nG92 E0\n\n; ready [physical_printer_preset] -end_gcode = G92 E0\n\nG0 Z{max_layer_z + 0.5} F600\n; retract the filament to make it easier to replace\nG0 E-25 F200\nG28\n\n M104 S0\nM140 S0\nM107\nM220 S100\nM84\n\n;\n; DON'T REMOVE these lines if you're using the smfix (https://github.com/macdylan/SMFix)\n; min_x = [first_layer_print_min_0]\n; min_y = [first_layer_print_min_1]\n; max_x = [first_layer_print_max_0]\n; max_y = [first_layer_print_max_1]\n; max_z = [max_layer_z]\n; total_layer_number = [layer_num]\n; +end_gcode = G92 E0\n\nG0 Z{max_layer_z + 2.0} F600\n; retract the filament to make it easier to replace\nG0 E-25 F200\nG28\n\n M104 S0\nM140 S0\nM107\nM220 S100\nM84\n\n;\n; DON'T REMOVE these lines if you're using the smfix (https://github.com/macdylan/SMFix)\n; min_x = [first_layer_print_min_0]\n; min_y = [first_layer_print_min_1]\n; max_x = [first_layer_print_max_0]\n; max_y = [first_layer_print_max_1]\n; max_z = [max_layer_z]\n; total_layer_number = [layer_num]\n; before_layer_gcode = ; layer_num: [layer_num]\nG92 E0 bed_shape = 0x0,320x0,320x350,0x350 max_print_height = 330 @@ -2526,7 +2523,7 @@ inherits = *fdm_linear2_dual* name = *fdm_a250_dual* printer_notes = PRINTER_MODEL_SNAPMAKER_A250_DUAL\n start_gcode = ; Model: Snapmaker A250 Dual ({nozzle_diameter[0]}/{nozzle_diameter[1]})\n; Update: 20231019\n; Maintained by https://github.com/macdylan/3dp-configs\n; Printer : [printer_preset]\n; Profile : [print_preset]\n; Plate : [physical_printer_preset]\n; --- initial_extruder: [initial_extruder]\n; --- has_wipe_tower: [has_wipe_tower]\n; --- total_toolchanges: [total_toolchanges]\n; --- T0: {is_extruder_used[0]}\n; --- T1: {is_extruder_used[1]}\n\nM201 X[machine_max_acceleration_x] Y[machine_max_acceleration_y] Z[machine_max_acceleration_z] E[machine_max_acceleration_e]\nM203 X[machine_max_feedrate_x] Y[machine_max_feedrate_y] Z[machine_max_feedrate_z] E[machine_max_feedrate_e]\nM204 P[machine_max_acceleration_extruding] R[machine_max_acceleration_retracting] T[machine_max_acceleration_travel]\nM205 X[machine_max_jerk_x] Y[machine_max_jerk_y] Z[machine_max_jerk_z] E[machine_max_jerk_e]\n\nT[initial_extruder]\n\nM140 S{first_layer_bed_temperature[initial_extruder]}\n\n; you can clean the nozzle\n{if is_extruder_used[0]}M104 T0 S165{endif}\n{if is_extruder_used[1]}M104 T1 S165{endif}\nM204 S100\nG28\nG0 Z136 F960.0\nG0 Y125.0 F3420.0\nG0 X115.0\n\nM190 R{first_layer_bed_temperature[initial_extruder]}\n\nG28\nG0 X0\nG0 Z0.2 F960.0\nG0 Y0 F3420.0\nG0 X230\nG0 Y250\nG0 X0\nG0 Y0\n\nM83\n\n{if is_extruder_used[0]}M104 T0 S{max(250, min(290, first_layer_temperature[0] + 15))}{endif}\n{if is_extruder_used[1]}M104 T1 S{max(250, min(290, first_layer_temperature[1] + 15))}{endif}\n\n{if is_extruder_used[0] and initial_extruder != 0}\n T0\nG0 Z20 F960.0\nG0 X{if 0 == 0}-10{else}240{endif} F3420.0\nG0 Y0\n\nM109 S{max(250, min(290, first_layer_temperature[0] + 15))} C2 W1; common flush temp\nG0 E45 F80.0\n\nM106 S{min(255, (max_fan_speed[0] + 10) * 2.55)}\nM104 S{first_layer_temperature[0] + 5}\n\nG0 E45 F200\n\nG0 E-0.5 F200\nM107\n\nG0 Z0.1 F960.0\nG0 X{if 0 == 0}10{else}220{endif} F3420.0\nG0 X{if 0 == 0}-10{else}240{endif}\n\nG0 Z1.0 F960.0\n\nM109 S{first_layer_temperature[0]} C3 W1\nG1 X{if 0 == 0}105.0{else}125.0{endif} F3420.0\nG1 Z0.3 F960.0\nG1 E4 F200\nG1 X{if 0 == 0}0{else}230{endif} E6.54809 F3420.0\nG1 Y11 E0.68599\nG1 X{if 0 == 0}0.5{else}229.5{endif}\nG1 E0.4\nG1 Y0.8 E0.6361\nG1 X{if 0 == 0}9.5{else}220.5{endif} E0.59245\nG1 E-0.5 F200\nG92 E0\n\n M104 S{is_nil(idle_temperature[0]) ? temperature[0] + standby_temperature_delta : idle_temperature[0]}\n{endif}\n{if is_extruder_used[1] and initial_extruder != 1}\n T1\nG0 Z20 F960.0\nG0 X{if 1 == 0}-10{else}240{endif} F3420.0\nG0 Y0\n\nM109 S{max(250, min(290, first_layer_temperature[1] + 15))} C2 W1; common flush temp\nG0 E45 F80.0\n\nM106 S{min(255, (max_fan_speed[1] + 10) * 2.55)}\nM104 S{first_layer_temperature[1] + 5}\n\nG0 E45 F200\n\nG0 E-0.5 F200\nM107\n\nG0 Z0.1 F960.0\nG0 X{if 1 == 0}10{else}220{endif} F3420.0\nG0 X{if 1 == 0}-10{else}240{endif}\n\nG0 Z1.0 F960.0\n\nM109 S{first_layer_temperature[1]} C3 W1\nG1 X{if 1 == 0}105.0{else}125.0{endif} F3420.0\nG1 Z0.3 F960.0\nG1 E4 F200\nG1 X{if 1 == 0}0{else}230{endif} E6.54809 F3420.0\nG1 Y11 E0.68599\nG1 X{if 1 == 0}0.5{else}229.5{endif}\nG1 E0.4\nG1 Y0.8 E0.6361\nG1 X{if 1 == 0}9.5{else}220.5{endif} E0.59245\nG1 E-0.5 F200\nG92 E0\n\n M104 S{is_nil(idle_temperature[1]) ? temperature[1] + standby_temperature_delta : idle_temperature[1]}\n{endif}\n\nT[initial_extruder]\nG0 Z20 F960.0\nG0 X{if initial_extruder == 0}-10{else}240{endif} F3420.0\nG0 Y0\n\nM109 S{max(250, min(290, first_layer_temperature[initial_extruder] + 15))} C2 W1; common flush temp\nG0 E45 F80.0\n\nM106 S{min(255, (max_fan_speed[initial_extruder] + 10) * 2.55)}\nM104 S{first_layer_temperature[initial_extruder] + 5}\n\nG0 E45 F200\n\nG0 E-0.5 F200\nM107\n\nG0 Z0.1 F960.0\nG0 X{if initial_extruder == 0}10{else}220{endif} F3420.0\nG0 X{if initial_extruder == 0}-10{else}240{endif}\n\nG0 Z1.0 F960.0\n\nM109 S{first_layer_temperature[initial_extruder]} C3 W1\nG1 X{if initial_extruder == 0}105.0{else}125.0{endif} F3420.0\nG1 Z0.3 F960.0\nG1 E4 F200\nG1 X{if initial_extruder == 0}0{else}230{endif} E6.54809 F3420.0\nG1 Y11 E0.68599\nG1 X{if initial_extruder == 0}0.5{else}229.5{endif}\nG1 E0.4\nG1 Y0.8 E0.6361\nG1 X{if initial_extruder == 0}9.5{else}220.5{endif} E0.59245\nG1 E-0.5 F200\nG92 E0\n\n; ready [physical_printer_preset] -end_gcode = G92 E0\n\nG0 Z{max_layer_z + 0.5} F600\n; retract the filament to make it easier to replace\nG0 E-35 F200\nG28\n\n {if is_extruder_used[0]}M104 T0 S0{endif}\n {if is_extruder_used[1]}M104 T1 S0{endif}\nM140 S0\nM107\nM220 S100\nM84\n\n;\n; DON'T REMOVE these lines if you're using the smfix (https://github.com/macdylan/SMFix)\n; min_x = [first_layer_print_min_0]\n; min_y = [first_layer_print_min_1]\n; max_x = [first_layer_print_max_0]\n; max_y = [first_layer_print_max_1]\n; max_z = [max_layer_z]\n; total_layer_number = [layer_num]\n; +end_gcode = G92 E0\n\nG0 Z{max_layer_z + 2.0} F600\n; retract the filament to make it easier to replace\nG0 E-35 F200\nG28\n\n {if is_extruder_used[0]}M104 T0 S0{endif}\n {if is_extruder_used[1]}M104 T1 S0{endif}\nM140 S0\nM107\nM220 S100\nM84\n\n;\n; DON'T REMOVE these lines if you're using the smfix (https://github.com/macdylan/SMFix)\n; min_x = [first_layer_print_min_0]\n; min_y = [first_layer_print_min_1]\n; max_x = [first_layer_print_max_0]\n; max_y = [first_layer_print_max_1]\n; max_z = [max_layer_z]\n; total_layer_number = [layer_num]\n; toolchange_gcode = ;***** Update: 20231010\n{if current_extruder != next_extruder }\n; Change T[current_extruder] -> T[next_extruder] (layer [layer_num]\n; layer\nT{next_extruder}\n\nM107 P[current_extruder] ;fan off T[current_extruder]\nM104 T[current_extruder] S{is_nil(idle_temperature[current_extruder]) ? temperature[current_extruder] + standby_temperature_delta : idle_temperature[current_extruder]} ;standby T[current_extruder]\n\n{if layer_num == 1 &&\n ((filament_type[current_extruder] == "PLA" || filament_type[current_extruder] == "TPU")\n || (filament_type[next_extruder] == "PLA" || filament_type[next_extruder] == "TPU"))\n}\n; set bed temp: {filament_type[current_extruder]}({bed_temperature[current_extruder]}) -> {filament_type[next_extruder]}({bed_temperature[next_extruder]})\nM140 S{min(bed_temperature[current_extruder], bed_temperature[next_extruder])}\n{endif}\n\nM109 T[next_extruder] S{layer_num < 1 ? first_layer_temperature[next_extruder] : temperature[next_extruder]} C3 W1 ;wait T{next_extruder}\n{if layer_num >= disable_fan_first_layers[next_extruder]}\n M106 P[next_extruder] S{min_fan_speed[next_extruder] * 255.0 / 100.0} ; restore fan speed for T[next_extruder]\n{endif}\n\n{if layer_z <= (first_layer_height + 0.001)}\n M204 S[first_layer_acceleration] ;first layer accel\n{elsif default_acceleration > 0}\n M204 S[default_acceleration] ;default accel\n{endif}\n\n{endif} before_layer_gcode = ; layer_num: [layer_num]\nG92 E0 bed_shape = 0x0,230x0,230x250,0x250 @@ -2537,7 +2534,7 @@ inherits = *fdm_linear2_dual* name = *fdm_a350_dual* printer_notes = PRINTER_MODEL_SNAPMAKER_A350_DUAL\n start_gcode = ; Model: Snapmaker A350 Dual ({nozzle_diameter[0]}/{nozzle_diameter[1]})\n; Update: 20231019\n; Maintained by https://github.com/macdylan/3dp-configs\n; Printer : [printer_preset]\n; Profile : [print_preset]\n; Plate : [physical_printer_preset]\n; --- initial_extruder: [initial_extruder]\n; --- has_wipe_tower: [has_wipe_tower]\n; --- total_toolchanges: [total_toolchanges]\n; --- T0: {is_extruder_used[0]}\n; --- T1: {is_extruder_used[1]}\n\nM201 X[machine_max_acceleration_x] Y[machine_max_acceleration_y] Z[machine_max_acceleration_z] E[machine_max_acceleration_e]\nM203 X[machine_max_feedrate_x] Y[machine_max_feedrate_y] Z[machine_max_feedrate_z] E[machine_max_feedrate_e]\nM204 P[machine_max_acceleration_extruding] R[machine_max_acceleration_retracting] T[machine_max_acceleration_travel]\nM205 X[machine_max_jerk_x] Y[machine_max_jerk_y] Z[machine_max_jerk_z] E[machine_max_jerk_e]\n\nT[initial_extruder]\n\nM140 S{first_layer_bed_temperature[initial_extruder]}\n\n; you can clean the nozzle\n{if is_extruder_used[0]}M104 T0 S165{endif}\n{if is_extruder_used[1]}M104 T1 S165{endif}\nM204 S100\nG28\nG0 Z193 F960.0\nG0 Y175.0 F3420.0\nG0 X160.0\n\nM190 R{first_layer_bed_temperature[initial_extruder]}\n\nG28\nG0 X0\nG0 Z0.2 F960.0\nG0 Y0 F3420.0\nG0 X320\nG0 Y350\nG0 X0\nG0 Y0\n\nM83\n\n{if is_extruder_used[0]}M104 T0 S{max(250, min(290, first_layer_temperature[0] + 15))}{endif}\n{if is_extruder_used[1]}M104 T1 S{max(250, min(290, first_layer_temperature[1] + 15))}{endif}\n\n{if is_extruder_used[0] and initial_extruder != 0}\n T0\nG0 Z20 F960.0\nG0 X{if 0 == 0}-10{else}330{endif} F3420.0\nG0 Y0\n\nM109 S{max(250, min(290, first_layer_temperature[0] + 15))} C2 W1; common flush temp\nG0 E45 F80.0\n\nM106 S{min(255, (max_fan_speed[0] + 10) * 2.55)}\nM104 S{first_layer_temperature[0] + 5}\n\nG0 E45 F200\n\nG0 E-0.5 F200\nM107\n\nG0 Z0.1 F960.0\nG0 X{if 0 == 0}10{else}310{endif} F3420.0\nG0 X{if 0 == 0}-10{else}330{endif}\n\nG0 Z1.0 F960.0\n\nM109 S{first_layer_temperature[0]} C3 W1\nG1 X{if 0 == 0}150.0{else}170.0{endif} F3420.0\nG1 Z0.3 F960.0\nG1 E4 F200\nG1 X{if 0 == 0}0{else}320{endif} E9.35442 F3420.0\nG1 Y11 E0.68599\nG1 X{if 0 == 0}0.5{else}319.5{endif}\nG1 E0.4\nG1 Y0.8 E0.6361\nG1 X{if 0 == 0}9.5{else}310.5{endif} E0.59245\nG1 E-0.5 F200\nG92 E0\n\n M104 S{is_nil(idle_temperature[0]) ? temperature[0] + standby_temperature_delta : idle_temperature[0]}\n{endif}\n{if is_extruder_used[1] and initial_extruder != 1}\n T1\nG0 Z20 F960.0\nG0 X{if 1 == 0}-10{else}330{endif} F3420.0\nG0 Y0\n\nM109 S{max(250, min(290, first_layer_temperature[1] + 15))} C2 W1; common flush temp\nG0 E45 F80.0\n\nM106 S{min(255, (max_fan_speed[1] + 10) * 2.55)}\nM104 S{first_layer_temperature[1] + 5}\n\nG0 E45 F200\n\nG0 E-0.5 F200\nM107\n\nG0 Z0.1 F960.0\nG0 X{if 1 == 0}10{else}310{endif} F3420.0\nG0 X{if 1 == 0}-10{else}330{endif}\n\nG0 Z1.0 F960.0\n\nM109 S{first_layer_temperature[1]} C3 W1\nG1 X{if 1 == 0}150.0{else}170.0{endif} F3420.0\nG1 Z0.3 F960.0\nG1 E4 F200\nG1 X{if 1 == 0}0{else}320{endif} E9.35442 F3420.0\nG1 Y11 E0.68599\nG1 X{if 1 == 0}0.5{else}319.5{endif}\nG1 E0.4\nG1 Y0.8 E0.6361\nG1 X{if 1 == 0}9.5{else}310.5{endif} E0.59245\nG1 E-0.5 F200\nG92 E0\n\n M104 S{is_nil(idle_temperature[1]) ? temperature[1] + standby_temperature_delta : idle_temperature[1]}\n{endif}\n\nT[initial_extruder]\nG0 Z20 F960.0\nG0 X{if initial_extruder == 0}-10{else}330{endif} F3420.0\nG0 Y0\n\nM109 S{max(250, min(290, first_layer_temperature[initial_extruder] + 15))} C2 W1; common flush temp\nG0 E45 F80.0\n\nM106 S{min(255, (max_fan_speed[initial_extruder] + 10) * 2.55)}\nM104 S{first_layer_temperature[initial_extruder] + 5}\n\nG0 E45 F200\n\nG0 E-0.5 F200\nM107\n\nG0 Z0.1 F960.0\nG0 X{if initial_extruder == 0}10{else}310{endif} F3420.0\nG0 X{if initial_extruder == 0}-10{else}330{endif}\n\nG0 Z1.0 F960.0\n\nM109 S{first_layer_temperature[initial_extruder]} C3 W1\nG1 X{if initial_extruder == 0}150.0{else}170.0{endif} F3420.0\nG1 Z0.3 F960.0\nG1 E4 F200\nG1 X{if initial_extruder == 0}0{else}320{endif} E9.35442 F3420.0\nG1 Y11 E0.68599\nG1 X{if initial_extruder == 0}0.5{else}319.5{endif}\nG1 E0.4\nG1 Y0.8 E0.6361\nG1 X{if initial_extruder == 0}9.5{else}310.5{endif} E0.59245\nG1 E-0.5 F200\nG92 E0\n\n; ready [physical_printer_preset] -end_gcode = G92 E0\n\nG0 Z{max_layer_z + 0.5} F600\n; retract the filament to make it easier to replace\nG0 E-35 F200\nG28\n\n {if is_extruder_used[0]}M104 T0 S0{endif}\n {if is_extruder_used[1]}M104 T1 S0{endif}\nM140 S0\nM107\nM220 S100\nM84\n\n;\n; DON'T REMOVE these lines if you're using the smfix (https://github.com/macdylan/SMFix)\n; min_x = [first_layer_print_min_0]\n; min_y = [first_layer_print_min_1]\n; max_x = [first_layer_print_max_0]\n; max_y = [first_layer_print_max_1]\n; max_z = [max_layer_z]\n; total_layer_number = [layer_num]\n; +end_gcode = G92 E0\n\nG0 Z{max_layer_z + 2.0} F600\n; retract the filament to make it easier to replace\nG0 E-35 F200\nG28\n\n {if is_extruder_used[0]}M104 T0 S0{endif}\n {if is_extruder_used[1]}M104 T1 S0{endif}\nM140 S0\nM107\nM220 S100\nM84\n\n;\n; DON'T REMOVE these lines if you're using the smfix (https://github.com/macdylan/SMFix)\n; min_x = [first_layer_print_min_0]\n; min_y = [first_layer_print_min_1]\n; max_x = [first_layer_print_max_0]\n; max_y = [first_layer_print_max_1]\n; max_z = [max_layer_z]\n; total_layer_number = [layer_num]\n; toolchange_gcode = ;***** Update: 20231010\n{if current_extruder != next_extruder }\n; Change T[current_extruder] -> T[next_extruder] (layer [layer_num]\n; layer\nT{next_extruder}\n\nM107 P[current_extruder] ;fan off T[current_extruder]\nM104 T[current_extruder] S{is_nil(idle_temperature[current_extruder]) ? temperature[current_extruder] + standby_temperature_delta : idle_temperature[current_extruder]} ;standby T[current_extruder]\n\n{if layer_num == 1 &&\n ((filament_type[current_extruder] == "PLA" || filament_type[current_extruder] == "TPU")\n || (filament_type[next_extruder] == "PLA" || filament_type[next_extruder] == "TPU"))\n}\n; set bed temp: {filament_type[current_extruder]}({bed_temperature[current_extruder]}) -> {filament_type[next_extruder]}({bed_temperature[next_extruder]})\nM140 S{min(bed_temperature[current_extruder], bed_temperature[next_extruder])}\n{endif}\n\nM109 T[next_extruder] S{layer_num < 1 ? first_layer_temperature[next_extruder] : temperature[next_extruder]} C3 W1 ;wait T{next_extruder}\n{if layer_num >= disable_fan_first_layers[next_extruder]}\n M106 P[next_extruder] S{min_fan_speed[next_extruder] * 255.0 / 100.0} ; restore fan speed for T[next_extruder]\n{endif}\n\n{if layer_z <= (first_layer_height + 0.001)}\n M204 S[first_layer_acceleration] ;first layer accel\n{elsif default_acceleration > 0}\n M204 S[default_acceleration] ;default accel\n{endif}\n\n{endif} before_layer_gcode = ; layer_num: [layer_num]\nG92 E0 bed_shape = 0x0,320x0,320x350,0x350 From 7e889bbe7cec18d4b4e063b42141eda49444d13b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hejl?= Date: Wed, 3 Jan 2024 15:35:40 +0100 Subject: [PATCH 10/91] SPE-2054: Fixed missing infills on multi-part models caused by 3cb2f5f58f952bc104260c84292411894f957552 reported in #11721. The temporary variable used for reordering ExPolygons wasn't cleared, and it contained empty ExPolygons from previous reordering. This caused those empty ExPolygons replaced actual ExPolygons for infill. Another issue was that m_fill_expolygons was reordered, but m_fill_expolygons_bboxes were left untouched. --- src/libslic3r/Layer.cpp | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/src/libslic3r/Layer.cpp b/src/libslic3r/Layer.cpp index af82ba2922..96bfeffaa0 100644 --- a/src/libslic3r/Layer.cpp +++ b/src/libslic3r/Layer.cpp @@ -874,12 +874,14 @@ void Layer::sort_perimeters_into_islands( int sort_region_id = -1; // Temporary vector of fills for reordering. ExPolygons fills_temp; + // Temporary vector of fill_bboxes for reordering. + BoundingBoxes fill_bboxes_temp; // Vector of new positions of the above. std::vector new_positions; do { sort_region_id = -1; for (size_t source_slice_idx = 0; source_slice_idx < fill_expolygons_ranges.size(); ++ source_slice_idx) - if (ExPolygonRange fill_range = fill_expolygons_ranges[source_slice_idx]; fill_range.size() > 1) { + if (const ExPolygonRange fill_range = fill_expolygons_ranges[source_slice_idx]; fill_range.size() > 1) { // More than one expolygon exists for a single island. Check whether they are contiguous inside a single LayerRegion::fill_expolygons() vector. uint32_t fill_idx = *fill_range.begin(); if (const int fill_regon_id = map_expolygon_to_region_and_fill[fill_idx].region_id; fill_regon_id != -1) { @@ -916,15 +918,23 @@ void Layer::sort_perimeters_into_islands( // Not referenced by any map_expolygon_to_region_and_fill. new_pos = last ++; // Move just the content of m_fill_expolygons to fills_temp, but don't move the container vector. - auto &fills = layerm.m_fill_expolygons; + auto &fills = layerm.m_fill_expolygons; + auto &fill_bboxes = layerm.m_fill_expolygons_bboxes; + + assert(fills.size() == fill_bboxes.size()); assert(last == int(fills.size())); - fills_temp.reserve(fills.size()); - fills_temp.insert(fills_temp.end(), std::make_move_iterator(fills.begin()), std::make_move_iterator(fills.end())); - for (ExPolygon &ex : fills) - ex.clear(); - // Move / reoder the expolygons back into m_fill_expolygons. - for (size_t old_pos = 0; old_pos < new_positions.size(); ++ old_pos) - fills[new_positions[old_pos]] = std::move(fills_temp[old_pos]); + + fills_temp.resize(fills.size()); + fills_temp.assign(std::make_move_iterator(fills.begin()), std::make_move_iterator(fills.end())); + + fill_bboxes_temp.resize(fill_bboxes.size()); + fill_bboxes_temp.assign(std::make_move_iterator(fill_bboxes.begin()), std::make_move_iterator(fill_bboxes.end())); + + // Move / reorder the ExPolygons and BoundingBoxes back into m_fill_expolygons and m_fill_expolygons_bboxes. + for (size_t old_pos = 0; old_pos < new_positions.size(); ++old_pos) { + fills[new_positions[old_pos]] = std::move(fills_temp[old_pos]); + fill_bboxes[new_positions[old_pos]] = std::move(fill_bboxes_temp[old_pos]); + } } } while (sort_region_id != -1); } else { @@ -956,7 +966,7 @@ void Layer::sort_perimeters_into_islands( // Check whether the fill expolygons of this island were split into multiple regions. island.fill_region_id = LayerIsland::fill_region_composite_id; for (uint32_t fill_idx : fill_range) { - if (const int fill_regon_id = map_expolygon_to_region_and_fill[fill_idx].region_id; + if (const int fill_regon_id = map_expolygon_to_region_and_fill[fill_idx].region_id; fill_regon_id == -1 || (island.fill_region_id != LayerIsland::fill_region_composite_id && int(island.fill_region_id) != fill_regon_id)) { island.fill_region_id = LayerIsland::fill_region_composite_id; break; From c7d31f980a442f709d959c029a94852cb3c532d5 Mon Sep 17 00:00:00 2001 From: Kristian Nielsen Date: Wed, 20 Dec 2023 17:40:25 +0100 Subject: [PATCH 11/91] Fix missing braces around multi-line if () Signed-off-by: Kristian Nielsen --- src/libslic3r/GCode/WipeTowerIntegration.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libslic3r/GCode/WipeTowerIntegration.cpp b/src/libslic3r/GCode/WipeTowerIntegration.cpp index 4b51d27c6e..3b2bb4ddd3 100644 --- a/src/libslic3r/GCode/WipeTowerIntegration.cpp +++ b/src/libslic3r/GCode/WipeTowerIntegration.cpp @@ -81,10 +81,10 @@ std::string WipeTowerIntegration::append_tcr(GCodeGenerator &gcodegen, const Wip if (is_ramming) gcodegen.m_wipe.reset_path(); // We don't want wiping on the ramming lines. toolchange_gcode_str = gcodegen.set_extruder(new_extruder_id, tcr.print_z); // TODO: toolchange_z vs print_z - if (gcodegen.config().wipe_tower) + if (gcodegen.config().wipe_tower) { deretraction_str += gcodegen.writer().get_travel_to_z_gcode(z, "restore layer Z"); deretraction_str += gcodegen.unretract(); - + } } assert(toolchange_gcode_str.empty() || toolchange_gcode_str.back() == '\n'); assert(deretraction_str.empty() || deretraction_str.back() == '\n'); From 2c671d8d6cf70a0794bbc2e25d48e1f191753f2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hejl?= Date: Wed, 3 Jan 2024 23:50:15 +0100 Subject: [PATCH 12/91] Use memcpy instead of strncpy in GCodeFormatter::emit_string() to silence the warning. The warning was there because std::string_view::data() returns a pointer to a buffer that is not necessarily null-terminated. So, strncpy shouldn't be used on non-null-terminated buffers, but we always relied only on the buffer length, so it couldn't cause any issues. --- src/libslic3r/GCode/GCodeWriter.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libslic3r/GCode/GCodeWriter.hpp b/src/libslic3r/GCode/GCodeWriter.hpp index b51b6269c5..d91e67728d 100644 --- a/src/libslic3r/GCode/GCodeWriter.hpp +++ b/src/libslic3r/GCode/GCodeWriter.hpp @@ -200,7 +200,8 @@ public: } void emit_string(const std::string_view s) { - strncpy(ptr_err.ptr, s.data(), s.size()); + // Be aware that std::string_view::data() returns a pointer to a buffer that is not necessarily null-terminated. + memcpy(ptr_err.ptr, s.data(), s.size()); ptr_err.ptr += s.size(); } From 611afd97895a092bc226c11b373b1451cf0f4171 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hejl?= Date: Wed, 3 Jan 2024 23:55:02 +0100 Subject: [PATCH 13/91] Replace some deprecated boost functions. Actually, all those deprecated functions were internally called those new functions. So there isn't any risk to use them directly. --- src/libslic3r/PrintBase.cpp | 2 +- src/libslic3r/utils.cpp | 2 +- src/slic3r/GUI/DownloaderFileGet.cpp | 2 +- src/slic3r/GUI/GalleryDialog.cpp | 2 +- src/slic3r/GUI/Plater.cpp | 6 +++--- src/slic3r/GUI/RemovableDriveManager.cpp | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/libslic3r/PrintBase.cpp b/src/libslic3r/PrintBase.cpp index 18d9833974..ca13365d15 100644 --- a/src/libslic3r/PrintBase.cpp +++ b/src/libslic3r/PrintBase.cpp @@ -78,7 +78,7 @@ std::string PrintBase::output_filename(const std::string &format, const std::str cfg.opt_string("input_filename_base") + default_ext : this->placeholder_parser().process(format, 0, &cfg); if (filename.extension().empty()) - filename = boost::filesystem::change_extension(filename, default_ext); + filename.replace_extension(default_ext); return filename.string(); } catch (std::runtime_error &err) { throw Slic3r::PlaceholderParserError(_u8L("Failed processing of the output_filename_format template.") + "\n" + err.what()); diff --git a/src/libslic3r/utils.cpp b/src/libslic3r/utils.cpp index 09fa98ca1f..f4d7c51da1 100644 --- a/src/libslic3r/utils.cpp +++ b/src/libslic3r/utils.cpp @@ -707,7 +707,7 @@ CopyFileResult copy_file_inner(const std::string& from, const std::string& to, s // That may happen when copying on some exotic file system, for example Linux on Chrome. copy_file_linux(source, target, ec); #else // __linux__ - boost::filesystem::copy_file(source, target, boost::filesystem::copy_option::overwrite_if_exists, ec); + boost::filesystem::copy_file(source, target, boost::filesystem::copy_options::overwrite_existing, ec); #endif // __linux__ if (ec) { error_message = ec.message(); diff --git a/src/slic3r/GUI/DownloaderFileGet.cpp b/src/slic3r/GUI/DownloaderFileGet.cpp index 137a7e9bc1..ef9b0256e0 100644 --- a/src/slic3r/GUI/DownloaderFileGet.cpp +++ b/src/slic3r/GUI/DownloaderFileGet.cpp @@ -138,7 +138,7 @@ void FileGet::priv::get_perform() if (m_written == 0) { boost::filesystem::path dest_path = m_dest_folder / m_filename; - std::string extension = boost::filesystem::extension(dest_path); + std::string extension = dest_path.extension().string(); std::string just_filename = m_filename.substr(0, m_filename.size() - extension.size()); std::string final_filename = just_filename; // Find unsed filename diff --git a/src/slic3r/GUI/GalleryDialog.cpp b/src/slic3r/GUI/GalleryDialog.cpp index cb4e6764c9..23c2cc8e08 100644 --- a/src/slic3r/GUI/GalleryDialog.cpp +++ b/src/slic3r/GUI/GalleryDialog.cpp @@ -503,7 +503,7 @@ void GalleryDialog::change_thumbnail() png_path.replace_extension("png"); fs::path current = fs::path(into_u8(input_files.Item(0))); - fs::copy_file(current, png_path, fs::copy_option::overwrite_if_exists); + fs::copy_file(current, png_path, fs::copy_options::overwrite_existing); } catch (fs::filesystem_error const& e) { std::cerr << e.what() << '\n'; diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 2642bcc450..ab98771f64 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -5633,7 +5633,7 @@ void Plater::convert_gcode_to_ascii() if (res == EResult::InvalidMagicNumber) { in_file.close(); out_file.close(); - boost::filesystem::copy_file(input_path, output_path, boost::filesystem::copy_option::overwrite_if_exists); + boost::filesystem::copy_file(input_path, output_path, boost::filesystem::copy_options::overwrite_existing); } else if (res != EResult::Success) { MessageDialog msg_dlg(this, _L(std::string(translate_result(res))), _L("Error converting G-code file"), wxICON_INFORMATION | wxOK); @@ -5712,7 +5712,7 @@ void Plater::convert_gcode_to_binary() if (res == EResult::AlreadyBinarized) { in_file.close(); out_file.close(); - boost::filesystem::copy_file(input_path, output_path, boost::filesystem::copy_option::overwrite_if_exists); + boost::filesystem::copy_file(input_path, output_path, boost::filesystem::copy_options::overwrite_existing); } else if (res != EResult::Success) { MessageDialog msg_dlg(this, _L(std::string(translate_result(res))), _L("Error converting G-code file"), wxICON_INFORMATION | wxOK); @@ -5945,7 +5945,7 @@ bool Plater::preview_zip_archive(const boost::filesystem::path& archive_path) std::replace(name.begin(), name.end(), '\\', '/'); // rename if file exists std::string filename = path.filename().string(); - std::string extension = boost::filesystem::extension(path); + std::string extension = path.extension().string(); std::string just_filename = filename.substr(0, filename.size() - extension.size()); std::string final_filename = just_filename; diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp index 52ae1dad8b..399ea8180d 100644 --- a/src/slic3r/GUI/RemovableDriveManager.cpp +++ b/src/slic3r/GUI/RemovableDriveManager.cpp @@ -759,7 +759,7 @@ namespace search_for_drives_internal stat(path.c_str(), &buf); uid_t uid = buf.st_uid; if (getuid() == uid) - out.emplace_back(DriveData{ boost::filesystem::basename(boost::filesystem::path(path)), path }); + out.emplace_back(DriveData{ boost::filesystem::path(path).stem().string(), path }); } } } From a27aea45989c2a26038b0d84fd51bf7d6104166f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hejl?= Date: Wed, 3 Jan 2024 23:57:51 +0100 Subject: [PATCH 14/91] Remove the unused variable new_radius in Arc Welder tests. --- tests/libslic3r/test_arc_welder.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/libslic3r/test_arc_welder.cpp b/tests/libslic3r/test_arc_welder.cpp index 44b88655ea..f0ab8fbab3 100644 --- a/tests/libslic3r/test_arc_welder.cpp +++ b/tests/libslic3r/test_arc_welder.cpp @@ -280,7 +280,6 @@ TEST_CASE("least squares arc fitting, interpolating end points", "[ArcWelder]") REQUIRE(new_center_opt); if (new_center_opt) { Vec2d new_center = *new_center_opt; - double new_radius = (new_center - start_pos).norm(); double total_deviation = 0; double new_total_deviation = 0; for (const Vec2d &s : samples) { From da88c2affcda5b79320e1ab0389f6056a535da39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hejl?= Date: Thu, 4 Jan 2024 00:09:49 +0100 Subject: [PATCH 15/91] Silence the warning about the unused total_extrusion_length in Arachne tests. --- tests/libslic3r/test_arachne.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/libslic3r/test_arachne.cpp b/tests/libslic3r/test_arachne.cpp index c5b2f35a9b..2953cfcfab 100644 --- a/tests/libslic3r/test_arachne.cpp +++ b/tests/libslic3r/test_arachne.cpp @@ -478,7 +478,7 @@ TEST_CASE("Arachne - #8849 - Missing part of model", "[ArachneMissingPart8849]") export_perimeters_to_svg(debug_out_path("arachne-missing-part-8849.svg"), polygons, perimeters, union_ex(wall_tool_paths.getInnerContour())); #endif - int64_t total_extrusion_length = 0; + [[maybe_unused]] int64_t total_extrusion_length = 0; for (Arachne::VariableWidthLines &perimeter : perimeters) for (Arachne::ExtrusionLine &extrusion_line : perimeter) total_extrusion_length += extrusion_line.getLength(); From 124ce1c31fb24ce05191971997d985e56ac69daa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hejl?= Date: Thu, 4 Jan 2024 00:10:20 +0100 Subject: [PATCH 16/91] Silence the warning about the unused function get_deviation_sum_squared() in Arc Welder. --- src/libslic3r/Geometry/ArcWelder.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libslic3r/Geometry/ArcWelder.cpp b/src/libslic3r/Geometry/ArcWelder.cpp index 4b02a31dce..0bc71aea3a 100644 --- a/src/libslic3r/Geometry/ArcWelder.cpp +++ b/src/libslic3r/Geometry/ArcWelder.cpp @@ -120,6 +120,7 @@ static inline bool circle_approximation_sufficient(const Circle &circle, const P return true; } +#if 0 static inline bool get_deviation_sum_squared(const Circle &circle, const Points::const_iterator begin, const Points::const_iterator end, const double tolerance, double &total_deviation) { // The circle was calculated from the 1st and last point of the point sequence, thus the fitting of those points does not need to be evaluated. @@ -148,6 +149,7 @@ static inline bool get_deviation_sum_squared(const Circle &circle, const Points: return true; } +#endif double arc_fit_variance(const Point &start_pos, const Point &end_pos, const float radius, bool is_ccw, const Points::const_iterator begin, const Points::const_iterator end) From ca811aaa7d0beecd2e0bd5c58b3794febb2f07c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hejl?= Date: Thu, 4 Jan 2024 00:11:03 +0100 Subject: [PATCH 17/91] Move the function ptree_get_value() inside _WIN32 ifdef. --- src/slic3r/Utils/WifiScanner.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/slic3r/Utils/WifiScanner.cpp b/src/slic3r/Utils/WifiScanner.cpp index 260583516d..aa4c8f4e9f 100644 --- a/src/slic3r/Utils/WifiScanner.cpp +++ b/src/slic3r/Utils/WifiScanner.cpp @@ -24,6 +24,8 @@ #endif //__linux__ namespace { + +#ifdef _WIN32 bool ptree_get_value(const boost::property_tree::ptree& pt, const std::string& target, std::string& result) { // Check if the current node has the target element @@ -41,7 +43,7 @@ bool ptree_get_value(const boost::property_tree::ptree& pt, const std::string& t return false; // Element not found in this subtree } -#ifdef _WIN32 + // Fill SSID map. Implementation from Raspberry Pi imager and Win32 Api examples. // https://github.com/raspberrypi/rpi-imager/blob/qml/src/windows/winwlancredentials.cpp // https://learn.microsoft.com/en-us/windows/win32/api/wlanapi/nf-wlanapi-wlangetavailablenetworklist From b67c4785f0d300b5615126ea1df1d518dd6d00b0 Mon Sep 17 00:00:00 2001 From: Filip Sykala - NTB T15p Date: Fri, 5 Jan 2024 11:24:51 +0100 Subject: [PATCH 18/91] Fix style preview size per resolution --- src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp | 4 ++-- src/slic3r/GUI/Jobs/CreateFontStyleImagesJob.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp index b92b931ded..74778056b7 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp @@ -3582,7 +3582,7 @@ GuiCfg create_gui_configuration() float space = line_height_with_spacing - line_height; const ImGuiStyle &style = ImGui::GetStyle(); - cfg.max_style_name_width = ImGui::CalcTextSize("Maximal font name, extended").x; + cfg.max_style_name_width = ImGui::CalcTextSize("Maximal style name..").x; cfg.icon_width = static_cast(std::ceil(line_height)); // make size pair number @@ -3701,7 +3701,7 @@ GuiCfg create_gui_configuration() ImVec2(cfg.minimal_window_size_with_advance.x, cfg.minimal_window_size_with_advance.y + input_height); - int max_style_image_width = static_cast(std::round(cfg.max_style_name_width/2 - 2 * style.FramePadding.x)); + int max_style_image_width = static_cast(std::round(cfg.max_style_name_width - 2 * style.FramePadding.x)); int max_style_image_height = static_cast(std::round(1.5 * input_height)); cfg.max_style_image_size = Vec2i(max_style_image_width, max_style_image_height); cfg.face_name_size = Vec2i(cfg.input_width, line_height_with_spacing); diff --git a/src/slic3r/GUI/Jobs/CreateFontStyleImagesJob.cpp b/src/slic3r/GUI/Jobs/CreateFontStyleImagesJob.cpp index 0b51be2480..78e5fdb9fd 100644 --- a/src/slic3r/GUI/Jobs/CreateFontStyleImagesJob.cpp +++ b/src/slic3r/GUI/Jobs/CreateFontStyleImagesJob.cpp @@ -46,12 +46,12 @@ void CreateFontStyleImagesJob::process(Ctl &ctl) // create image description StyleManager::StyleImage &image = m_images[index]; BoundingBox &bounding_box = image.bounding_box; - for (ExPolygon &shape : shapes) + for (const ExPolygon &shape : shapes) bounding_box.merge(BoundingBox(shape.contour.points)); for (ExPolygon &shape : shapes) shape.translate(-bounding_box.min); // calculate conversion from FontPoint to screen pixels by size of font - double scale = get_text_shape_scale(item.prop, *item.font.font_file); + double scale = get_text_shape_scale(item.prop, *item.font.font_file) * m_input.ppm; scales[index] = scale; //double scale = font_prop.size_in_mm * SCALING_FACTOR; From eb9b8c0c2b112f0f7649e58f4f6d7977380b8442 Mon Sep 17 00:00:00 2001 From: Filip Sykala - NTB T15p Date: Fri, 5 Jan 2024 11:25:34 +0100 Subject: [PATCH 19/91] Align font preview to left. (closer to font name) --- src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp | 2 +- src/slic3r/GUI/Jobs/CreateFontNameImageJob.cpp | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp index 74778056b7..467f08c605 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp @@ -3705,7 +3705,7 @@ GuiCfg create_gui_configuration() int max_style_image_height = static_cast(std::round(1.5 * input_height)); cfg.max_style_image_size = Vec2i(max_style_image_width, max_style_image_height); cfg.face_name_size = Vec2i(cfg.input_width, line_height_with_spacing); - cfg.face_name_texture_offset_x = cfg.face_name_size.x() + space; + cfg.face_name_texture_offset_x = cfg.face_name_size.x() + style.WindowPadding.x + space; return cfg; } } // namespace diff --git a/src/slic3r/GUI/Jobs/CreateFontNameImageJob.cpp b/src/slic3r/GUI/Jobs/CreateFontNameImageJob.cpp index 3c080148f1..299fbf92fb 100644 --- a/src/slic3r/GUI/Jobs/CreateFontNameImageJob.cpp +++ b/src/slic3r/GUI/Jobs/CreateFontNameImageJob.cpp @@ -146,8 +146,9 @@ void CreateFontImageJob::finalize(bool canceled, std::exception_ptr &) glsafe(::glBindTexture(target, m_input.texture_id)); GLsizei w = m_tex_size.x(), h = m_tex_size.y(); - GLint xoffset = m_input.size.x() - m_tex_size.x(), // arrange right - yoffset = m_input.size.y() * m_input.index; + GLint xoffset = 0; // align to left + // GLint xoffset = m_input.size.x() - m_tex_size.x(); // align right + GLint yoffset = m_input.size.y() * m_input.index; glsafe(::glTexSubImage2D(target, m_input.level, xoffset, yoffset, w, h, m_input.format, m_input.type, m_result.data())); From ff13a7c99bde28cf1549f986f13d53080aeb05a8 Mon Sep 17 00:00:00 2001 From: Filip Sykala - NTB T15p Date: Fri, 5 Jan 2024 14:25:05 +0100 Subject: [PATCH 20/91] Store undo/redo snap after stop input-sliding --- src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp | 32 +++++++++++++++++----- src/slic3r/GUI/Gizmos/GLGizmoSVG.cpp | 36 ++++++++++++++++++------- src/slic3r/GUI/SurfaceDrag.cpp | 25 +++-------------- src/slic3r/GUI/SurfaceDrag.hpp | 8 +++--- 4 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp index b92b931ded..6cccfa3c09 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp @@ -77,6 +77,14 @@ using namespace Slic3r::GUI; using namespace Slic3r::GUI::Emboss; namespace { +// TRN - Title in Undo/Redo stack after rotate with text around emboss axe +const std::string rotation_snapshot_name = L("Text rotate"); +// NOTE: Translation is made in "m_parent.do_rotate()" + +// TRN - Title in Undo/Redo stack after move with text along emboss axe - From surface +const std::string move_snapshot_name = L("Text move"); +// NOTE: Translation is made in "m_parent.do_translate()" + template struct Limit { // Limitation for view slider range in GUI MinMax gui; @@ -978,7 +986,7 @@ void GLGizmoEmboss::on_stop_dragging() m_rotate_gizmo.set_angle(PI/2); // apply rotation - m_parent.do_rotate(L("Text-Rotate")); + m_parent.do_rotate(rotation_snapshot_name); m_rotate_start_angle.reset(); volume_transformation_changed(); } @@ -2139,7 +2147,7 @@ void fix_transformation(const StyleManager::Style &from, const StyleManager::Sty // fix rotation float f_angle = f_angle_opt.value_or(.0f); float t_angle = t_angle_opt.value_or(.0f); - do_local_z_rotate(canvas, t_angle - f_angle); + do_local_z_rotate(canvas.get_selection(), t_angle - f_angle); } // fix distance (Z move) when exists difference in styles @@ -2148,7 +2156,7 @@ void fix_transformation(const StyleManager::Style &from, const StyleManager::Sty if (!is_approx(f_move_opt, t_move_opt)) { float f_move = f_move_opt.value_or(.0f); float t_move = t_move_opt.value_or(.0f); - do_local_z_move(canvas, t_move - f_move); + do_local_z_move(canvas.get_selection(), t_move - f_move); } } } // namesapce @@ -2412,6 +2420,10 @@ bool GLGizmoEmboss::revertible(const std::string &name, ImGui::SameLine(undo_offset); // change cursor postion if (draw_button(m_icons, IconType::undo)) { value = *default_value; + + // !! Fix to detect change of value after revert of float-slider + m_imgui->get_last_slider_status().deactivated_after_edit = true; + return true; } else if (ImGui::IsItemHovered()) ImGui::SetTooltip("%s", undo_tooltip.c_str()); @@ -2841,9 +2853,14 @@ void GLGizmoEmboss::draw_advanced() if (font_prop.per_glyph){ process(); } else { - do_local_z_move(m_parent, distance.value_or(.0f) - prev_distance); - } + do_local_z_move(m_parent.get_selection(), distance.value_or(.0f) - prev_distance); + } } + + // Apply move to model(backend) + if (m_imgui->get_last_slider_status().deactivated_after_edit) + m_parent.do_rotate(move_snapshot_name); + m_imgui->disabled_end(); // allowe_surface_distance // slider for Clock-wise angle in degress @@ -2865,7 +2882,7 @@ void GLGizmoEmboss::draw_advanced() Geometry::to_range_pi_pi(angle_rad); double diff_angle = angle_rad - angle; - do_local_z_rotate(m_parent, diff_angle); + do_local_z_rotate(m_parent.get_selection(), diff_angle); // calc angle after rotation const Selection &selection = m_parent.get_selection(); @@ -2882,6 +2899,9 @@ void GLGizmoEmboss::draw_advanced() if (use_surface || font_prop.per_glyph) process(); } + // Apply rotation on model (backend) + if (m_imgui->get_last_slider_status().deactivated_after_edit) + m_parent.do_rotate(rotation_snapshot_name); // Keep up - lock button icon if (!m_volume->is_the_only_one_part()) { diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSVG.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSVG.cpp index 2d08f9d7eb..57fc48bd0b 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSVG.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSVG.cpp @@ -51,6 +51,14 @@ GLGizmoSVG::GLGizmoSVG(GLCanvas3D &parent) // Private functions to create emboss volume namespace{ +// TRN - Title in Undo/Redo stack after rotate with SVG around emboss axe +const std::string rotation_snapshot_name = L("SVG rotate"); +// NOTE: Translation is made in "m_parent.do_rotate()" + +// TRN - Title in Undo/Redo stack after move with SVG along emboss axe - From surface +const std::string move_snapshot_name = L("SVG move"); +// NOTE: Translation is made in "m_parent.do_translate()" + // Variable keep limits for variables const struct Limits { @@ -539,7 +547,7 @@ void GLGizmoSVG::on_stop_dragging() // apply rotation // TRN This is an item label in the undo-redo stack. - m_parent.do_rotate(L("SVG-Rotate")); + m_parent.do_rotate(rotation_snapshot_name); m_rotate_start_angle.reset(); volume_transformation_changed(); @@ -1832,18 +1840,20 @@ void GLGizmoSVG::draw_distance() if (m_imgui->slider_optional_float("##distance", m_distance, min_distance, max_distance, "%.2f mm", 1.f, false, move_tooltip)) is_moved = true; } - - bool can_reset = m_distance.has_value(); - if (can_reset) { + bool is_stop_sliding = m_imgui->get_last_slider_status().deactivated_after_edit; + bool is_reseted = false; + if (m_distance.has_value()) { if (reset_button(m_icons)) { m_distance.reset(); - is_moved = true; + is_reseted = true; } else if (ImGui::IsItemHovered()) ImGui::SetTooltip("%s", _u8L("Reset distance").c_str()); } - if (is_moved) - do_local_z_move(m_parent, m_distance.value_or(.0f) - prev_distance); + if (is_moved || is_reseted) + do_local_z_move(m_parent.get_selection(), m_distance.value_or(.0f) - prev_distance); + if (is_stop_sliding || is_reseted) + m_parent.do_move(move_snapshot_name); } void GLGizmoSVG::draw_rotation() @@ -1865,7 +1875,7 @@ void GLGizmoSVG::draw_rotation() double diff_angle = angle_rad - angle; - do_local_z_rotate(m_parent, diff_angle); + do_local_z_rotate(m_parent.get_selection(), diff_angle); // calc angle after rotation m_angle = calc_angle(m_parent.get_selection()); @@ -1874,20 +1884,28 @@ void GLGizmoSVG::draw_rotation() if (m_volume->emboss_shape->projection.use_surface) process(); } + bool is_stop_sliding = m_imgui->get_last_slider_status().deactivated_after_edit; // Reset button + bool is_reseted = false; if (m_angle.has_value()) { if (reset_button(m_icons)) { - do_local_z_rotate(m_parent, -(*m_angle)); + do_local_z_rotate(m_parent.get_selection(), -(*m_angle)); m_angle.reset(); // recalculate for surface cut if (m_volume->emboss_shape->projection.use_surface) process(); + + is_reseted = true; } else if (ImGui::IsItemHovered()) ImGui::SetTooltip("%s", _u8L("Reset rotation").c_str()); } + // Apply rotation on model (backend) + if (is_stop_sliding || is_reseted) + m_parent.do_rotate(rotation_snapshot_name); + // Keep up - lock button icon if (!m_volume->is_the_only_one_part()) { ImGui::SameLine(m_gui_cfg->lock_offset); diff --git a/src/slic3r/GUI/SurfaceDrag.cpp b/src/slic3r/GUI/SurfaceDrag.cpp index 39573dbf96..100847bf48 100644 --- a/src/slic3r/GUI/SurfaceDrag.cpp +++ b/src/slic3r/GUI/SurfaceDrag.cpp @@ -322,11 +322,11 @@ bool face_selected_volume_to_camera(const Camera &camera, GLCanvas3D &canvas, co return false; ModelObject &object = *object_ptr; - ModelInstance *instance_ptr = get_model_instance(gl_volume, object); + const ModelInstance *instance_ptr = get_model_instance(gl_volume, object); assert(instance_ptr != nullptr); if (instance_ptr == nullptr) return false; - ModelInstance &instance = *instance_ptr; + const ModelInstance &instance = *instance_ptr; ModelVolume *volume_ptr = get_model_volume(gl_volume, object); assert(volume_ptr != nullptr); @@ -385,10 +385,7 @@ bool face_selected_volume_to_camera(const Camera &camera, GLCanvas3D &canvas, co return true; } -void do_local_z_rotate(GLCanvas3D &canvas, double relative_angle) -{ - Selection &selection = canvas.get_selection(); - +void do_local_z_rotate(Selection &selection, double relative_angle) { assert(!selection.is_empty()); if(selection.is_empty()) return; @@ -418,17 +415,9 @@ void do_local_z_rotate(GLCanvas3D &canvas, double relative_angle) selection.rotate(Vec3d(0., 0., relative_angle), get_drag_transformation_type(selection)); }; selection_transform(selection, selection_rotate_fnc); - - std::string snapshot_name; // empty meand no store undo / redo - // NOTE: it use L instead of _L macro because prefix _ is appended - // inside function do_move - // snapshot_name = L("Set text rotation"); - canvas.do_rotate(snapshot_name); } -void do_local_z_move(GLCanvas3D &canvas, double relative_move) { - - Selection &selection = canvas.get_selection(); +void do_local_z_move(Selection &selection, double relative_move) { assert(!selection.is_empty()); if (selection.is_empty()) return; @@ -438,12 +427,6 @@ void do_local_z_move(GLCanvas3D &canvas, double relative_move) { selection.translate(translate, TransformationType::Local); }; selection_transform(selection, selection_translate_fnc); - - std::string snapshot_name; // empty mean no store undo / redo - // NOTE: it use L instead of _L macro because prefix _ is appended inside - // function do_move - // snapshot_name = L("Set surface distance"); - canvas.do_move(snapshot_name); } TransformationType get_drag_transformation_type(const Selection &selection) diff --git a/src/slic3r/GUI/SurfaceDrag.hpp b/src/slic3r/GUI/SurfaceDrag.hpp index 9f1c0e3c07..44c57c41c7 100644 --- a/src/slic3r/GUI/SurfaceDrag.hpp +++ b/src/slic3r/GUI/SurfaceDrag.hpp @@ -136,16 +136,16 @@ bool face_selected_volume_to_camera(const Camera &camera, GLCanvas3D &canvas, co /// /// Rotation around z Axis(emboss direction) /// -/// Selected volume for rotation +/// Selected volume for rotation /// Relative angle to rotate around emboss direction -void do_local_z_rotate(GLCanvas3D &canvas, double relative_angle); +void do_local_z_rotate(Selection &selection, double relative_angle); /// /// Translation along local z Axis (emboss direction) /// -/// Selected volume for translate +/// Selected volume for translate /// Relative move along emboss direction -void do_local_z_move(GLCanvas3D &canvas, double relative_move); +void do_local_z_move(Selection &selection, double relative_move); /// /// Distiguish between object and volume From e922fdceb4e12dc5f22bf9dab71bfe84a8ec5be8 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Fri, 22 Dec 2023 13:38:01 +0100 Subject: [PATCH 21/91] Fixed usage of custom filename extension in SLA mode, broken in 283fd6f. --- src/slic3r/GUI/GUI_App.cpp | 6 +++--- src/slic3r/GUI/GUI_App.hpp | 2 +- src/slic3r/GUI/Plater.cpp | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index d632e9ba2d..75f52eaf36 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -567,7 +567,7 @@ wxString file_wildcards(FileType file_type, const std::string &custom_extension) return file_wildcards(file_wildcards_by_type[file_type], custom_extension); } -wxString sla_wildcards(const char *formatid) +wxString sla_wildcards(const char *formatid, const std::string& custom_extension) { const ArchiveEntry *entry = get_archive_entry(formatid); wxString ret; @@ -587,11 +587,11 @@ wxString sla_wildcards(const char *formatid) wc.file_extensions.emplace_back(ext); } - ret = file_wildcards(wc, {}); + ret = file_wildcards(wc, custom_extension); } if (ret.empty()) - ret = file_wildcards(FT_SL1); + ret = file_wildcards(FT_SL1, custom_extension); return ret; } diff --git a/src/slic3r/GUI/GUI_App.hpp b/src/slic3r/GUI/GUI_App.hpp index 8663301e7d..4e2854d3aa 100644 --- a/src/slic3r/GUI/GUI_App.hpp +++ b/src/slic3r/GUI/GUI_App.hpp @@ -85,7 +85,7 @@ enum FileType extern wxString file_wildcards(FileType file_type, const std::string &custom_extension = {}); -wxString sla_wildcards(const char *formatid); +wxString sla_wildcards(const char *formatid, const std::string& custom_extension); enum ConfigMenuIDs { ConfigMenuWizard, diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index ab98771f64..71aacc326d 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -6794,7 +6794,7 @@ void Plater::export_gcode(bool prefer_removable) start_dir, from_path(default_output_file.filename()), printer_technology() == ptFFF ? GUI::file_wildcards(FT_GCODE, ext) : - GUI::sla_wildcards(p->sla_print.printer_config().sla_archive_format.value.c_str()), + GUI::sla_wildcards(p->sla_print.printer_config().sla_archive_format.value.c_str(), ext), wxFD_SAVE | wxFD_OVERWRITE_PROMPT ); if (dlg.ShowModal() == wxID_OK) { From 141ae5a916870350b380ebb867408d60d14b2a8e Mon Sep 17 00:00:00 2001 From: YuSanka Date: Fri, 5 Jan 2024 14:15:49 +0100 Subject: [PATCH 22/91] ConfigWizard : Fixed a crash, when some of material pages doesn't exist --- src/slic3r/GUI/ConfigWizard.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/ConfigWizard.cpp b/src/slic3r/GUI/ConfigWizard.cpp index 1329fdbef3..7ab9242aac 100644 --- a/src/slic3r/GUI/ConfigWizard.cpp +++ b/src/slic3r/GUI/ConfigWizard.cpp @@ -2785,8 +2785,10 @@ bool ConfigWizard::priv::on_bnt_finish() * than last changes wouldn't be updated for filaments/materials. * SO, do that before check_and_install_missing_materials() */ - page_filaments->check_and_update_presets(); - page_sla_materials->check_and_update_presets(); + if (page_filaments) + page_filaments->check_and_update_presets(); + if (page_sla_materials) + page_sla_materials->check_and_update_presets(); // there's 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; From fe16f5bdd1b718ca73aa6d44838f92af4019b7b9 Mon Sep 17 00:00:00 2001 From: Filip Sykala - NTB T15p Date: Fri, 5 Jan 2024 15:40:46 +0100 Subject: [PATCH 23/91] Store/Load align and per_glyph in Slicer.ini for text style --- src/slic3r/Utils/EmbossStyleManager.cpp | 59 +++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/src/slic3r/Utils/EmbossStyleManager.cpp b/src/slic3r/Utils/EmbossStyleManager.cpp index 5c368673a1..6c428ee86c 100644 --- a/src/slic3r/Utils/EmbossStyleManager.cpp +++ b/src/slic3r/Utils/EmbossStyleManager.cpp @@ -14,6 +14,9 @@ #include "slic3r/GUI/Jobs/CreateFontStyleImagesJob.hpp" #include "slic3r/GUI/ImGuiWrapper.hpp" // check of font ranges +#include +#include + using namespace Slic3r; using namespace Slic3r::Emboss; using namespace Slic3r::GUI::Emboss; @@ -38,6 +41,20 @@ void store_style_index(AppConfig &cfg, size_t index); StyleManager::Styles load_styles(const AppConfig &cfg); void store_styles(AppConfig &cfg, const StyleManager::Styles &styles); void make_unique_name(const StyleManager::Styles &styles, std::string &name); + +// Enum map to string and vice versa +using HorizontalAlignToName = boost::bimap; +const HorizontalAlignToName horizontal_align_to_name = +boost::assign::list_of + (FontProp::HorizontalAlign::left, "left") + (FontProp::HorizontalAlign::center, "center") + (FontProp::HorizontalAlign::right, "right"); +using VerticalAlignToName = boost::bimap; +const VerticalAlignToName vertical_align_to_name = +boost::assign::list_of + (FontProp::VerticalAlign::top, "top") + (FontProp::VerticalAlign::center, "middle") + (FontProp::VerticalAlign::bottom, "bottom"); } // namespace void StyleManager::init(AppConfig *app_config) @@ -535,6 +552,9 @@ const std::string APP_CONFIG_FONT_DESCRIPTOR = "descriptor"; const std::string APP_CONFIG_FONT_LINE_HEIGHT = "line_height"; const std::string APP_CONFIG_FONT_DEPTH = "depth"; const std::string APP_CONFIG_FONT_USE_SURFACE = "use_surface"; +const std::string APP_CONFIG_PER_GLYPH = "per_glyph"; +const std::string APP_CONFIG_VERTICAL_ALIGN = "vertical_align"; +const std::string APP_CONFIG_HORIZONTAL_ALIGN = "horizontal_align"; const std::string APP_CONFIG_FONT_BOLDNESS = "boldness"; const std::string APP_CONFIG_FONT_SKEW = "skew"; const std::string APP_CONFIG_FONT_DISTANCE = "distance"; @@ -561,6 +581,36 @@ bool read(const Section §ion, const std::string &key, bool &value) return true; } +bool read(const Section §ion, const std::string &key, Slic3r::FontProp::HorizontalAlign &value) { + auto item = section.find(key); + if (item == section.end()) + return false; + + const std::string &data = item->second; + if (data.empty()) + return false; + + const auto& map = horizontal_align_to_name.right; + auto it = map.find(data); + value = (it != map.end()) ? it->second : Slic3r::FontProp::HorizontalAlign::center; + return true; +} + +bool read(const Section §ion, const std::string &key, Slic3r::FontProp::VerticalAlign &value) { + auto item = section.find(key); + if (item == section.end()) + return false; + + const std::string &data = item->second; + if (data.empty()) + return false; + + const auto &map = vertical_align_to_name.right; + auto it = map.find(data); + value = (it != map.end()) ? it->second : Slic3r::FontProp::VerticalAlign::center; + return true; +} + bool read(const Section §ion, const std::string &key, float &value) { auto item = section.find(key); @@ -650,6 +700,9 @@ std::optional load_style(const Section &app_cfg_section) read(app_cfg_section, APP_CONFIG_FONT_DEPTH, depth); ep.depth = depth; read(app_cfg_section, APP_CONFIG_FONT_USE_SURFACE, ep.use_surface); + read(app_cfg_section, APP_CONFIG_PER_GLYPH, fp.per_glyph); + read(app_cfg_section, APP_CONFIG_HORIZONTAL_ALIGN, fp.align.first); + read(app_cfg_section, APP_CONFIG_VERTICAL_ALIGN, fp.align.second); read(app_cfg_section, APP_CONFIG_FONT_BOLDNESS, fp.boldness); read(app_cfg_section, APP_CONFIG_FONT_SKEW, fp.skew); read(app_cfg_section, APP_CONFIG_FONT_DISTANCE, s.distance); @@ -671,6 +724,12 @@ void store_style(AppConfig &cfg, const StyleManager::Style &s, unsigned index) data[APP_CONFIG_FONT_DEPTH] = std::to_string(ep.depth); if (ep.use_surface) data[APP_CONFIG_FONT_USE_SURFACE] = "true"; + if (fp.per_glyph) + data[APP_CONFIG_PER_GLYPH] = "true"; + if (fp.align.first != FontProp::HorizontalAlign::center) + data[APP_CONFIG_HORIZONTAL_ALIGN] = horizontal_align_to_name.left.find(fp.align.first)->second; + if (fp.align.second != FontProp::VerticalAlign::center) + data[APP_CONFIG_VERTICAL_ALIGN] = vertical_align_to_name.left.find(fp.align.second)->second; if (fp.boldness.has_value()) data[APP_CONFIG_FONT_BOLDNESS] = std::to_string(*fp.boldness); if (fp.skew.has_value()) From f9825bb6f438aefcc81d5f0179d16915b2ccaedd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hejl?= Date: Thu, 4 Jan 2024 14:42:51 +0100 Subject: [PATCH 24/91] Silence warnings in ExtrusionSimulator about unused variables that were there just for debugging purposes. --- src/libslic3r/ExtrusionSimulator.cpp | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/src/libslic3r/ExtrusionSimulator.cpp b/src/libslic3r/ExtrusionSimulator.cpp index 6408c4b144..fcd89b1f2d 100644 --- a/src/libslic3r/ExtrusionSimulator.cpp +++ b/src/libslic3r/ExtrusionSimulator.cpp @@ -699,13 +699,16 @@ void gcode_spread_points( } } */ - float area_total = 0; - float volume_total = 0; - float volume_excess = 0; - float volume_deficit = 0; - size_t n_cells = 0; - float area_circle_total = 0; + + float area_total = 0; + float volume_total = 0; + size_t n_cells = 0; + #if 0 + float volume_excess = 0; + float volume_deficit = 0; + float area_circle_total = 0; + // The intermediate lines. for (int j = row_first; j < row_last; ++ j) { const std::pair &span1 = spans[j]; @@ -759,7 +762,11 @@ void gcode_spread_points( cell.volume = acc[j][i]; cell.area = mask[j][i]; assert(cell.area >= 0.f && cell.area <= 1.000001f); - area_circle_total += area; + +#if 0 + area_circle_total += area; +#endif + if (cell.area < area) cell.area = area; cell.fraction_covered = std::clamp((cell.area > 0) ? (area / cell.area) : 0, 0.f, 1.f); @@ -769,10 +776,15 @@ void gcode_spread_points( } float cell_height = cell.volume / cell.area; cell.excess_height = cell_height - height_target; + +#if 0 + area_circle_total += area; if (cell.excess_height > 0.f) volume_excess += cell.excess_height * cell.area * cell.fraction_covered; else volume_deficit -= cell.excess_height * cell.area * cell.fraction_covered; +#endif + volume_total += cell.volume * cell.fraction_covered; area_total += cell.area * cell.fraction_covered; } From 413241fcbc936a1e6c565c1d58fb8943c595c65b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hejl?= Date: Thu, 4 Jan 2024 14:44:30 +0100 Subject: [PATCH 25/91] Remove unused variable path_length from GCodeGenerator::_extrude(). This variable hasn't been used since the beginning. --- src/libslic3r/GCode.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 8853ad9ce6..30df60c786 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -3142,7 +3142,7 @@ std::string GCodeGenerator::_extrude( gcode += m_writer.set_speed(F, "", cooling_marker_setspeed_comments); if (dynamic_speed_and_fan_speed.second >= 0) gcode += ";_SET_FAN_SPEED" + std::to_string(int(dynamic_speed_and_fan_speed.second)) + "\n"; - double path_length = 0.; + std::string comment; if (m_config.gcode_comments) { comment = description; @@ -3176,16 +3176,13 @@ std::string GCodeGenerator::_extrude( } if (radius == 0) { // Extrude line segment. - if (const double line_length = (p - prev).norm(); line_length > 0) { - path_length += line_length; + if (const double line_length = (p - prev).norm(); line_length > 0) gcode += m_writer.extrude_to_xy(p, e_per_mm * line_length, comment); - } } else { double angle = Geometry::ArcWelder::arc_angle(prev.cast(), p.cast(), double(radius)); assert(angle > 0); const double line_length = angle * std::abs(radius); - path_length += line_length; - const double dE = e_per_mm * line_length; + const double dE = e_per_mm * line_length; assert(dE > 0); gcode += m_writer.extrude_to_xy_G2G3IJ(p, ij, it->ccw(), dE, comment); } From 41aff15c515db78c8fae1970a68123ead7341459 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hejl?= Date: Thu, 4 Jan 2024 14:50:49 +0100 Subject: [PATCH 26/91] Remove unused lambda capture plater in lambda function fix_and_update_progress() inside check_objects_after_cut(). --- src/slic3r/GUI/Gizmos/GLGizmoCut.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp b/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp index 48d119e7dc..9873d2f6d0 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp @@ -3310,7 +3310,7 @@ static void check_objects_after_cut(const ModelObjectPtrs& objects) for (int obj_idx : err_objects_idxs) model_names.push_back(objects[obj_idx]->name); - auto fix_and_update_progress = [plater, model_names, &objects](const int obj_idx, int model_idx, + auto fix_and_update_progress = [model_names, &objects](const int obj_idx, int model_idx, wxProgressDialog& progress_dlg, std::vector& succes_models, std::vector>& failed_models) -> bool From 69b29a202fd8a4a768e7fd61f114b4b92ce07f12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hejl?= Date: Thu, 4 Jan 2024 14:53:39 +0100 Subject: [PATCH 27/91] Remove forgotten variable m_wifi_config_dialog_was_declined from Slic3r::GUI::GUI_App class. --- src/slic3r/GUI/GUI_App.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/slic3r/GUI/GUI_App.hpp b/src/slic3r/GUI/GUI_App.hpp index 4e2854d3aa..b1dc3cb99b 100644 --- a/src/slic3r/GUI/GUI_App.hpp +++ b/src/slic3r/GUI/GUI_App.hpp @@ -404,7 +404,6 @@ private: bool m_datadir_redefined { false }; bool m_wifi_config_dialog_shown { false }; - bool m_wifi_config_dialog_was_declined { false }; }; DECLARE_APP(GUI_App) From a98b97643e89004e5bed2ce1d9f4132955bc35f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hejl?= Date: Thu, 4 Jan 2024 15:00:47 +0100 Subject: [PATCH 28/91] Avoid unnecessary copy of the variable 'pair' in WifiConfigDialog::rescan_networks(). --- src/slic3r/GUI/WifiConfigDialog.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slic3r/GUI/WifiConfigDialog.cpp b/src/slic3r/GUI/WifiConfigDialog.cpp index 6b088d8ad5..e5be758be5 100644 --- a/src/slic3r/GUI/WifiConfigDialog.cpp +++ b/src/slic3r/GUI/WifiConfigDialog.cpp @@ -192,7 +192,7 @@ void WifiConfigDialog::rescan_networks(bool select) std::string current = m_wifi_scanner->get_current_ssid(); const auto& map = m_wifi_scanner->get_map(); m_ssid_combo->Clear(); - for (const auto pair : map) { + for (const auto &pair : map) { m_ssid_combo->Append(pair.first); // select ssid of current network (if connected) if (current == pair.first) From 7e8f45a302a501cf60cf67b0eefbded2f6b03c80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hejl?= Date: Thu, 4 Jan 2024 15:06:23 +0100 Subject: [PATCH 29/91] Remove unused variable 'some_compatible' from ExtruderFilaments::update_compatible_internal(). This variable hasn't been used since the beginning. --- src/libslic3r/Preset.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index 44c29c32c2..75dda312ef 100644 --- a/src/libslic3r/Preset.cpp +++ b/src/libslic3r/Preset.cpp @@ -2253,7 +2253,6 @@ size_t ExtruderFilaments::update_compatible_internal(const PresetWithVendorProfi const ConfigOption* opt = active_printer.preset.config.option("nozzle_diameter"); if (opt) config.set_key_value("num_extruders", new ConfigOptionInt((int)static_cast(opt)->values.size())); - bool some_compatible = false; // Adjust printer preset config to the first extruder from m_extruder_id Preset printer_preset_adjusted = active_printer.preset; @@ -2281,7 +2280,6 @@ size_t ExtruderFilaments::update_compatible_internal(const PresetWithVendorProfi const PresetWithVendorProfile this_preset_with_vendor_profile = m_filaments->get_preset_with_vendor_profile(*preset); bool was_compatible = extr_filament.is_compatible; extr_filament.is_compatible = is_compatible_with_printer(this_preset_with_vendor_profile, active_printer_adjusted, &config); - some_compatible |= extr_filament.is_compatible; if (active_print != nullptr) extr_filament.is_compatible &= is_compatible_with_print(this_preset_with_vendor_profile, *active_print, active_printer_adjusted); if (!extr_filament.is_compatible && is_selected && From 229946a25c7da5b1810faf280c10a842eb1aa596 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hejl?= Date: Fri, 5 Jan 2024 16:28:04 +0100 Subject: [PATCH 30/91] Reorganize getArea() in TreeModelVolumes to silence the warning ( may be used uninitialized in this function). This warning was shown because the previous code was triggering a bug in GCC. More about the bug can be found here: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86465. --- src/libslic3r/Support/TreeModelVolumes.hpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/libslic3r/Support/TreeModelVolumes.hpp b/src/libslic3r/Support/TreeModelVolumes.hpp index 57ca9fae7a..eeabccd55e 100644 --- a/src/libslic3r/Support/TreeModelVolumes.hpp +++ b/src/libslic3r/Support/TreeModelVolumes.hpp @@ -244,12 +244,16 @@ private: */ std::optional> getArea(const TreeModelVolumes::RadiusLayerPair &key) const { std::lock_guard guard(m_mutex); + if (key.second >= LayerIndex(m_data.size())) - return std::optional>{}; - const auto &layer = m_data[key.second]; + return std::nullopt; + + const LayerData &layer = m_data[key.second]; auto it = layer.find(key.first); - return it == layer.end() ? - std::optional>{} : std::optional>{ it->second }; + if (it == layer.end()) + return std::nullopt; + + return std::optional>{it->second}; } // Get a collision area at a given layer for a radius that is a lower or equial to the key radius. std::optional>> get_lower_bound_area(const TreeModelVolumes::RadiusLayerPair &key) const { From 7ab3e5490c26b15c624d75a33108e42ce24570b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hejl?= Date: Fri, 5 Jan 2024 18:41:19 +0100 Subject: [PATCH 31/91] SPE-2096: Fixed calculation of maximum wipe length in XY coordinates. Also, comparing the accumulated length of the path for wipe was incorrectly mixing scaled and unscaled distances. --- src/libslic3r/GCode/Wipe.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/libslic3r/GCode/Wipe.cpp b/src/libslic3r/GCode/Wipe.cpp index fd7cacd0bf..e75c599297 100644 --- a/src/libslic3r/GCode/Wipe.cpp +++ b/src/libslic3r/GCode/Wipe.cpp @@ -21,9 +21,9 @@ void Wipe::init(const PrintConfig &config, const std::vector &extr if (config.wipe.get_at(id)) { // Wipe length to extrusion ratio. const double xy_to_e = this->calc_xy_to_e_ratio(config, id); - wipe_xy = std::max(wipe_xy, xy_to_e * config.retract_length.get_at(id)); + wipe_xy = std::max(wipe_xy, config.retract_length.get_at(id) / xy_to_e); if (multimaterial) - wipe_xy = std::max(wipe_xy, xy_to_e * config.retract_length_toolchange.get_at(id)); + wipe_xy = std::max(wipe_xy, config.retract_length_toolchange.get_at(id) / xy_to_e); } if (wipe_xy == 0) @@ -37,11 +37,11 @@ void Wipe::set_path(SmoothPath &&path, bool reversed) this->reset_path(); if (this->enabled() && ! path.empty()) { - if (reversed) { + if (coord_t wipe_len_max_scaled = scaled(m_wipe_len_max); reversed) { m_path = std::move(path.back().path); Geometry::ArcWelder::reverse(m_path); int64_t len = Geometry::ArcWelder::estimate_path_length(m_path); - for (auto it = std::next(path.rbegin()); len < m_wipe_len_max && it != path.rend(); ++ it) { + for (auto it = std::next(path.rbegin()); len < wipe_len_max_scaled && it != path.rend(); ++ it) { if (it->path_attributes.role.is_bridge()) break; // Do not perform a wipe on bridges. assert(it->path.size() >= 2); @@ -55,7 +55,7 @@ void Wipe::set_path(SmoothPath &&path, bool reversed) } else { m_path = std::move(path.front().path); int64_t len = Geometry::ArcWelder::estimate_path_length(m_path); - for (auto it = std::next(path.begin()); len < m_wipe_len_max && it != path.end(); ++ it) { + for (auto it = std::next(path.begin()); len < wipe_len_max_scaled && it != path.end(); ++ it) { if (it->path_attributes.role.is_bridge()) break; // Do not perform a wipe on bridges. assert(it->path.size() >= 2); From 852faddc5b92039af48b1d7c8786ac8a74972b98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20=C5=A0ach?= Date: Fri, 1 Dec 2023 16:31:30 +0100 Subject: [PATCH 32/91] Rewrite retraction.t to c++ --- t/retraction.t | 260 --------------------- tests/fff_print/CMakeLists.txt | 1 + tests/fff_print/test_retraction.cpp | 337 ++++++++++++++++++++++++++++ 3 files changed, 338 insertions(+), 260 deletions(-) delete mode 100644 t/retraction.t create mode 100644 tests/fff_print/test_retraction.cpp diff --git a/t/retraction.t b/t/retraction.t deleted file mode 100644 index f773c3f080..0000000000 --- a/t/retraction.t +++ /dev/null @@ -1,260 +0,0 @@ -use Test::More tests => 26; -use strict; -use warnings; - -BEGIN { - use FindBin; - use lib "$FindBin::Bin/../lib"; - use local::lib "$FindBin::Bin/../local-lib"; -} - -use List::Util qw(any); -use Slic3r; -use Slic3r::Test qw(_eq); - -{ - my $config = Slic3r::Config::new_from_defaults; - my $duplicate = 1; - - my $test = sub { - my ($conf) = @_; - $conf ||= $config; - - my $print = Slic3r::Test::init_print('20mm_cube', config => $conf, duplicate => $duplicate); - - my $tool = 0; - my @toolchange_count = (); # track first usages so that we don't expect retract_length_toolchange when extruders are used for the first time - my @retracted = (0); - my @retracted_length = (0); - my $lifted = 0; - my $lift_dist = 0; # track lifted distance for toolchanges and extruders with different retract_lift values - my $changed_tool = 0; - my $wait_for_toolchange = 0; - Slic3r::GCode::Reader->new->parse(Slic3r::Test::gcode($print), sub { - my ($self, $cmd, $args, $info) = @_; - - if ($cmd =~ /^T(\d+)/) { - $tool = $1; - $changed_tool = 1; - $wait_for_toolchange = 0; - $toolchange_count[$tool] //= 0; - $toolchange_count[$tool]++; - } elsif ($cmd =~ /^G[01]$/ && !$args->{Z}) { # ignore lift taking place after retraction - fail 'toolchange happens right after retraction' if $wait_for_toolchange; - } - - if ($info->{dist_Z}) { - # lift move or lift + change layer - if (_eq($info->{dist_Z}, $print->print->config->get_at('retract_lift', $tool)) - || (_eq($info->{dist_Z}, $conf->layer_height + $print->print->config->get_at('retract_lift', $tool)) && $print->print->config->get_at('retract_lift', $tool) > 0)) { - fail 'only lifting while retracted' if !$retracted[$tool]; - fail 'double lift' if $lifted; - $lifted = 1; - $lift_dist = $info->{dist_Z}; - } - if ($info->{dist_Z} < 0) { - fail 'going down only after lifting' if !$lifted; - fail 'going down by the same amount of the lift or by the amount needed to get to next layer' - if !_eq($info->{dist_Z}, -$lift_dist) - && !_eq($info->{dist_Z}, -lift_dist + $conf->layer_height); - $lift_dist = 0; - $lifted = 0; - } - fail 'move Z at travel speed' if ($args->{F} // $self->F) != $conf->travel_speed * 60; - } - if ($info->{retracting}) { - $retracted[$tool] = 1; - $retracted_length[$tool] += -$info->{dist_E}; - if (_eq($retracted_length[$tool], $print->print->config->get_at('retract_length', $tool))) { - # okay - } elsif (_eq($retracted_length[$tool], $print->print->config->get_at('retract_length_toolchange', $tool))) { - $wait_for_toolchange = 1; - } else { - fail 'retracted by the correct amount'; - } - } - if ($info->{extruding}) { - fail 'only extruding while not lifted' if $lifted; - if ($retracted[$tool]) { - my $expected_amount = $retracted_length[$tool] + $print->print->config->get_at('retract_restart_extra', $tool); - if ($changed_tool && $toolchange_count[$tool] > 1) { - $expected_amount = $print->print->config->get_at('retract_length_toolchange', $tool) + $print->print->config->get_at('retract_restart_extra_toolchange', $tool); - $changed_tool = 0; - } - fail 'unretracted by the correct amount' && exit - if !_eq($info->{dist_E}, $expected_amount); - $retracted[$tool] = 0; - $retracted_length[$tool] = 0; - } - } - if ($info->{travel} && $info->{dist_XY} >= $print->print->config->get_at('retract_before_travel', $tool)) { - fail 'retracted before long travel move' if !$retracted[$tool]; - } - }); - - 1; - }; - - $config->set('nozzle_diameter', [0.6,0.6,0.6,0.6]); - $config->set('first_layer_height', $config->layer_height); - $config->set('first_layer_speed', '100%'); - $config->set('start_gcode', ''); # to avoid dealing with the nozzle lift in start G-code - $config->set('retract_length', [1.5]); - $config->set('retract_before_travel', [3]); - $config->set('only_retract_when_crossing_perimeters', 0); - - my $retract_tests = sub { - my ($descr) = @_; - - ok $test->(), "retraction$descr"; - - my $conf = $config->clone; - $conf->set('retract_restart_extra', [1]); - ok $test->($conf), "restart extra length$descr"; - - $conf->set('retract_restart_extra', [-1]); - ok $test->($conf), "negative restart extra length$descr"; - - $conf->set('retract_lift', [1, 2]); - ok $test->($conf), "lift$descr"; - }; - - $retract_tests->(''); - - $duplicate = 2; - $retract_tests->(' (duplicate)'); - - $duplicate = 1; - $config->set('infill_extruder', 2); - $config->set('skirts', 4); - $config->set('skirt_height', 3); - $retract_tests->(' (dual extruder with multiple skirt layers)'); -} - -{ - my $config = Slic3r::Config::new_from_defaults; - $config->set('start_gcode', ''); # prevent any default priming Z move from affecting our lift detection - $config->set('retract_length', [0]); - $config->set('retract_layer_change', [0]); - $config->set('retract_lift', [0.2]); - - my $print = Slic3r::Test::init_print('20mm_cube', config => $config); - my $retracted = 0; - my $layer_changes_with_retraction = 0; - my $retractions = my $z_restores = 0; - Slic3r::GCode::Reader->new->parse(Slic3r::Test::gcode($print), sub { - my ($self, $cmd, $args, $info) = @_; - - if ($info->{retracting}) { - $retracted = 1; - $retractions++; - } elsif ($info->{extruding} && $retracted) { - $retracted = 0; - } - - if ($info->{dist_Z} && $retracted) { - $layer_changes_with_retraction++; - } - if ($info->{dist_Z} && $args->{Z} < $self->{Z}) { - $z_restores++; - } - }); - - is $layer_changes_with_retraction, 0, 'no retraction on layer change'; - is $retractions, 0, 'no retractions'; - is $z_restores, 0, 'no lift'; -} - -{ - my $config = Slic3r::Config::new_from_defaults; - $config->set('use_firmware_retraction', 1); - - my $print = Slic3r::Test::init_print('20mm_cube', config => $config); - my $retracted = 0; - my $double_retractions = my $double_unretractions = 0; - Slic3r::GCode::Reader->new->parse(Slic3r::Test::gcode($print), sub { - my ($self, $cmd, $args, $info) = @_; - - if ($cmd eq 'G10') { - $double_retractions++ if $retracted; - $retracted = 1; - } elsif ($cmd eq 'G11') { - $double_unretractions++ if !$retracted; - $retracted = 0; - } - }); - - is $double_retractions, 0, 'no double retractions'; - is $double_unretractions, 0, 'no double unretractions'; -} - -{ - my $config = Slic3r::Config::new_from_defaults; - $config->set('use_firmware_retraction', 1); - $config->set('retract_length', [0]); - - my $print = Slic3r::Test::init_print('20mm_cube', config => $config); - my $retracted = 0; - Slic3r::GCode::Reader->new->parse(Slic3r::Test::gcode($print), sub { - my ($self, $cmd, $args, $info) = @_; - - if ($cmd eq 'G10') { - $retracted = 1; - } - }); - - ok $retracted, 'retracting also when --retract-length is 0 but --use-firmware-retraction is enabled'; -} - -{ - my $config = Slic3r::Config::new_from_defaults; - $config->set('nozzle_diameter', [0.6,0.6,0.6,0.6]); - $config->set('start_gcode', ''); - $config->set('retract_lift', [3, 4]); - - my @lifted_at = (); - my $test = sub { - my $print = Slic3r::Test::init_print('20mm_cube', config => $config, duplicate => 2); - @lifted_at = (); - Slic3r::GCode::Reader->new->parse(Slic3r::Test::gcode($print), sub { - my ($self, $cmd, $args, $info) = @_; - - if ($cmd eq 'G1' && $info->{dist_Z} < 0) { - push @lifted_at, $info->{new_Z}; - } - }); - }; - - $config->set('retract_lift_above', [0, 0]); - $config->set('retract_lift_below', [0, 0]); - $test->(); - ok !!@lifted_at, 'lift takes place when above/below == 0'; - - $config->set('retract_lift_above', [5, 6]); - $config->set('retract_lift_below', [15, 13]); - $test->(); - ok !!@lifted_at, 'lift takes place when above/below != 0'; - ok !(any { $_ < $config->get_at('retract_lift_above', 0) } @lifted_at), - 'Z is not lifted below the configured value'; - ok !(any { $_ > $config->get_at('retract_lift_below', 0) } @lifted_at), - 'Z is not lifted above the configured value'; - - # check lifting with different values for 2. extruder - $config->set('perimeter_extruder', 2); - $config->set('infill_extruder', 2); - $config->set('retract_lift_above', [0, 0]); - $config->set('retract_lift_below', [0, 0]); - $test->(); - ok !!@lifted_at, 'lift takes place when above/below == 0 for 2. extruder'; - - $config->set('retract_lift_above', [5, 6]); - $config->set('retract_lift_below', [15, 13]); - $test->(); - ok !!@lifted_at, 'lift takes place when above/below != 0 for 2. extruder'; - ok !(any { $_ < $config->get_at('retract_lift_above', 1) } @lifted_at), - 'Z is not lifted below the configured value for 2. extruder'; - ok !(any { $_ > $config->get_at('retract_lift_below', 1) } @lifted_at), - 'Z is not lifted above the configured value for 2. extruder'; -} - -__END__ diff --git a/tests/fff_print/CMakeLists.txt b/tests/fff_print/CMakeLists.txt index ed128bf2e0..b21d543969 100644 --- a/tests/fff_print/CMakeLists.txt +++ b/tests/fff_print/CMakeLists.txt @@ -17,6 +17,7 @@ add_executable(${_TEST_NAME}_tests test_gcode_layer_changes.cpp test_gcodefindreplace.cpp test_gcodewriter.cpp + test_retraction.cpp test_model.cpp test_multi.cpp test_perimeters.cpp diff --git a/tests/fff_print/test_retraction.cpp b/tests/fff_print/test_retraction.cpp new file mode 100644 index 0000000000..d75a92368b --- /dev/null +++ b/tests/fff_print/test_retraction.cpp @@ -0,0 +1,337 @@ +/** + * Ported from t/retraction.t + */ + +#include + +#include +#include + +#include "test_data.hpp" +#include + +using namespace Slic3r; +using namespace Test; + +void check_gcode(std::initializer_list meshes, const DynamicPrintConfig& config) { + std::string gcode = Slic3r::Test::slice(meshes, config); + + constexpr std::size_t tools_count = 4; + std::size_t tool = 0; + std::array toolchange_count{0}; // Track first usages so that we don't expect retract_length_toolchange when extruders are used for the first time + std::array retracted{false}; + std::array retracted_length{0}; + bool lifted = false; + double lift_dist = 0; // Track lifted distance for toolchanges and extruders with different retract_lift values + bool changed_tool = false; + bool wait_for_toolchange = false; + + + GCodeReader parser; + parser.parse_buffer(gcode, [&] (Slic3r::GCodeReader &self, const Slic3r::GCodeReader::GCodeLine &line) { + std::regex regex{"^T(\\d+)"}; + std::smatch matches; + std::string cmd{line.cmd()}; + if (std::regex_match(cmd, matches, regex)) { + tool = std::stoul(matches[1].str()); + changed_tool = true; + wait_for_toolchange = false; + toolchange_count[tool]++; + } else if (std::regex_match(cmd, std::regex{"^G[01]$"}) && !line.has(Z)) { // ignore lift taking place after retraction + INFO("Toolchange must not happen right after retraction."); + CHECK(!wait_for_toolchange); + } + + const double retract_length = config.option("retract_length")->get_at(tool); + const double retract_before_travel = config.option("retract_before_travel")->get_at(tool); + const double retract_length_toolchange = config.option("retract_length_toolchange")->get_at(tool); + const double retract_restart_extra = config.option("retract_restart_extra")->get_at(tool); + const double retract_restart_extra_toolchange = config.option("retract_restart_extra_toolchange")->get_at(tool); + + if (line.dist_Z(self) != 0) { + // lift move or lift + change layer + const double retract_lift = config.option("retract_lift")->get_at(tool); + if ( + line.dist_Z(self) == Approx(retract_lift) + || ( + line.dist_Z(self) == Approx(config.opt_float("layer_height") + retract_lift) + && retract_lift > 0 + ) + ) { + INFO("Only lift while retracted"); + CHECK(retracted[tool]); + INFO("No double lift"); + CHECK(!lifted); + lifted = true; + lift_dist = line.dist_Z(self); + } + if (line.dist_Z(self) < 0) { + INFO("Must be lifted before going down.") + CHECK(lifted); + INFO("Going down by the same amount of the lift or by the amount needed to get to next layer"); + CHECK(( + line.dist_Z(self) == Approx(-lift_dist) + || line.dist_Z(self) == Approx(-lift_dist + config.opt_float("layer_height")) + )); + lift_dist = 0; + lifted = false; + } + const double feedrate = line.has_f() ? line.f() : self.f(); + INFO("move Z at travel speed"); + CHECK(feedrate == Approx(config.opt_float("travel_speed") * 60)); + } + if (line.retracting(self)) { + retracted[tool] = true; + retracted_length[tool] += -line.dist_E(self); + if (retracted_length[tool] == Approx(retract_length)) { + // okay + } else if (retracted_length[tool] == Approx(retract_length_toolchange)) { + wait_for_toolchange = true; + } else { + INFO("Not retracted by the correct amount."); + CHECK(false); + } + } + if (line.extruding(self)) { + INFO("Only extruding while not lifted"); + CHECK(!lifted); + if (retracted[tool]) { + double expected_amount = retracted_length[tool] + retract_restart_extra; + if (changed_tool && toolchange_count[tool] > 1) { + expected_amount = retract_length_toolchange + retract_restart_extra_toolchange; + changed_tool = false; + } + INFO("Unretracted by the correct amount"); + REQUIRE(line.dist_E(self) == Approx(expected_amount)); + retracted[tool] = false; + retracted_length[tool] = 0; + } + } + if (line.travel() && line.dist_XY(self) >= retract_before_travel) { + INFO("Retracted before long travel move"); + CHECK(retracted[tool]); + } + }); +} + +void test_slicing(std::initializer_list meshes, DynamicPrintConfig& config) { + SECTION("Retraction") { + check_gcode(meshes, config); + } + + SECTION("Restart extra length") { + config.set_deserialize_strict({{ "retract_restart_extra", "1" }}); + check_gcode(meshes, config); + } + + SECTION("Negative restart extra length") { + config.set_deserialize_strict({{ "retract_restart_extra", "-1" }}); + check_gcode(meshes, config); + } + + SECTION("Retract_lift") { + config.set_deserialize_strict({{ "retract_lift", "1,2" }}); + check_gcode(meshes, config); + } + +} + +TEST_CASE("Slicing with retraction and lifing", "[retraction]") { + DynamicPrintConfig config = Slic3r::DynamicPrintConfig::full_print_config(); + config.set_deserialize_strict({ + { "nozzle_diameter", "0.6,0.6,0.6,0.6" }, + { "first_layer_height", config.opt_float("layer_height") }, + { "first_layer_speed", "100%" }, + { "start_gcode", "" }, // To avoid dealing with the nozzle lift in start G-code + { "retract_length", "1.5" }, + { "retract_before_travel", "3" }, + { "only_retract_when_crossing_perimeters", 0 }, + }); + + SECTION("Standard run") { + //test_slicing({TestMesh::cube_20x20x20}, config); + } + SECTION("With duplicate cube") { + //test_slicing({TestMesh::cube_20x20x20, TestMesh::cube_20x20x20}, config); + } + SECTION("Dual extruder with multiple skirt layers") { + config.set_deserialize_strict({ + {"infill_extruder", 2}, + {"skirts", 4}, + {"skirt_height", 3}, + }); + test_slicing({TestMesh::cube_20x20x20}, config); + } +} + +TEST_CASE("Z moves", "[retraction]") { + + DynamicPrintConfig config = Slic3r::DynamicPrintConfig::full_print_config(); + config.set_deserialize_strict({ + { "start_gcode", "" }, // To avoid dealing with the nozzle lift in start G-code + { "retract_length", "0" }, + { "retract_layer_change", "0" }, + { "retract_lift", "0.2" }, + }); + + bool retracted = false; + unsigned layer_changes_with_retraction = 0; + unsigned retractions = 0; + unsigned z_restores = 0; + + std::string gcode = Slic3r::Test::slice({TestMesh::cube_20x20x20}, config); + GCodeReader parser; + parser.parse_buffer(gcode, [&] (Slic3r::GCodeReader &self, const Slic3r::GCodeReader::GCodeLine &line) { + if (line.retracting(self)) { + retracted = true; + retractions++; + } else if (line.extruding(self) && retracted) { + retracted = 0; + } + + if (line.dist_Z(self) != 0 && retracted) { + layer_changes_with_retraction++; + } + + if (line.dist_Z(self) < 0) { + z_restores++; + } + }); + + INFO("no retraction on layer change"); + CHECK(layer_changes_with_retraction == 0); + INFO("no retractions"); + CHECK(retractions == 0); + INFO("no lift"); + CHECK(z_restores == 0); +} + +TEST_CASE("Firmware retraction handling", "[retraction]") { + + DynamicPrintConfig config = Slic3r::DynamicPrintConfig::full_print_config(); + config.set_deserialize_strict({ + { "use_firmware_retraction", 1 }, + }); + + bool retracted = false; + unsigned double_retractions = 0; + unsigned double_unretractions = 0; + + std::string gcode = Slic3r::Test::slice({TestMesh::cube_20x20x20}, config); + GCodeReader parser; + parser.parse_buffer(gcode, [&] (Slic3r::GCodeReader &self, const Slic3r::GCodeReader::GCodeLine &line) { + if (line.cmd_is("G10")) { + if (retracted) + double_retractions++; + retracted = true; + } else if (line.cmd_is("G11")) { + if (!retracted) + double_unretractions++; + retracted = 0; + } + }); + INFO("No double retractions"); + CHECK(double_retractions == 0); + INFO("No double unretractions"); + CHECK(double_unretractions == 0); +} + +TEST_CASE("Firmware retraction when length is 0", "[retraction]") { + + DynamicPrintConfig config = Slic3r::DynamicPrintConfig::full_print_config(); + config.set_deserialize_strict({ + { "use_firmware_retraction", 1 }, + { "retract_length", "0" }, + }); + + bool retracted = false; + + std::string gcode = Slic3r::Test::slice({TestMesh::cube_20x20x20}, config); + GCodeReader parser; + parser.parse_buffer(gcode, [&] (Slic3r::GCodeReader &self, const Slic3r::GCodeReader::GCodeLine &line) { + if (line.cmd_is("G10")) { + retracted = true; + } + }); + INFO("Retracting also when --retract-length is 0 but --use-firmware-retraction is enabled"); + CHECK(retracted); +} + +std::vector get_lift_layers(const DynamicPrintConfig& config) { + std::vector result; + const std::string gcode = Slic3r::Test::slice({TestMesh::cube_20x20x20}, config); + GCodeReader parser; + parser.parse_buffer(gcode, [&] (Slic3r::GCodeReader &self, const Slic3r::GCodeReader::GCodeLine &line) { + if (line.cmd_is("G1") && line.dist_Z(self) < 0) { + result.push_back(line.new_Z(self)); + } + }); + return result; +} + +bool values_are_in_range(const std::vector& values, double from, double to) { + for (const double& value : values) { + if (value < from || value > to) { + return false; + } + } + return true; +} + +TEST_CASE("Lift above/bellow layers", "[retraction]") { + + DynamicPrintConfig config = Slic3r::DynamicPrintConfig::full_print_config(); + config.set_deserialize_strict({ + { "nozzle_diameter", "0.6,0.6,0.6,0.6" }, + { "start_gcode", "" }, + { "retract_lift", "3,4" }, + }); + + config.set_deserialize_strict({ + { "retract_lift_above", "0, 0" }, + { "retract_lift_below", "0, 0" }, + }); + std::vector lift_layers = get_lift_layers(config); + INFO("lift takes place when above/below == 0"); + CHECK(!lift_layers.empty()); + + config.set_deserialize_strict({ + { "retract_lift_above", "5, 6" }, + { "retract_lift_below", "15, 13" }, + }); + lift_layers = get_lift_layers(config); + INFO("lift takes place when above/below != 0"); + CHECK(!lift_layers.empty()); + + double retract_lift_above = config.option("retract_lift_above")->get_at(0); + double retract_lift_below = config.option("retract_lift_below")->get_at(0); + + INFO("Z is not lifted above/below the configured value"); + CHECK(values_are_in_range(lift_layers, retract_lift_above, retract_lift_below)); + + // check lifting with different values for 2. extruder + config.set_deserialize_strict({ + {"perimeter_extruder", 2}, + {"infill_extruder", 2}, + {"retract_lift_above", "0, 0"}, + {"retract_lift_below", "0, 0"} + }); + + lift_layers = get_lift_layers(config); + INFO("lift takes place when above/below == 0 for 2. extruder"); + CHECK(!lift_layers.empty()); + + config.set_deserialize_strict({ + { "retract_lift_above", "5, 6" }, + { "retract_lift_below", "15, 13" }, + }); + lift_layers = get_lift_layers(config); + INFO("lift takes place when above/below != 0 for 2. extruder"); + CHECK(!lift_layers.empty()); + + retract_lift_above = config.option("retract_lift_above")->get_at(1); + retract_lift_below = config.option("retract_lift_below")->get_at(1); + + INFO("Z is not lifted above/below the configured value for 2. extruder"); + CHECK(values_are_in_range(lift_layers, retract_lift_above, retract_lift_below)); +} From 6e871a874a4c1e5973ceb323993f940ac78d21eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20=C5=A0ach?= Date: Fri, 15 Dec 2023 11:05:45 +0100 Subject: [PATCH 33/91] Rewrite gcode.t to c++ --- t/gcode.t | 243 ---------------------- tests/fff_print/test_data.cpp | 31 ++- tests/fff_print/test_data.hpp | 10 +- tests/fff_print/test_gcode.cpp | 302 ++++++++++++++++++++++++++++ tests/fff_print/test_retraction.cpp | 28 ++- 5 files changed, 344 insertions(+), 270 deletions(-) delete mode 100644 t/gcode.t diff --git a/t/gcode.t b/t/gcode.t deleted file mode 100644 index 7bf6b06535..0000000000 --- a/t/gcode.t +++ /dev/null @@ -1,243 +0,0 @@ -use Test::More tests => 22; -use strict; -use warnings; - -BEGIN { - use FindBin; - use lib "$FindBin::Bin/../lib"; - use local::lib "$FindBin::Bin/../local-lib"; -} - -use List::Util qw(first); -use Slic3r; -use Slic3r::Geometry qw(scale convex_hull); -use Slic3r::Test; - -{ - my $config = Slic3r::Config::new_from_defaults; - $config->set('wipe', [1]); - $config->set('retract_layer_change', [0]); - - my $print = Slic3r::Test::init_print('20mm_cube', config => $config); - my $have_wipe = 0; - my @retract_speeds = (); - my $extruded_on_this_layer = 0; - my $wiping_on_new_layer = 0; - Slic3r::GCode::Reader->new->parse(Slic3r::Test::gcode($print), sub { - my ($self, $cmd, $args, $info) = @_; - - if ($info->{travel} && $info->{dist_Z}) { - # changing layer - $extruded_on_this_layer = 0; - } elsif ($info->{extruding} && $info->{dist_XY}) { - $extruded_on_this_layer = 1; - } elsif ($info->{retracting} && $info->{dist_XY} > 0) { - $have_wipe = 1; - $wiping_on_new_layer = 1 if !$extruded_on_this_layer; - my $move_time = $info->{dist_XY} / ($args->{F} // $self->F); - push @retract_speeds, abs($info->{dist_E}) / $move_time; - } - }); - - ok $have_wipe, "wipe"; - ok !defined (first { abs($_ - $config->retract_speed->[0]*60) < 5 } @retract_speeds), 'wipe moves don\'t retract faster than configured speed'; - ok !$wiping_on_new_layer, 'no wiping after layer change'; -} - -{ - my $config = Slic3r::Config::new_from_defaults; - $config->set('z_offset', 5); - $config->set('start_gcode', ''); - - my $test = sub { - my ($comment) = @_; - my $print = Slic3r::Test::init_print('20mm_cube', config => $config); - my $moves_below_z_offset = 0; - Slic3r::GCode::Reader->new->parse(Slic3r::Test::gcode($print), sub { - my ($self, $cmd, $args, $info) = @_; - - if ($info->{travel} && exists $args->{Z}) { - $moves_below_z_offset++ if $args->{Z} < $config->z_offset; - } - }); - is $moves_below_z_offset, 0, "no Z moves below Z offset ($comment)"; - }; - - $test->("no lift"); - - $config->set('retract_lift', [3]); - $test->("lift < z_offset"); - - $config->set('retract_lift', [6]); - $test->("lift > z_offset"); -} - -{ - # This tests the following behavior: - # - complete objects does not crash - # - no hard-coded "E" are generated - # - Z moves are correctly generated for both objects - # - no travel moves go outside skirt - # - temperatures are set correctly - my $config = Slic3r::Config::new_from_defaults; - $config->set('gcode_comments', 1); - $config->set('complete_objects', 1); - $config->set('extrusion_axis', 'A'); - $config->set('start_gcode', ''); # prevent any default extra Z move - $config->set('layer_height', 0.4); - $config->set('first_layer_height', 0.4); - $config->set('temperature', [200]); - $config->set('first_layer_temperature', [210]); - my $print = Slic3r::Test::init_print('20mm_cube', config => $config, duplicate => 2); - ok my $gcode = Slic3r::Test::gcode($print), "complete_objects"; - my @z_moves = (); - my @travel_moves = (); # array of scaled points - my @extrusions = (); # array of scaled points - my @temps = (); - Slic3r::GCode::Reader->new->parse($gcode, sub { - my ($self, $cmd, $args, $info) = @_; - fail 'unexpected E argument' if defined $args->{E}; - if (defined $args->{Z}) { - push @z_moves, $args->{Z}; - } - - if ($info->{dist_XY}) { - if ($info->{extruding} || $args->{A}) { - push @extrusions, Slic3r::Point->new_scale($info->{new_X}, $info->{new_Y}); - } else { - push @travel_moves, Slic3r::Point->new_scale($info->{new_X}, $info->{new_Y}) - if @extrusions; # skip initial travel move to first skirt point - } - } elsif ($cmd eq 'M104' || $cmd eq 'M109') { - push @temps, $args->{S} if !@temps || $args->{S} != $temps[-1]; - } - }); - my $layer_count = 20/0.4; # cube is 20mm tall - is scalar(@z_moves), 2*$layer_count, 'complete_objects generates the correct number of Z moves'; - is_deeply [ @z_moves[0..($layer_count-1)] ], [ @z_moves[$layer_count..$#z_moves] ], 'complete_objects generates the correct Z moves'; - - my $convex_hull = convex_hull(\@extrusions); - ok !(defined first { !$convex_hull->contains_point($_) } @travel_moves), 'all travel moves happen within skirt'; - - is_deeply \@temps, [210, 200, 210, 200, 0], 'expected temperature changes'; -} - -{ - my $config = Slic3r::Config::new_from_defaults; - $config->set('retract_length', [1000000]); - $config->set('use_relative_e_distances', 1); - $config->set('layer_gcode', "G92 E0\n"); - my $print = Slic3r::Test::init_print('20mm_cube', config => $config); - Slic3r::Test::gcode($print); - ok $print->print->total_used_filament > 0, 'final retraction is not considered in total used filament'; -} - -{ - my $test = sub { - my ($print, $comment) = @_; - - my @percent = (); - my $got_100 = 0; - my $extruding_after_100 = 0; - Slic3r::GCode::Reader->new->parse(Slic3r::Test::gcode($print), sub { - my ($self, $cmd, $args, $info) = @_; - - if ($cmd eq 'M73') { - push @percent, $args->{P}; - $got_100 = 1 if $args->{P} eq '100'; - } - if ($info->{extruding} && $got_100) { - $extruding_after_100 = 1; - } - }); - # the extruder heater is turned off when M73 P100 is reached - ok !(defined first { $_ > 100 } @percent), "M73 is never given more than 100% ($comment)"; - ok !$extruding_after_100, "no extrusions after M73 P100 ($comment)"; - }; - - { - my $config = Slic3r::Config::new_from_defaults; - $config->set('gcode_flavor', 'sailfish'); - $config->set('raft_layers', 3); - my $print = Slic3r::Test::init_print('20mm_cube', config => $config); - $test->($print, 'single object'); - } - - { - my $config = Slic3r::Config::new_from_defaults; - $config->set('gcode_flavor', 'sailfish'); - my $print = Slic3r::Test::init_print('20mm_cube', config => $config, duplicate => 2); - $test->($print, 'two copies of single object'); - } - - { - my $config = Slic3r::Config::new_from_defaults; - $config->set('gcode_flavor', 'sailfish'); - my $print = Slic3r::Test::init_print(['20mm_cube','20mm_cube'], config => $config); - $test->($print, 'two objects'); - } - - { - my $config = Slic3r::Config::new_from_defaults; - $config->set('gcode_flavor', 'sailfish'); - my $print = Slic3r::Test::init_print('20mm_cube', config => $config, scale_xyz => [1,1, 1/(20/$config->layer_height) ]); - $test->($print, 'one layer object'); - } -} - -#{ -# [input_filename] placeholder was removed in 0cbbe96. -# my $config = Slic3r::Config::new_from_defaults; -# $config->set('start_gcode', 'START:[input_filename]'); -# my $print = Slic3r::Test::init_print('20mm_cube', config => $config); -# my $gcode = Slic3r::Test::gcode($print); -# like $gcode, qr/START:20mm_cube/, '[input_filename] is also available in custom G-code'; -#} - -# The current Spiral Vase slicing code removes the holes and all but the largest contours from each slice, -# therefore the following test is no more valid. -#{ -# my $config = Slic3r::Config::new_from_defaults; -# $config->set('spiral_vase', 1); -# my $print = Slic3r::Test::init_print('cube_with_hole', config => $config); -# -# my $spiral = 0; -# Slic3r::GCode::Reader->new->parse(Slic3r::Test::gcode($print), sub { -# my ($self, $cmd, $args, $info) = @_; -# -# if ($cmd eq 'G1' && exists $args->{E} && exists $args->{Z}) { -# $spiral = 1; -# } -# }); -# -# ok !$spiral, 'spiral vase is correctly disabled on layers with multiple loops'; -#} - - -{ - # Tests that the Repetier flavor produces M201 Xnnn Ynnn for resetting - # acceleration, also that M204 Snnn syntax is not generated. - my $config = Slic3r::Config::new_from_defaults; - $config->set('gcode_flavor', 'repetier'); - $config->set('default_acceleration', 1337); - my $print = Slic3r::Test::init_print('cube_with_hole', config => $config); - - my $has_accel = 0; - my $has_m204 = 0; - Slic3r::GCode::Reader->new->parse(Slic3r::Test::gcode($print), sub { - my ($self, $cmd, $args, $info) = @_; - - if ($cmd eq 'M201' && exists $args->{X} && exists $args->{Y}) { - if ($args->{X} == 1337 && $args->{Y} == 1337) { - $has_accel = 1; - } - } - if ($cmd eq 'M204' && exists $args->{S}) { - $has_m204 = 1; - } - }); - ok $has_accel, 'M201 is generated for repetier firmware.'; - ok !$has_m204, 'M204 is not generated for repetier firmware'; -} - -__END__ diff --git a/tests/fff_print/test_data.cpp b/tests/fff_print/test_data.cpp index 79064e2c72..b28196b2bd 100644 --- a/tests/fff_print/test_data.cpp +++ b/tests/fff_print/test_data.cpp @@ -236,7 +236,7 @@ static bool verbose_gcode() return s == "1" || s == "on" || s == "yes"; } -void init_print(std::vector &&meshes, Slic3r::Print &print, Slic3r::Model &model, const DynamicPrintConfig &config_in, bool comments) +void init_print(std::vector &&meshes, Slic3r::Print &print, Slic3r::Model &model, const DynamicPrintConfig &config_in, bool comments, unsigned duplicate_count) { DynamicPrintConfig config = DynamicPrintConfig::full_print_config(); config.apply(config_in); @@ -247,10 +247,19 @@ void init_print(std::vector &&meshes, Slic3r::Print &print, Slic3r for (const TriangleMesh &t : meshes) { ModelObject *object = model.add_object(); object->name += "object.stl"; - object->add_volume(std::move(t)); + object->add_volume(t); object->add_instance(); } - arrange_objects(model, arr2::to_arrange_bed(get_bed_shape(config)), arr2::ArrangeSettings{}.set_distance_from_objects(min_object_distance(config))); + + double distance = min_object_distance(config); + arr2::ArrangeSettings arrange_settings{}; + arrange_settings.set_distance_from_objects(distance); + arr2::ArrangeBed bed{arr2::to_arrange_bed(get_bed_shape(config))}; + if (duplicate_count > 1) { + duplicate(model, duplicate_count, bed, arrange_settings); + } + + arrange_objects(model, bed, arrange_settings); model.center_instances_around_point({100, 100}); for (ModelObject *mo : model.objects) { mo->ensure_on_bed(); @@ -262,36 +271,36 @@ void init_print(std::vector &&meshes, Slic3r::Print &print, Slic3r print.set_status_silent(); } -void init_print(std::initializer_list test_meshes, Slic3r::Print &print, Slic3r::Model &model, const Slic3r::DynamicPrintConfig &config_in, bool comments) +void init_print(std::initializer_list test_meshes, Slic3r::Print &print, Slic3r::Model &model, const Slic3r::DynamicPrintConfig &config_in, bool comments, unsigned duplicate_count) { std::vector triangle_meshes; triangle_meshes.reserve(test_meshes.size()); for (const TestMesh test_mesh : test_meshes) triangle_meshes.emplace_back(mesh(test_mesh)); - init_print(std::move(triangle_meshes), print, model, config_in, comments); + init_print(std::move(triangle_meshes), print, model, config_in, comments, duplicate_count); } -void init_print(std::initializer_list input_meshes, Slic3r::Print &print, Slic3r::Model &model, const DynamicPrintConfig &config_in, bool comments) +void init_print(std::initializer_list input_meshes, Slic3r::Print &print, Slic3r::Model &model, const DynamicPrintConfig &config_in, bool comments, unsigned duplicate_count) { std::vector triangle_meshes; triangle_meshes.reserve(input_meshes.size()); for (const TriangleMesh &input_mesh : input_meshes) triangle_meshes.emplace_back(input_mesh); - init_print(std::move(triangle_meshes), print, model, config_in, comments); + init_print(std::move(triangle_meshes), print, model, config_in, comments, duplicate_count); } -void init_print(std::initializer_list meshes, Slic3r::Print &print, Slic3r::Model &model, std::initializer_list config_items, bool comments) +void init_print(std::initializer_list meshes, Slic3r::Print &print, Slic3r::Model &model, std::initializer_list config_items, bool comments, unsigned duplicate_count) { Slic3r::DynamicPrintConfig config = Slic3r::DynamicPrintConfig::full_print_config(); config.set_deserialize_strict(config_items); - init_print(meshes, print, model, config, comments); + init_print(meshes, print, model, config, comments, duplicate_count); } -void init_print(std::initializer_list meshes, Slic3r::Print &print, Slic3r::Model &model, std::initializer_list config_items, bool comments) +void init_print(std::initializer_list meshes, Slic3r::Print &print, Slic3r::Model &model, std::initializer_list config_items, bool comments, unsigned duplicate_count) { Slic3r::DynamicPrintConfig config = Slic3r::DynamicPrintConfig::full_print_config(); config.set_deserialize_strict(config_items); - init_print(meshes, print, model, config, comments); + init_print(meshes, print, model, config, comments, duplicate_count); } void init_and_process_print(std::initializer_list meshes, Slic3r::Print &print, const DynamicPrintConfig &config, bool comments) diff --git a/tests/fff_print/test_data.hpp b/tests/fff_print/test_data.hpp index fd110caf1b..12ff0f551d 100644 --- a/tests/fff_print/test_data.hpp +++ b/tests/fff_print/test_data.hpp @@ -63,11 +63,11 @@ template bool _equiv(const T& a, const T& b, double epsilon) { return abs(a - b) < epsilon; } Slic3r::Model model(const std::string& model_name, TriangleMesh&& _mesh); -void init_print(std::vector &&meshes, Slic3r::Print &print, Slic3r::Model& model, const DynamicPrintConfig &config_in, bool comments = false); -void init_print(std::initializer_list meshes, Slic3r::Print &print, Slic3r::Model& model, const Slic3r::DynamicPrintConfig &config_in = Slic3r::DynamicPrintConfig::full_print_config(), bool comments = false); -void init_print(std::initializer_list meshes, Slic3r::Print &print, Slic3r::Model& model, const Slic3r::DynamicPrintConfig &config_in = Slic3r::DynamicPrintConfig::full_print_config(), bool comments = false); -void init_print(std::initializer_list meshes, Slic3r::Print &print, Slic3r::Model& model, std::initializer_list config_items, bool comments = false); -void init_print(std::initializer_list meshes, Slic3r::Print &print, Slic3r::Model& model, std::initializer_list config_items, bool comments = false); +void init_print(std::vector &&meshes, Slic3r::Print &print, Slic3r::Model& model, const DynamicPrintConfig &config_in, bool comments = false, unsigned duplicate_count = 1); +void init_print(std::initializer_list meshes, Slic3r::Print &print, Slic3r::Model& model, const Slic3r::DynamicPrintConfig &config_in = Slic3r::DynamicPrintConfig::full_print_config(), bool comments = false, unsigned duplicate_count = 1); +void init_print(std::initializer_list meshes, Slic3r::Print &print, Slic3r::Model& model, const Slic3r::DynamicPrintConfig &config_in = Slic3r::DynamicPrintConfig::full_print_config(), bool comments = false, unsigned duplicate = 1); +void init_print(std::initializer_list meshes, Slic3r::Print &print, Slic3r::Model& model, std::initializer_list config_items, bool comments = false, unsigned duplicate = 1); +void init_print(std::initializer_list meshes, Slic3r::Print &print, Slic3r::Model& model, std::initializer_list config_items, bool comments = false, unsigned duplicate = 1); void init_and_process_print(std::initializer_list meshes, Slic3r::Print &print, const DynamicPrintConfig& config, bool comments = false); void init_and_process_print(std::initializer_list meshes, Slic3r::Print &print, const DynamicPrintConfig& config, bool comments = false); diff --git a/tests/fff_print/test_gcode.cpp b/tests/fff_print/test_gcode.cpp index 3ec1758b4e..a61ca2dd8a 100644 --- a/tests/fff_print/test_gcode.cpp +++ b/tests/fff_print/test_gcode.cpp @@ -1,10 +1,22 @@ +/** + * Mostly ported from t/gcode.t + */ + #include #include +#include +#include #include "libslic3r/GCode.hpp" +#include "libslic3r/Geometry/ConvexHull.hpp" +#include "libslic3r/ModelArrange.hpp" +#include "test_data.hpp" using namespace Slic3r; +using namespace Test; + +constexpr bool debug_files = false; SCENARIO("Origin manipulation", "[GCode]") { Slic3r::GCodeGenerator gcodegen; @@ -20,3 +32,293 @@ SCENARIO("Origin manipulation", "[GCode]") { } } } + + +TEST_CASE("Wiping speeds", "[GCode]") { + DynamicPrintConfig config = Slic3r::DynamicPrintConfig::full_print_config(); + config.set_deserialize_strict({ + { "wipe", "1" }, + { "retract_layer_change", "0" }, + }); + bool have_wipe = false; + std::vector retract_speeds; + bool extruded_on_this_layer = false; + bool wiping_on_new_layer = false; + + GCodeReader parser; + std::string gcode = Slic3r::Test::slice({TestMesh::cube_20x20x20}, config); + parser.parse_buffer(gcode, [&] (Slic3r::GCodeReader &self, const Slic3r::GCodeReader::GCodeLine &line) { + if (line.travel() && line.dist_Z(self) != 0) { + extruded_on_this_layer = false; + } else if (line.extruding(self) && line.dist_XY(self) > 0) { + extruded_on_this_layer = true; + } else if (line.retracting(self) && line.dist_XY(self) > 0) { + have_wipe = true; + wiping_on_new_layer = !extruded_on_this_layer; + const double f = line.has_f() ? line.f() : self.f(); + double move_time = line.dist_XY(self) / f; + retract_speeds.emplace_back(std::abs(line.dist_E(self)) / move_time); + } + }); + CHECK(have_wipe); + double expected_retract_speed = config.option("retract_speed")->get_at(0) * 60; + for (const double retract_speed : retract_speeds) { + INFO("Wipe moves don\'t retract faster than configured speed"); + CHECK(retract_speed < expected_retract_speed); + } + INFO("No wiping after layer change") + CHECK(!wiping_on_new_layer); +} + +bool has_moves_below_z_offset(const DynamicPrintConfig& config) { + GCodeReader parser; + std::string gcode = Slic3r::Test::slice({TestMesh::cube_20x20x20}, config); + + unsigned moves_below_z_offset{}; + double configured_offset = config.opt_float("z_offset"); + parser.parse_buffer(gcode, [&] (Slic3r::GCodeReader &self, const Slic3r::GCodeReader::GCodeLine &line) { + if (line.travel() && line.has_z() && line.z() < configured_offset) { + moves_below_z_offset++; + } + }); + return moves_below_z_offset > 0; +} + +TEST_CASE("Z moves with offset", "[GCode]") { + DynamicPrintConfig config = Slic3r::DynamicPrintConfig::full_print_config(); + config.set_deserialize_strict({ + { "z_offset", 5 }, + { "start_gcode", "" }, + }); + + INFO("No lift"); + CHECK(!has_moves_below_z_offset(config)); + + config.set_deserialize_strict({{ "retract_lift", "3" }}); + INFO("Lift < z offset"); + CHECK(!has_moves_below_z_offset(config)); + + config.set_deserialize_strict({{ "retract_lift", "6" }}); + INFO("Lift > z offset"); + CHECK(!has_moves_below_z_offset(config)); +} + +std::optional parse_axis(const std::string& line, const std::string& axis) { + std::smatch matches; + if (std::regex_search(line, matches, std::regex{axis + "(\\d+)"})) { + std::string matchedValue = matches[1].str(); + return std::stod(matchedValue); + } + return std::nullopt; +} + +/** +* This tests the following behavior: +* - complete objects does not crash +* - no hard-coded "E" are generated +* - Z moves are correctly generated for both objects +* - no travel moves go outside skirt +* - temperatures are set correctly +*/ +TEST_CASE("Extrusion, travels, temeperatures", "[GCode]") { + DynamicPrintConfig config = Slic3r::DynamicPrintConfig::full_print_config(); + config.set_deserialize_strict({ + { "gcode_comments", 1 }, + { "complete_objects", 1 }, + { "extrusion_axis", 'A' }, + { "start_gcode", "" }, // prevent any default extra Z move + { "layer_height", 0.4 }, + { "first_layer_height", 0.4 }, + { "temperature", "200" }, + { "first_layer_temperature", "210" } + }); + + std::vector z_moves; + Points travel_moves; + Points extrusions; + std::vector temps; + + GCodeReader parser; + + Print print; + Model model; + Test::init_print({TestMesh::cube_20x20x20}, print, model, config, false, 2); + std::string gcode = Test::gcode(print); + parser.parse_buffer(gcode, [&] (Slic3r::GCodeReader &self, const Slic3r::GCodeReader::GCodeLine &line) { + INFO("Unexpected E argument"); + CHECK(!line.has_e()); + + if (line.has_z()) { + z_moves.emplace_back(line.z()); + } + if (line.has_x() || line.has_y()) { + if (line.extruding(self) || line.has_unknown_axis()) { + extrusions.emplace_back(scaled(line.x()), scaled(line.y())); + } else if (!extrusions.empty()){ // skip initial travel move to first skirt point + travel_moves.emplace_back(scaled(line.x()), scaled(line.y())); + } + } else if (line.cmd_is("M104") || line.cmd_is("M109")) { + const std::optional parsed_temperature = parse_axis(line.raw(), "S"); + if (!parsed_temperature) { + FAIL("Failed to parse temperature!"); + } + if (temps.empty() || temps.back() != parsed_temperature) { + temps.emplace_back(*parsed_temperature); + } + } + }); + + const unsigned layer_count = 20 / 0.4; + INFO("Complete_objects generates the correct number of Z moves."); + CHECK(z_moves.size() == layer_count * 2); + auto first_moves = tcb::span{z_moves}.subspan(0, layer_count); + auto second_moves = tcb::span{z_moves}.subspan(layer_count); + + CHECK( std::vector(first_moves.begin(), first_moves.end()) == std::vector(second_moves.begin(), second_moves.end())); + const Polygon convex_hull{Geometry::convex_hull(extrusions)}; + INFO("All travel moves happen within skirt."); + for (const Point& travel_move : travel_moves) { + CHECK(convex_hull.contains(travel_move)); + } + INFO("Expected temperature changes"); + CHECK(temps == std::vector{210, 200, 210, 200, 0}); +} + + +TEST_CASE("Used filament", "[GCode]") { + DynamicPrintConfig config = Slic3r::DynamicPrintConfig::full_print_config(); + config.set_deserialize_strict({ + { "retract_length", "1000000" }, + { "use_relative_e_distances", 1 }, + { "layer_gcode", "G92 E0\n" }, + }); + GCodeReader parser; + Print print; + Model model; + Test::init_print({TestMesh::cube_20x20x20}, print, model, config); + Test::gcode(print); + + INFO("Final retraction is not considered in total used filament"); + CHECK(print.print_statistics().total_used_filament > 0); +} + +void check_m73s(Print& print){ + std::vector percent{}; + bool got_100 = false; + bool extruding_after_100 = 0; + + GCodeReader parser; + std::string gcode = Slic3r::Test::gcode(print); + parser.parse_buffer(gcode, [&] (Slic3r::GCodeReader &self, const Slic3r::GCodeReader::GCodeLine &line) { + + if (line.cmd_is("M73")) { + std::optional p = parse_axis(line.raw(), "P"); + if (!p) { + FAIL("Failed to parse percent"); + } + percent.emplace_back(*p); + got_100 = p == Approx(100); + } + if (line.extruding(self) && got_100) { + extruding_after_100 = true; + } + }); + INFO("M73 is never given more than 100%"); + for (const double value : percent) { + CHECK(value <= 100); + } + INFO("No extrusions after M73 P100."); + CHECK(!extruding_after_100); +} + + +TEST_CASE("M73s have correct percent values", "[GCode]") { + DynamicPrintConfig config = Slic3r::DynamicPrintConfig::full_print_config(); + + SECTION("Single object") { + config.set_deserialize_strict({ + {" gcode_flavor", "sailfish" }, + {" raft_layers", 3 }, + }); + + Print print; + Model model; + Test::init_print({TestMesh::cube_20x20x20}, print, model, config); + check_m73s(print); + } + + SECTION("Two copies of single object") { + config.set_deserialize_strict({ + {" gcode_flavor", "sailfish" }, + }); + Print print; + Model model; + + Test::init_print({TestMesh::cube_20x20x20}, print, model, config, false, 2); + check_m73s(print); + + if constexpr (debug_files) { + std::ofstream gcode_file{"M73_2_copies.gcode"}; + gcode_file << Test::gcode(print); + } + } + + SECTION("Two objects") { + config.set_deserialize_strict({ + {" gcode_flavor", "sailfish" }, + }); + Print print; + Model model; + Test::init_print({TestMesh::cube_20x20x20, TestMesh::cube_20x20x20}, print, model, config); + check_m73s(print); + } + + SECTION("One layer object") { + config.set_deserialize_strict({ + {" gcode_flavor", "sailfish" }, + }); + Print print; + Model model; + TriangleMesh test_mesh{mesh(TestMesh::cube_20x20x20)}; + const double layer_height = config.opt_float("layer_height"); + test_mesh.scale(Vec3f{1, 1, layer_height/20}); + Test::init_print({test_mesh}, print, model, config); + check_m73s(print); + + if constexpr (debug_files) { + std::ofstream gcode_file{"M73_one_layer.gcode"}; + gcode_file << Test::gcode(print); + } + } +} + + +TEST_CASE("M201 for acceleation reset", "[GCode]") { + DynamicPrintConfig config = Slic3r::DynamicPrintConfig::full_print_config(); + config.set_deserialize_strict({ + { "gcode_flavor", "repetier" }, + { "default_acceleration", 1337 }, + }); + + GCodeReader parser; + std::string gcode = Slic3r::Test::slice({TestMesh::cube_with_hole}, config); + + bool has_accel = false; + bool has_m204 = false; + + parser.parse_buffer(gcode, [&] (Slic3r::GCodeReader &self, const Slic3r::GCodeReader::GCodeLine &line) { + if (line.cmd_is("M201") && line.has_x() && line.has_y()) { + if (line.x() == 1337 && line.y() == 1337) { + has_accel = true; + } + } + if (line.cmd_is("M204") && line.raw().find('S') != std::string::npos) { + has_m204 = true; + } + }); + + INFO("M201 is generated for repetier firmware."); + CHECK(has_accel); + INFO("M204 is not generated for repetier firmware"); + CHECK(!has_m204); +} diff --git a/tests/fff_print/test_retraction.cpp b/tests/fff_print/test_retraction.cpp index d75a92368b..0c7d42a766 100644 --- a/tests/fff_print/test_retraction.cpp +++ b/tests/fff_print/test_retraction.cpp @@ -13,9 +13,7 @@ using namespace Slic3r; using namespace Test; -void check_gcode(std::initializer_list meshes, const DynamicPrintConfig& config) { - std::string gcode = Slic3r::Test::slice(meshes, config); - +void check_gcode(std::initializer_list meshes, const DynamicPrintConfig& config, const unsigned duplicate) { constexpr std::size_t tools_count = 4; std::size_t tool = 0; std::array toolchange_count{0}; // Track first usages so that we don't expect retract_length_toolchange when extruders are used for the first time @@ -26,6 +24,10 @@ void check_gcode(std::initializer_list meshes, const DynamicPrintConfi bool changed_tool = false; bool wait_for_toolchange = false; + Print print; + Model model; + Test::init_print({TestMesh::cube_20x20x20}, print, model, config, false, duplicate); + std::string gcode = Test::gcode(print); GCodeReader parser; parser.parse_buffer(gcode, [&] (Slic3r::GCodeReader &self, const Slic3r::GCodeReader::GCodeLine &line) { @@ -114,24 +116,24 @@ void check_gcode(std::initializer_list meshes, const DynamicPrintConfi }); } -void test_slicing(std::initializer_list meshes, DynamicPrintConfig& config) { +void test_slicing(std::initializer_list meshes, DynamicPrintConfig& config, const unsigned duplicate = 1) { SECTION("Retraction") { - check_gcode(meshes, config); + check_gcode(meshes, config, duplicate); } SECTION("Restart extra length") { config.set_deserialize_strict({{ "retract_restart_extra", "1" }}); - check_gcode(meshes, config); + check_gcode(meshes, config, duplicate); } SECTION("Negative restart extra length") { config.set_deserialize_strict({{ "retract_restart_extra", "-1" }}); - check_gcode(meshes, config); + check_gcode(meshes, config, duplicate); } SECTION("Retract_lift") { config.set_deserialize_strict({{ "retract_lift", "1,2" }}); - check_gcode(meshes, config); + check_gcode(meshes, config, duplicate); } } @@ -149,10 +151,10 @@ TEST_CASE("Slicing with retraction and lifing", "[retraction]") { }); SECTION("Standard run") { - //test_slicing({TestMesh::cube_20x20x20}, config); + test_slicing({TestMesh::cube_20x20x20}, config); } SECTION("With duplicate cube") { - //test_slicing({TestMesh::cube_20x20x20, TestMesh::cube_20x20x20}, config); + test_slicing({TestMesh::cube_20x20x20}, config, 2); } SECTION("Dual extruder with multiple skirt layers") { config.set_deserialize_strict({ @@ -258,8 +260,12 @@ TEST_CASE("Firmware retraction when length is 0", "[retraction]") { } std::vector get_lift_layers(const DynamicPrintConfig& config) { + Print print; + Model model; + Test::init_print({TestMesh::cube_20x20x20}, print, model, config, false, 2); + std::string gcode = Test::gcode(print); + std::vector result; - const std::string gcode = Slic3r::Test::slice({TestMesh::cube_20x20x20}, config); GCodeReader parser; parser.parse_buffer(gcode, [&] (Slic3r::GCodeReader &self, const Slic3r::GCodeReader::GCodeLine &line) { if (line.cmd_is("G1") && line.dist_Z(self) < 0) { From 3e28ea3379f869db3980104324ef682ba2caf276 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20=C5=A0ach?= Date: Fri, 15 Dec 2023 11:42:58 +0100 Subject: [PATCH 34/91] Rewrite layers.t to c++ --- t/layers.t | 79 ------------------------ tests/fff_print/CMakeLists.txt | 3 +- tests/fff_print/test_layers.cpp | 103 ++++++++++++++++++++++++++++++++ 3 files changed, 105 insertions(+), 80 deletions(-) delete mode 100644 t/layers.t create mode 100644 tests/fff_print/test_layers.cpp diff --git a/t/layers.t b/t/layers.t deleted file mode 100644 index 6065d786fc..0000000000 --- a/t/layers.t +++ /dev/null @@ -1,79 +0,0 @@ -use Test::More tests => 5; -use strict; -use warnings; - -BEGIN { - use FindBin; - use lib "$FindBin::Bin/../lib"; - use local::lib "$FindBin::Bin/../local-lib"; -} - -use List::Util qw(first); -use Slic3r; -use Slic3r::Test qw(_eq); - -{ - my $config = Slic3r::Config::new_from_defaults; - - my $test = sub { - my ($conf) = @_; - $conf ||= $config; - - my $print = Slic3r::Test::init_print('20mm_cube', config => $conf); - - my @z = (); - my @increments = (); - Slic3r::GCode::Reader->new->parse(Slic3r::Test::gcode($print), sub { - my ($self, $cmd, $args, $info) = @_; - - if ($info->{dist_Z}) { - push @z, 1*$args->{Z}; - push @increments, $info->{dist_Z}; - } - }); - - fail 'wrong first layer height' - if $z[0] ne $config->get_value('first_layer_height') + $config->z_offset; - - fail 'wrong second layer height' - if $z[1] ne $config->get_value('first_layer_height') + $config->get_value('layer_height') + $config->z_offset; - - fail 'wrong layer height' - if first { !_eq($_, $config->layer_height) } @increments[1..$#increments]; - - 1; - }; - - $config->set('start_gcode', ''); # to avoid dealing with the nozzle lift in start G-code - $config->set('layer_height', 0.3); - $config->set('first_layer_height', 0.2); - ok $test->(), "absolute first layer height"; - - $config->set('first_layer_height', 0.6 * $config->layer_height); - ok $test->(), "relative first layer height"; - - $config->set('z_offset', 0.9); - ok $test->(), "positive Z offset"; - - $config->set('z_offset', -0.8); - ok $test->(), "negative Z offset"; -} - -{ - my $config = Slic3r::Config->new; - $config->set('fill_density', 0); # just for making the test faster - $config->set('binary_gcode', 0); - my $print = Slic3r::Test::init_print('20mm_cube', config => $config, scale => 2); - - my @z = (); - Slic3r::GCode::Reader->new->parse(Slic3r::Test::gcode($print), sub { - my ($self, $cmd, $args, $info) = @_; - - if ($info->{dist_Z}) { - push @z, 1*$args->{Z}; - } - }); - ok $z[-1] > 20*1.8 && $z[-1] < 20*2.2, 'resulting G-code has reasonable height'; -} - -__END__ diff --git a/tests/fff_print/CMakeLists.txt b/tests/fff_print/CMakeLists.txt index b21d543969..43d314a01c 100644 --- a/tests/fff_print/CMakeLists.txt +++ b/tests/fff_print/CMakeLists.txt @@ -17,13 +17,14 @@ add_executable(${_TEST_NAME}_tests test_gcode_layer_changes.cpp test_gcodefindreplace.cpp test_gcodewriter.cpp - test_retraction.cpp + test_layers.cpp test_model.cpp test_multi.cpp test_perimeters.cpp test_print.cpp test_printgcode.cpp test_printobject.cpp + test_retraction.cpp test_shells.cpp test_skirt_brim.cpp test_support_material.cpp diff --git a/tests/fff_print/test_layers.cpp b/tests/fff_print/test_layers.cpp new file mode 100644 index 0000000000..6523d1318b --- /dev/null +++ b/tests/fff_print/test_layers.cpp @@ -0,0 +1,103 @@ +/** +* Ported from t/layers.t +*/ + +#include +#include "test_data.hpp" + +using namespace Slic3r; +using namespace Slic3r::Test; + +void check_layers(const DynamicPrintConfig& config) { + GCodeReader parser; + std::string gcode = Slic3r::Test::slice({TestMesh::cube_20x20x20}, config); + + std::vector z; + std::vector increments; + + parser.parse_buffer(gcode, [&] (Slic3r::GCodeReader &self, const Slic3r::GCodeReader::GCodeLine &line) { + if (line.has_z()) { + z.emplace_back(line.z()); + increments.emplace_back(line.dist_Z(self)); + } + }); + + const double first_layer_height = config.opt_float("first_layer_height"); + const double z_offset = config.opt_float("z_offset"); + const double layer_height = config.opt_float("layer_height"); + INFO("Correct first layer height."); + CHECK(z.at(0) == Approx(first_layer_height + z_offset)); + INFO("Correct second layer height") + CHECK(z.at(1) == Approx(first_layer_height + layer_height + z_offset)); + + INFO("Correct layer height") + for (const double increment : tcb::span{increments}.subspan(1)) { + CHECK(increment == Approx(layer_height)); + } +} + +TEST_CASE("Layer heights are correct", "[Layers]") { + DynamicPrintConfig config = Slic3r::DynamicPrintConfig::full_print_config(); + config.set_deserialize_strict({ + { "start_gcode", "" }, + { "layer_height", 0.3 }, + { "first_layer_height", 0.2 }, + }); + + SECTION("Absolute first layer height") { + check_layers(config); + } + + SECTION("Relative layer height") { + const double layer_height = config.opt_float("layer_height"); + config.set_deserialize_strict({ + { "first_layer_height", 0.6 * layer_height }, + }); + + check_layers(config); + } + + SECTION("Positive z offset") { + config.set_deserialize_strict({ + { "z_offset", 0.9 }, + }); + + check_layers(config); + } + + SECTION("Negative z offset") { + config.set_deserialize_strict({ + { "z_offset", -0.8 }, + }); + + check_layers(config); + } +} + +TEST_CASE("GCode has reasonable height", "[Layers]") { + DynamicPrintConfig config = Slic3r::DynamicPrintConfig::full_print_config(); + config.set_deserialize_strict({ + { "fill_density", 0 }, + { "gcode_binary", 0 }, + }); + + Print print; + Model model; + TriangleMesh test_mesh{mesh(TestMesh::cube_20x20x20)}; + test_mesh.scale(2); + Test::init_print({test_mesh}, print, model, config); + const std::string gcode{Test::gcode(print)}; + + std::vector z; + + GCodeReader parser; + parser.parse_buffer(gcode, [&] (Slic3r::GCodeReader &self, const Slic3r::GCodeReader::GCodeLine &line) { + if (line.dist_Z(self) != Approx(0)) { + z.emplace_back(line.z()); + } + }); + + REQUIRE(!z.empty()); + INFO("Last Z is: " + std::to_string(z.back())); + CHECK((z.back() > 20*1.8 && z.back() < 20*2.2)); +} From 87e9538993146f7cd1dc3abcf710559cb04d64f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20=C5=A0ach?= Date: Fri, 15 Dec 2023 12:27:26 +0100 Subject: [PATCH 35/91] Remove forgotten t/skirt_brim.t. The test is already ported to c++ in tests/fff_print/test_skirt_brim.cpp. --- t/skirt_brim.t | 146 ---------------------------------------------- xs/CMakeLists.txt | 1 - 2 files changed, 147 deletions(-) delete mode 100644 t/skirt_brim.t diff --git a/t/skirt_brim.t b/t/skirt_brim.t deleted file mode 100644 index beb3c94c50..0000000000 --- a/t/skirt_brim.t +++ /dev/null @@ -1,146 +0,0 @@ -use Test::More tests => 6; -use strict; -use warnings; - -BEGIN { - use FindBin; - use lib "$FindBin::Bin/../lib"; - use local::lib "$FindBin::Bin/../local-lib"; -} - -use List::Util qw(first); -use Slic3r; -use Slic3r::Geometry qw(unscale convex_hull); -use Slic3r::Test; - -{ - my $config = Slic3r::Config::new_from_defaults; - $config->set('skirts', 1); - $config->set('skirt_height', 2); - $config->set('perimeters', 0); - $config->set('support_material_speed', 99); - $config->set('cooling', [ 0 ]); # to prevent speeds to be altered - $config->set('first_layer_speed', '100%'); # to prevent speeds to be altered - - my $test = sub { - my ($conf) = @_; - $conf ||= $config; - - my $print = Slic3r::Test::init_print(['20mm_cube','20mm_cube'], config => $config); - - my %layers_with_skirt = (); # Z => $count - Slic3r::GCode::Reader->new->parse(Slic3r::Test::gcode($print), sub { - my ($self, $cmd, $args, $info) = @_; - - if (defined $self->Z) { - $layers_with_skirt{$self->Z} //= 0; - $layers_with_skirt{$self->Z} = 1 - if $info->{extruding} && ($args->{F} // $self->F) == $config->support_material_speed*60; - } - }); - fail "wrong number of layers with skirt" - unless (grep $_, values %layers_with_skirt) == $config->skirt_height; - }; - - ok $test->(), "skirt_height is honored when printing multiple objects too"; -} - -{ - my $config = Slic3r::Config::new_from_defaults; - $config->set('skirts', 0); - $config->set('perimeters', 0); - $config->set('top_solid_layers', 0); # to prevent solid shells and their speeds - $config->set('bottom_solid_layers', 0); # to prevent solid shells and their speeds - $config->set('brim_width', 5); - $config->set('support_material_speed', 99); - $config->set('cooling', [ 0 ]); # to prevent speeds to be altered - $config->set('first_layer_speed', '100%'); # to prevent speeds to be altered - - my $print = Slic3r::Test::init_print('20mm_cube', config => $config); - - my %layers_with_brim = (); # Z => $count - Slic3r::GCode::Reader->new->parse(Slic3r::Test::gcode($print), sub { - my ($self, $cmd, $args, $info) = @_; - - if (defined $self->Z) { - $layers_with_brim{$self->Z} //= 0; - $layers_with_brim{$self->Z} = 1 - if $info->{extruding} && $info->{dist_XY} > 0 && ($args->{F} // $self->F) != $config->infill_speed*60; - } - }); - is scalar(grep $_, values %layers_with_brim), 1, "brim is generated"; -} - -{ - my $config = Slic3r::Config::new_from_defaults; - $config->set('skirts', 1); - $config->set('brim_width', 10); - - my $print = Slic3r::Test::init_print('20mm_cube', config => $config); - ok Slic3r::Test::gcode($print), 'successful G-code generation when skirt is smaller than brim width'; -} - -{ - my $config = Slic3r::Config::new_from_defaults; - $config->set('skirts', 1); - $config->set('skirt_height', 0); - - my $print = Slic3r::Test::init_print('20mm_cube', config => $config); - ok Slic3r::Test::gcode($print), 'successful G-code generation when skirt_height = 0 and skirts > 0'; -} - -{ - my $config = Slic3r::Config::new_from_defaults; - # Define 4 extruders. - $config->set('nozzle_diameter', [0.4, 0.4, 0.4, 0.4]); - $config->set('layer_height', 0.4); - $config->set('first_layer_height', 0.4); - $config->set('skirts', 1); - $config->set('skirt_distance', 0); - $config->set('support_material_speed', 99); - $config->set('perimeter_extruder', 1); - $config->set('support_material_extruder', 2); - $config->set('cooling', [ 0 ]); # to prevent speeds to be altered - $config->set('first_layer_speed', '100%'); # to prevent speeds to be altered - - my $print = Slic3r::Test::init_print('overhang', config => $config); - $print->process; - - # we enable support material after skirt has been generated - $config->set('support_material', 1); - $print->apply($print->print->model->clone, $config); - - my $skirt_length = 0; - my @extrusion_points = (); - my $tool = undef; - Slic3r::GCode::Reader->new->parse(Slic3r::Test::gcode($print), sub { - my ($self, $cmd, $args, $info) = @_; - - if ($cmd =~ /^T(\d+)/) { - $tool = $1; - } elsif (defined $self->Z && $self->Z == $config->first_layer_height) { - # we're on first layer - if ($info->{extruding} && $info->{dist_XY} > 0) { - my $speed = ($args->{F} // $self->F) / 60; - if ($speed == $config->support_material_speed && $tool == $config->perimeter_extruder-1) { - # skirt uses support material speed but first object's extruder - $skirt_length += $info->{dist_XY}; - } else { - push @extrusion_points, my $point = Slic3r::Point->new_scale($args->{X}, $args->{Y}); - } - } - } - }); - my $convex_hull = convex_hull(\@extrusion_points); - my $hull_perimeter = unscale($convex_hull->split_at_first_point->length); - ok $skirt_length > $hull_perimeter, 'skirt lenght is large enough to contain object with support'; -} - -{ - my $config = Slic3r::Config::new_from_defaults; - $config->set('min_skirt_length', 20); - my $print = Slic3r::Test::init_print('20mm_cube', config => $config); - ok Slic3r::Test::gcode($print), 'no crash when using min_skirt_length'; -} - -__END__ diff --git a/xs/CMakeLists.txt b/xs/CMakeLists.txt index 312733490b..64c970926c 100644 --- a/xs/CMakeLists.txt +++ b/xs/CMakeLists.txt @@ -235,4 +235,3 @@ if (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND NOT CMAKE_CROSSCOMPILING AND ("${CMAK endif () add_test (NAME xs COMMAND ${PERL_ENV_VARS} "${PERL_EXECUTABLE}" ${PERL_PROVE} -I ${PERL_LOCAL_LIB_DIR}/lib/perl5 WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}) -add_test (NAME integration COMMAND ${PERL_ENV_VARS} "${PERL_EXECUTABLE}" ${PERL_PROVE} WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/..) From f78ab3e78817f233787da5c82cbe2ff332004407 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20=C5=A0ach?= Date: Fri, 15 Dec 2023 15:42:36 +0100 Subject: [PATCH 36/91] Rewrite xs/t/10_line.t to c++ --- tests/libslic3r/CMakeLists.txt | 1 + tests/libslic3r/test_line.cpp | 59 ++++++++++++++++++++++++++++++ xs/t/10_line.t | 66 ---------------------------------- 3 files changed, 60 insertions(+), 66 deletions(-) create mode 100644 tests/libslic3r/test_line.cpp delete mode 100644 xs/t/10_line.t diff --git a/tests/libslic3r/CMakeLists.txt b/tests/libslic3r/CMakeLists.txt index d10494461a..bb53fb9b1e 100644 --- a/tests/libslic3r/CMakeLists.txt +++ b/tests/libslic3r/CMakeLists.txt @@ -2,6 +2,7 @@ get_filename_component(_TEST_NAME ${CMAKE_CURRENT_LIST_DIR} NAME) add_executable(${_TEST_NAME}_tests ${_TEST_NAME}_tests.cpp + test_line.cpp test_3mf.cpp test_aabbindirect.cpp test_kdtreeindirect.cpp diff --git a/tests/libslic3r/test_line.cpp b/tests/libslic3r/test_line.cpp new file mode 100644 index 0000000000..4a8edf224f --- /dev/null +++ b/tests/libslic3r/test_line.cpp @@ -0,0 +1,59 @@ +/** + * Ported from xs/t/10_line.t + */ + +#include +#include +#include "test_utils.hpp" + +using namespace Slic3r; + +TEST_CASE("Line can be translated", "[Line]") { + Line line{{100, 100}, {200, 100}}; + + line.translate(10, -5); + CHECK(Points{line.a, line.b} == Points{{110, 95}, {210, 95}}); +} + +TEST_CASE("Check if lines are parallel", "[Line]") { + CHECK(Line{{0, 0}, {100, 0}}.parallel_to(Line{{200, 200}, {0, 200}})); +} + +TEST_CASE("Parallel lines under angles", "[Line]") { + auto base_angle = GENERATE(0, M_PI/3, M_PI/2, M_PI); + + Line line{{0, 0}, {100, 0}}; + line.rotate(base_angle, {0, 0}); + Line clone{line}; + + INFO("Line is parallel to self"); + CHECK(line.parallel_to(clone)); + + clone.reverse(); + INFO("Line is parallel to self + PI"); + CHECK(line.parallel_to(clone)); + + INFO("Line is parallel to its direction"); + CHECK(line.parallel_to(line.direction())); + INFO("Line is parallel to its direction + PI"); + line.parallel_to(line.direction() + M_PI); + INFO("line is parallel to its direction - PI") + line.parallel_to(line.direction() - M_PI); + + SECTION("Line is parallel within epsilon") { + clone = line; + clone.rotate(EPSILON/2, {0, 0}); + CHECK(line.parallel_to(clone)); + clone = line; + clone.rotate(-EPSILON/2, {0, 0}); + CHECK(line.parallel_to(clone)); + } +} + +TEST_CASE("Intersection infinite", "[Line]") { + const Line a{{100, 0}, {200, 0}}; + const Line b{{300, 300}, {300, 100}}; + Point r; + a.intersection_infinite(b, &r); + CHECK(r == Point{300, 0}); +} diff --git a/xs/t/10_line.t b/xs/t/10_line.t deleted file mode 100644 index 886573f7b6..0000000000 --- a/xs/t/10_line.t +++ /dev/null @@ -1,66 +0,0 @@ -#!/usr/bin/perl - -use strict; -use warnings; - -use Slic3r::XS; -use Test::More tests => 35; - -use constant PI => 4 * atan2(1, 1); -use constant EPSILON => 1E-4; - -my $points = [ - [100, 100], - [200, 100], -]; - -my $line = Slic3r::Line->new(@$points); - -{ - my $clone = $line->clone; - $clone->translate(10, -5); - is_deeply $clone->pp, [ - [110, 95], - [210, 95], - ], 'translate'; -} - -{ - ok +Slic3r::Line->new([0,0],[200,0])->parallel_to_line(Slic3r::Line->new([200,200],[0,200])), 'parallel_to'; -} - -foreach my $base_angle (0, PI/4, PI/2, PI) { - my $line = Slic3r::Line->new([0,0], [100,0]); - $line->rotate($base_angle, [0,0]); - my $clone = $line->clone; - ok $line->parallel_to_line($clone), 'line is parallel to self'; - $clone->reverse; - ok $line->parallel_to_line($clone), 'line is parallel to self + PI'; - ok $line->parallel_to($line->direction), 'line is parallel to its direction'; - ok $line->parallel_to($line->direction + PI), 'line is parallel to its direction + PI'; - ok $line->parallel_to($line->direction - PI), 'line is parallel to its direction - PI'; - { - my $line2 = $line->clone; - $line2->reverse; - ok $line->parallel_to_line($line2), 'line is parallel to its opposite'; - } - { - my $line2 = $line->clone; - $line2->rotate(+(EPSILON)/2, [0,0]); - ok $line->parallel_to_line($line2), 'line is parallel within epsilon'; - } - { - my $line2 = $line->clone; - $line2->rotate(-(EPSILON)/2, [0,0]); - ok $line->parallel_to_line($line2), 'line is parallel within epsilon'; - } -} - -{ - my $a = Slic3r::Line->new([100, 0], [200, 0]); - my $b = Slic3r::Line->new([300, 300], [300, 100]); - my $r = $a->intersection_infinite($b); - is_deeply $r->pp, [300, 0], 'intersection_infinite'; -} - -__END__ From 37a707b05f04dd776f8d8a95b855315895f6422c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20=C5=A0ach?= Date: Fri, 15 Dec 2023 16:07:16 +0100 Subject: [PATCH 37/91] Rewrite xs/t/03_point.t to c++ --- tests/libslic3r/CMakeLists.txt | 1 + tests/libslic3r/test_point.cpp | 46 +++++++++++++++++++++++++ xs/t/03_point.t | 62 ---------------------------------- 3 files changed, 47 insertions(+), 62 deletions(-) create mode 100644 tests/libslic3r/test_point.cpp delete mode 100644 xs/t/03_point.t diff --git a/tests/libslic3r/CMakeLists.txt b/tests/libslic3r/CMakeLists.txt index bb53fb9b1e..69539e82d3 100644 --- a/tests/libslic3r/CMakeLists.txt +++ b/tests/libslic3r/CMakeLists.txt @@ -3,6 +3,7 @@ get_filename_component(_TEST_NAME ${CMAKE_CURRENT_LIST_DIR} NAME) add_executable(${_TEST_NAME}_tests ${_TEST_NAME}_tests.cpp test_line.cpp + test_point.cpp test_3mf.cpp test_aabbindirect.cpp test_kdtreeindirect.cpp diff --git a/tests/libslic3r/test_point.cpp b/tests/libslic3r/test_point.cpp new file mode 100644 index 0000000000..06d4433b09 --- /dev/null +++ b/tests/libslic3r/test_point.cpp @@ -0,0 +1,46 @@ + +/** + * Ported from xs/t/03_point.t + * - it used to check ccw() but it does not exist anymore + * and cross product uses doubles + */ + +#include +#include +#include "test_utils.hpp" + +using namespace Slic3r; + +TEST_CASE("Nearest point", "[Point]") { + const Point point{10, 15}; + const Point point2{30, 15}; + + const Point nearest{nearest_point({point2, Point{100, 200}}, point).first}; + CHECK(nearest == point2); +} + +TEST_CASE("Distance to line", "[Point]") { + const Line line{{0, 0}, {100, 0}}; + CHECK(line.distance_to(Point{0, 0}) == Approx(0)); + CHECK(line.distance_to(Point{100, 0}) == Approx(0)); + CHECK(line.distance_to(Point{50, 0}) == Approx(0)); + CHECK(line.distance_to(Point{150, 0}) == Approx(50)); + CHECK(line.distance_to(Point{0, 50}) == Approx(50)); + CHECK(line.distance_to(Point{50, 50}) == Approx(50)); + CHECK(line.perp_distance_to(Point{50, 50}) == Approx(50)); + CHECK(line.perp_distance_to(Point{150, 50}) == Approx(50)); +} + +TEST_CASE("Distance to diagonal line", "[Point]") { + const Line line{{50, 50}, {125, -25}}; + CHECK(std::abs(line.distance_to(Point{100, 0})) == Approx(0)); +} + +TEST_CASE("Perp distance to line does not overflow", "[Point]") { + const Line line{ + {18335846, 18335845}, + {18335846, 1664160}, + }; + + CHECK(line.distance_to(Point{1664161, 18335848}) == Approx(16671685)); +} diff --git a/xs/t/03_point.t b/xs/t/03_point.t deleted file mode 100644 index 389e120c75..0000000000 --- a/xs/t/03_point.t +++ /dev/null @@ -1,62 +0,0 @@ -#!/usr/bin/perl - -use strict; -use warnings; - -use Slic3r::XS; -use Test::More tests => 16; - -my $point = Slic3r::Point->new(10, 15); - -my $point2 = $point->clone; -$point2->scale(2); -is_deeply [ @$point2 ], [20, 30], 'scale'; - -$point2->translate(10, -15); -is_deeply [ @$point2 ], [30, 15], 'translate'; - -{ - my $point3 = Slic3r::Point->new(4300000, -9880845); - is $point->[0], $point->x, 'x accessor'; - is $point->[1], $point->y, 'y accessor'; #,, -} - -{ - my $nearest = $point->nearest_point([ $point2, Slic3r::Point->new(100, 200) ]); - ok $nearest->coincides_with($point2), 'nearest_point'; -} - -{ - my $line = Slic3r::Line->new([0,0], [100,0]); - is +Slic3r::Point->new(0,0) ->distance_to_line($line), 0, 'distance_to_line()'; - is +Slic3r::Point->new(100,0)->distance_to_line($line), 0, 'distance_to_line()'; - is +Slic3r::Point->new(50,0) ->distance_to_line($line), 0, 'distance_to_line()'; - is +Slic3r::Point->new(150,0)->distance_to_line($line), 50, 'distance_to_line()'; - is +Slic3r::Point->new(0,50) ->distance_to_line($line), 50, 'distance_to_line()'; - is +Slic3r::Point->new(50,50)->distance_to_line($line), 50, 'distance_to_line()'; - is +Slic3r::Point->new(50,50) ->perp_distance_to_line($line), 50, 'perp_distance_to_line()'; - is +Slic3r::Point->new(150,50)->perp_distance_to_line($line), 50, 'perp_distance_to_line()'; -} - -{ - my $line = Slic3r::Line->new([50,50], [125,-25]); - cmp_ok(abs(Slic3r::Point->new(100,0)->distance_to_line($line)), '<=', 4e-15, 'distance_to_line()'); -} - -{ - my $line = Slic3r::Line->new( - [18335846,18335845], - [18335846,1664160], - ); - $point = Slic3r::Point->new(1664161,18335848); - is $point->perp_distance_to_line($line), 16671685, 'perp_distance_to_line() does not overflow'; -} - -{ - my $p0 = Slic3r::Point->new(76975850,89989996); - my $p1 = Slic3r::Point->new(76989990,109989991); - my $p2 = Slic3r::Point->new(76989987,89989994); - ok $p0->ccw($p1, $p2) < 0, 'ccw() does not overflow'; -} - -__END__ From 9164dd55e6c84cba1e9fff0387306e1f3b4f5a71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20=C5=A0ach?= Date: Fri, 15 Dec 2023 16:46:14 +0100 Subject: [PATCH 38/91] Rewrite xs/t/09_polyline.t to c++ --- tests/libslic3r/test_polyline.cpp | 91 +++++++++++++++++++++++++++++++ xs/t/09_polyline.t | 86 ----------------------------- 2 files changed, 91 insertions(+), 86 deletions(-) delete mode 100644 xs/t/09_polyline.t diff --git a/tests/libslic3r/test_polyline.cpp b/tests/libslic3r/test_polyline.cpp index 89a84d40a3..3a51b78dd8 100644 --- a/tests/libslic3r/test_polyline.cpp +++ b/tests/libslic3r/test_polyline.cpp @@ -1,3 +1,6 @@ +/** +* Ported from xs/t/09_polyline.t +*/ #include #include "libslic3r/Point.hpp" @@ -5,6 +8,74 @@ using namespace Slic3r; +struct PolylineTestCase { + Polyline polyline{ + {100, 100}, + {200, 100}, + {200, 200} + }; +}; + +TEST_CASE_METHOD(PolylineTestCase, "Lines can be retrieved", "[Polyline]") { + + CHECK(polyline.lines() == Lines{ + {{100, 100}, {200, 100}}, + {{200, 100}, {200, 200}}, + }); +} + +TEST_CASE_METHOD(PolylineTestCase, "Clip", "[Polyline]") { + const double len = polyline.length(); + polyline.clip_end(len/3); + CHECK(std::abs(polyline.length() - 2.0/3.0*len) < 1); +} + +TEST_CASE_METHOD(PolylineTestCase, "Append", "[Polyline]") { + Polyline tested_polyline{polyline}; + tested_polyline.append(tested_polyline); + Points expected{polyline.points}; + expected.insert(expected.end(), polyline.points.begin(), polyline.points.end()); + + CHECK(tested_polyline.points == expected); +} + +TEST_CASE_METHOD(PolylineTestCase, "Extend end", "[Polyline]") { + CHECK(polyline.length() == 100*2); + polyline.extend_end(50); + CHECK(polyline.length() == 100*2 + 50); +} + +TEST_CASE_METHOD(PolylineTestCase, "Extend start", "[Polyline]") { + CHECK(polyline.length() == 100*2); + polyline.extend_start(50); + CHECK(polyline.length() == 100*2 + 50); +} + +TEST_CASE_METHOD(PolylineTestCase, "Split", "[Polyline]") { + Polyline p1; + Polyline p2; + const Point point{150, 100}; + polyline.split_at(point, &p1, &p2); + CHECK(p1.size() == 2); + CHECK(p2.size() == 3); + CHECK(p1.last_point() == point); + CHECK(p2.first_point() == point); +} + +TEST_CASE_METHOD(PolylineTestCase, "Split at first point", "[Polyline]") { + Polyline to_split{ + polyline.points[0], + polyline.points[1], + polyline.points[2], + polyline.points[0] + }; + Polyline p1; + Polyline p2; + to_split.split_at(to_split.first_point(), &p1, &p2); + CHECK(p1.size() == 1); + CHECK(p2.size() == 4); +} + SCENARIO("Simplify polyne, template", "[Polyline]") { Points polyline{ {0,0}, {1000,0}, {2000,0}, {2000,1000}, {2000,2000}, {1000,2000}, {0,2000}, {0,1000}, {0,0} }; @@ -44,4 +115,24 @@ SCENARIO("Simplify polyline", "[Polyline]") } } } + + GIVEN("polyline 3") { + auto polyline = Polyline{ {0,0}, {100,0}, {50,10} }; + WHEN("simplified with Douglas-Peucker") { + polyline.simplify(25.); + THEN("not simplified") { + REQUIRE(polyline == Polyline{ {0,0}, {100, 0}, {50,10} }); + } + } + } + + GIVEN("polyline 4") { + auto polyline = Polyline{ {0,0}, {20,0}, {50,0}, {80,0}, {100,0} }; + WHEN("simplified with Douglas-Peucker") { + polyline.simplify(2.); + THEN("not simplified") { + REQUIRE(polyline == Polyline{ {0,0}, {100,0} }); + } + } + } } diff --git a/xs/t/09_polyline.t b/xs/t/09_polyline.t deleted file mode 100644 index 7da74b93da..0000000000 --- a/xs/t/09_polyline.t +++ /dev/null @@ -1,86 +0,0 @@ -#!/usr/bin/perl - -use strict; -use warnings; - -use Slic3r::XS; -use Test::More tests => 15; - -my $points = [ - [100, 100], - [200, 100], - [200, 200], -]; - -my $polyline = Slic3r::Polyline->new(@$points); - -my $lines = $polyline->lines; -is_deeply [ map $_->pp, @$lines ], [ - [ [100, 100], [200, 100] ], - [ [200, 100], [200, 200] ], -], 'polyline lines'; - -$polyline->append_polyline($polyline->clone); -is_deeply $polyline->pp, [ @$points, @$points ], 'append_polyline'; - -{ - my $len = $polyline->length; - $polyline->clip_end($len/3); - ok abs($polyline->length - ($len-($len/3))) < 1, 'clip_end'; -} - -{ - my $polyline = Slic3r::Polyline->new( - [0,0], [20,0], [50,0], [80,0], [100,0], - ); - $polyline->simplify(2); - is_deeply $polyline->pp, [ [0,0], [100,0] ], 'Douglas-Peucker'; -} - -{ - my $polyline = Slic3r::Polyline->new( - [0,0], [50,50], [100,0], [125,-25], [150,50], - ); - $polyline->simplify(25); - is_deeply $polyline->pp, [ [0, 0], [50, 50], [125, -25], [150, 50] ], 'Douglas-Peucker'; -} - -{ - my $polyline = Slic3r::Polyline->new( - [0,0], [100,0], [50,10], - ); - $polyline->simplify(25); - is_deeply $polyline->pp, [ [0,0], [100,0], [50,10] ], 'Douglas-Peucker uses shortest distance instead of perpendicular distance'; -} - -{ - my $polyline = Slic3r::Polyline->new(@$points); - is $polyline->length, 100*2, 'length'; - $polyline->extend_end(50); - is $polyline->length, 100*2 + 50, 'extend_end'; - $polyline->extend_start(50); - is $polyline->length, 100*2 + 50 + 50, 'extend_start'; -} - -{ - my $polyline = Slic3r::Polyline->new(@$points); - my $p1 = Slic3r::Polyline->new; - my $p2 = Slic3r::Polyline->new; - my $point = Slic3r::Point->new(150, 100); - $polyline->split_at($point, $p1, $p2); - is scalar(@$p1), 2, 'split_at'; - is scalar(@$p2), 3, 'split_at'; - ok $p1->last_point->coincides_with($point), 'split_at'; - ok $p2->first_point->coincides_with($point), 'split_at'; -} - -{ - my $polyline = Slic3r::Polyline->new(@$points[0,1,2,0]); - my $p1 = Slic3r::Polyline->new; - my $p2 = Slic3r::Polyline->new; - $polyline->split_at($polyline->first_point, $p1, $p2); - is scalar(@$p1), 1, 'split_at'; - is scalar(@$p2), 4, 'split_at'; -} - -__END__ From 6b01ae30db49257be7541077927b0adcf443ba7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20=C5=A0ach?= Date: Mon, 18 Dec 2023 13:23:00 +0100 Subject: [PATCH 39/91] Rewrite xs/t/15_config.t to c++. --- tests/libslic3r/test_config.cpp | 233 ++++++++++++++++++++++++++++++++ 1 file changed, 233 insertions(+) diff --git a/tests/libslic3r/test_config.cpp b/tests/libslic3r/test_config.cpp index 50e61b3b04..229edeebae 100644 --- a/tests/libslic3r/test_config.cpp +++ b/tests/libslic3r/test_config.cpp @@ -11,6 +11,239 @@ using namespace Slic3r; +TEST_CASE("Dynamic config serialization - tests ConfigBase", "[Config]"){ + DynamicPrintConfig config; + INFO("Serialize float"); + config.set_key_value("layer_height", new ConfigOptionFloat(0.3)); + CHECK(config.opt_serialize("layer_height") == "0.3"); + + INFO("Serialize int"); + config.set_key_value("perimeters", new ConfigOptionInt(2)); + CHECK(config.opt_serialize("perimeters") == "2"); + + INFO("Serialize float or percent"); + config.set_key_value("first_layer_height", new ConfigOptionFloatOrPercent(30, true)); + CHECK(config.opt_serialize("first_layer_height") == "30%"); + + INFO("Serialize bool"); + config.set_key_value("use_relative_e_distances", new ConfigOptionBool(true)); + CHECK(config.opt_serialize("use_relative_e_distances") == "1"); + + INFO("Serialize enum"); + config.set_key_value("gcode_flavor", new ConfigOptionEnum(gcfTeacup)); + CHECK(config.opt_serialize("gcode_flavor") == "teacup"); + + INFO("Serialize string"); + config.set_key_value("extrusion_axis", new ConfigOptionString("A")); + CHECK(config.opt_serialize("extrusion_axis") == "A"); + + INFO("Serialize string with newline"); + config.set_key_value("notes", new ConfigOptionString("foo\nbar")); + CHECK(config.opt_serialize("notes") == "foo\\nbar"); + config.set_deserialize_strict("notes", "bar\\nbaz"); + INFO("Deserialize string with newline"); + CHECK(config.opt_string("notes") == "bar\nbaz"); + + INFO("Serialize points"); + config.set_key_value("extruder_offset", new ConfigOptionPoints({{10, 20}, {30, 45}})); + CHECK(config.opt_serialize("extruder_offset") == "10x20,30x45"); + INFO("Deserialize points"); + config.set_deserialize_strict("extruder_offset", "20x10"); + CHECK(config.option("extruder_offset")->values == std::vector{Vec2d{20, 10}}); + + INFO("Serialize floats"); + config.set_key_value("nozzle_diameter", new ConfigOptionFloats({0.2, 3})); + CHECK(config.opt_serialize("nozzle_diameter") == "0.2,3"); + INFO("Deserialize floats"); + config.set_deserialize_strict("nozzle_diameter", "0.1,0.4"); + CHECK_THAT(config.option("nozzle_diameter")->values, Catch::Matchers::Approx(std::vector{0.1, 0.4})); + INFO("Deserialize floats from one value"); + config.set_deserialize_strict("nozzle_diameter", "3"); + CHECK_THAT(config.option("nozzle_diameter")->values, Catch::Matchers::Approx(std::vector{3.0})); + + INFO("Serialize ints"); + config.set_key_value("temperature", new ConfigOptionInts({180, 210})); + CHECK(config.opt_serialize("temperature") == "180,210"); + INFO("Deserialize ints"); + config.set_deserialize_strict("temperature", "195,220"); + CHECK(config.option("temperature")->values == std::vector{195,220}); + + INFO("Serialize bools"); + config.set_key_value("wipe", new ConfigOptionBools({true, false})); + CHECK(config.opt_serialize("wipe") == "1,0"); + INFO("Deserialize bools"); + config.set_deserialize_strict("wipe", "0,1,1"); + CHECK(config.option("wipe")->values == std::vector{false, true, true}); + + INFO("Deserialize bools from empty stirng"); + config.set_deserialize_strict("wipe", ""); + CHECK(config.option("wipe")->values == std::vector{}); + + INFO("Deserialize bools from value"); + config.set_deserialize_strict({{"wipe", 1}}); + CHECK(config.option("wipe")->values == std::vector{true}); + + INFO("Serialize strings"); + config.set_key_value("post_process", new ConfigOptionStrings({"foo", "bar"})); + CHECK(config.opt_serialize("post_process") == "foo;bar"); + INFO("Deserialize strings"); + config.set_deserialize_strict("post_process", "bar;baz"); + CHECK(config.option("post_process")->values == std::vector{"bar", "baz"}); +} + +TEST_CASE("Get keys", "[Config]"){ + DynamicPrintConfig config = DynamicPrintConfig::full_print_config(); + CHECK(!config.keys().empty()); +} + +TEST_CASE("Set not already set option", "[Config]") { + DynamicPrintConfig config; + config.set_deserialize_strict("filament_diameter", "3"); +} + +TEST_CASE("Config apply dynamic to static", "[Config]") { + DynamicPrintConfig config; + config.set_deserialize_strict("perimeters", "2"); + + // This trick is taken directly from perl. + StaticPrintConfig* config2 = static_cast(new FullPrintConfig()); + config2->apply(config, true); + + CHECK(config2->opt_int("perimeters") == 2); +} + +TEST_CASE("Config apply static to dynamic", "[Config]") { + // This trick is taken directly from perl. + StaticPrintConfig* config = static_cast(new FullPrintConfig()); + + DynamicPrintConfig config2; + config2.apply(*config, true); + + CHECK( + config2.opt_int("perimeters") == + DynamicPrintConfig::full_print_config().opt_int("perimeters") + ); +} + +TEST_CASE("Config apply dynamic to dynamic", "[Config]") { + + DynamicPrintConfig config; + config.set_key_value("extruder_offset", new ConfigOptionPoints({{0, 0}, {20, 0}, {0, 20}})); + DynamicPrintConfig config2; + config2.apply(config, true); + + CHECK( + config2.option("extruder_offset")->values == + std::vector{{0, 0}, {20, 0}, {0, 20}} + ); +} + +TEST_CASE("Get abs value on percent", "[Config]") { + StaticPrintConfig* config = static_cast(new FullPrintConfig()); + + config->set_deserialize_strict("solid_infill_speed", "60"); + config->set_deserialize_strict("top_solid_infill_speed", "10%"); + CHECK(config->get_abs_value("top_solid_infill_speed") == 6); +} + +TEST_CASE("No interference between DynamicConfig objects", "[Config]") { + DynamicPrintConfig config; + config.set_key_value("fill_pattern", new ConfigOptionString("line")); + DynamicPrintConfig config2; + config2.set_key_value("fill_pattern", new ConfigOptionString("hilbertcurve")); + CHECK(config.opt_string("fill_pattern") == "line"); +} + +TEST_CASE("Normalize fdm extruder", "[Config]") { + DynamicPrintConfig config; + config.set("extruder", 2, true); + config.set("perimeter_extruder", 3, true); + config.normalize_fdm(); + INFO("Extruder option is removed after normalize()."); + CHECK(!config.has("extruder")); + INFO("Undefined extruder is populated with default extruder."); + CHECK(config.opt_int("infill_extruder") == 2); + INFO("Defined extruder is not overwritten by default extruder."); + CHECK(config.opt_int("perimeter_extruder") == 3); +} + +TEST_CASE("Normalize fdm infill extruder", "[Config]") { + DynamicPrintConfig config; + config.set("infill_extruder", 2, true); + config.normalize_fdm(); + INFO("Undefined solid infill extruder is populated with infill extruder."); + CHECK(config.opt_int("solid_infill_extruder") == 2); +} + +TEST_CASE("Normalize fdm retract layer change", "[Config]") { + DynamicPrintConfig config; + config.set("spiral_vase", true, true); + config.set_key_value("retract_layer_change", new ConfigOptionBools({true, false})); + config.normalize_fdm(); + CHECK(config.option("retract_layer_change")->values == std::vector{0, 0}); +} + +TEST_CASE("Can read ini with invalid items", "[Config]") { + std::string path = std::string(TEST_DATA_DIR) + "/test_config/bad_config_options.ini"; + + DynamicPrintConfig config; + config.load(path, ForwardCompatibilitySubstitutionRule::Disable); + //Did not crash. +} + +struct SerializationTestData { + std::string name; + std::vector values; + std::string serialized; +}; + +TEST_CASE("Config serialization of multiple values", "[Config]"){ + DynamicPrintConfig config = DynamicPrintConfig::full_print_config(); + std::vector test_data{ + { + "empty", + {}, + "" + }, + { + "single empty", + {""}, + "\"\"" + }, + { + "single noempty, simple", + {"RGB"}, + "RGB" + }, + { + "multiple noempty, simple", + {"ABC", "DEF", "09182745@!#$*(&"}, + "ABC;DEF;09182745@!#$*(&" + }, + { + "multiple, simple, some empty", + {"ABC", "DEF", "", "09182745@!#$*(&", ""}, + "ABC;DEF;;09182745@!#$*(&;" + }, + { + "complex", + {"some \"quoted\" notes", "yet\n some notes", "whatever \n notes", ""}, + "\"some \\\"quoted\\\" notes\";\"yet\\n some notes\";\"whatever \\n notes\";" + } + }; + + for (const SerializationTestData& data : test_data) { + config.set_key_value("filament_notes", new ConfigOptionStrings(data.values)); + CHECK(config.opt_serialize("filament_notes") == data.serialized); + + config.set_deserialize_strict("filament_notes", ""); + CHECK(config.option("filament_notes")->values == std::vector{}); + + config.set_deserialize_strict("filament_notes", data.serialized); + CHECK(config.option("filament_notes")->values == data.values); + } +} + SCENARIO("Generic config validation performs as expected.", "[Config]") { GIVEN("A config generated from default options") { Slic3r::DynamicPrintConfig config = Slic3r::DynamicPrintConfig::full_print_config(); From f2868767abcf1f031dc1e537b4c3d4615f717397 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20=C5=A0ach?= Date: Mon, 18 Dec 2023 13:23:23 +0100 Subject: [PATCH 40/91] Remove obsolete perl files --- Build.PL | 132 - CMakeLists.txt | 13 - cmake/modules/FindPerlEmbed.cmake | 88 - xs/CMakeLists.txt | 237 - xs/lib/Slic3r/XS.pm | 125 - xs/main.xs.in | 26 - xs/src/perlglue.cpp | 527 -- xs/src/ppport.h | 7063 --------------------- xs/src/xsinit.h | 262 - xs/t/15_config.t | 252 - xs/t/inc/22_config_bad_config_options.ini | 7 - xs/xsp/Config.xsp | 218 - xs/xsp/ExPolygon.xsp | 57 - xs/xsp/Geometry.xsp | 51 - xs/xsp/Line.xsp | 78 - xs/xsp/Model.xsp | 286 - xs/xsp/Point.xsp | 129 - xs/xsp/Polygon.xsp | 65 - xs/xsp/Polyline.xsp | 74 - xs/xsp/Print.xsp | 68 - xs/xsp/TriangleMesh.xsp | 115 - xs/xsp/XS.xsp | 38 - xs/xsp/my.map | 344 - xs/xsp/mytype.map | 0 xs/xsp/typemap.xspt | 99 - 25 files changed, 10354 deletions(-) delete mode 100644 Build.PL delete mode 100644 cmake/modules/FindPerlEmbed.cmake delete mode 100644 xs/CMakeLists.txt delete mode 100644 xs/lib/Slic3r/XS.pm delete mode 100644 xs/main.xs.in delete mode 100644 xs/src/perlglue.cpp delete mode 100644 xs/src/ppport.h delete mode 100644 xs/src/xsinit.h delete mode 100644 xs/t/15_config.t delete mode 100644 xs/t/inc/22_config_bad_config_options.ini delete mode 100644 xs/xsp/Config.xsp delete mode 100644 xs/xsp/ExPolygon.xsp delete mode 100644 xs/xsp/Geometry.xsp delete mode 100644 xs/xsp/Line.xsp delete mode 100644 xs/xsp/Model.xsp delete mode 100644 xs/xsp/Point.xsp delete mode 100644 xs/xsp/Polygon.xsp delete mode 100644 xs/xsp/Polyline.xsp delete mode 100644 xs/xsp/Print.xsp delete mode 100644 xs/xsp/TriangleMesh.xsp delete mode 100644 xs/xsp/XS.xsp delete mode 100644 xs/xsp/my.map delete mode 100644 xs/xsp/mytype.map delete mode 100644 xs/xsp/typemap.xspt diff --git a/Build.PL b/Build.PL deleted file mode 100644 index 1c3b0e3a7f..0000000000 --- a/Build.PL +++ /dev/null @@ -1,132 +0,0 @@ -#!/usr/bin/perl - -print "This script is currently used for installing Perl dependenices for running\n"; -print "the libslic3r unit / integration tests through Perl prove.\n"; -print "If you don't plan to run the unit / integration tests, you don't need to\n"; -print "install these dependencies to build and run PrusaSlicer.\n"; - -use strict; -use warnings; - -use Config; -use File::Spec; - -my %prereqs = qw( - Devel::CheckLib 0 - ExtUtils::MakeMaker 6.80 - ExtUtils::ParseXS 3.22 - ExtUtils::XSpp 0 - ExtUtils::XSpp::Cmd 0 - ExtUtils::CppGuess 0 - ExtUtils::Typemaps 0 - ExtUtils::Typemaps::Basic 0 - File::Basename 0 - File::Spec 0 - Getopt::Long 0 - Module::Build::WithXSpp 0.14 - Moo 1.003001 - POSIX 0 - Scalar::Util 0 - Test::More 0 - IO::Scalar 0 - Time::HiRes 0 -); -my %recommends = qw( - Class::XSAccessor 0 - Test::Harness 0 -); - -my $sudo = grep { $_ eq '--sudo' } @ARGV; -my $nolocal = grep { $_ eq '--nolocal' } @ARGV; - -my @missing_prereqs = (); -if ($ENV{SLIC3R_NO_AUTO}) { - foreach my $module (sort keys %prereqs) { - my $version = $prereqs{$module}; - next if eval "use $module $version; 1"; - push @missing_prereqs, $module if exists $prereqs{$module}; - print "Missing prerequisite $module $version\n"; - } - foreach my $module (sort keys %recommends) { - my $version = $recommends{$module}; - next if eval "use $module $version; 1"; - print "Missing optional $module $version\n"; - } -} else { - my @try = ( - $ENV{CPANM} // (), - File::Spec->catfile($Config{sitebin}, 'cpanm'), - File::Spec->catfile($Config{installscript}, 'cpanm'), - ); - - my $cpanm; - foreach my $path (@try) { - if (-e $path) { # don't use -x because it fails on Windows - $cpanm = $path; - last; - } - } - if (!$cpanm) { - if ($^O =~ /^(?:darwin|linux)$/ && system(qw(which cpanm)) == 0) { - $cpanm = 'cpanm'; - } - } - die <<'EOF' -cpanm was not found. Please install it before running this script. - -There are several ways to install cpanm, try one of these: - - apt-get install cpanminus - curl -L http://cpanmin.us | perl - --sudo App::cpanminus - cpan App::cpanminus - -If it is installed in a non-standard location you can do: - - CPANM=/path/to/cpanm perl Build.PL - -EOF - if !$cpanm; - my @cpanm_args = (); - push @cpanm_args, "--sudo" if $sudo; - - # install local::lib without --local-lib otherwise it's not usable afterwards - if (!eval "use local::lib qw(local-lib); 1") { - my $res = system $cpanm, @cpanm_args, 'local::lib'; - warn "Warning: local::lib is required. You might need to run the `cpanm --sudo local::lib` command in order to install it.\n" - if $res != 0; - } - - push @cpanm_args, ('--local-lib', 'local-lib') if ! $nolocal; - - # make sure our cpanm is updated (old ones don't support the ~ syntax) - system $cpanm, @cpanm_args, 'App::cpanminus'; - - my %modules = (%prereqs, %recommends); - foreach my $module (sort keys %modules) { - my $version = $modules{$module}; - my @cmd = ($cpanm, @cpanm_args); - - # temporary workaround for upstream bug in test - push @cmd, '--notest' - if $module =~ /^(?:OpenGL|Test::Harness)$/; - - push @cmd, "$module~$version"; - - my $res = system @cmd; - if ($res != 0) { - if (exists $prereqs{$module}) { - push @missing_prereqs, $module; - } else { - printf "Don't worry, this module is optional.\n"; - } - } - } -} - -print "\n"; -print "In the next step, you need to build the PrusaSlicer C++ library.\n"; -print "1) Create a build directory and change to it\n"; -print "2) run cmake .. -DCMAKE_BUILD_TYPE=Release\n"; -print "3) run make\n"; -print "4) to execute the automatic tests, run ctest --verbose\n"; -__END__ diff --git a/CMakeLists.txt b/CMakeLists.txt index dcfe0ca67b..3b37dbac67 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -39,7 +39,6 @@ option(SLIC3R_FHS "Assume PrusaSlicer is to be installed in a FHS option(SLIC3R_PCH "Use precompiled headers" 1) option(SLIC3R_MSVC_COMPILE_PARALLEL "Compile on Visual Studio in parallel" 1) option(SLIC3R_MSVC_PDB "Generate PDB files on MSVC in Release mode" 1) -option(SLIC3R_PERL_XS "Compile XS Perl module and enable Perl unit and integration tests" 0) option(SLIC3R_ASAN "Enable ASan on Clang and GCC" 0) option(SLIC3R_UBSAN "Enable UBSan on Clang and GCC" 0) option(SLIC3R_ENABLE_FORMAT_STEP "Enable compilation of STEP file support" ON) @@ -83,7 +82,6 @@ option(SLIC3R_BUILD_TESTS "Build unit tests" ON) if (IS_CROSS_COMPILE) message("Detected cross compilation setup. Tests and encoding checks will be forcedly disabled!") - set(SLIC3R_PERL_XS OFF CACHE BOOL "" FORCE) set(SLIC3R_BUILD_TESTS OFF CACHE BOOL "" FORCE) endif () @@ -176,10 +174,6 @@ if(NOT WIN32) add_compile_options("$<$:-DDEBUG>") endif() -# To be able to link libslic3r with the Perl XS module. -# Once we get rid of Perl and libslic3r is linked statically, we can get rid of -fPIC -set(CMAKE_POSITION_INDEPENDENT_CODE ON) - # WIN10SDK_PATH is used to point CMake to the WIN10 SDK installation directory. # We pick it from environment if it is not defined in another way if(WIN32) @@ -619,13 +613,6 @@ set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT P add_dependencies(gettext_make_pot hintsToPot) -# Perl bindings, currently only used for the unit / integration tests of libslic3r. -# Also runs the unit / integration tests. -#FIXME Port the tests into C++ to finally get rid of the Perl! -if (SLIC3R_PERL_XS) - add_subdirectory(xs) -endif () - if(SLIC3R_BUILD_SANDBOXES) add_subdirectory(sandboxes) endif() diff --git a/cmake/modules/FindPerlEmbed.cmake b/cmake/modules/FindPerlEmbed.cmake deleted file mode 100644 index b12fc40634..0000000000 --- a/cmake/modules/FindPerlEmbed.cmake +++ /dev/null @@ -1,88 +0,0 @@ -# Find the dependencies for linking with the Perl runtime library. - -# Check for the Perl & PerlLib modules -include(LibFindMacros) -libfind_package(PerlEmbed Perl) -libfind_package(PerlEmbed PerlLibs) - -# Execute an Alien::Wx module to find the relevant information regarding -# the wxWidgets used by the Perl interpreter. -# Perl specific stuff -set(PerlEmbed_TEMP_INCLUDE ${CMAKE_CURRENT_BINARY_DIR}/PerlEmbed_TEMP_INCLUDE.txt) -execute_process( - COMMAND ${PERL_EXECUTABLE} -MExtUtils::Embed -e " -# Import Perl modules. -use strict; -use warnings; -use Config; -use Text::ParseWords; -use ExtUtils::CppGuess; - -# Test for a Visual Studio compiler -my \$cpp_guess = ExtUtils::CppGuess->new; -my \$mswin = \$^O eq 'MSWin32'; -my \$msvc = \$cpp_guess->is_msvc; - -# Query the available data from Alien::wxWidgets. -my \$ccflags; -my \$ldflags; -{ local *STDOUT; open STDOUT, '>', \\\$ccflags; ccflags; } -{ local *STDOUT; open STDOUT, '>', \\\$ldflags; ldopts; } -\$ccflags = ' ' . \$ccflags; -\$ldflags = ' ' . \$ldflags; - -my \$filename = '${PerlEmbed_TEMP_INCLUDE}'; -open(my $fh, '>', \$filename) or die \"Could not open file '\$filename' \$!\"; - -# Convert a space separated lists to CMake semicolon separated lists, -# escape the backslashes, -# export the resulting list to a temp file. -sub cmake_set_var { - my (\$varname, \$content) = @_; - # Remove line separators. - \$content =~ s/\\r|\\n//g; - # Escape the path separators. - \$content =~ s/\\\\/\\\\\\\\\\\\\\\\/g; - my @words = shellwords(\$content); - print \$fh \"set(PerlEmbed_\$varname \\\"\" . join(';', @words) . \"\\\")\\n\"; -} -cmake_set_var('ARCHNAME', \$Config{archname}); -cmake_set_var('CCFLAGS', \$ccflags); -\$ldflags =~ s/ -L/ -LIBPATH:/g if \$msvc; -cmake_set_var('LD', \$Config{ld}); -cmake_set_var('LDFLAGS', \$ldflags); -cmake_set_var('CCCDLFLAGS', \$Config{cccdlflags}); -cmake_set_var('LDDLFLAGS', \$Config{lddlflags}); -cmake_set_var('DLEXT', \$Config{dlext}); -close \$fh; -") -include(${PerlEmbed_TEMP_INCLUDE}) -file(REMOVE ${PerlEmbed_TEMP_INCLUDE}) -unset(PerlEmbed_TEMP_INCLUDE) - -if (PerlEmbed_DEBUG) - # First show the configuration extracted by FindPerl & FindPerlLibs: - message(STATUS " PERL_INCLUDE_PATH = ${PERL_INCLUDE_PATH}") - message(STATUS " PERL_LIBRARY = ${PERL_LIBRARY}") - message(STATUS " PERL_EXECUTABLE = ${PERL_EXECUTABLE}") - message(STATUS " PERL_SITESEARCH = ${PERL_SITESEARCH}") - message(STATUS " PERL_SITELIB = ${PERL_SITELIB}") - message(STATUS " PERL_VENDORARCH = ${PERL_VENDORARCH}") - message(STATUS " PERL_VENDORLIB = ${PERL_VENDORLIB}") - message(STATUS " PERL_ARCHLIB = ${PERL_ARCHLIB}") - message(STATUS " PERL_PRIVLIB = ${PERL_PRIVLIB}") - message(STATUS " PERL_EXTRA_C_FLAGS = ${PERL_EXTRA_C_FLAGS}") - # Second show the configuration extracted by this module (FindPerlEmbed): - message(STATUS " PerlEmbed_ARCHNAME = ${PerlEmbed_ARCHNAME}") - message(STATUS " PerlEmbed_CCFLAGS = ${PerlEmbed_CCFLAGS}") - message(STATUS " PerlEmbed_CCCDLFLAGS = ${PerlEmbed_CCCDLFLAGS}") - message(STATUS " LD = ${PerlEmbed_LD}") - message(STATUS " PerlEmbed_LDFLAGS = ${PerlEmbed_LDFLAGS}") - message(STATUS " PerlEmbed_LDDLFLAGS = ${PerlEmbed_LDDLFLAGS}") -endif() - -include(FindPackageHandleStandardArgs) - -find_package_handle_standard_args(PerlEmbed - REQUIRED_VARS PerlEmbed_CCFLAGS PerlEmbed_LDFLAGS - VERSION_VAR PERL_VERSION) diff --git a/xs/CMakeLists.txt b/xs/CMakeLists.txt deleted file mode 100644 index 64c970926c..0000000000 --- a/xs/CMakeLists.txt +++ /dev/null @@ -1,237 +0,0 @@ -project(XS) - -# Find the Perl interpreter, add local-lib to PATH and PERL5LIB environment variables, -# so the locally installed modules (mainly the Alien::wxPerl) will be reached. -if (WIN32) - set(ENV_PATH_SEPARATOR ";") -else() - set(ENV_PATH_SEPARATOR ":") -endif() - -# Install the XS.pm and XS.{so,dll,bundle} into the local-lib directory. -set(PERL_LOCAL_LIB_DIR ${PROJECT_SOURCE_DIR}/../local-lib) - -set(ENV{PATH} "${PERL_LOCAL_LIB_DIR}/bin${ENV_PATH_SEPARATOR}$ENV{PATH}") -set(PERL_INCLUDE "${PERL_LOCAL_LIB_DIR}/lib/perl5${ENV_PATH_SEPARATOR}$ENV{PERL5LIB}") -message("PATH: $ENV{PATH}") -message("PERL_INCLUDE: ${PERL_INCLUDE}") -find_package(Perl REQUIRED) -if (WIN32) - # On Windows passing the PERL5LIB variable causes various problems (such as with MAX_PATH and others), - # basically I've found no good way to do it on Windows. - set(PERL5LIB_ENV_CMD "") -else() - set(PERL5LIB_ENV_CMD ${CMAKE_COMMAND} -E env PERL5LIB=${PERL_INCLUDE}) -endif() - -# Perl specific stuff -find_package(PerlLibs REQUIRED) -set(PerlEmbed_DEBUG 1) -find_package(PerlEmbed REQUIRED) - -# Generate the Slic3r Perl module (XS) typemap file. -set(MyTypemap ${CMAKE_CURRENT_BINARY_DIR}/typemap) -add_custom_command( - OUTPUT ${MyTypemap} - DEPENDS ${CMAKE_CURRENT_LIST_DIR}/xsp/my.map - COMMAND ${PERL5LIB_ENV_CMD} ${PERL_EXECUTABLE} -MExtUtils::Typemaps -MExtUtils::Typemaps::Basic -e "$typemap = ExtUtils::Typemaps->new(file => \"${CMAKE_CURRENT_LIST_DIR}/xsp/my.map\"); $typemap->merge(typemap => ExtUtils::Typemaps::Basic->new); $typemap->write(file => \"${MyTypemap}\")" - VERBATIM -) - -# Generate the Slic3r Perl module (XS) main.xs file. -set(XS_MAIN_XS ${CMAKE_CURRENT_BINARY_DIR}/main.xs) -set(XSP_DIR ${CMAKE_CURRENT_SOURCE_DIR}/xsp) -#FIXME list the dependecies explicitely, add dependency on the typemap. -set(XS_XSP_FILES - ${XSP_DIR}/Config.xsp - ${XSP_DIR}/ExPolygon.xsp - ${XSP_DIR}/Geometry.xsp - ${XSP_DIR}/Line.xsp - ${XSP_DIR}/Model.xsp - ${XSP_DIR}/Point.xsp - ${XSP_DIR}/Polygon.xsp - ${XSP_DIR}/Polyline.xsp - ${XSP_DIR}/Print.xsp - ${XSP_DIR}/TriangleMesh.xsp - ${XSP_DIR}/XS.xsp -) -foreach (file ${XS_XSP_FILES}) - if (MSVC) - # Visual Studio C compiler has issues with FILE pragmas containing quotes. - set(INCLUDE_COMMANDS "${INCLUDE_COMMANDS}INCLUDE_COMMAND: $^X -MExtUtils::XSpp::Cmd -e xspp -- -t ${CMAKE_CURRENT_LIST_DIR}/xsp/typemap.xspt ${file}\n") - else () - set(INCLUDE_COMMANDS "${INCLUDE_COMMANDS}INCLUDE_COMMAND: $^X -MExtUtils::XSpp::Cmd -e xspp -- -t \"${CMAKE_CURRENT_LIST_DIR}/xsp/typemap.xspt\" \"${file}\"\n") - endif () -endforeach () -configure_file(main.xs.in ${XS_MAIN_XS} @ONLY) # Insert INCLUDE_COMMANDS into main.xs - -# Generate the Slic3r Perl module (XS) XS.cpp file. -#FIXME add the dependency on main.xs and typemap. -set(XS_MAIN_CPP ${CMAKE_CURRENT_BINARY_DIR}/XS.cpp) -add_custom_command( - OUTPUT ${XS_MAIN_CPP} - DEPENDS ${MyTypemap} ${XS_XSP_FILES} ${CMAKE_CURRENT_LIST_DIR}/xsp/typemap.xspt - COMMAND ${PERL5LIB_ENV_CMD} xsubpp -typemap typemap -output ${XS_MAIN_CPP} -hiertype ${XS_MAIN_XS} - VERBATIM -) - -# Define the Perl XS shared library. -if(APPLE) - set(XS_SHARED_LIBRARY_TYPE MODULE) -else() - set(XS_SHARED_LIBRARY_TYPE SHARED) -endif() -add_library(XS ${XS_SHARED_LIBRARY_TYPE} - ${XS_MAIN_CPP} - src/perlglue.cpp - src/ppport.h - src/xsinit.h - xsp/my.map - # mytype.map is empty. Is it required by Build.PL or the Perl xspp module? - xsp/mytype.map - # Used by Perl xsubpp to generate XS.cpp - xsp/typemap.xspt -) -if(APPLE) - set_target_properties(XS PROPERTIES BUNDLE TRUE) - # Ignore undefined symbols of the perl interpreter, they will be found in the caller image. - target_link_libraries(XS "-undefined dynamic_lookup") -endif() -target_link_libraries(XS libslic3r) - -target_include_directories(XS PRIVATE src ${LIBDIR}/libslic3r) -target_compile_definitions(XS PRIVATE -DSLIC3RXS) -set_target_properties(XS PROPERTIES PREFIX "") # Prevent cmake from generating libXS.so instead of XS.so - -if (APPLE) - # -liconv: boost links to libiconv by default - target_link_libraries(XS "-liconv -framework IOKit" "-framework CoreFoundation" -lc++) -elseif (MSVC) - target_link_libraries(XS ) -else () - target_link_libraries(XS -lstdc++) -endif () - -# Windows specific stuff -if (WIN32) - target_compile_definitions(XS PRIVATE -DNOGDI -DNOMINMAX -DHAS_BOOL) -endif () - -# SLIC3R_MSVC_PDB -if (MSVC AND SLIC3R_MSVC_PDB AND "${CMAKE_BUILD_TYPE}" STREQUAL "Release") - set_target_properties(XS PROPERTIES - COMPILE_FLAGS "/Zi" - LINK_FLAGS "/DEBUG /OPT:REF /OPT:ICF" - ) -endif() - -if (CMAKE_BUILD_TYPE MATCHES DEBUG) - target_compile_definitions(XS PRIVATE -DSLIC3R_DEBUG -DDEBUG -D_DEBUG) -else () - target_compile_definitions(XS PRIVATE -DNDEBUG) -endif () - -target_include_directories(XS PRIVATE ${PERL_INCLUDE_PATH}) -target_compile_options(XS PRIVATE ${PerlEmbed_CCFLAGS}) - -if (WIN32) - target_link_libraries(XS ${PERL_LIBRARY}) -endif() - - -set(PERL_LOCAL_LIB_ARCH_DIR "${PERL_LOCAL_LIB_DIR}/lib/perl5/${PerlEmbed_ARCHNAME}") -add_custom_command( - TARGET XS - POST_BUILD - COMMAND ${CMAKE_COMMAND} -E make_directory "${PERL_LOCAL_LIB_ARCH_DIR}/auto/Slic3r/XS/" - COMMAND ${CMAKE_COMMAND} -E copy "$" "${PERL_LOCAL_LIB_ARCH_DIR}/auto/Slic3r/XS/" - COMMAND ${CMAKE_COMMAND} -E make_directory "${PERL_LOCAL_LIB_ARCH_DIR}/Slic3r/" - COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/lib/Slic3r/XS.pm" "${PERL_LOCAL_LIB_ARCH_DIR}/Slic3r/" - COMMENT "Installing XS.pm and XS.{so,dll,bundle} into the local-lib directory ..." -) -if(APPLE) - add_custom_command( - TARGET XS - POST_BUILD - COMMAND ${CMAKE_COMMAND} -E rename "${PERL_LOCAL_LIB_ARCH_DIR}/auto/Slic3r/XS/XS" "${PERL_LOCAL_LIB_ARCH_DIR}/auto/Slic3r/XS/XS.bundle" - ) -endif() - -if (MSVC) - # Here we associate some additional properties with the MSVC project to enable compilation and debugging out of the box. - get_filename_component(PROPS_PERL_BIN_PATH "${PERL_EXECUTABLE}" DIRECTORY) - string(REPLACE "/" "\\" PROPS_PERL_BIN_PATH "${PROPS_PERL_BIN_PATH}") - string(REPLACE "/" "\\" PROPS_PERL_EXECUTABLE "${PERL_EXECUTABLE}") - string(REPLACE "/" "\\" PROPS_CMAKE_SOURCE_DIR "${CMAKE_SOURCE_DIR}") - configure_file("../cmake/msvc/xs.wperl.props.in" "${CMAKE_BINARY_DIR}/xs.wperl.props" NEWLINE_STYLE CRLF) - set_target_properties(XS PROPERTIES VS_USER_PROPS "${CMAKE_BINARY_DIR}/xs.wperl.props") - - if ("${CMAKE_SIZEOF_VOID_P}" STREQUAL "8") - set(_bits 64) - elseif ("${CMAKE_SIZEOF_VOID_P}" STREQUAL "4") - set(_bits 32) - endif () - add_custom_command(TARGET XS POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy ${TOP_LEVEL_PROJECT_DIR}/deps/+GMP/gmp/lib/win${_bits}/libgmp-10.dll "${PERL_LOCAL_LIB_ARCH_DIR}/auto/Slic3r/XS/" - COMMENT "Installing gmp runtime into the local-lib directory ..." - VERBATIM) - - add_custom_command(TARGET XS POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy ${TOP_LEVEL_PROJECT_DIR}/deps/+MPFR/mpfr/lib/win${_bits}/libmpfr-4.dll "${PERL_LOCAL_LIB_ARCH_DIR}/auto/Slic3r/XS/" - COMMENT "Installing mpfr runtime into the local-lib directory ..." - VERBATIM) -endif() - -# Installation -install(TARGETS XS DESTINATION ${PERL_VENDORARCH}/auto/Slic3r/XS) -install(FILES lib/Slic3r/XS.pm DESTINATION ${PERL_VENDORLIB}/Slic3r) - -# Unit / integration tests -enable_testing() -get_filename_component(PERL_BIN_PATH "${PERL_EXECUTABLE}" DIRECTORY) -if (MSVC) - set(PERL_PROVE "${PERL_BIN_PATH}/prove.bat") -else () - set(PERL_PROVE "${PERL_BIN_PATH}/prove") -endif () - -set(PERL_ENV_VARS "") -if (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND NOT CMAKE_CROSSCOMPILING AND ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")) - if (SLIC3R_ASAN OR SLIC3R_UBSAN) - set(PERL_ENV_VARS env) - endif () - - if (SLIC3R_ASAN) - # Find the location of libasan.so for passing it into LD_PRELOAD. It works with GCC and Clang on Linux. - # On Centos 7 calling "gcc -print-file-name=libasan.so" returns path to "ld script" instead of path to shared library. - set(_asan_compiled_bin ${CMAKE_CURRENT_BINARY_DIR}/detect_libasan) - set(_asan_source_file ${_asan_compiled_bin}.c) - # Compile and link simple C application with enabled address sanitizer. - file(WRITE ${_asan_source_file} "int main(){}") - include(GetPrerequisites) - execute_process(COMMAND ${CMAKE_C_COMPILER} ${_asan_source_file} -fsanitize=address -lasan -o ${_asan_compiled_bin}) - # Extract from the compiled application absolute path of libasan. - get_prerequisites(${_asan_compiled_bin} _asan_shared_libraries_list 0 0 "" "") - list(FILTER _asan_shared_libraries_list INCLUDE REGEX libasan) - set(PERL_ENV_VARS ${PERL_ENV_VARS} "LD_PRELOAD=${_asan_shared_libraries_list}") - - # Suppressed memory leak reports that come from Perl. - set(PERL_LEAK_SUPPRESSION_FILE ${CMAKE_CURRENT_BINARY_DIR}/leak_suppression.txt) - file(WRITE ${PERL_LEAK_SUPPRESSION_FILE} - "leak:Perl_safesysmalloc\n" - "leak:Perl_safesyscalloc\n" - "leak:Perl_safesysrealloc\n" - "leak:__newlocale\n") - - # Suppress a few memory leak reports and disable informing about suppressions. - # Print reports about memory leaks but exit with zero exit code when any memory leaks is found to make unit tests pass. - set(PERL_ENV_VARS ${PERL_ENV_VARS} "LSAN_OPTIONS=suppressions=${PERL_LEAK_SUPPRESSION_FILE}:print_suppressions=0:exitcode=0") - endif () - - if (SLIC3R_UBSAN) - # Do not show full stacktrace for reports from UndefinedBehaviorSanitizer in Perl tests. - set(PERL_ENV_VARS ${PERL_ENV_VARS} "UBSAN_OPTIONS=print_stacktrace=0") - endif () -endif () - -add_test (NAME xs COMMAND ${PERL_ENV_VARS} "${PERL_EXECUTABLE}" ${PERL_PROVE} -I ${PERL_LOCAL_LIB_DIR}/lib/perl5 WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}) diff --git a/xs/lib/Slic3r/XS.pm b/xs/lib/Slic3r/XS.pm deleted file mode 100644 index 60c9a9316d..0000000000 --- a/xs/lib/Slic3r/XS.pm +++ /dev/null @@ -1,125 +0,0 @@ -package Slic3r::XS; -use warnings; -use strict; - -our $VERSION = '0.01'; - -use Carp qw(); -use XSLoader; -XSLoader::load(__PACKAGE__, $VERSION); - -package Slic3r::Line; -use overload - '@{}' => sub { $_[0]->arrayref }, - 'fallback' => 1; - -package Slic3r::Point; -use overload - '@{}' => sub { $_[0]->arrayref }, - 'fallback' => 1; - -package Slic3r::Pointf; -use overload - '@{}' => sub { $_[0]->arrayref }, - 'fallback' => 1; - -package Slic3r::Pointf3; -use overload - '@{}' => sub { [ $_[0]->x, $_[0]->y, $_[0]->z ] }, #, - 'fallback' => 1; - -sub pp { - my ($self) = @_; - return [ @$self ]; -} - -package Slic3r::ExPolygon; -use overload - '@{}' => sub { $_[0]->arrayref }, - 'fallback' => 1; - -package Slic3r::Polyline; -use overload - '@{}' => sub { $_[0]->arrayref }, - 'fallback' => 1; - -package Slic3r::Polygon; -use overload - '@{}' => sub { $_[0]->arrayref }, - 'fallback' => 1; - -package Slic3r::Surface; - -sub new { - my ($class, %args) = @_; - - # defensive programming: make sure no negative bridge_angle is supplied - die "Error: invalid negative bridge_angle\n" - if defined $args{bridge_angle} && $args{bridge_angle} < 0; - - return $class->_new( - $args{expolygon} // (die "Missing required expolygon\n"), - $args{surface_type} // (die "Missing required surface_type\n"), - $args{thickness} // -1, - $args{thickness_layers} // 1, - $args{bridge_angle} // -1, - $args{extra_perimeters} // 0, - ); -} - -sub clone { - my ($self, %args) = @_; - - return (ref $self)->_new( - delete $args{expolygon} // $self->expolygon, - delete $args{surface_type} // $self->surface_type, - delete $args{thickness} // $self->thickness, - delete $args{thickness_layers} // $self->thickness_layers, - delete $args{bridge_angle} // $self->bridge_angle, - delete $args{extra_perimeters} // $self->extra_perimeters, - ); -} - -package Slic3r::Surface::Collection; -use overload - '@{}' => sub { $_[0]->arrayref }, - 'fallback' => 1; - -sub new { - my ($class, @surfaces) = @_; - - my $self = $class->_new; - $self->append($_) for @surfaces; - return $self; -} - -package main; -for my $class (qw( - Slic3r::Config - Slic3r::Config::GCode - Slic3r::Config::Print - Slic3r::Config::Static - Slic3r::ExPolygon - Slic3r::Line - Slic3r::Model - Slic3r::Model::Instance - Slic3r::Model::Material - Slic3r::Model::Object - Slic3r::Model::Volume - Slic3r::Point - Slic3r::Point3 - Slic3r::Pointf - Slic3r::Pointf3 - Slic3r::Polygon - Slic3r::Polyline - Slic3r::Polyline::Collection - Slic3r::Print - Slic3r::TriangleMesh - )) -{ - no strict 'refs'; - my $ref_class = $class . "::Ref"; - eval "package $ref_class; our \@ISA = '$class'; sub DESTROY {};"; -} - -1; diff --git a/xs/main.xs.in b/xs/main.xs.in deleted file mode 100644 index d8db108be5..0000000000 --- a/xs/main.xs.in +++ /dev/null @@ -1,26 +0,0 @@ -#include -#include -#include -#include - -#ifdef __cplusplus -/* extern "C" { */ -#endif -#include "EXTERN.h" -#include "perl.h" -#include "XSUB.h" -#include "ppport.h" -#undef do_open -#undef do_close -#ifdef __cplusplus -/* } */ -#endif - -#ifdef _WIN32 - #undef XS_EXTERNAL - #define XS_EXTERNAL(name) __declspec(dllexport) XSPROTO(name) -#endif /* MSVC */ - -MODULE = Slic3r::XS PACKAGE = Slic3r::XS - -@INCLUDE_COMMANDS@ \ No newline at end of file diff --git a/xs/src/perlglue.cpp b/xs/src/perlglue.cpp deleted file mode 100644 index 500cbee836..0000000000 --- a/xs/src/perlglue.cpp +++ /dev/null @@ -1,527 +0,0 @@ -#ifdef SLIC3RXS -#include - -namespace Slic3r { - -REGISTER_CLASS(ExPolygon, "ExPolygon"); -REGISTER_CLASS(GCodeGenerator, "GCode"); -REGISTER_CLASS(Line, "Line"); -REGISTER_CLASS(Polygon, "Polygon"); -REGISTER_CLASS(Polyline, "Polyline"); -REGISTER_CLASS(Print, "Print"); -REGISTER_CLASS(PrintObject, "Print::Object"); -REGISTER_CLASS(PrintRegion, "Print::Region"); -REGISTER_CLASS(Model, "Model"); -REGISTER_CLASS(ModelMaterial, "Model::Material"); -REGISTER_CLASS(ModelObject, "Model::Object"); -REGISTER_CLASS(ModelVolume, "Model::Volume"); -REGISTER_CLASS(ModelInstance, "Model::Instance"); -REGISTER_CLASS(BoundingBox, "Geometry::BoundingBox"); -REGISTER_CLASS(Point, "Point"); -__REGISTER_CLASS(Vec2d, "Pointf"); -__REGISTER_CLASS(Vec3d, "Pointf3"); -REGISTER_CLASS(DynamicPrintConfig, "Config"); -REGISTER_CLASS(StaticPrintConfig, "Config::Static"); -REGISTER_CLASS(GCodeConfig, "Config::GCode"); -REGISTER_CLASS(PrintConfig, "Config::Print"); -REGISTER_CLASS(Surface, "Surface"); -REGISTER_CLASS(SurfaceCollection, "Surface::Collection"); -REGISTER_CLASS(FullPrintConfig, "Config::Full"); -REGISTER_CLASS(TriangleMesh, "TriangleMesh"); - -SV* ConfigBase__as_hash(ConfigBase* THIS) -{ - HV* hv = newHV(); - for (auto &key : THIS->keys()) - (void)hv_store(hv, key.c_str(), key.length(), ConfigBase__get(THIS, key), 0); - return newRV_noinc((SV*)hv); -} - -SV* ConfigBase__get(ConfigBase* THIS, const t_config_option_key &opt_key) -{ - ConfigOption *opt = THIS->option(opt_key, false); - return (opt == nullptr) ? - &PL_sv_undef : - ConfigOption_to_SV(*opt, *THIS->def()->get(opt_key)); -} - -SV* ConfigOption_to_SV(const ConfigOption &opt, const ConfigOptionDef &def) -{ - switch (def.type) { - case coFloat: - case coPercent: - return newSVnv(static_cast(&opt)->value); - case coFloats: - case coPercents: - { - auto optv = static_cast(&opt); - AV* av = newAV(); - av_fill(av, optv->values.size()-1); - for (const double &v : optv->values) - av_store(av, &v - optv->values.data(), newSVnv(v)); - return newRV_noinc((SV*)av); - } - case coInt: - return newSViv(static_cast(&opt)->value); - case coInts: - { - auto optv = static_cast(&opt); - AV* av = newAV(); - av_fill(av, optv->values.size()-1); - for (const int &v : optv->values) - av_store(av, &v - optv->values.data(), newSViv(v)); - return newRV_noinc((SV*)av); - } - case coString: - { - auto optv = static_cast(&opt); - // we don't serialize() because that would escape newlines - return newSVpvn_utf8(optv->value.c_str(), optv->value.length(), true); - } - case coStrings: - { - auto optv = static_cast(&opt); - AV* av = newAV(); - av_fill(av, optv->values.size()-1); - for (const std::string &v : optv->values) - av_store(av, &v - optv->values.data(), newSVpvn_utf8(v.c_str(), v.length(), true)); - return newRV_noinc((SV*)av); - } - case coPoint: - return perl_to_SV_clone_ref(static_cast(&opt)->value); - case coPoint3: - return perl_to_SV_clone_ref(static_cast(&opt)->value); - case coPoints: - { - auto optv = static_cast(&opt); - AV* av = newAV(); - av_fill(av, optv->values.size()-1); - for (const Vec2d &v : optv->values) - av_store(av, &v - optv->values.data(), perl_to_SV_clone_ref(v)); - return newRV_noinc((SV*)av); - } - case coBool: - return newSViv(static_cast(&opt)->value ? 1 : 0); - case coBools: - { - auto optv = static_cast(&opt); - AV* av = newAV(); - av_fill(av, optv->values.size()-1); - for (size_t i = 0; i < optv->values.size(); ++ i) - av_store(av, i, newSViv(optv->values[i] ? 1 : 0)); - return newRV_noinc((SV*)av); - } - default: - std::string serialized = opt.serialize(); - return newSVpvn_utf8(serialized.c_str(), serialized.length(), true); - } -} - -SV* ConfigBase__get_at(ConfigBase* THIS, const t_config_option_key &opt_key, size_t i) -{ - ConfigOption* opt = THIS->option(opt_key, false); - if (opt == nullptr) - return &PL_sv_undef; - - const ConfigOptionDef* def = THIS->def()->get(opt_key); - switch (def->type) { - case coFloats: - case coPercents: - return newSVnv(static_cast(opt)->get_at(i)); - case coInts: - return newSViv(static_cast(opt)->get_at(i)); - case coStrings: - { - // we don't serialize() because that would escape newlines - const std::string &val = static_cast(opt)->get_at(i); - return newSVpvn_utf8(val.c_str(), val.length(), true); - } - case coPoints: - return perl_to_SV_clone_ref(static_cast(opt)->get_at(i)); - case coBools: - return newSViv(static_cast(opt)->get_at(i) ? 1 : 0); - default: - return &PL_sv_undef; - } -} - -bool ConfigBase__set(ConfigBase* THIS, const t_config_option_key &opt_key, SV* value) -{ - ConfigOption* opt = THIS->option(opt_key, true); - if (opt == nullptr) - CONFESS("Trying to set non-existing option"); - const ConfigOptionDef* def = THIS->def()->get(opt_key); - if (opt->type() != def->type) - CONFESS("Option type is different from the definition"); - switch (def->type) { - case coFloat: - if (!looks_like_number(value)) - return false; - static_cast(opt)->value = SvNV(value); - break; - case coFloats: - { - std::vector &values = static_cast(opt)->values; - AV* av = (AV*)SvRV(value); - const size_t len = av_len(av)+1; - values.clear(); - values.reserve(len); - for (size_t i = 0; i < len; ++ i) { - SV** elem = av_fetch(av, i, 0); - if (elem == NULL || !looks_like_number(*elem)) return false; - values.emplace_back(SvNV(*elem)); - } - break; - } - case coPercents: - { - std::vector &values = static_cast(opt)->values; - AV* av = (AV*)SvRV(value); - const size_t len = av_len(av)+1; - values.clear(); - values.reserve(len); - for (size_t i = 0; i < len; i++) { - SV** elem = av_fetch(av, i, 0); - if (elem == NULL || !looks_like_number(*elem)) return false; - values.emplace_back(SvNV(*elem)); - } - break; - } - case coInt: - if (!looks_like_number(value)) return false; - static_cast(opt)->value = SvIV(value); - break; - case coInts: - { - std::vector &values = static_cast(opt)->values; - AV* av = (AV*)SvRV(value); - const size_t len = av_len(av)+1; - values.clear(); - values.reserve(len); - for (size_t i = 0; i < len; i++) { - SV** elem = av_fetch(av, i, 0); - if (elem == NULL || !looks_like_number(*elem)) return false; - values.emplace_back(SvIV(*elem)); - } - break; - } - case coString: - static_cast(opt)->value = std::string(SvPV_nolen(value), SvCUR(value)); - break; - case coStrings: - { - std::vector &values = static_cast(opt)->values; - AV* av = (AV*)SvRV(value); - const size_t len = av_len(av)+1; - values.clear(); - values.reserve(len); - for (size_t i = 0; i < len; i++) { - SV** elem = av_fetch(av, i, 0); - if (elem == NULL) return false; - values.emplace_back(std::string(SvPV_nolen(*elem), SvCUR(*elem))); - } - break; - } - case coPoint: - return from_SV_check(value, &static_cast(opt)->value); -// case coPoint3: - // not gonna fix it, die Perl die! -// return from_SV_check(value, &static_cast(opt)->value); - case coPoints: - { - std::vector &values = static_cast(opt)->values; - AV* av = (AV*)SvRV(value); - const size_t len = av_len(av)+1; - values.clear(); - values.reserve(len); - for (size_t i = 0; i < len; i++) { - SV** elem = av_fetch(av, i, 0); - Vec2d point(Vec2d::Zero()); - if (elem == NULL || !from_SV_check(*elem, &point)) return false; - values.emplace_back(point); - } - break; - } - case coBool: - static_cast(opt)->value = SvTRUE(value); - break; - case coBools: - { - std::vector &values = static_cast(opt)->values; - AV* av = (AV*)SvRV(value); - const size_t len = av_len(av)+1; - values.clear(); - values.reserve(len); - for (size_t i = 0; i < len; i++) { - SV** elem = av_fetch(av, i, 0); - if (elem == NULL) return false; - values.emplace_back(SvTRUE(*elem)); - } - break; - } - default: - if (! opt->deserialize(std::string(SvPV_nolen(value)), ForwardCompatibilitySubstitutionRule::Disable)) - return false; - } - return true; -} - -/* This method is implemented as a workaround for this typemap bug: - https://rt.cpan.org/Public/Bug/Display.html?id=94110 */ -bool ConfigBase__set_deserialize(ConfigBase* THIS, const t_config_option_key &opt_key, SV* str) -{ - size_t len; - const char * c = SvPV(str, len); - std::string value(c, len); - ConfigSubstitutionContext ctxt{ ForwardCompatibilitySubstitutionRule::Disable }; - return THIS->set_deserialize_nothrow(opt_key, value, ctxt); -} - -void ConfigBase__set_ifndef(ConfigBase* THIS, const t_config_option_key &opt_key, SV* value, bool deserialize) -{ - if (THIS->has(opt_key)) - return; - if (deserialize) - ConfigBase__set_deserialize(THIS, opt_key, value); - else - ConfigBase__set(THIS, opt_key, value); -} - -bool StaticConfig__set(StaticConfig* THIS, const t_config_option_key &opt_key, SV* value) -{ - const ConfigOptionDef* optdef = THIS->def()->get(opt_key); - if (optdef->shortcut.empty()) - return ConfigBase__set(THIS, opt_key, value); - for (const t_config_option_key &key : optdef->shortcut) - if (! StaticConfig__set(THIS, key, value)) - return false; - return true; -} - -SV* to_AV(ExPolygon* expolygon) -{ - const unsigned int num_holes = expolygon->holes.size(); - AV* av = newAV(); - av_extend(av, num_holes); // -1 +1 - - av_store(av, 0, perl_to_SV_ref(expolygon->contour)); - - for (unsigned int i = 0; i < num_holes; i++) { - av_store(av, i+1, perl_to_SV_ref(expolygon->holes[i])); - } - return newRV_noinc((SV*)av); -} - -SV* to_SV_pureperl(const ExPolygon* expolygon) -{ - const unsigned int num_holes = expolygon->holes.size(); - AV* av = newAV(); - av_extend(av, num_holes); // -1 +1 - av_store(av, 0, to_SV_pureperl(&expolygon->contour)); - for (unsigned int i = 0; i < num_holes; i++) { - av_store(av, i+1, to_SV_pureperl(&expolygon->holes[i])); - } - return newRV_noinc((SV*)av); -} - -void from_SV(SV* expoly_sv, ExPolygon* expolygon) -{ - AV* expoly_av = (AV*)SvRV(expoly_sv); - const unsigned int num_polygons = av_len(expoly_av)+1; - expolygon->holes.resize(num_polygons-1); - - SV** polygon_sv = av_fetch(expoly_av, 0, 0); - from_SV(*polygon_sv, &expolygon->contour); - for (unsigned int i = 0; i < num_polygons-1; i++) { - polygon_sv = av_fetch(expoly_av, i+1, 0); - from_SV(*polygon_sv, &expolygon->holes[i]); - } -} - -void from_SV_check(SV* expoly_sv, ExPolygon* expolygon) -{ - if (sv_isobject(expoly_sv) && (SvTYPE(SvRV(expoly_sv)) == SVt_PVMG)) { - if (!sv_isa(expoly_sv, perl_class_name(expolygon)) && !sv_isa(expoly_sv, perl_class_name_ref(expolygon))) - CONFESS("Not a valid %s object", perl_class_name(expolygon)); - // a XS ExPolygon was supplied - *expolygon = *(ExPolygon *)SvIV((SV*)SvRV( expoly_sv )); - } else { - // a Perl arrayref was supplied - from_SV(expoly_sv, expolygon); - } -} - -void from_SV(SV* line_sv, Line* THIS) -{ - AV* line_av = (AV*)SvRV(line_sv); - from_SV_check(*av_fetch(line_av, 0, 0), &THIS->a); - from_SV_check(*av_fetch(line_av, 1, 0), &THIS->b); -} - -void from_SV_check(SV* line_sv, Line* THIS) -{ - if (sv_isobject(line_sv) && (SvTYPE(SvRV(line_sv)) == SVt_PVMG)) { - if (!sv_isa(line_sv, perl_class_name(THIS)) && !sv_isa(line_sv, perl_class_name_ref(THIS))) - CONFESS("Not a valid %s object", perl_class_name(THIS)); - *THIS = *(Line*)SvIV((SV*)SvRV( line_sv )); - } else { - from_SV(line_sv, THIS); - } -} - -SV* to_AV(Line* THIS) -{ - AV* av = newAV(); - av_extend(av, 1); - - av_store(av, 0, perl_to_SV_ref(THIS->a)); - av_store(av, 1, perl_to_SV_ref(THIS->b)); - - return newRV_noinc((SV*)av); -} - -SV* to_SV_pureperl(const Line* THIS) -{ - AV* av = newAV(); - av_extend(av, 1); - av_store(av, 0, to_SV_pureperl(&THIS->a)); - av_store(av, 1, to_SV_pureperl(&THIS->b)); - return newRV_noinc((SV*)av); -} - -void from_SV(SV* poly_sv, MultiPoint* THIS) -{ - AV* poly_av = (AV*)SvRV(poly_sv); - const unsigned int num_points = av_len(poly_av)+1; - THIS->points.resize(num_points); - - for (unsigned int i = 0; i < num_points; i++) { - SV** point_sv = av_fetch(poly_av, i, 0); - from_SV_check(*point_sv, &THIS->points[i]); - } -} - -void from_SV_check(SV* poly_sv, MultiPoint* THIS) -{ - if (sv_isobject(poly_sv) && (SvTYPE(SvRV(poly_sv)) == SVt_PVMG)) { - *THIS = *(MultiPoint*)SvIV((SV*)SvRV( poly_sv )); - } else { - from_SV(poly_sv, THIS); - } -} - -SV* to_AV(MultiPoint* THIS) -{ - const unsigned int num_points = THIS->points.size(); - AV* av = newAV(); - if (num_points > 0) av_extend(av, num_points-1); - for (unsigned int i = 0; i < num_points; i++) { - av_store(av, i, perl_to_SV_ref(THIS->points[i])); - } - return newRV_noinc((SV*)av); -} - -SV* to_SV_pureperl(const MultiPoint* THIS) -{ - const unsigned int num_points = THIS->points.size(); - AV* av = newAV(); - if (num_points > 0) av_extend(av, num_points-1); - for (unsigned int i = 0; i < num_points; i++) { - av_store(av, i, to_SV_pureperl(&THIS->points[i])); - } - return newRV_noinc((SV*)av); -} - -void from_SV_check(SV* poly_sv, Polygon* THIS) -{ - if (sv_isobject(poly_sv) && !sv_isa(poly_sv, perl_class_name(THIS)) && !sv_isa(poly_sv, perl_class_name_ref(THIS))) - CONFESS("Not a valid %s object", perl_class_name(THIS)); - - from_SV_check(poly_sv, (MultiPoint*)THIS); -} - -void from_SV_check(SV* poly_sv, Polyline* THIS) -{ - if (!sv_isa(poly_sv, perl_class_name(THIS)) && !sv_isa(poly_sv, perl_class_name_ref(THIS))) - CONFESS("Not a valid %s object", perl_class_name(THIS)); - - from_SV_check(poly_sv, (MultiPoint*)THIS); -} - -SV* to_SV_pureperl(const Point* THIS) -{ - AV* av = newAV(); - av_fill(av, 1); - av_store(av, 0, newSViv((*THIS)(0))); - av_store(av, 1, newSViv((*THIS)(1))); - return newRV_noinc((SV*)av); -} - -void from_SV(SV* point_sv, Point* point) -{ - AV* point_av = (AV*)SvRV(point_sv); - // get a double from Perl and round it, otherwise - // it would get truncated - (*point) = Point(SvNV(*av_fetch(point_av, 0, 0)), SvNV(*av_fetch(point_av, 1, 0))); -} - -void from_SV_check(SV* point_sv, Point* point) -{ - if (sv_isobject(point_sv) && (SvTYPE(SvRV(point_sv)) == SVt_PVMG)) { - if (!sv_isa(point_sv, perl_class_name(point)) && !sv_isa(point_sv, perl_class_name_ref(point))) - CONFESS("Not a valid %s object (got %s)", perl_class_name(point), HvNAME(SvSTASH(SvRV(point_sv)))); - *point = *(Point*)SvIV((SV*)SvRV( point_sv )); - } else { - from_SV(point_sv, point); - } -} - -SV* to_SV_pureperl(const Vec2d* point) -{ - AV* av = newAV(); - av_fill(av, 1); - av_store(av, 0, newSVnv((*point)(0))); - av_store(av, 1, newSVnv((*point)(1))); - return newRV_noinc((SV*)av); -} - -bool from_SV(SV* point_sv, Vec2d* point) -{ - AV* point_av = (AV*)SvRV(point_sv); - SV* sv_x = *av_fetch(point_av, 0, 0); - SV* sv_y = *av_fetch(point_av, 1, 0); - if (!looks_like_number(sv_x) || !looks_like_number(sv_y)) return false; - - *point = Vec2d(SvNV(sv_x), SvNV(sv_y)); - return true; -} - -bool from_SV_check(SV* point_sv, Vec2d* point) -{ - if (sv_isobject(point_sv) && (SvTYPE(SvRV(point_sv)) == SVt_PVMG)) { - if (!sv_isa(point_sv, perl_class_name(point)) && !sv_isa(point_sv, perl_class_name_ref(point))) - CONFESS("Not a valid %s object (got %s)", perl_class_name(point), HvNAME(SvSTASH(SvRV(point_sv)))); - *point = *(Vec2d*)SvIV((SV*)SvRV( point_sv )); - return true; - } else { - return from_SV(point_sv, point); - } -} - -void from_SV_check(SV* surface_sv, Surface* THIS) -{ - if (!sv_isa(surface_sv, perl_class_name(THIS)) && !sv_isa(surface_sv, perl_class_name_ref(THIS))) - CONFESS("Not a valid %s object", perl_class_name(THIS)); - // a XS Surface was supplied - *THIS = *(Surface *)SvIV((SV*)SvRV( surface_sv )); -} - -SV* to_SV(TriangleMesh* THIS) -{ - SV* sv = newSV(0); - sv_setref_pv( sv, perl_class_name(THIS), (void*)THIS ); - return sv; -} - -} -#endif diff --git a/xs/src/ppport.h b/xs/src/ppport.h deleted file mode 100644 index ec2f1cc36c..0000000000 --- a/xs/src/ppport.h +++ /dev/null @@ -1,7063 +0,0 @@ -#if 0 -<<'SKIP'; -#endif -/* ----------------------------------------------------------------------- - - ppport.h -- Perl/Pollution/Portability Version 3.19 - - Automatically created by Devel::PPPort running under perl 5.010000. - - Do NOT edit this file directly! -- Edit PPPort_pm.PL and the - includes in parts/inc/ instead. - - Use 'perldoc ppport.h' to view the documentation below. - ----------------------------------------------------------------------- - -SKIP - -=pod - -=head1 NAME - -ppport.h - Perl/Pollution/Portability version 3.19 - -=head1 SYNOPSIS - - perl ppport.h [options] [source files] - - Searches current directory for files if no [source files] are given - - --help show short help - - --version show version - - --patch=file write one patch file with changes - --copy=suffix write changed copies with suffix - --diff=program use diff program and options - - --compat-version=version provide compatibility with Perl version - --cplusplus accept C++ comments - - --quiet don't output anything except fatal errors - --nodiag don't show diagnostics - --nohints don't show hints - --nochanges don't suggest changes - --nofilter don't filter input files - - --strip strip all script and doc functionality from - ppport.h - - --list-provided list provided API - --list-unsupported list unsupported API - --api-info=name show Perl API portability information - -=head1 COMPATIBILITY - -This version of F is designed to support operation with Perl -installations back to 5.003, and has been tested up to 5.10.0. - -=head1 OPTIONS - -=head2 --help - -Display a brief usage summary. - -=head2 --version - -Display the version of F. - -=head2 --patch=I - -If this option is given, a single patch file will be created if -any changes are suggested. This requires a working diff program -to be installed on your system. - -=head2 --copy=I - -If this option is given, a copy of each file will be saved with -the given suffix that contains the suggested changes. This does -not require any external programs. Note that this does not -automagially add a dot between the original filename and the -suffix. If you want the dot, you have to include it in the option -argument. - -If neither C<--patch> or C<--copy> are given, the default is to -simply print the diffs for each file. This requires either -C or a C program to be installed. - -=head2 --diff=I - -Manually set the diff program and options to use. The default -is to use C, when installed, and output unified -context diffs. - -=head2 --compat-version=I - -Tell F to check for compatibility with the given -Perl version. The default is to check for compatibility with Perl -version 5.003. You can use this option to reduce the output -of F if you intend to be backward compatible only -down to a certain Perl version. - -=head2 --cplusplus - -Usually, F will detect C++ style comments and -replace them with C style comments for portability reasons. -Using this option instructs F to leave C++ -comments untouched. - -=head2 --quiet - -Be quiet. Don't print anything except fatal errors. - -=head2 --nodiag - -Don't output any diagnostic messages. Only portability -alerts will be printed. - -=head2 --nohints - -Don't output any hints. Hints often contain useful portability -notes. Warnings will still be displayed. - -=head2 --nochanges - -Don't suggest any changes. Only give diagnostic output and hints -unless these are also deactivated. - -=head2 --nofilter - -Don't filter the list of input files. By default, files not looking -like source code (i.e. not *.xs, *.c, *.cc, *.cpp or *.h) are skipped. - -=head2 --strip - -Strip all script and documentation functionality from F. -This reduces the size of F dramatically and may be useful -if you want to include F in smaller modules without -increasing their distribution size too much. - -The stripped F will have a C<--unstrip> option that allows -you to undo the stripping, but only if an appropriate C -module is installed. - -=head2 --list-provided - -Lists the API elements for which compatibility is provided by -F. Also lists if it must be explicitly requested, -if it has dependencies, and if there are hints or warnings for it. - -=head2 --list-unsupported - -Lists the API elements that are known not to be supported by -F and below which version of Perl they probably -won't be available or work. - -=head2 --api-info=I - -Show portability information for API elements matching I. -If I is surrounded by slashes, it is interpreted as a regular -expression. - -=head1 DESCRIPTION - -In order for a Perl extension (XS) module to be as portable as possible -across differing versions of Perl itself, certain steps need to be taken. - -=over 4 - -=item * - -Including this header is the first major one. This alone will give you -access to a large part of the Perl API that hasn't been available in -earlier Perl releases. Use - - perl ppport.h --list-provided - -to see which API elements are provided by ppport.h. - -=item * - -You should avoid using deprecated parts of the API. For example, using -global Perl variables without the C prefix is deprecated. Also, -some API functions used to have a C prefix. Using this form is -also deprecated. You can safely use the supported API, as F -will provide wrappers for older Perl versions. - -=item * - -If you use one of a few functions or variables that were not present in -earlier versions of Perl, and that can't be provided using a macro, you -have to explicitly request support for these functions by adding one or -more C<#define>s in your source code before the inclusion of F. - -These functions or variables will be marked C in the list shown -by C<--list-provided>. - -Depending on whether you module has a single or multiple files that -use such functions or variables, you want either C or global -variants. - -For a C function or variable (used only in a single source -file), use: - - #define NEED_function - #define NEED_variable - -For a global function or variable (used in multiple source files), -use: - - #define NEED_function_GLOBAL - #define NEED_variable_GLOBAL - -Note that you mustn't have more than one global request for the -same function or variable in your project. - - Function / Variable Static Request Global Request - ----------------------------------------------------------------------------------------- - PL_parser NEED_PL_parser NEED_PL_parser_GLOBAL - PL_signals NEED_PL_signals NEED_PL_signals_GLOBAL - eval_pv() NEED_eval_pv NEED_eval_pv_GLOBAL - grok_bin() NEED_grok_bin NEED_grok_bin_GLOBAL - grok_hex() NEED_grok_hex NEED_grok_hex_GLOBAL - grok_number() NEED_grok_number NEED_grok_number_GLOBAL - grok_numeric_radix() NEED_grok_numeric_radix NEED_grok_numeric_radix_GLOBAL - grok_oct() NEED_grok_oct NEED_grok_oct_GLOBAL - load_module() NEED_load_module NEED_load_module_GLOBAL - my_snprintf() NEED_my_snprintf NEED_my_snprintf_GLOBAL - my_sprintf() NEED_my_sprintf NEED_my_sprintf_GLOBAL - my_strlcat() NEED_my_strlcat NEED_my_strlcat_GLOBAL - my_strlcpy() NEED_my_strlcpy NEED_my_strlcpy_GLOBAL - newCONSTSUB() NEED_newCONSTSUB NEED_newCONSTSUB_GLOBAL - newRV_noinc() NEED_newRV_noinc NEED_newRV_noinc_GLOBAL - newSV_type() NEED_newSV_type NEED_newSV_type_GLOBAL - newSVpvn_flags() NEED_newSVpvn_flags NEED_newSVpvn_flags_GLOBAL - newSVpvn_share() NEED_newSVpvn_share NEED_newSVpvn_share_GLOBAL - pv_display() NEED_pv_display NEED_pv_display_GLOBAL - pv_escape() NEED_pv_escape NEED_pv_escape_GLOBAL - pv_pretty() NEED_pv_pretty NEED_pv_pretty_GLOBAL - sv_2pv_flags() NEED_sv_2pv_flags NEED_sv_2pv_flags_GLOBAL - sv_2pvbyte() NEED_sv_2pvbyte NEED_sv_2pvbyte_GLOBAL - sv_catpvf_mg() NEED_sv_catpvf_mg NEED_sv_catpvf_mg_GLOBAL - sv_catpvf_mg_nocontext() NEED_sv_catpvf_mg_nocontext NEED_sv_catpvf_mg_nocontext_GLOBAL - sv_pvn_force_flags() NEED_sv_pvn_force_flags NEED_sv_pvn_force_flags_GLOBAL - sv_setpvf_mg() NEED_sv_setpvf_mg NEED_sv_setpvf_mg_GLOBAL - sv_setpvf_mg_nocontext() NEED_sv_setpvf_mg_nocontext NEED_sv_setpvf_mg_nocontext_GLOBAL - vload_module() NEED_vload_module NEED_vload_module_GLOBAL - vnewSVpvf() NEED_vnewSVpvf NEED_vnewSVpvf_GLOBAL - warner() NEED_warner NEED_warner_GLOBAL - -To avoid namespace conflicts, you can change the namespace of the -explicitly exported functions / variables using the C -macro. Just C<#define> the macro before including C: - - #define DPPP_NAMESPACE MyOwnNamespace_ - #include "ppport.h" - -The default namespace is C. - -=back - -The good thing is that most of the above can be checked by running -F on your source code. See the next section for -details. - -=head1 EXAMPLES - -To verify whether F is needed for your module, whether you -should make any changes to your code, and whether any special defines -should be used, F can be run as a Perl script to check your -source code. Simply say: - - perl ppport.h - -The result will usually be a list of patches suggesting changes -that should at least be acceptable, if not necessarily the most -efficient solution, or a fix for all possible problems. - -If you know that your XS module uses features only available in -newer Perl releases, if you're aware that it uses C++ comments, -and if you want all suggestions as a single patch file, you could -use something like this: - - perl ppport.h --compat-version=5.6.0 --cplusplus --patch=test.diff - -If you only want your code to be scanned without any suggestions -for changes, use: - - perl ppport.h --nochanges - -You can specify a different C program or options, using -the C<--diff> option: - - perl ppport.h --diff='diff -C 10' - -This would output context diffs with 10 lines of context. - -If you want to create patched copies of your files instead, use: - - perl ppport.h --copy=.new - -To display portability information for the C function, -use: - - perl ppport.h --api-info=newSVpvn - -Since the argument to C<--api-info> can be a regular expression, -you can use - - perl ppport.h --api-info=/_nomg$/ - -to display portability information for all C<_nomg> functions or - - perl ppport.h --api-info=/./ - -to display information for all known API elements. - -=head1 BUGS - -If this version of F is causing failure during -the compilation of this module, please check if newer versions -of either this module or C are available on CPAN -before sending a bug report. - -If F was generated using the latest version of -C and is causing failure of this module, please -file a bug report using the CPAN Request Tracker at L. - -Please include the following information: - -=over 4 - -=item 1. - -The complete output from running "perl -V" - -=item 2. - -This file. - -=item 3. - -The name and version of the module you were trying to build. - -=item 4. - -A full log of the build that failed. - -=item 5. - -Any other information that you think could be relevant. - -=back - -For the latest version of this code, please get the C -module from CPAN. - -=head1 COPYRIGHT - -Version 3.x, Copyright (c) 2004-2009, Marcus Holland-Moritz. - -Version 2.x, Copyright (C) 2001, Paul Marquess. - -Version 1.x, Copyright (C) 1999, Kenneth Albanowski. - -This program is free software; you can redistribute it and/or -modify it under the same terms as Perl itself. - -=head1 SEE ALSO - -See L. - -=cut - -use strict; - -# Disable broken TRIE-optimization -BEGIN { eval '${^RE_TRIE_MAXBUF} = -1' if $] >= 5.009004 && $] <= 5.009005 } - -my $VERSION = 3.19; - -my %opt = ( - quiet => 0, - diag => 1, - hints => 1, - changes => 1, - cplusplus => 0, - filter => 1, - strip => 0, - version => 0, -); - -my($ppport) = $0 =~ /([\w.]+)$/; -my $LF = '(?:\r\n|[\r\n])'; # line feed -my $HS = "[ \t]"; # horizontal whitespace - -# Never use C comments in this file! -my $ccs = '/'.'*'; -my $cce = '*'.'/'; -my $rccs = quotemeta $ccs; -my $rcce = quotemeta $cce; - -eval { - require Getopt::Long; - Getopt::Long::GetOptions(\%opt, qw( - help quiet diag! filter! hints! changes! cplusplus strip version - patch=s copy=s diff=s compat-version=s - list-provided list-unsupported api-info=s - )) or usage(); -}; - -if ($@ and grep /^-/, @ARGV) { - usage() if "@ARGV" =~ /^--?h(?:elp)?$/; - die "Getopt::Long not found. Please don't use any options.\n"; -} - -if ($opt{version}) { - print "This is $0 $VERSION.\n"; - exit 0; -} - -usage() if $opt{help}; -strip() if $opt{strip}; - -if (exists $opt{'compat-version'}) { - my($r,$v,$s) = eval { parse_version($opt{'compat-version'}) }; - if ($@) { - die "Invalid version number format: '$opt{'compat-version'}'\n"; - } - die "Only Perl 5 is supported\n" if $r != 5; - die "Invalid version number: $opt{'compat-version'}\n" if $v >= 1000 || $s >= 1000; - $opt{'compat-version'} = sprintf "%d.%03d%03d", $r, $v, $s; -} -else { - $opt{'compat-version'} = 5; -} - -my %API = map { /^(\w+)\|([^|]*)\|([^|]*)\|(\w*)$/ - ? ( $1 => { - ($2 ? ( base => $2 ) : ()), - ($3 ? ( todo => $3 ) : ()), - (index($4, 'v') >= 0 ? ( varargs => 1 ) : ()), - (index($4, 'p') >= 0 ? ( provided => 1 ) : ()), - (index($4, 'n') >= 0 ? ( nothxarg => 1 ) : ()), - } ) - : die "invalid spec: $_" } qw( -AvFILLp|5.004050||p -AvFILL||| -CLASS|||n -CPERLscope|5.005000||p -CX_CURPAD_SAVE||| -CX_CURPAD_SV||| -CopFILEAV|5.006000||p -CopFILEGV_set|5.006000||p -CopFILEGV|5.006000||p -CopFILESV|5.006000||p -CopFILE_set|5.006000||p -CopFILE|5.006000||p -CopSTASHPV_set|5.006000||p -CopSTASHPV|5.006000||p -CopSTASH_eq|5.006000||p -CopSTASH_set|5.006000||p -CopSTASH|5.006000||p -CopyD|5.009002||p -Copy||| -CvPADLIST||| -CvSTASH||| -CvWEAKOUTSIDE||| -DEFSV_set|5.011000||p -DEFSV|5.004050||p -END_EXTERN_C|5.005000||p -ENTER||| -ERRSV|5.004050||p -EXTEND||| -EXTERN_C|5.005000||p -F0convert|||n -FREETMPS||| -GIMME_V||5.004000|n -GIMME|||n -GROK_NUMERIC_RADIX|5.007002||p -G_ARRAY||| -G_DISCARD||| -G_EVAL||| -G_METHOD|5.006001||p -G_NOARGS||| -G_SCALAR||| -G_VOID||5.004000| -GetVars||| -GvSVn|5.009003||p -GvSV||| -Gv_AMupdate||| -HEf_SVKEY||5.004000| -HeHASH||5.004000| -HeKEY||5.004000| -HeKLEN||5.004000| -HePV||5.004000| -HeSVKEY_force||5.004000| -HeSVKEY_set||5.004000| -HeSVKEY||5.004000| -HeUTF8||5.011000| -HeVAL||5.004000| -HvNAMELEN_get|5.009003||p -HvNAME_get|5.009003||p -HvNAME||| -INT2PTR|5.006000||p -IN_LOCALE_COMPILETIME|5.007002||p -IN_LOCALE_RUNTIME|5.007002||p -IN_LOCALE|5.007002||p -IN_PERL_COMPILETIME|5.008001||p -IS_NUMBER_GREATER_THAN_UV_MAX|5.007002||p -IS_NUMBER_INFINITY|5.007002||p -IS_NUMBER_IN_UV|5.007002||p -IS_NUMBER_NAN|5.007003||p -IS_NUMBER_NEG|5.007002||p -IS_NUMBER_NOT_INT|5.007002||p -IVSIZE|5.006000||p -IVTYPE|5.006000||p -IVdf|5.006000||p -LEAVE||| -LVRET||| -MARK||| -MULTICALL||5.011000| -MY_CXT_CLONE|5.009002||p -MY_CXT_INIT|5.007003||p -MY_CXT|5.007003||p -MoveD|5.009002||p -Move||| -NOOP|5.005000||p -NUM2PTR|5.006000||p -NVTYPE|5.006000||p -NVef|5.006001||p -NVff|5.006001||p -NVgf|5.006001||p -Newxc|5.009003||p -Newxz|5.009003||p -Newx|5.009003||p -Nullav||| -Nullch||| -Nullcv||| -Nullhv||| -Nullsv||| -ORIGMARK||| -PAD_BASE_SV||| -PAD_CLONE_VARS||| -PAD_COMPNAME_FLAGS||| -PAD_COMPNAME_GEN_set||| -PAD_COMPNAME_GEN||| -PAD_COMPNAME_OURSTASH||| -PAD_COMPNAME_PV||| -PAD_COMPNAME_TYPE||| -PAD_DUP||| -PAD_RESTORE_LOCAL||| -PAD_SAVE_LOCAL||| -PAD_SAVE_SETNULLPAD||| -PAD_SETSV||| -PAD_SET_CUR_NOSAVE||| -PAD_SET_CUR||| -PAD_SVl||| -PAD_SV||| -PERLIO_FUNCS_CAST|5.009003||p -PERLIO_FUNCS_DECL|5.009003||p -PERL_ABS|5.008001||p -PERL_BCDVERSION|5.011000||p -PERL_GCC_BRACE_GROUPS_FORBIDDEN|5.008001||p -PERL_HASH|5.004000||p -PERL_INT_MAX|5.004000||p -PERL_INT_MIN|5.004000||p -PERL_LONG_MAX|5.004000||p -PERL_LONG_MIN|5.004000||p -PERL_MAGIC_arylen|5.007002||p -PERL_MAGIC_backref|5.007002||p -PERL_MAGIC_bm|5.007002||p -PERL_MAGIC_collxfrm|5.007002||p -PERL_MAGIC_dbfile|5.007002||p -PERL_MAGIC_dbline|5.007002||p -PERL_MAGIC_defelem|5.007002||p -PERL_MAGIC_envelem|5.007002||p -PERL_MAGIC_env|5.007002||p -PERL_MAGIC_ext|5.007002||p -PERL_MAGIC_fm|5.007002||p -PERL_MAGIC_glob|5.011000||p -PERL_MAGIC_isaelem|5.007002||p -PERL_MAGIC_isa|5.007002||p -PERL_MAGIC_mutex|5.011000||p -PERL_MAGIC_nkeys|5.007002||p -PERL_MAGIC_overload_elem|5.007002||p -PERL_MAGIC_overload_table|5.007002||p -PERL_MAGIC_overload|5.007002||p -PERL_MAGIC_pos|5.007002||p -PERL_MAGIC_qr|5.007002||p -PERL_MAGIC_regdata|5.007002||p -PERL_MAGIC_regdatum|5.007002||p -PERL_MAGIC_regex_global|5.007002||p -PERL_MAGIC_shared_scalar|5.007003||p -PERL_MAGIC_shared|5.007003||p -PERL_MAGIC_sigelem|5.007002||p -PERL_MAGIC_sig|5.007002||p -PERL_MAGIC_substr|5.007002||p -PERL_MAGIC_sv|5.007002||p -PERL_MAGIC_taint|5.007002||p -PERL_MAGIC_tiedelem|5.007002||p -PERL_MAGIC_tiedscalar|5.007002||p -PERL_MAGIC_tied|5.007002||p -PERL_MAGIC_utf8|5.008001||p -PERL_MAGIC_uvar_elem|5.007003||p -PERL_MAGIC_uvar|5.007002||p -PERL_MAGIC_vec|5.007002||p -PERL_MAGIC_vstring|5.008001||p -PERL_PV_ESCAPE_ALL|5.009004||p -PERL_PV_ESCAPE_FIRSTCHAR|5.009004||p -PERL_PV_ESCAPE_NOBACKSLASH|5.009004||p -PERL_PV_ESCAPE_NOCLEAR|5.009004||p -PERL_PV_ESCAPE_QUOTE|5.009004||p -PERL_PV_ESCAPE_RE|5.009005||p -PERL_PV_ESCAPE_UNI_DETECT|5.009004||p -PERL_PV_ESCAPE_UNI|5.009004||p -PERL_PV_PRETTY_DUMP|5.009004||p -PERL_PV_PRETTY_ELLIPSES|5.010000||p -PERL_PV_PRETTY_LTGT|5.009004||p -PERL_PV_PRETTY_NOCLEAR|5.010000||p -PERL_PV_PRETTY_QUOTE|5.009004||p -PERL_PV_PRETTY_REGPROP|5.009004||p -PERL_QUAD_MAX|5.004000||p -PERL_QUAD_MIN|5.004000||p -PERL_REVISION|5.006000||p -PERL_SCAN_ALLOW_UNDERSCORES|5.007003||p -PERL_SCAN_DISALLOW_PREFIX|5.007003||p -PERL_SCAN_GREATER_THAN_UV_MAX|5.007003||p -PERL_SCAN_SILENT_ILLDIGIT|5.008001||p -PERL_SHORT_MAX|5.004000||p -PERL_SHORT_MIN|5.004000||p -PERL_SIGNALS_UNSAFE_FLAG|5.008001||p -PERL_SUBVERSION|5.006000||p -PERL_SYS_INIT3||5.006000| -PERL_SYS_INIT||| -PERL_SYS_TERM||5.011000| -PERL_UCHAR_MAX|5.004000||p -PERL_UCHAR_MIN|5.004000||p -PERL_UINT_MAX|5.004000||p -PERL_UINT_MIN|5.004000||p -PERL_ULONG_MAX|5.004000||p -PERL_ULONG_MIN|5.004000||p -PERL_UNUSED_ARG|5.009003||p -PERL_UNUSED_CONTEXT|5.009004||p -PERL_UNUSED_DECL|5.007002||p -PERL_UNUSED_VAR|5.007002||p -PERL_UQUAD_MAX|5.004000||p -PERL_UQUAD_MIN|5.004000||p -PERL_USE_GCC_BRACE_GROUPS|5.009004||p -PERL_USHORT_MAX|5.004000||p -PERL_USHORT_MIN|5.004000||p -PERL_VERSION|5.006000||p -PL_DBsignal|5.005000||p -PL_DBsingle|||pn -PL_DBsub|||pn -PL_DBtrace|||pn -PL_Sv|5.005000||p -PL_bufend|5.011000||p -PL_bufptr|5.011000||p -PL_compiling|5.004050||p -PL_copline|5.011000||p -PL_curcop|5.004050||p -PL_curstash|5.004050||p -PL_debstash|5.004050||p -PL_defgv|5.004050||p -PL_diehook|5.004050||p -PL_dirty|5.004050||p -PL_dowarn|||pn -PL_errgv|5.004050||p -PL_error_count|5.011000||p -PL_expect|5.011000||p -PL_hexdigit|5.005000||p -PL_hints|5.005000||p -PL_in_my_stash|5.011000||p -PL_in_my|5.011000||p -PL_last_in_gv|||n -PL_laststatval|5.005000||p -PL_lex_state|5.011000||p -PL_lex_stuff|5.011000||p -PL_linestr|5.011000||p -PL_modglobal||5.005000|n -PL_na|5.004050||pn -PL_no_modify|5.006000||p -PL_ofsgv|||n -PL_parser|5.009005||p -PL_perl_destruct_level|5.004050||p -PL_perldb|5.004050||p -PL_ppaddr|5.006000||p -PL_rsfp_filters|5.004050||p -PL_rsfp|5.004050||p -PL_rs|||n -PL_signals|5.008001||p -PL_stack_base|5.004050||p -PL_stack_sp|5.004050||p -PL_statcache|5.005000||p -PL_stdingv|5.004050||p -PL_sv_arenaroot|5.004050||p -PL_sv_no|5.004050||pn -PL_sv_undef|5.004050||pn -PL_sv_yes|5.004050||pn -PL_tainted|5.004050||p -PL_tainting|5.004050||p -PL_tokenbuf|5.011000||p -POP_MULTICALL||5.011000| -POPi|||n -POPl|||n -POPn|||n -POPpbytex||5.007001|n -POPpx||5.005030|n -POPp|||n -POPs|||n -PTR2IV|5.006000||p -PTR2NV|5.006000||p -PTR2UV|5.006000||p -PTR2nat|5.009003||p -PTR2ul|5.007001||p -PTRV|5.006000||p -PUSHMARK||| -PUSH_MULTICALL||5.011000| -PUSHi||| -PUSHmortal|5.009002||p -PUSHn||| -PUSHp||| -PUSHs||| -PUSHu|5.004000||p -PUTBACK||| -PerlIO_clearerr||5.007003| -PerlIO_close||5.007003| -PerlIO_context_layers||5.009004| -PerlIO_eof||5.007003| -PerlIO_error||5.007003| -PerlIO_fileno||5.007003| -PerlIO_fill||5.007003| -PerlIO_flush||5.007003| -PerlIO_get_base||5.007003| -PerlIO_get_bufsiz||5.007003| -PerlIO_get_cnt||5.007003| -PerlIO_get_ptr||5.007003| -PerlIO_read||5.007003| -PerlIO_seek||5.007003| -PerlIO_set_cnt||5.007003| -PerlIO_set_ptrcnt||5.007003| -PerlIO_setlinebuf||5.007003| -PerlIO_stderr||5.007003| -PerlIO_stdin||5.007003| -PerlIO_stdout||5.007003| -PerlIO_tell||5.007003| -PerlIO_unread||5.007003| -PerlIO_write||5.007003| -Perl_signbit||5.009005|n -PoisonFree|5.009004||p -PoisonNew|5.009004||p -PoisonWith|5.009004||p -Poison|5.008000||p -RETVAL|||n -Renewc||| -Renew||| -SAVECLEARSV||| -SAVECOMPPAD||| -SAVEPADSV||| -SAVETMPS||| -SAVE_DEFSV|5.004050||p -SPAGAIN||| -SP||| -START_EXTERN_C|5.005000||p -START_MY_CXT|5.007003||p -STMT_END|||p -STMT_START|||p -STR_WITH_LEN|5.009003||p -ST||| -SV_CONST_RETURN|5.009003||p -SV_COW_DROP_PV|5.008001||p -SV_COW_SHARED_HASH_KEYS|5.009005||p -SV_GMAGIC|5.007002||p -SV_HAS_TRAILING_NUL|5.009004||p -SV_IMMEDIATE_UNREF|5.007001||p -SV_MUTABLE_RETURN|5.009003||p -SV_NOSTEAL|5.009002||p -SV_SMAGIC|5.009003||p -SV_UTF8_NO_ENCODING|5.008001||p -SVfARG|5.009005||p -SVf_UTF8|5.006000||p -SVf|5.006000||p -SVt_IV||| -SVt_NV||| -SVt_PVAV||| -SVt_PVCV||| -SVt_PVHV||| -SVt_PVMG||| -SVt_PV||| -Safefree||| -Slab_Alloc||| -Slab_Free||| -Slab_to_rw||| -StructCopy||| -SvCUR_set||| -SvCUR||| -SvEND||| -SvGAMAGIC||5.006001| -SvGETMAGIC|5.004050||p -SvGROW||| -SvIOK_UV||5.006000| -SvIOK_notUV||5.006000| -SvIOK_off||| -SvIOK_only_UV||5.006000| -SvIOK_only||| -SvIOK_on||| -SvIOKp||| -SvIOK||| -SvIVX||| -SvIV_nomg|5.009001||p -SvIV_set||| -SvIVx||| -SvIV||| -SvIsCOW_shared_hash||5.008003| -SvIsCOW||5.008003| -SvLEN_set||| -SvLEN||| -SvLOCK||5.007003| -SvMAGIC_set|5.009003||p -SvNIOK_off||| -SvNIOKp||| -SvNIOK||| -SvNOK_off||| -SvNOK_only||| -SvNOK_on||| -SvNOKp||| -SvNOK||| -SvNVX||| -SvNV_set||| -SvNVx||| -SvNV||| -SvOK||| -SvOOK_offset||5.011000| -SvOOK||| -SvPOK_off||| -SvPOK_only_UTF8||5.006000| -SvPOK_only||| -SvPOK_on||| -SvPOKp||| -SvPOK||| -SvPVX_const|5.009003||p -SvPVX_mutable|5.009003||p -SvPVX||| -SvPV_const|5.009003||p -SvPV_flags_const_nolen|5.009003||p -SvPV_flags_const|5.009003||p -SvPV_flags_mutable|5.009003||p -SvPV_flags|5.007002||p -SvPV_force_flags_mutable|5.009003||p -SvPV_force_flags_nolen|5.009003||p -SvPV_force_flags|5.007002||p -SvPV_force_mutable|5.009003||p -SvPV_force_nolen|5.009003||p -SvPV_force_nomg_nolen|5.009003||p -SvPV_force_nomg|5.007002||p -SvPV_force|||p -SvPV_mutable|5.009003||p -SvPV_nolen_const|5.009003||p -SvPV_nolen|5.006000||p -SvPV_nomg_const_nolen|5.009003||p -SvPV_nomg_const|5.009003||p -SvPV_nomg|5.007002||p -SvPV_renew|5.009003||p -SvPV_set||| -SvPVbyte_force||5.009002| -SvPVbyte_nolen||5.006000| -SvPVbytex_force||5.006000| -SvPVbytex||5.006000| -SvPVbyte|5.006000||p -SvPVutf8_force||5.006000| -SvPVutf8_nolen||5.006000| -SvPVutf8x_force||5.006000| -SvPVutf8x||5.006000| -SvPVutf8||5.006000| -SvPVx||| -SvPV||| -SvREFCNT_dec||| -SvREFCNT_inc_NN|5.009004||p -SvREFCNT_inc_simple_NN|5.009004||p -SvREFCNT_inc_simple_void_NN|5.009004||p -SvREFCNT_inc_simple_void|5.009004||p -SvREFCNT_inc_simple|5.009004||p -SvREFCNT_inc_void_NN|5.009004||p -SvREFCNT_inc_void|5.009004||p -SvREFCNT_inc|||p -SvREFCNT||| -SvROK_off||| -SvROK_on||| -SvROK||| -SvRV_set|5.009003||p -SvRV||| -SvRXOK||5.009005| -SvRX||5.009005| -SvSETMAGIC||| -SvSHARED_HASH|5.009003||p -SvSHARE||5.007003| -SvSTASH_set|5.009003||p -SvSTASH||| -SvSetMagicSV_nosteal||5.004000| -SvSetMagicSV||5.004000| -SvSetSV_nosteal||5.004000| -SvSetSV||| -SvTAINTED_off||5.004000| -SvTAINTED_on||5.004000| -SvTAINTED||5.004000| -SvTAINT||| -SvTRUE||| -SvTYPE||| -SvUNLOCK||5.007003| -SvUOK|5.007001|5.006000|p -SvUPGRADE||| -SvUTF8_off||5.006000| -SvUTF8_on||5.006000| -SvUTF8||5.006000| -SvUVXx|5.004000||p -SvUVX|5.004000||p -SvUV_nomg|5.009001||p -SvUV_set|5.009003||p -SvUVx|5.004000||p -SvUV|5.004000||p -SvVOK||5.008001| -SvVSTRING_mg|5.009004||p -THIS|||n -UNDERBAR|5.009002||p -UTF8_MAXBYTES|5.009002||p -UVSIZE|5.006000||p -UVTYPE|5.006000||p -UVXf|5.007001||p -UVof|5.006000||p -UVuf|5.006000||p -UVxf|5.006000||p -WARN_ALL|5.006000||p -WARN_AMBIGUOUS|5.006000||p -WARN_ASSERTIONS|5.011000||p -WARN_BAREWORD|5.006000||p -WARN_CLOSED|5.006000||p -WARN_CLOSURE|5.006000||p -WARN_DEBUGGING|5.006000||p -WARN_DEPRECATED|5.006000||p -WARN_DIGIT|5.006000||p -WARN_EXEC|5.006000||p -WARN_EXITING|5.006000||p -WARN_GLOB|5.006000||p -WARN_INPLACE|5.006000||p -WARN_INTERNAL|5.006000||p -WARN_IO|5.006000||p -WARN_LAYER|5.008000||p -WARN_MALLOC|5.006000||p -WARN_MISC|5.006000||p -WARN_NEWLINE|5.006000||p -WARN_NUMERIC|5.006000||p -WARN_ONCE|5.006000||p -WARN_OVERFLOW|5.006000||p -WARN_PACK|5.006000||p -WARN_PARENTHESIS|5.006000||p -WARN_PIPE|5.006000||p -WARN_PORTABLE|5.006000||p -WARN_PRECEDENCE|5.006000||p -WARN_PRINTF|5.006000||p -WARN_PROTOTYPE|5.006000||p -WARN_QW|5.006000||p -WARN_RECURSION|5.006000||p -WARN_REDEFINE|5.006000||p -WARN_REGEXP|5.006000||p -WARN_RESERVED|5.006000||p -WARN_SEMICOLON|5.006000||p -WARN_SEVERE|5.006000||p -WARN_SIGNAL|5.006000||p -WARN_SUBSTR|5.006000||p -WARN_SYNTAX|5.006000||p -WARN_TAINT|5.006000||p -WARN_THREADS|5.008000||p -WARN_UNINITIALIZED|5.006000||p -WARN_UNOPENED|5.006000||p -WARN_UNPACK|5.006000||p -WARN_UNTIE|5.006000||p -WARN_UTF8|5.006000||p -WARN_VOID|5.006000||p -XCPT_CATCH|5.009002||p -XCPT_RETHROW|5.009002||p -XCPT_TRY_END|5.009002||p -XCPT_TRY_START|5.009002||p -XPUSHi||| -XPUSHmortal|5.009002||p -XPUSHn||| -XPUSHp||| -XPUSHs||| -XPUSHu|5.004000||p -XSPROTO|5.010000||p -XSRETURN_EMPTY||| -XSRETURN_IV||| -XSRETURN_NO||| -XSRETURN_NV||| -XSRETURN_PV||| -XSRETURN_UNDEF||| -XSRETURN_UV|5.008001||p -XSRETURN_YES||| -XSRETURN|||p -XST_mIV||| -XST_mNO||| -XST_mNV||| -XST_mPV||| -XST_mUNDEF||| -XST_mUV|5.008001||p -XST_mYES||| -XS_VERSION_BOOTCHECK||| -XS_VERSION||| -XSprePUSH|5.006000||p -XS||| -ZeroD|5.009002||p -Zero||| -_aMY_CXT|5.007003||p -_pMY_CXT|5.007003||p -aMY_CXT_|5.007003||p -aMY_CXT|5.007003||p -aTHXR_|5.011000||p -aTHXR|5.011000||p -aTHX_|5.006000||p -aTHX|5.006000||p -add_data|||n -addmad||| -allocmy||| -amagic_call||| -amagic_cmp_locale||| -amagic_cmp||| -amagic_i_ncmp||| -amagic_ncmp||| -any_dup||| -ao||| -append_elem||| -append_list||| -append_madprops||| -apply_attrs_my||| -apply_attrs_string||5.006001| -apply_attrs||| -apply||| -atfork_lock||5.007003|n -atfork_unlock||5.007003|n -av_arylen_p||5.009003| -av_clear||| -av_create_and_push||5.009005| -av_create_and_unshift_one||5.009005| -av_delete||5.006000| -av_exists||5.006000| -av_extend||| -av_fetch||| -av_fill||| -av_iter_p||5.011000| -av_len||| -av_make||| -av_pop||| -av_push||| -av_reify||| -av_shift||| -av_store||| -av_undef||| -av_unshift||| -ax|||n -bad_type||| -bind_match||| -block_end||| -block_gimme||5.004000| -block_start||| -boolSV|5.004000||p -boot_core_PerlIO||| -boot_core_UNIVERSAL||| -boot_core_mro||| -bytes_from_utf8||5.007001| -bytes_to_uni|||n -bytes_to_utf8||5.006001| -call_argv|5.006000||p -call_atexit||5.006000| -call_list||5.004000| -call_method|5.006000||p -call_pv|5.006000||p -call_sv|5.006000||p -calloc||5.007002|n -cando||| -cast_i32||5.006000| -cast_iv||5.006000| -cast_ulong||5.006000| -cast_uv||5.006000| -check_type_and_open||| -check_uni||| -checkcomma||| -checkposixcc||| -ckWARN|5.006000||p -ck_anoncode||| -ck_bitop||| -ck_concat||| -ck_defined||| -ck_delete||| -ck_die||| -ck_each||| -ck_eof||| -ck_eval||| -ck_exec||| -ck_exists||| -ck_exit||| -ck_ftst||| -ck_fun||| -ck_glob||| -ck_grep||| -ck_index||| -ck_join||| -ck_lfun||| -ck_listiob||| -ck_match||| -ck_method||| -ck_null||| -ck_open||| -ck_readline||| -ck_repeat||| -ck_require||| -ck_return||| -ck_rfun||| -ck_rvconst||| -ck_sassign||| -ck_select||| -ck_shift||| -ck_sort||| -ck_spair||| -ck_split||| -ck_subr||| -ck_substr||| -ck_svconst||| -ck_trunc||| -ck_unpack||| -ckwarn_d||5.009003| -ckwarn||5.009003| -cl_and|||n -cl_anything|||n -cl_init_zero|||n -cl_init|||n -cl_is_anything|||n -cl_or|||n -clear_placeholders||| -closest_cop||| -convert||| -cop_free||| -cr_textfilter||| -create_eval_scope||| -croak_nocontext|||vn -croak_xs_usage||5.011000| -croak|||v -csighandler||5.009003|n -curmad||| -custom_op_desc||5.007003| -custom_op_name||5.007003| -cv_ckproto_len||| -cv_clone||| -cv_const_sv||5.004000| -cv_dump||| -cv_undef||| -cx_dump||5.005000| -cx_dup||| -cxinc||| -dAXMARK|5.009003||p -dAX|5.007002||p -dITEMS|5.007002||p -dMARK||| -dMULTICALL||5.009003| -dMY_CXT_SV|5.007003||p -dMY_CXT|5.007003||p -dNOOP|5.006000||p -dORIGMARK||| -dSP||| -dTHR|5.004050||p -dTHXR|5.011000||p -dTHXa|5.006000||p -dTHXoa|5.006000||p -dTHX|5.006000||p -dUNDERBAR|5.009002||p -dVAR|5.009003||p -dXCPT|5.009002||p -dXSARGS||| -dXSI32||| -dXSTARG|5.006000||p -deb_curcv||| -deb_nocontext|||vn -deb_stack_all||| -deb_stack_n||| -debop||5.005000| -debprofdump||5.005000| -debprof||| -debstackptrs||5.007003| -debstack||5.007003| -debug_start_match||| -deb||5.007003|v -del_sv||| -delete_eval_scope||| -delimcpy||5.004000| -deprecate_old||| -deprecate||| -despatch_signals||5.007001| -destroy_matcher||| -die_nocontext|||vn -die_where||| -die|||v -dirp_dup||| -div128||| -djSP||| -do_aexec5||| -do_aexec||| -do_aspawn||| -do_binmode||5.004050| -do_chomp||| -do_chop||| -do_close||| -do_dump_pad||| -do_eof||| -do_exec3||| -do_execfree||| -do_exec||| -do_gv_dump||5.006000| -do_gvgv_dump||5.006000| -do_hv_dump||5.006000| -do_ipcctl||| -do_ipcget||| -do_join||| -do_kv||| -do_magic_dump||5.006000| -do_msgrcv||| -do_msgsnd||| -do_oddball||| -do_op_dump||5.006000| -do_op_xmldump||| -do_open9||5.006000| -do_openn||5.007001| -do_open||5.004000| -do_pmop_dump||5.006000| -do_pmop_xmldump||| -do_print||| -do_readline||| -do_seek||| -do_semop||| -do_shmio||| -do_smartmatch||| -do_spawn_nowait||| -do_spawn||| -do_sprintf||| -do_sv_dump||5.006000| -do_sysseek||| -do_tell||| -do_trans_complex_utf8||| -do_trans_complex||| -do_trans_count_utf8||| -do_trans_count||| -do_trans_simple_utf8||| -do_trans_simple||| -do_trans||| -do_vecget||| -do_vecset||| -do_vop||| -docatch||| -doeval||| -dofile||| -dofindlabel||| -doform||| -doing_taint||5.008001|n -dooneliner||| -doopen_pm||| -doparseform||| -dopoptoeval||| -dopoptogiven||| -dopoptolabel||| -dopoptoloop||| -dopoptosub_at||| -dopoptowhen||| -doref||5.009003| -dounwind||| -dowantarray||| -dump_all||5.006000| -dump_eval||5.006000| -dump_exec_pos||| -dump_fds||| -dump_form||5.006000| -dump_indent||5.006000|v -dump_mstats||| -dump_packsubs||5.006000| -dump_sub||5.006000| -dump_sv_child||| -dump_trie_interim_list||| -dump_trie_interim_table||| -dump_trie||| -dump_vindent||5.006000| -dumpuntil||| -dup_attrlist||| -emulate_cop_io||| -eval_pv|5.006000||p -eval_sv|5.006000||p -exec_failed||| -expect_number||| -fbm_compile||5.005000| -fbm_instr||5.005000| -feature_is_enabled||| -fetch_cop_label||5.011000| -filter_add||| -filter_del||| -filter_gets||| -filter_read||| -find_and_forget_pmops||| -find_array_subscript||| -find_beginning||| -find_byclass||| -find_hash_subscript||| -find_in_my_stash||| -find_runcv||5.008001| -find_rundefsvoffset||5.009002| -find_script||| -find_uninit_var||| -first_symbol|||n -fold_constants||| -forbid_setid||| -force_ident||| -force_list||| -force_next||| -force_version||| -force_word||| -forget_pmop||| -form_nocontext|||vn -form||5.004000|v -fp_dup||| -fprintf_nocontext|||vn -free_global_struct||| -free_tied_hv_pool||| -free_tmps||| -gen_constant_list||| -get_arena||| -get_aux_mg||| -get_av|5.006000||p -get_context||5.006000|n -get_cvn_flags||5.009005| -get_cv|5.006000||p -get_db_sub||| -get_debug_opts||| -get_hash_seed||| -get_hv|5.006000||p -get_isa_hash||| -get_mstats||| -get_no_modify||| -get_num||| -get_op_descs||5.005000| -get_op_names||5.005000| -get_opargs||| -get_ppaddr||5.006000| -get_re_arg||| -get_sv|5.006000||p -get_vtbl||5.005030| -getcwd_sv||5.007002| -getenv_len||| -glob_2number||| -glob_assign_glob||| -glob_assign_ref||| -gp_dup||| -gp_free||| -gp_ref||| -grok_bin|5.007003||p -grok_hex|5.007003||p -grok_number|5.007002||p -grok_numeric_radix|5.007002||p -grok_oct|5.007003||p -group_end||| -gv_AVadd||| -gv_HVadd||| -gv_IOadd||| -gv_SVadd||| -gv_autoload4||5.004000| -gv_check||| -gv_const_sv||5.009003| -gv_dump||5.006000| -gv_efullname3||5.004000| -gv_efullname4||5.006001| -gv_efullname||| -gv_ename||| -gv_fetchfile_flags||5.009005| -gv_fetchfile||| -gv_fetchmeth_autoload||5.007003| -gv_fetchmethod_autoload||5.004000| -gv_fetchmethod_flags||5.011000| -gv_fetchmethod||| -gv_fetchmeth||| -gv_fetchpvn_flags|5.009002||p -gv_fetchpvs|5.009004||p -gv_fetchpv||| -gv_fetchsv||5.009002| -gv_fullname3||5.004000| -gv_fullname4||5.006001| -gv_fullname||| -gv_get_super_pkg||| -gv_handler||5.007001| -gv_init_sv||| -gv_init||| -gv_name_set||5.009004| -gv_stashpvn|5.004000||p -gv_stashpvs|5.009003||p -gv_stashpv||| -gv_stashsv||| -he_dup||| -hek_dup||| -hfreeentries||| -hsplit||| -hv_assert||5.011000| -hv_auxinit|||n -hv_backreferences_p||| -hv_clear_placeholders||5.009001| -hv_clear||| -hv_common_key_len||5.010000| -hv_common||5.010000| -hv_copy_hints_hv||| -hv_delayfree_ent||5.004000| -hv_delete_common||| -hv_delete_ent||5.004000| -hv_delete||| -hv_eiter_p||5.009003| -hv_eiter_set||5.009003| -hv_exists_ent||5.004000| -hv_exists||| -hv_fetch_ent||5.004000| -hv_fetchs|5.009003||p -hv_fetch||| -hv_free_ent||5.004000| -hv_iterinit||| -hv_iterkeysv||5.004000| -hv_iterkey||| -hv_iternext_flags||5.008000| -hv_iternextsv||| -hv_iternext||| -hv_iterval||| -hv_kill_backrefs||| -hv_ksplit||5.004000| -hv_magic_check|||n -hv_magic||| -hv_name_set||5.009003| -hv_notallowed||| -hv_placeholders_get||5.009003| -hv_placeholders_p||5.009003| -hv_placeholders_set||5.009003| -hv_riter_p||5.009003| -hv_riter_set||5.009003| -hv_scalar||5.009001| -hv_store_ent||5.004000| -hv_store_flags||5.008000| -hv_stores|5.009004||p -hv_store||| -hv_undef||| -ibcmp_locale||5.004000| -ibcmp_utf8||5.007003| -ibcmp||| -incline||| -incpush_if_exists||| -incpush_use_sep||| -incpush||| -ingroup||| -init_argv_symbols||| -init_debugger||| -init_global_struct||| -init_i18nl10n||5.006000| -init_i18nl14n||5.006000| -init_ids||| -init_interp||| -init_main_stash||| -init_perllib||| -init_postdump_symbols||| -init_predump_symbols||| -init_stacks||5.005000| -init_tm||5.007002| -instr||| -intro_my||| -intuit_method||| -intuit_more||| -invert||| -io_close||| -isALNUMC|5.006000||p -isALNUM||| -isALPHA||| -isASCII|5.006000||p -isBLANK|5.006001||p -isCNTRL|5.006000||p -isDIGIT||| -isGRAPH|5.006000||p -isGV_with_GP|5.009004||p -isLOWER||| -isPRINT|5.004000||p -isPSXSPC|5.006001||p -isPUNCT|5.006000||p -isSPACE||| -isUPPER||| -isXDIGIT|5.006000||p -is_an_int||| -is_gv_magical_sv||| -is_handle_constructor|||n -is_list_assignment||| -is_lvalue_sub||5.007001| -is_uni_alnum_lc||5.006000| -is_uni_alnumc_lc||5.006000| -is_uni_alnumc||5.006000| -is_uni_alnum||5.006000| -is_uni_alpha_lc||5.006000| -is_uni_alpha||5.006000| -is_uni_ascii_lc||5.006000| -is_uni_ascii||5.006000| -is_uni_cntrl_lc||5.006000| -is_uni_cntrl||5.006000| -is_uni_digit_lc||5.006000| -is_uni_digit||5.006000| -is_uni_graph_lc||5.006000| -is_uni_graph||5.006000| -is_uni_idfirst_lc||5.006000| -is_uni_idfirst||5.006000| -is_uni_lower_lc||5.006000| -is_uni_lower||5.006000| -is_uni_print_lc||5.006000| -is_uni_print||5.006000| -is_uni_punct_lc||5.006000| -is_uni_punct||5.006000| -is_uni_space_lc||5.006000| -is_uni_space||5.006000| -is_uni_upper_lc||5.006000| -is_uni_upper||5.006000| -is_uni_xdigit_lc||5.006000| -is_uni_xdigit||5.006000| -is_utf8_alnumc||5.006000| -is_utf8_alnum||5.006000| -is_utf8_alpha||5.006000| -is_utf8_ascii||5.006000| -is_utf8_char_slow|||n -is_utf8_char||5.006000| -is_utf8_cntrl||5.006000| -is_utf8_common||| -is_utf8_digit||5.006000| -is_utf8_graph||5.006000| -is_utf8_idcont||5.008000| -is_utf8_idfirst||5.006000| -is_utf8_lower||5.006000| -is_utf8_mark||5.006000| -is_utf8_print||5.006000| -is_utf8_punct||5.006000| -is_utf8_space||5.006000| -is_utf8_string_loclen||5.009003| -is_utf8_string_loc||5.008001| -is_utf8_string||5.006001| -is_utf8_upper||5.006000| -is_utf8_xdigit||5.006000| -isa_lookup||| -items|||n -ix|||n -jmaybe||| -join_exact||| -keyword||| -leave_scope||| -lex_end||| -lex_start||| -linklist||| -listkids||| -list||| -load_module_nocontext|||vn -load_module|5.006000||pv -localize||| -looks_like_bool||| -looks_like_number||| -lop||| -mPUSHi|5.009002||p -mPUSHn|5.009002||p -mPUSHp|5.009002||p -mPUSHs|5.011000||p -mPUSHu|5.009002||p -mXPUSHi|5.009002||p -mXPUSHn|5.009002||p -mXPUSHp|5.009002||p -mXPUSHs|5.011000||p -mXPUSHu|5.009002||p -mad_free||| -madlex||| -madparse||| -magic_clear_all_env||| -magic_clearenv||| -magic_clearhint||| -magic_clearisa||| -magic_clearpack||| -magic_clearsig||| -magic_dump||5.006000| -magic_existspack||| -magic_freearylen_p||| -magic_freeovrld||| -magic_getarylen||| -magic_getdefelem||| -magic_getnkeys||| -magic_getpack||| -magic_getpos||| -magic_getsig||| -magic_getsubstr||| -magic_gettaint||| -magic_getuvar||| -magic_getvec||| -magic_get||| -magic_killbackrefs||| -magic_len||| -magic_methcall||| -magic_methpack||| -magic_nextpack||| -magic_regdata_cnt||| -magic_regdatum_get||| -magic_regdatum_set||| -magic_scalarpack||| -magic_set_all_env||| -magic_setamagic||| -magic_setarylen||| -magic_setcollxfrm||| -magic_setdbline||| -magic_setdefelem||| -magic_setenv||| -magic_sethint||| -magic_setisa||| -magic_setmglob||| -magic_setnkeys||| -magic_setpack||| -magic_setpos||| -magic_setregexp||| -magic_setsig||| -magic_setsubstr||| -magic_settaint||| -magic_setutf8||| -magic_setuvar||| -magic_setvec||| -magic_set||| -magic_sizepack||| -magic_wipepack||| -make_matcher||| -make_trie_failtable||| -make_trie||| -malloc_good_size|||n -malloced_size|||n -malloc||5.007002|n -markstack_grow||| -matcher_matches_sv||| -measure_struct||| -memEQ|5.004000||p -memNE|5.004000||p -mem_collxfrm||| -mem_log_common|||n -mess_alloc||| -mess_nocontext|||vn -mess||5.006000|v -method_common||| -mfree||5.007002|n -mg_clear||| -mg_copy||| -mg_dup||| -mg_find||| -mg_free||| -mg_get||| -mg_length||5.005000| -mg_localize||| -mg_magical||| -mg_set||| -mg_size||5.005000| -mini_mktime||5.007002| -missingterm||| -mode_from_discipline||| -modkids||| -mod||| -more_bodies||| -more_sv||| -moreswitches||| -mro_get_from_name||5.011000| -mro_get_linear_isa_dfs||| -mro_get_linear_isa||5.009005| -mro_get_private_data||5.011000| -mro_isa_changed_in||| -mro_meta_dup||| -mro_meta_init||| -mro_method_changed_in||5.009005| -mro_register||5.011000| -mro_set_mro||5.011000| -mro_set_private_data||5.011000| -mul128||| -mulexp10|||n -my_atof2||5.007002| -my_atof||5.006000| -my_attrs||| -my_bcopy|||n -my_betoh16|||n -my_betoh32|||n -my_betoh64|||n -my_betohi|||n -my_betohl|||n -my_betohs|||n -my_bzero|||n -my_chsize||| -my_clearenv||| -my_cxt_index||| -my_cxt_init||| -my_dirfd||5.009005| -my_exit_jump||| -my_exit||| -my_failure_exit||5.004000| -my_fflush_all||5.006000| -my_fork||5.007003|n -my_htobe16|||n -my_htobe32|||n -my_htobe64|||n -my_htobei|||n -my_htobel|||n -my_htobes|||n -my_htole16|||n -my_htole32|||n -my_htole64|||n -my_htolei|||n -my_htolel|||n -my_htoles|||n -my_htonl||| -my_kid||| -my_letoh16|||n -my_letoh32|||n -my_letoh64|||n -my_letohi|||n -my_letohl|||n -my_letohs|||n -my_lstat||| -my_memcmp||5.004000|n -my_memset|||n -my_ntohl||| -my_pclose||5.004000| -my_popen_list||5.007001| -my_popen||5.004000| -my_setenv||| -my_snprintf|5.009004||pvn -my_socketpair||5.007003|n -my_sprintf|5.009003||pvn -my_stat||| -my_strftime||5.007002| -my_strlcat|5.009004||pn -my_strlcpy|5.009004||pn -my_swabn|||n -my_swap||| -my_unexec||| -my_vsnprintf||5.009004|n -need_utf8|||n -newANONATTRSUB||5.006000| -newANONHASH||| -newANONLIST||| -newANONSUB||| -newASSIGNOP||| -newATTRSUB||5.006000| -newAVREF||| -newAV||| -newBINOP||| -newCONDOP||| -newCONSTSUB|5.004050||p -newCVREF||| -newDEFSVOP||| -newFORM||| -newFOROP||| -newGIVENOP||5.009003| -newGIVWHENOP||| -newGP||| -newGVOP||| -newGVREF||| -newGVgen||| -newHVREF||| -newHVhv||5.005000| -newHV||| -newIO||| -newLISTOP||| -newLOGOP||| -newLOOPEX||| -newLOOPOP||| -newMADPROP||| -newMADsv||| -newMYSUB||| -newNULLLIST||| -newOP||| -newPADOP||| -newPMOP||| -newPROG||| -newPVOP||| -newRANGE||| -newRV_inc|5.004000||p -newRV_noinc|5.004000||p -newRV||| -newSLICEOP||| -newSTATEOP||| -newSUB||| -newSVOP||| -newSVREF||| -newSV_type|5.009005||p -newSVhek||5.009003| -newSViv||| -newSVnv||| -newSVpvf_nocontext|||vn -newSVpvf||5.004000|v -newSVpvn_flags|5.011000||p -newSVpvn_share|5.007001||p -newSVpvn_utf8|5.011000||p -newSVpvn|5.004050||p -newSVpvs_flags|5.011000||p -newSVpvs_share||5.009003| -newSVpvs|5.009003||p -newSVpv||| -newSVrv||| -newSVsv||| -newSVuv|5.006000||p -newSV||| -newTOKEN||| -newUNOP||| -newWHENOP||5.009003| -newWHILEOP||5.009003| -newXS_flags||5.009004| -newXSproto||5.006000| -newXS||5.006000| -new_collate||5.006000| -new_constant||| -new_ctype||5.006000| -new_he||| -new_logop||| -new_numeric||5.006000| -new_stackinfo||5.005000| -new_version||5.009000| -new_warnings_bitfield||| -next_symbol||| -nextargv||| -nextchar||| -ninstr||| -no_bareword_allowed||| -no_fh_allowed||| -no_op||| -not_a_number||| -nothreadhook||5.008000| -nuke_stacks||| -num_overflow|||n -offer_nice_chunk||| -oopsAV||| -oopsHV||| -op_clear||| -op_const_sv||| -op_dump||5.006000| -op_free||| -op_getmad_weak||| -op_getmad||| -op_null||5.007002| -op_refcnt_dec||| -op_refcnt_inc||| -op_refcnt_lock||5.009002| -op_refcnt_unlock||5.009002| -op_xmldump||| -open_script||| -pMY_CXT_|5.007003||p -pMY_CXT|5.007003||p -pTHX_|5.006000||p -pTHX|5.006000||p -packWARN|5.007003||p -pack_cat||5.007003| -pack_rec||| -package||| -packlist||5.008001| -pad_add_anon||| -pad_add_name||| -pad_alloc||| -pad_block_start||| -pad_check_dup||| -pad_compname_type||| -pad_findlex||| -pad_findmy||| -pad_fixup_inner_anons||| -pad_free||| -pad_leavemy||| -pad_new||| -pad_peg|||n -pad_push||| -pad_reset||| -pad_setsv||| -pad_sv||5.011000| -pad_swipe||| -pad_tidy||| -pad_undef||| -parse_body||| -parse_unicode_opts||| -parser_dup||| -parser_free||| -path_is_absolute|||n -peep||| -pending_Slabs_to_ro||| -perl_alloc_using|||n -perl_alloc|||n -perl_clone_using|||n -perl_clone|||n -perl_construct|||n -perl_destruct||5.007003|n -perl_free|||n -perl_parse||5.006000|n -perl_run|||n -pidgone||| -pm_description||| -pmflag||| -pmop_dump||5.006000| -pmop_xmldump||| -pmruntime||| -pmtrans||| -pop_scope||| -pregcomp||5.009005| -pregexec||| -pregfree2||5.011000| -pregfree||| -prepend_elem||| -prepend_madprops||| -printbuf||| -printf_nocontext|||vn -process_special_blocks||| -ptr_table_clear||5.009005| -ptr_table_fetch||5.009005| -ptr_table_find|||n -ptr_table_free||5.009005| -ptr_table_new||5.009005| -ptr_table_split||5.009005| -ptr_table_store||5.009005| -push_scope||| -put_byte||| -pv_display|5.006000||p -pv_escape|5.009004||p -pv_pretty|5.009004||p -pv_uni_display||5.007003| -qerror||| -qsortsvu||| -re_compile||5.009005| -re_croak2||| -re_dup_guts||| -re_intuit_start||5.009005| -re_intuit_string||5.006000| -readpipe_override||| -realloc||5.007002|n -reentrant_free||| -reentrant_init||| -reentrant_retry|||vn -reentrant_size||| -ref_array_or_hash||| -refcounted_he_chain_2hv||| -refcounted_he_fetch||| -refcounted_he_free||| -refcounted_he_new_common||| -refcounted_he_new||| -refcounted_he_value||| -refkids||| -refto||| -ref||5.011000| -reg_check_named_buff_matched||| -reg_named_buff_all||5.009005| -reg_named_buff_exists||5.009005| -reg_named_buff_fetch||5.009005| -reg_named_buff_firstkey||5.009005| -reg_named_buff_iter||| -reg_named_buff_nextkey||5.009005| -reg_named_buff_scalar||5.009005| -reg_named_buff||| -reg_namedseq||| -reg_node||| -reg_numbered_buff_fetch||| -reg_numbered_buff_length||| -reg_numbered_buff_store||| -reg_qr_package||| -reg_recode||| -reg_scan_name||| -reg_skipcomment||| -reg_temp_copy||| -reganode||| -regatom||| -regbranch||| -regclass_swash||5.009004| -regclass||| -regcppop||| -regcppush||| -regcurly|||n -regdump_extflags||| -regdump||5.005000| -regdupe_internal||| -regexec_flags||5.005000| -regfree_internal||5.009005| -reghop3|||n -reghop4|||n -reghopmaybe3|||n -reginclass||| -reginitcolors||5.006000| -reginsert||| -regmatch||| -regnext||5.005000| -regpiece||| -regpposixcc||| -regprop||| -regrepeat||| -regtail_study||| -regtail||| -regtry||| -reguni||| -regwhite|||n -reg||| -repeatcpy||| -report_evil_fh||| -report_uninit||| -require_pv||5.006000| -require_tie_mod||| -restore_magic||| -rninstr||| -rsignal_restore||| -rsignal_save||| -rsignal_state||5.004000| -rsignal||5.004000| -run_body||| -run_user_filter||| -runops_debug||5.005000| -runops_standard||5.005000| -rvpv_dup||| -rxres_free||| -rxres_restore||| -rxres_save||| -safesyscalloc||5.006000|n -safesysfree||5.006000|n -safesysmalloc||5.006000|n -safesysrealloc||5.006000|n -same_dirent||| -save_I16||5.004000| -save_I32||| -save_I8||5.006000| -save_adelete||5.011000| -save_aelem||5.004050| -save_alloc||5.006000| -save_aptr||| -save_ary||| -save_bool||5.008001| -save_clearsv||| -save_delete||| -save_destructor_x||5.006000| -save_destructor||5.006000| -save_freeop||| -save_freepv||| -save_freesv||| -save_generic_pvref||5.006001| -save_generic_svref||5.005030| -save_gp||5.004000| -save_hash||| -save_hek_flags|||n -save_helem_flags||5.011000| -save_helem||5.004050| -save_hints||| -save_hptr||| -save_int||| -save_item||| -save_iv||5.005000| -save_lines||| -save_list||| -save_long||| -save_magic||| -save_mortalizesv||5.007001| -save_nogv||| -save_op||| -save_padsv_and_mortalize||5.011000| -save_pptr||| -save_pushi32ptr||| -save_pushptri32ptr||| -save_pushptrptr||| -save_pushptr||5.011000| -save_re_context||5.006000| -save_scalar_at||| -save_scalar||| -save_set_svflags||5.009000| -save_shared_pvref||5.007003| -save_sptr||| -save_svref||| -save_vptr||5.006000| -savepvn||| -savepvs||5.009003| -savepv||| -savesharedpvn||5.009005| -savesharedpv||5.007003| -savestack_grow_cnt||5.008001| -savestack_grow||| -savesvpv||5.009002| -sawparens||| -scalar_mod_type|||n -scalarboolean||| -scalarkids||| -scalarseq||| -scalarvoid||| -scalar||| -scan_bin||5.006000| -scan_commit||| -scan_const||| -scan_formline||| -scan_heredoc||| -scan_hex||| -scan_ident||| -scan_inputsymbol||| -scan_num||5.007001| -scan_oct||| -scan_pat||| -scan_str||| -scan_subst||| -scan_trans||| -scan_version||5.009001| -scan_vstring||5.009005| -scan_word||| -scope||| -screaminstr||5.005000| -search_const||| -seed||5.008001| -sequence_num||| -sequence_tail||| -sequence||| -set_context||5.006000|n -set_numeric_local||5.006000| -set_numeric_radix||5.006000| -set_numeric_standard||5.006000| -setdefout||| -share_hek_flags||| -share_hek||5.004000| -si_dup||| -sighandler|||n -simplify_sort||| -skipspace0||| -skipspace1||| -skipspace2||| -skipspace||| -softref2xv||| -sortcv_stacked||| -sortcv_xsub||| -sortcv||| -sortsv_flags||5.009003| -sortsv||5.007003| -space_join_names_mortal||| -ss_dup||| -stack_grow||| -start_force||| -start_glob||| -start_subparse||5.004000| -stashpv_hvname_match||5.011000| -stdize_locale||| -store_cop_label||| -strEQ||| -strGE||| -strGT||| -strLE||| -strLT||| -strNE||| -str_to_version||5.006000| -strip_return||| -strnEQ||| -strnNE||| -study_chunk||| -sub_crush_depth||| -sublex_done||| -sublex_push||| -sublex_start||| -sv_2bool||| -sv_2cv||| -sv_2io||| -sv_2iuv_common||| -sv_2iuv_non_preserve||| -sv_2iv_flags||5.009001| -sv_2iv||| -sv_2mortal||| -sv_2num||| -sv_2nv||| -sv_2pv_flags|5.007002||p -sv_2pv_nolen|5.006000||p -sv_2pvbyte_nolen|5.006000||p -sv_2pvbyte|5.006000||p -sv_2pvutf8_nolen||5.006000| -sv_2pvutf8||5.006000| -sv_2pv||| -sv_2uv_flags||5.009001| -sv_2uv|5.004000||p -sv_add_arena||| -sv_add_backref||| -sv_backoff||| -sv_bless||| -sv_cat_decode||5.008001| -sv_catpv_mg|5.004050||p -sv_catpvf_mg_nocontext|||pvn -sv_catpvf_mg|5.006000|5.004000|pv -sv_catpvf_nocontext|||vn -sv_catpvf||5.004000|v -sv_catpvn_flags||5.007002| -sv_catpvn_mg|5.004050||p -sv_catpvn_nomg|5.007002||p -sv_catpvn||| -sv_catpvs|5.009003||p -sv_catpv||| -sv_catsv_flags||5.007002| -sv_catsv_mg|5.004050||p -sv_catsv_nomg|5.007002||p -sv_catsv||| -sv_catxmlpvn||| -sv_catxmlsv||| -sv_chop||| -sv_clean_all||| -sv_clean_objs||| -sv_clear||| -sv_cmp_locale||5.004000| -sv_cmp||| -sv_collxfrm||| -sv_compile_2op||5.008001| -sv_copypv||5.007003| -sv_dec||| -sv_del_backref||| -sv_derived_from||5.004000| -sv_destroyable||5.010000| -sv_does||5.009004| -sv_dump||| -sv_dup_inc_multiple||| -sv_dup||| -sv_eq||| -sv_exp_grow||| -sv_force_normal_flags||5.007001| -sv_force_normal||5.006000| -sv_free2||| -sv_free_arenas||| -sv_free||| -sv_gets||5.004000| -sv_grow||| -sv_i_ncmp||| -sv_inc||| -sv_insert_flags||5.011000| -sv_insert||| -sv_isa||| -sv_isobject||| -sv_iv||5.005000| -sv_kill_backrefs||| -sv_len_utf8||5.006000| -sv_len||| -sv_magic_portable|5.011000|5.004000|p -sv_magicext||5.007003| -sv_magic||| -sv_mortalcopy||| -sv_ncmp||| -sv_newmortal||| -sv_newref||| -sv_nolocking||5.007003| -sv_nosharing||5.007003| -sv_nounlocking||| -sv_nv||5.005000| -sv_peek||5.005000| -sv_pos_b2u_midway||| -sv_pos_b2u||5.006000| -sv_pos_u2b_cached||| -sv_pos_u2b_forwards|||n -sv_pos_u2b_midway|||n -sv_pos_u2b||5.006000| -sv_pvbyten_force||5.006000| -sv_pvbyten||5.006000| -sv_pvbyte||5.006000| -sv_pvn_force_flags|5.007002||p -sv_pvn_force||| -sv_pvn_nomg|5.007003|5.005000|p -sv_pvn||5.005000| -sv_pvutf8n_force||5.006000| -sv_pvutf8n||5.006000| -sv_pvutf8||5.006000| -sv_pv||5.006000| -sv_recode_to_utf8||5.007003| -sv_reftype||| -sv_release_COW||| -sv_replace||| -sv_report_used||| -sv_reset||| -sv_rvweaken||5.006000| -sv_setiv_mg|5.004050||p -sv_setiv||| -sv_setnv_mg|5.006000||p -sv_setnv||| -sv_setpv_mg|5.004050||p -sv_setpvf_mg_nocontext|||pvn -sv_setpvf_mg|5.006000|5.004000|pv -sv_setpvf_nocontext|||vn -sv_setpvf||5.004000|v -sv_setpviv_mg||5.008001| -sv_setpviv||5.008001| -sv_setpvn_mg|5.004050||p -sv_setpvn||| -sv_setpvs|5.009004||p -sv_setpv||| -sv_setref_iv||| -sv_setref_nv||| -sv_setref_pvn||| -sv_setref_pv||| -sv_setref_uv||5.007001| -sv_setsv_cow||| -sv_setsv_flags||5.007002| -sv_setsv_mg|5.004050||p -sv_setsv_nomg|5.007002||p -sv_setsv||| -sv_setuv_mg|5.004050||p -sv_setuv|5.004000||p -sv_tainted||5.004000| -sv_taint||5.004000| -sv_true||5.005000| -sv_unglob||| -sv_uni_display||5.007003| -sv_unmagic||| -sv_unref_flags||5.007001| -sv_unref||| -sv_untaint||5.004000| -sv_upgrade||| -sv_usepvn_flags||5.009004| -sv_usepvn_mg|5.004050||p -sv_usepvn||| -sv_utf8_decode||5.006000| -sv_utf8_downgrade||5.006000| -sv_utf8_encode||5.006000| -sv_utf8_upgrade_flags_grow||5.011000| -sv_utf8_upgrade_flags||5.007002| -sv_utf8_upgrade_nomg||5.007002| -sv_utf8_upgrade||5.007001| -sv_uv|5.005000||p -sv_vcatpvf_mg|5.006000|5.004000|p -sv_vcatpvfn||5.004000| -sv_vcatpvf|5.006000|5.004000|p -sv_vsetpvf_mg|5.006000|5.004000|p -sv_vsetpvfn||5.004000| -sv_vsetpvf|5.006000|5.004000|p -sv_xmlpeek||| -svtype||| -swallow_bom||| -swap_match_buff||| -swash_fetch||5.007002| -swash_get||| -swash_init||5.006000| -sys_init3||5.010000|n -sys_init||5.010000|n -sys_intern_clear||| -sys_intern_dup||| -sys_intern_init||| -sys_term||5.010000|n -taint_env||| -taint_proper||| -tmps_grow||5.006000| -toLOWER||| -toUPPER||| -to_byte_substr||| -to_uni_fold||5.007003| -to_uni_lower_lc||5.006000| -to_uni_lower||5.007003| -to_uni_title_lc||5.006000| -to_uni_title||5.007003| -to_uni_upper_lc||5.006000| -to_uni_upper||5.007003| -to_utf8_case||5.007003| -to_utf8_fold||5.007003| -to_utf8_lower||5.007003| -to_utf8_substr||| -to_utf8_title||5.007003| -to_utf8_upper||5.007003| -token_free||| -token_getmad||| -tokenize_use||| -tokeq||| -tokereport||| -too_few_arguments||| -too_many_arguments||| -uiv_2buf|||n -unlnk||| -unpack_rec||| -unpack_str||5.007003| -unpackstring||5.008001| -unshare_hek_or_pvn||| -unshare_hek||| -unsharepvn||5.004000| -unwind_handler_stack||| -update_debugger_info||| -upg_version||5.009005| -usage||| -utf16_to_utf8_reversed||5.006001| -utf16_to_utf8||5.006001| -utf8_distance||5.006000| -utf8_hop||5.006000| -utf8_length||5.007001| -utf8_mg_pos_cache_update||| -utf8_to_bytes||5.006001| -utf8_to_uvchr||5.007001| -utf8_to_uvuni||5.007001| -utf8n_to_uvchr||| -utf8n_to_uvuni||5.007001| -utilize||| -uvchr_to_utf8_flags||5.007003| -uvchr_to_utf8||| -uvuni_to_utf8_flags||5.007003| -uvuni_to_utf8||5.007001| -validate_suid||| -varname||| -vcmp||5.009000| -vcroak||5.006000| -vdeb||5.007003| -vdie_common||| -vdie_croak_common||| -vdie||| -vform||5.006000| -visit||| -vivify_defelem||| -vivify_ref||| -vload_module|5.006000||p -vmess||5.006000| -vnewSVpvf|5.006000|5.004000|p -vnormal||5.009002| -vnumify||5.009000| -vstringify||5.009000| -vverify||5.009003| -vwarner||5.006000| -vwarn||5.006000| -wait4pid||| -warn_nocontext|||vn -warner_nocontext|||vn -warner|5.006000|5.004000|pv -warn|||v -watch||| -whichsig||| -write_no_mem||| -write_to_stderr||| -xmldump_all||| -xmldump_attr||| -xmldump_eval||| -xmldump_form||| -xmldump_indent|||v -xmldump_packsubs||| -xmldump_sub||| -xmldump_vindent||| -yyerror||| -yylex||| -yyparse||| -yywarn||| -); - -if (exists $opt{'list-unsupported'}) { - my $f; - for $f (sort { lc $a cmp lc $b } keys %API) { - next unless $API{$f}{todo}; - print "$f ", '.'x(40-length($f)), " ", format_version($API{$f}{todo}), "\n"; - } - exit 0; -} - -# Scan for possible replacement candidates - -my(%replace, %need, %hints, %warnings, %depends); -my $replace = 0; -my($hint, $define, $function); - -sub find_api -{ - my $code = shift; - $code =~ s{ - / (?: \*[^*]*\*+(?:[^$ccs][^*]*\*+)* / | /[^\r\n]*) - | "[^"\\]*(?:\\.[^"\\]*)*" - | '[^'\\]*(?:\\.[^'\\]*)*' }{}egsx; - grep { exists $API{$_} } $code =~ /(\w+)/mg; -} - -while () { - if ($hint) { - my $h = $hint->[0] eq 'Hint' ? \%hints : \%warnings; - if (m{^\s*\*\s(.*?)\s*$}) { - for (@{$hint->[1]}) { - $h->{$_} ||= ''; # suppress warning with older perls - $h->{$_} .= "$1\n"; - } - } - else { undef $hint } - } - - $hint = [$1, [split /,?\s+/, $2]] - if m{^\s*$rccs\s+(Hint|Warning):\s+(\w+(?:,?\s+\w+)*)\s*$}; - - if ($define) { - if ($define->[1] =~ /\\$/) { - $define->[1] .= $_; - } - else { - if (exists $API{$define->[0]} && $define->[1] !~ /^DPPP_\(/) { - my @n = find_api($define->[1]); - push @{$depends{$define->[0]}}, @n if @n - } - undef $define; - } - } - - $define = [$1, $2] if m{^\s*#\s*define\s+(\w+)(?:\([^)]*\))?\s+(.*)}; - - if ($function) { - if (/^}/) { - if (exists $API{$function->[0]}) { - my @n = find_api($function->[1]); - push @{$depends{$function->[0]}}, @n if @n - } - undef $function; - } - else { - $function->[1] .= $_; - } - } - - $function = [$1, ''] if m{^DPPP_\(my_(\w+)\)}; - - $replace = $1 if m{^\s*$rccs\s+Replace:\s+(\d+)\s+$rcce\s*$}; - $replace{$2} = $1 if $replace and m{^\s*#\s*define\s+(\w+)(?:\([^)]*\))?\s+(\w+)}; - $replace{$2} = $1 if m{^\s*#\s*define\s+(\w+)(?:\([^)]*\))?\s+(\w+).*$rccs\s+Replace\s+$rcce}; - $replace{$1} = $2 if m{^\s*$rccs\s+Replace (\w+) with (\w+)\s+$rcce\s*$}; - - if (m{^\s*$rccs\s+(\w+(\s*,\s*\w+)*)\s+depends\s+on\s+(\w+(\s*,\s*\w+)*)\s+$rcce\s*$}) { - my @deps = map { s/\s+//g; $_ } split /,/, $3; - my $d; - for $d (map { s/\s+//g; $_ } split /,/, $1) { - push @{$depends{$d}}, @deps; - } - } - - $need{$1} = 1 if m{^#if\s+defined\(NEED_(\w+)(?:_GLOBAL)?\)}; -} - -for (values %depends) { - my %s; - $_ = [sort grep !$s{$_}++, @$_]; -} - -if (exists $opt{'api-info'}) { - my $f; - my $count = 0; - my $match = $opt{'api-info'} =~ m!^/(.*)/$! ? $1 : "^\Q$opt{'api-info'}\E\$"; - for $f (sort { lc $a cmp lc $b } keys %API) { - next unless $f =~ /$match/; - print "\n=== $f ===\n\n"; - my $info = 0; - if ($API{$f}{base} || $API{$f}{todo}) { - my $base = format_version($API{$f}{base} || $API{$f}{todo}); - print "Supported at least starting from perl-$base.\n"; - $info++; - } - if ($API{$f}{provided}) { - my $todo = $API{$f}{todo} ? format_version($API{$f}{todo}) : "5.003"; - print "Support by $ppport provided back to perl-$todo.\n"; - print "Support needs to be explicitly requested by NEED_$f.\n" if exists $need{$f}; - print "Depends on: ", join(', ', @{$depends{$f}}), ".\n" if exists $depends{$f}; - print "\n$hints{$f}" if exists $hints{$f}; - print "\nWARNING:\n$warnings{$f}" if exists $warnings{$f}; - $info++; - } - print "No portability information available.\n" unless $info; - $count++; - } - $count or print "Found no API matching '$opt{'api-info'}'."; - print "\n"; - exit 0; -} - -if (exists $opt{'list-provided'}) { - my $f; - for $f (sort { lc $a cmp lc $b } keys %API) { - next unless $API{$f}{provided}; - my @flags; - push @flags, 'explicit' if exists $need{$f}; - push @flags, 'depend' if exists $depends{$f}; - push @flags, 'hint' if exists $hints{$f}; - push @flags, 'warning' if exists $warnings{$f}; - my $flags = @flags ? ' ['.join(', ', @flags).']' : ''; - print "$f$flags\n"; - } - exit 0; -} - -my @files; -my @srcext = qw( .xs .c .h .cc .cpp -c.inc -xs.inc ); -my $srcext = join '|', map { quotemeta $_ } @srcext; - -if (@ARGV) { - my %seen; - for (@ARGV) { - if (-e) { - if (-f) { - push @files, $_ unless $seen{$_}++; - } - else { warn "'$_' is not a file.\n" } - } - else { - my @new = grep { -f } glob $_ - or warn "'$_' does not exist.\n"; - push @files, grep { !$seen{$_}++ } @new; - } - } -} -else { - eval { - require File::Find; - File::Find::find(sub { - $File::Find::name =~ /($srcext)$/i - and push @files, $File::Find::name; - }, '.'); - }; - if ($@) { - @files = map { glob "*$_" } @srcext; - } -} - -if (!@ARGV || $opt{filter}) { - my(@in, @out); - my %xsc = map { /(.*)\.xs$/ ? ("$1.c" => 1, "$1.cc" => 1) : () } @files; - for (@files) { - my $out = exists $xsc{$_} || /\b\Q$ppport\E$/i || !/($srcext)$/i; - push @{ $out ? \@out : \@in }, $_; - } - if (@ARGV && @out) { - warning("Skipping the following files (use --nofilter to avoid this):\n| ", join "\n| ", @out); - } - @files = @in; -} - -die "No input files given!\n" unless @files; - -my(%files, %global, %revreplace); -%revreplace = reverse %replace; -my $filename; -my $patch_opened = 0; - -for $filename (@files) { - unless (open IN, "<$filename") { - warn "Unable to read from $filename: $!\n"; - next; - } - - info("Scanning $filename ..."); - - my $c = do { local $/; }; - close IN; - - my %file = (orig => $c, changes => 0); - - # Temporarily remove C/XS comments and strings from the code - my @ccom; - - $c =~ s{ - ( ^$HS*\#$HS*include\b[^\r\n]+\b(?:\Q$ppport\E|XSUB\.h)\b[^\r\n]* - | ^$HS*\#$HS*(?:define|elif|if(?:def)?)\b[^\r\n]* ) - | ( ^$HS*\#[^\r\n]* - | "[^"\\]*(?:\\.[^"\\]*)*" - | '[^'\\]*(?:\\.[^'\\]*)*' - | / (?: \*[^*]*\*+(?:[^$ccs][^*]*\*+)* / | /[^\r\n]* ) ) - }{ defined $2 and push @ccom, $2; - defined $1 ? $1 : "$ccs$#ccom$cce" }mgsex; - - $file{ccom} = \@ccom; - $file{code} = $c; - $file{has_inc_ppport} = $c =~ /^$HS*#$HS*include[^\r\n]+\b\Q$ppport\E\b/m; - - my $func; - - for $func (keys %API) { - my $match = $func; - $match .= "|$revreplace{$func}" if exists $revreplace{$func}; - if ($c =~ /\b(?:Perl_)?($match)\b/) { - $file{uses_replace}{$1}++ if exists $revreplace{$func} && $1 eq $revreplace{$func}; - $file{uses_Perl}{$func}++ if $c =~ /\bPerl_$func\b/; - if (exists $API{$func}{provided}) { - $file{uses_provided}{$func}++; - if (!exists $API{$func}{base} || $API{$func}{base} > $opt{'compat-version'}) { - $file{uses}{$func}++; - my @deps = rec_depend($func); - if (@deps) { - $file{uses_deps}{$func} = \@deps; - for (@deps) { - $file{uses}{$_} = 0 unless exists $file{uses}{$_}; - } - } - for ($func, @deps) { - $file{needs}{$_} = 'static' if exists $need{$_}; - } - } - } - if (exists $API{$func}{todo} && $API{$func}{todo} > $opt{'compat-version'}) { - if ($c =~ /\b$func\b/) { - $file{uses_todo}{$func}++; - } - } - } - } - - while ($c =~ /^$HS*#$HS*define$HS+(NEED_(\w+?)(_GLOBAL)?)\b/mg) { - if (exists $need{$2}) { - $file{defined $3 ? 'needed_global' : 'needed_static'}{$2}++; - } - else { warning("Possibly wrong #define $1 in $filename") } - } - - for (qw(uses needs uses_todo needed_global needed_static)) { - for $func (keys %{$file{$_}}) { - push @{$global{$_}{$func}}, $filename; - } - } - - $files{$filename} = \%file; -} - -# Globally resolve NEED_'s -my $need; -for $need (keys %{$global{needs}}) { - if (@{$global{needs}{$need}} > 1) { - my @targets = @{$global{needs}{$need}}; - my @t = grep $files{$_}{needed_global}{$need}, @targets; - @targets = @t if @t; - @t = grep /\.xs$/i, @targets; - @targets = @t if @t; - my $target = shift @targets; - $files{$target}{needs}{$need} = 'global'; - for (@{$global{needs}{$need}}) { - $files{$_}{needs}{$need} = 'extern' if $_ ne $target; - } - } -} - -for $filename (@files) { - exists $files{$filename} or next; - - info("=== Analyzing $filename ==="); - - my %file = %{$files{$filename}}; - my $func; - my $c = $file{code}; - my $warnings = 0; - - for $func (sort keys %{$file{uses_Perl}}) { - if ($API{$func}{varargs}) { - unless ($API{$func}{nothxarg}) { - my $changes = ($c =~ s{\b(Perl_$func\s*\(\s*)(?!aTHX_?)(\)|[^\s)]*\))} - { $1 . ($2 eq ')' ? 'aTHX' : 'aTHX_ ') . $2 }ge); - if ($changes) { - warning("Doesn't pass interpreter argument aTHX to Perl_$func"); - $file{changes} += $changes; - } - } - } - else { - warning("Uses Perl_$func instead of $func"); - $file{changes} += ($c =~ s{\bPerl_$func(\s*)\((\s*aTHX_?)?\s*} - {$func$1(}g); - } - } - - for $func (sort keys %{$file{uses_replace}}) { - warning("Uses $func instead of $replace{$func}"); - $file{changes} += ($c =~ s/\b$func\b/$replace{$func}/g); - } - - for $func (sort keys %{$file{uses_provided}}) { - if ($file{uses}{$func}) { - if (exists $file{uses_deps}{$func}) { - diag("Uses $func, which depends on ", join(', ', @{$file{uses_deps}{$func}})); - } - else { - diag("Uses $func"); - } - } - $warnings += hint($func); - } - - unless ($opt{quiet}) { - for $func (sort keys %{$file{uses_todo}}) { - print "*** WARNING: Uses $func, which may not be portable below perl ", - format_version($API{$func}{todo}), ", even with '$ppport'\n"; - $warnings++; - } - } - - for $func (sort keys %{$file{needed_static}}) { - my $message = ''; - if (not exists $file{uses}{$func}) { - $message = "No need to define NEED_$func if $func is never used"; - } - elsif (exists $file{needs}{$func} && $file{needs}{$func} ne 'static') { - $message = "No need to define NEED_$func when already needed globally"; - } - if ($message) { - diag($message); - $file{changes} += ($c =~ s/^$HS*#$HS*define$HS+NEED_$func\b.*$LF//mg); - } - } - - for $func (sort keys %{$file{needed_global}}) { - my $message = ''; - if (not exists $global{uses}{$func}) { - $message = "No need to define NEED_${func}_GLOBAL if $func is never used"; - } - elsif (exists $file{needs}{$func}) { - if ($file{needs}{$func} eq 'extern') { - $message = "No need to define NEED_${func}_GLOBAL when already needed globally"; - } - elsif ($file{needs}{$func} eq 'static') { - $message = "No need to define NEED_${func}_GLOBAL when only used in this file"; - } - } - if ($message) { - diag($message); - $file{changes} += ($c =~ s/^$HS*#$HS*define$HS+NEED_${func}_GLOBAL\b.*$LF//mg); - } - } - - $file{needs_inc_ppport} = keys %{$file{uses}}; - - if ($file{needs_inc_ppport}) { - my $pp = ''; - - for $func (sort keys %{$file{needs}}) { - my $type = $file{needs}{$func}; - next if $type eq 'extern'; - my $suffix = $type eq 'global' ? '_GLOBAL' : ''; - unless (exists $file{"needed_$type"}{$func}) { - if ($type eq 'global') { - diag("Files [@{$global{needs}{$func}}] need $func, adding global request"); - } - else { - diag("File needs $func, adding static request"); - } - $pp .= "#define NEED_$func$suffix\n"; - } - } - - if ($pp && ($c =~ s/^(?=$HS*#$HS*define$HS+NEED_\w+)/$pp/m)) { - $pp = ''; - $file{changes}++; - } - - unless ($file{has_inc_ppport}) { - diag("Needs to include '$ppport'"); - $pp .= qq(#include "$ppport"\n) - } - - if ($pp) { - $file{changes} += ($c =~ s/^($HS*#$HS*define$HS+NEED_\w+.*?)^/$1$pp/ms) - || ($c =~ s/^(?=$HS*#$HS*include.*\Q$ppport\E)/$pp/m) - || ($c =~ s/^($HS*#$HS*include.*XSUB.*\s*?)^/$1$pp/m) - || ($c =~ s/^/$pp/); - } - } - else { - if ($file{has_inc_ppport}) { - diag("No need to include '$ppport'"); - $file{changes} += ($c =~ s/^$HS*?#$HS*include.*\Q$ppport\E.*?$LF//m); - } - } - - # put back in our C comments - my $ix; - my $cppc = 0; - my @ccom = @{$file{ccom}}; - for $ix (0 .. $#ccom) { - if (!$opt{cplusplus} && $ccom[$ix] =~ s!^//!!) { - $cppc++; - $file{changes} += $c =~ s/$rccs$ix$rcce/$ccs$ccom[$ix] $cce/; - } - else { - $c =~ s/$rccs$ix$rcce/$ccom[$ix]/; - } - } - - if ($cppc) { - my $s = $cppc != 1 ? 's' : ''; - warning("Uses $cppc C++ style comment$s, which is not portable"); - } - - my $s = $warnings != 1 ? 's' : ''; - my $warn = $warnings ? " ($warnings warning$s)" : ''; - info("Analysis completed$warn"); - - if ($file{changes}) { - if (exists $opt{copy}) { - my $newfile = "$filename$opt{copy}"; - if (-e $newfile) { - error("'$newfile' already exists, refusing to write copy of '$filename'"); - } - else { - local *F; - if (open F, ">$newfile") { - info("Writing copy of '$filename' with changes to '$newfile'"); - print F $c; - close F; - } - else { - error("Cannot open '$newfile' for writing: $!"); - } - } - } - elsif (exists $opt{patch} || $opt{changes}) { - if (exists $opt{patch}) { - unless ($patch_opened) { - if (open PATCH, ">$opt{patch}") { - $patch_opened = 1; - } - else { - error("Cannot open '$opt{patch}' for writing: $!"); - delete $opt{patch}; - $opt{changes} = 1; - goto fallback; - } - } - mydiff(\*PATCH, $filename, $c); - } - else { -fallback: - info("Suggested changes:"); - mydiff(\*STDOUT, $filename, $c); - } - } - else { - my $s = $file{changes} == 1 ? '' : 's'; - info("$file{changes} potentially required change$s detected"); - } - } - else { - info("Looks good"); - } -} - -close PATCH if $patch_opened; - -exit 0; - - -sub try_use { eval "use @_;"; return $@ eq '' } - -sub mydiff -{ - local *F = shift; - my($file, $str) = @_; - my $diff; - - if (exists $opt{diff}) { - $diff = run_diff($opt{diff}, $file, $str); - } - - if (!defined $diff and try_use('Text::Diff')) { - $diff = Text::Diff::diff($file, \$str, { STYLE => 'Unified' }); - $diff = <
$tmp") { - print F $str; - close F; - - if (open F, "$prog $file $tmp |") { - while () { - s/\Q$tmp\E/$file.patched/; - $diff .= $_; - } - close F; - unlink $tmp; - return $diff; - } - - unlink $tmp; - } - else { - error("Cannot open '$tmp' for writing: $!"); - } - - return undef; -} - -sub rec_depend -{ - my($func, $seen) = @_; - return () unless exists $depends{$func}; - $seen = {%{$seen||{}}}; - return () if $seen->{$func}++; - my %s; - grep !$s{$_}++, map { ($_, rec_depend($_, $seen)) } @{$depends{$func}}; -} - -sub parse_version -{ - my $ver = shift; - - if ($ver =~ /^(\d+)\.(\d+)\.(\d+)$/) { - return ($1, $2, $3); - } - elsif ($ver !~ /^\d+\.[\d_]+$/) { - die "cannot parse version '$ver'\n"; - } - - $ver =~ s/_//g; - $ver =~ s/$/000000/; - - my($r,$v,$s) = $ver =~ /(\d+)\.(\d{3})(\d{3})/; - - $v = int $v; - $s = int $s; - - if ($r < 5 || ($r == 5 && $v < 6)) { - if ($s % 10) { - die "cannot parse version '$ver'\n"; - } - } - - return ($r, $v, $s); -} - -sub format_version -{ - my $ver = shift; - - $ver =~ s/$/000000/; - my($r,$v,$s) = $ver =~ /(\d+)\.(\d{3})(\d{3})/; - - $v = int $v; - $s = int $s; - - if ($r < 5 || ($r == 5 && $v < 6)) { - if ($s % 10) { - die "invalid version '$ver'\n"; - } - $s /= 10; - - $ver = sprintf "%d.%03d", $r, $v; - $s > 0 and $ver .= sprintf "_%02d", $s; - - return $ver; - } - - return sprintf "%d.%d.%d", $r, $v, $s; -} - -sub info -{ - $opt{quiet} and return; - print @_, "\n"; -} - -sub diag -{ - $opt{quiet} and return; - $opt{diag} and print @_, "\n"; -} - -sub warning -{ - $opt{quiet} and return; - print "*** ", @_, "\n"; -} - -sub error -{ - print "*** ERROR: ", @_, "\n"; -} - -my %given_hints; -my %given_warnings; -sub hint -{ - $opt{quiet} and return; - my $func = shift; - my $rv = 0; - if (exists $warnings{$func} && !$given_warnings{$func}++) { - my $warn = $warnings{$func}; - $warn =~ s!^!*** !mg; - print "*** WARNING: $func\n", $warn; - $rv++; - } - if ($opt{hints} && exists $hints{$func} && !$given_hints{$func}++) { - my $hint = $hints{$func}; - $hint =~ s/^/ /mg; - print " --- hint for $func ---\n", $hint; - } - $rv; -} - -sub usage -{ - my($usage) = do { local(@ARGV,$/)=($0); <> } =~ /^=head\d$HS+SYNOPSIS\s*^(.*?)\s*^=/ms; - my %M = ( 'I' => '*' ); - $usage =~ s/^\s*perl\s+\S+/$^X $0/; - $usage =~ s/([A-Z])<([^>]+)>/$M{$1}$2$M{$1}/g; - - print < }; - my($copy) = $self =~ /^=head\d\s+COPYRIGHT\s*^(.*?)^=\w+/ms; - $copy =~ s/^(?=\S+)/ /gms; - $self =~ s/^$HS+Do NOT edit.*?(?=^-)/$copy/ms; - $self =~ s/^SKIP.*(?=^__DATA__)/SKIP -if (\@ARGV && \$ARGV[0] eq '--unstrip') { - eval { require Devel::PPPort }; - \$@ and die "Cannot require Devel::PPPort, please install.\\n"; - if (eval \$Devel::PPPort::VERSION < $VERSION) { - die "$0 was originally generated with Devel::PPPort $VERSION.\\n" - . "Your Devel::PPPort is only version \$Devel::PPPort::VERSION.\\n" - . "Please install a newer version, or --unstrip will not work.\\n"; - } - Devel::PPPort::WriteFile(\$0); - exit 0; -} -print <$0" or die "cannot strip $0: $!\n"; - print OUT "$pl$c\n"; - - exit 0; -} - -__DATA__ -*/ - -#ifndef _P_P_PORTABILITY_H_ -#define _P_P_PORTABILITY_H_ - -#ifndef DPPP_NAMESPACE -# define DPPP_NAMESPACE DPPP_ -#endif - -#define DPPP_CAT2(x,y) CAT2(x,y) -#define DPPP_(name) DPPP_CAT2(DPPP_NAMESPACE, name) - -#ifndef PERL_REVISION -# if !defined(__PATCHLEVEL_H_INCLUDED__) && !(defined(PATCHLEVEL) && defined(SUBVERSION)) -# define PERL_PATCHLEVEL_H_IMPLICIT -# include -# endif -# if !(defined(PERL_VERSION) || (defined(SUBVERSION) && defined(PATCHLEVEL))) -# include -# endif -# ifndef PERL_REVISION -# define PERL_REVISION (5) - /* Replace: 1 */ -# define PERL_VERSION PATCHLEVEL -# define PERL_SUBVERSION SUBVERSION - /* Replace PERL_PATCHLEVEL with PERL_VERSION */ - /* Replace: 0 */ -# endif -#endif - -#define _dpppDEC2BCD(dec) ((((dec)/100)<<8)|((((dec)%100)/10)<<4)|((dec)%10)) -#define PERL_BCDVERSION ((_dpppDEC2BCD(PERL_REVISION)<<24)|(_dpppDEC2BCD(PERL_VERSION)<<12)|_dpppDEC2BCD(PERL_SUBVERSION)) - -/* It is very unlikely that anyone will try to use this with Perl 6 - (or greater), but who knows. - */ -#if PERL_REVISION != 5 -# error ppport.h only works with Perl version 5 -#endif /* PERL_REVISION != 5 */ -#ifndef dTHR -# define dTHR dNOOP -#endif -#ifndef dTHX -# define dTHX dNOOP -#endif - -#ifndef dTHXa -# define dTHXa(x) dNOOP -#endif -#ifndef pTHX -# define pTHX void -#endif - -#ifndef pTHX_ -# define pTHX_ -#endif - -#ifndef aTHX -# define aTHX -#endif - -#ifndef aTHX_ -# define aTHX_ -#endif - -#if (PERL_BCDVERSION < 0x5006000) -# ifdef USE_THREADS -# define aTHXR thr -# define aTHXR_ thr, -# else -# define aTHXR -# define aTHXR_ -# endif -# define dTHXR dTHR -#else -# define aTHXR aTHX -# define aTHXR_ aTHX_ -# define dTHXR dTHX -#endif -#ifndef dTHXoa -# define dTHXoa(x) dTHXa(x) -#endif - -#ifdef I_LIMITS -# include -#endif - -#ifndef PERL_UCHAR_MIN -# define PERL_UCHAR_MIN ((unsigned char)0) -#endif - -#ifndef PERL_UCHAR_MAX -# ifdef UCHAR_MAX -# define PERL_UCHAR_MAX ((unsigned char)UCHAR_MAX) -# else -# ifdef MAXUCHAR -# define PERL_UCHAR_MAX ((unsigned char)MAXUCHAR) -# else -# define PERL_UCHAR_MAX ((unsigned char)~(unsigned)0) -# endif -# endif -#endif - -#ifndef PERL_USHORT_MIN -# define PERL_USHORT_MIN ((unsigned short)0) -#endif - -#ifndef PERL_USHORT_MAX -# ifdef USHORT_MAX -# define PERL_USHORT_MAX ((unsigned short)USHORT_MAX) -# else -# ifdef MAXUSHORT -# define PERL_USHORT_MAX ((unsigned short)MAXUSHORT) -# else -# ifdef USHRT_MAX -# define PERL_USHORT_MAX ((unsigned short)USHRT_MAX) -# else -# define PERL_USHORT_MAX ((unsigned short)~(unsigned)0) -# endif -# endif -# endif -#endif - -#ifndef PERL_SHORT_MAX -# ifdef SHORT_MAX -# define PERL_SHORT_MAX ((short)SHORT_MAX) -# else -# ifdef MAXSHORT /* Often used in */ -# define PERL_SHORT_MAX ((short)MAXSHORT) -# else -# ifdef SHRT_MAX -# define PERL_SHORT_MAX ((short)SHRT_MAX) -# else -# define PERL_SHORT_MAX ((short) (PERL_USHORT_MAX >> 1)) -# endif -# endif -# endif -#endif - -#ifndef PERL_SHORT_MIN -# ifdef SHORT_MIN -# define PERL_SHORT_MIN ((short)SHORT_MIN) -# else -# ifdef MINSHORT -# define PERL_SHORT_MIN ((short)MINSHORT) -# else -# ifdef SHRT_MIN -# define PERL_SHORT_MIN ((short)SHRT_MIN) -# else -# define PERL_SHORT_MIN (-PERL_SHORT_MAX - ((3 & -1) == 3)) -# endif -# endif -# endif -#endif - -#ifndef PERL_UINT_MAX -# ifdef UINT_MAX -# define PERL_UINT_MAX ((unsigned int)UINT_MAX) -# else -# ifdef MAXUINT -# define PERL_UINT_MAX ((unsigned int)MAXUINT) -# else -# define PERL_UINT_MAX (~(unsigned int)0) -# endif -# endif -#endif - -#ifndef PERL_UINT_MIN -# define PERL_UINT_MIN ((unsigned int)0) -#endif - -#ifndef PERL_INT_MAX -# ifdef INT_MAX -# define PERL_INT_MAX ((int)INT_MAX) -# else -# ifdef MAXINT /* Often used in */ -# define PERL_INT_MAX ((int)MAXINT) -# else -# define PERL_INT_MAX ((int)(PERL_UINT_MAX >> 1)) -# endif -# endif -#endif - -#ifndef PERL_INT_MIN -# ifdef INT_MIN -# define PERL_INT_MIN ((int)INT_MIN) -# else -# ifdef MININT -# define PERL_INT_MIN ((int)MININT) -# else -# define PERL_INT_MIN (-PERL_INT_MAX - ((3 & -1) == 3)) -# endif -# endif -#endif - -#ifndef PERL_ULONG_MAX -# ifdef ULONG_MAX -# define PERL_ULONG_MAX ((unsigned long)ULONG_MAX) -# else -# ifdef MAXULONG -# define PERL_ULONG_MAX ((unsigned long)MAXULONG) -# else -# define PERL_ULONG_MAX (~(unsigned long)0) -# endif -# endif -#endif - -#ifndef PERL_ULONG_MIN -# define PERL_ULONG_MIN ((unsigned long)0L) -#endif - -#ifndef PERL_LONG_MAX -# ifdef LONG_MAX -# define PERL_LONG_MAX ((long)LONG_MAX) -# else -# ifdef MAXLONG -# define PERL_LONG_MAX ((long)MAXLONG) -# else -# define PERL_LONG_MAX ((long) (PERL_ULONG_MAX >> 1)) -# endif -# endif -#endif - -#ifndef PERL_LONG_MIN -# ifdef LONG_MIN -# define PERL_LONG_MIN ((long)LONG_MIN) -# else -# ifdef MINLONG -# define PERL_LONG_MIN ((long)MINLONG) -# else -# define PERL_LONG_MIN (-PERL_LONG_MAX - ((3 & -1) == 3)) -# endif -# endif -#endif - -#if defined(HAS_QUAD) && (defined(convex) || defined(uts)) -# ifndef PERL_UQUAD_MAX -# ifdef ULONGLONG_MAX -# define PERL_UQUAD_MAX ((unsigned long long)ULONGLONG_MAX) -# else -# ifdef MAXULONGLONG -# define PERL_UQUAD_MAX ((unsigned long long)MAXULONGLONG) -# else -# define PERL_UQUAD_MAX (~(unsigned long long)0) -# endif -# endif -# endif - -# ifndef PERL_UQUAD_MIN -# define PERL_UQUAD_MIN ((unsigned long long)0L) -# endif - -# ifndef PERL_QUAD_MAX -# ifdef LONGLONG_MAX -# define PERL_QUAD_MAX ((long long)LONGLONG_MAX) -# else -# ifdef MAXLONGLONG -# define PERL_QUAD_MAX ((long long)MAXLONGLONG) -# else -# define PERL_QUAD_MAX ((long long) (PERL_UQUAD_MAX >> 1)) -# endif -# endif -# endif - -# ifndef PERL_QUAD_MIN -# ifdef LONGLONG_MIN -# define PERL_QUAD_MIN ((long long)LONGLONG_MIN) -# else -# ifdef MINLONGLONG -# define PERL_QUAD_MIN ((long long)MINLONGLONG) -# else -# define PERL_QUAD_MIN (-PERL_QUAD_MAX - ((3 & -1) == 3)) -# endif -# endif -# endif -#endif - -/* This is based on code from 5.003 perl.h */ -#ifdef HAS_QUAD -# ifdef cray -#ifndef IVTYPE -# define IVTYPE int -#endif - -#ifndef IV_MIN -# define IV_MIN PERL_INT_MIN -#endif - -#ifndef IV_MAX -# define IV_MAX PERL_INT_MAX -#endif - -#ifndef UV_MIN -# define UV_MIN PERL_UINT_MIN -#endif - -#ifndef UV_MAX -# define UV_MAX PERL_UINT_MAX -#endif - -# ifdef INTSIZE -#ifndef IVSIZE -# define IVSIZE INTSIZE -#endif - -# endif -# else -# if defined(convex) || defined(uts) -#ifndef IVTYPE -# define IVTYPE long long -#endif - -#ifndef IV_MIN -# define IV_MIN PERL_QUAD_MIN -#endif - -#ifndef IV_MAX -# define IV_MAX PERL_QUAD_MAX -#endif - -#ifndef UV_MIN -# define UV_MIN PERL_UQUAD_MIN -#endif - -#ifndef UV_MAX -# define UV_MAX PERL_UQUAD_MAX -#endif - -# ifdef LONGLONGSIZE -#ifndef IVSIZE -# define IVSIZE LONGLONGSIZE -#endif - -# endif -# else -#ifndef IVTYPE -# define IVTYPE long -#endif - -#ifndef IV_MIN -# define IV_MIN PERL_LONG_MIN -#endif - -#ifndef IV_MAX -# define IV_MAX PERL_LONG_MAX -#endif - -#ifndef UV_MIN -# define UV_MIN PERL_ULONG_MIN -#endif - -#ifndef UV_MAX -# define UV_MAX PERL_ULONG_MAX -#endif - -# ifdef LONGSIZE -#ifndef IVSIZE -# define IVSIZE LONGSIZE -#endif - -# endif -# endif -# endif -#ifndef IVSIZE -# define IVSIZE 8 -#endif - -#ifndef PERL_QUAD_MIN -# define PERL_QUAD_MIN IV_MIN -#endif - -#ifndef PERL_QUAD_MAX -# define PERL_QUAD_MAX IV_MAX -#endif - -#ifndef PERL_UQUAD_MIN -# define PERL_UQUAD_MIN UV_MIN -#endif - -#ifndef PERL_UQUAD_MAX -# define PERL_UQUAD_MAX UV_MAX -#endif - -#else -#ifndef IVTYPE -# define IVTYPE long -#endif - -#ifndef IV_MIN -# define IV_MIN PERL_LONG_MIN -#endif - -#ifndef IV_MAX -# define IV_MAX PERL_LONG_MAX -#endif - -#ifndef UV_MIN -# define UV_MIN PERL_ULONG_MIN -#endif - -#ifndef UV_MAX -# define UV_MAX PERL_ULONG_MAX -#endif - -#endif - -#ifndef IVSIZE -# ifdef LONGSIZE -# define IVSIZE LONGSIZE -# else -# define IVSIZE 4 /* A bold guess, but the best we can make. */ -# endif -#endif -#ifndef UVTYPE -# define UVTYPE unsigned IVTYPE -#endif - -#ifndef UVSIZE -# define UVSIZE IVSIZE -#endif -#ifndef sv_setuv -# define sv_setuv(sv, uv) \ - STMT_START { \ - UV TeMpUv = uv; \ - if (TeMpUv <= IV_MAX) \ - sv_setiv(sv, TeMpUv); \ - else \ - sv_setnv(sv, (double)TeMpUv); \ - } STMT_END -#endif -#ifndef newSVuv -# define newSVuv(uv) ((uv) <= IV_MAX ? newSViv((IV)uv) : newSVnv((NV)uv)) -#endif -#ifndef sv_2uv -# define sv_2uv(sv) ((PL_Sv = (sv)), (UV) (SvNOK(PL_Sv) ? SvNV(PL_Sv) : sv_2nv(PL_Sv))) -#endif - -#ifndef SvUVX -# define SvUVX(sv) ((UV)SvIVX(sv)) -#endif - -#ifndef SvUVXx -# define SvUVXx(sv) SvUVX(sv) -#endif - -#ifndef SvUV -# define SvUV(sv) (SvIOK(sv) ? SvUVX(sv) : sv_2uv(sv)) -#endif - -#ifndef SvUVx -# define SvUVx(sv) ((PL_Sv = (sv)), SvUV(PL_Sv)) -#endif - -/* Hint: sv_uv - * Always use the SvUVx() macro instead of sv_uv(). - */ -#ifndef sv_uv -# define sv_uv(sv) SvUVx(sv) -#endif - -#if !defined(SvUOK) && defined(SvIOK_UV) -# define SvUOK(sv) SvIOK_UV(sv) -#endif -#ifndef XST_mUV -# define XST_mUV(i,v) (ST(i) = sv_2mortal(newSVuv(v)) ) -#endif - -#ifndef XSRETURN_UV -# define XSRETURN_UV(v) STMT_START { XST_mUV(0,v); XSRETURN(1); } STMT_END -#endif -#ifndef PUSHu -# define PUSHu(u) STMT_START { sv_setuv(TARG, (UV)(u)); PUSHTARG; } STMT_END -#endif - -#ifndef XPUSHu -# define XPUSHu(u) STMT_START { sv_setuv(TARG, (UV)(u)); XPUSHTARG; } STMT_END -#endif - -#ifdef HAS_MEMCMP -#ifndef memNE -# define memNE(s1,s2,l) (memcmp(s1,s2,l)) -#endif - -#ifndef memEQ -# define memEQ(s1,s2,l) (!memcmp(s1,s2,l)) -#endif - -#else -#ifndef memNE -# define memNE(s1,s2,l) (bcmp(s1,s2,l)) -#endif - -#ifndef memEQ -# define memEQ(s1,s2,l) (!bcmp(s1,s2,l)) -#endif - -#endif -#ifndef MoveD -# define MoveD(s,d,n,t) memmove((char*)(d),(char*)(s), (n) * sizeof(t)) -#endif - -#ifndef CopyD -# define CopyD(s,d,n,t) memcpy((char*)(d),(char*)(s), (n) * sizeof(t)) -#endif - -#ifdef HAS_MEMSET -#ifndef ZeroD -# define ZeroD(d,n,t) memzero((char*)(d), (n) * sizeof(t)) -#endif - -#else -#ifndef ZeroD -# define ZeroD(d,n,t) ((void)memzero((char*)(d), (n) * sizeof(t)), d) -#endif - -#endif -#ifndef PoisonWith -# define PoisonWith(d,n,t,b) (void)memset((char*)(d), (U8)(b), (n) * sizeof(t)) -#endif - -#ifndef PoisonNew -# define PoisonNew(d,n,t) PoisonWith(d,n,t,0xAB) -#endif - -#ifndef PoisonFree -# define PoisonFree(d,n,t) PoisonWith(d,n,t,0xEF) -#endif - -#ifndef Poison -# define Poison(d,n,t) PoisonFree(d,n,t) -#endif -#ifndef Newx -# define Newx(v,n,t) New(0,v,n,t) -#endif - -#ifndef Newxc -# define Newxc(v,n,t,c) Newc(0,v,n,t,c) -#endif - -#ifndef Newxz -# define Newxz(v,n,t) Newz(0,v,n,t) -#endif - -#ifndef PERL_UNUSED_DECL -# ifdef HASATTRIBUTE -# if (defined(__GNUC__) && defined(__cplusplus)) || defined(__INTEL_COMPILER) -# define PERL_UNUSED_DECL -# else -# define PERL_UNUSED_DECL __attribute__((unused)) -# endif -# else -# define PERL_UNUSED_DECL -# endif -#endif - -#ifndef PERL_UNUSED_ARG -# if defined(lint) && defined(S_SPLINT_S) /* www.splint.org */ -# include -# define PERL_UNUSED_ARG(x) NOTE(ARGUNUSED(x)) -# else -# define PERL_UNUSED_ARG(x) ((void)x) -# endif -#endif - -#ifndef PERL_UNUSED_VAR -# define PERL_UNUSED_VAR(x) ((void)x) -#endif - -#ifndef PERL_UNUSED_CONTEXT -# ifdef USE_ITHREADS -# define PERL_UNUSED_CONTEXT PERL_UNUSED_ARG(my_perl) -# else -# define PERL_UNUSED_CONTEXT -# endif -#endif -#ifndef NOOP -# define NOOP /*EMPTY*/(void)0 -#endif - -#ifndef dNOOP -# define dNOOP extern int /*@unused@*/ Perl___notused PERL_UNUSED_DECL -#endif - -#ifndef NVTYPE -# if defined(USE_LONG_DOUBLE) && defined(HAS_LONG_DOUBLE) -# define NVTYPE long double -# else -# define NVTYPE double -# endif -typedef NVTYPE NV; -#endif - -#ifndef INT2PTR -# if (IVSIZE == PTRSIZE) && (UVSIZE == PTRSIZE) -# define PTRV UV -# define INT2PTR(any,d) (any)(d) -# else -# if PTRSIZE == LONGSIZE -# define PTRV unsigned long -# else -# define PTRV unsigned -# endif -# define INT2PTR(any,d) (any)(PTRV)(d) -# endif -#endif - -#ifndef PTR2ul -# if PTRSIZE == LONGSIZE -# define PTR2ul(p) (unsigned long)(p) -# else -# define PTR2ul(p) INT2PTR(unsigned long,p) -# endif -#endif -#ifndef PTR2nat -# define PTR2nat(p) (PTRV)(p) -#endif - -#ifndef NUM2PTR -# define NUM2PTR(any,d) (any)PTR2nat(d) -#endif - -#ifndef PTR2IV -# define PTR2IV(p) INT2PTR(IV,p) -#endif - -#ifndef PTR2UV -# define PTR2UV(p) INT2PTR(UV,p) -#endif - -#ifndef PTR2NV -# define PTR2NV(p) NUM2PTR(NV,p) -#endif - -#undef START_EXTERN_C -#undef END_EXTERN_C -#undef EXTERN_C -#ifdef __cplusplus -# define START_EXTERN_C extern "C" { -# define END_EXTERN_C } -# define EXTERN_C extern "C" -#else -# define START_EXTERN_C -# define END_EXTERN_C -# define EXTERN_C extern -#endif - -#if defined(PERL_GCC_PEDANTIC) -# ifndef PERL_GCC_BRACE_GROUPS_FORBIDDEN -# define PERL_GCC_BRACE_GROUPS_FORBIDDEN -# endif -#endif - -#if defined(__GNUC__) && !defined(PERL_GCC_BRACE_GROUPS_FORBIDDEN) && !defined(__cplusplus) -# ifndef PERL_USE_GCC_BRACE_GROUPS -# define PERL_USE_GCC_BRACE_GROUPS -# endif -#endif - -#undef STMT_START -#undef STMT_END -#ifdef PERL_USE_GCC_BRACE_GROUPS -# define STMT_START (void)( /* gcc supports ``({ STATEMENTS; })'' */ -# define STMT_END ) -#else -# if defined(VOIDFLAGS) && (VOIDFLAGS) && (defined(sun) || defined(__sun__)) && !defined(__GNUC__) -# define STMT_START if (1) -# define STMT_END else (void)0 -# else -# define STMT_START do -# define STMT_END while (0) -# endif -#endif -#ifndef boolSV -# define boolSV(b) ((b) ? &PL_sv_yes : &PL_sv_no) -#endif - -/* DEFSV appears first in 5.004_56 */ -#ifndef DEFSV -# define DEFSV GvSV(PL_defgv) -#endif - -#ifndef SAVE_DEFSV -# define SAVE_DEFSV SAVESPTR(GvSV(PL_defgv)) -#endif - -#ifndef DEFSV_set -# define DEFSV_set(sv) (DEFSV = (sv)) -#endif - -/* Older perls (<=5.003) lack AvFILLp */ -#ifndef AvFILLp -# define AvFILLp AvFILL -#endif -#ifndef ERRSV -# define ERRSV get_sv("@",FALSE) -#endif - -/* Hint: gv_stashpvn - * This function's backport doesn't support the length parameter, but - * rather ignores it. Portability can only be ensured if the length - * parameter is used for speed reasons, but the length can always be - * correctly computed from the string argument. - */ -#ifndef gv_stashpvn -# define gv_stashpvn(str,len,create) gv_stashpv(str,create) -#endif - -/* Replace: 1 */ -#ifndef get_cv -# define get_cv perl_get_cv -#endif - -#ifndef get_sv -# define get_sv perl_get_sv -#endif - -#ifndef get_av -# define get_av perl_get_av -#endif - -#ifndef get_hv -# define get_hv perl_get_hv -#endif - -/* Replace: 0 */ -#ifndef dUNDERBAR -# define dUNDERBAR dNOOP -#endif - -#ifndef UNDERBAR -# define UNDERBAR DEFSV -#endif -#ifndef dAX -# define dAX I32 ax = MARK - PL_stack_base + 1 -#endif - -#ifndef dITEMS -# define dITEMS I32 items = SP - MARK -#endif -#ifndef dXSTARG -# define dXSTARG SV * targ = sv_newmortal() -#endif -#ifndef dAXMARK -# define dAXMARK I32 ax = POPMARK; \ - register SV ** const mark = PL_stack_base + ax++ -#endif -#ifndef XSprePUSH -# define XSprePUSH (sp = PL_stack_base + ax - 1) -#endif - -#if (PERL_BCDVERSION < 0x5005000) -# undef XSRETURN -# define XSRETURN(off) \ - STMT_START { \ - PL_stack_sp = PL_stack_base + ax + ((off) - 1); \ - return; \ - } STMT_END -#endif -#ifndef XSPROTO -# define XSPROTO(name) void name(pTHX_ CV* cv) -#endif - -#ifndef SVfARG -# define SVfARG(p) ((void*)(p)) -#endif -#ifndef PERL_ABS -# define PERL_ABS(x) ((x) < 0 ? -(x) : (x)) -#endif -#ifndef dVAR -# define dVAR dNOOP -#endif -#ifndef SVf -# define SVf "_" -#endif -#ifndef UTF8_MAXBYTES -# define UTF8_MAXBYTES UTF8_MAXLEN -#endif -#ifndef CPERLscope -# define CPERLscope(x) x -#endif -#ifndef PERL_HASH -# define PERL_HASH(hash,str,len) \ - STMT_START { \ - const char *s_PeRlHaSh = str; \ - I32 i_PeRlHaSh = len; \ - U32 hash_PeRlHaSh = 0; \ - while (i_PeRlHaSh--) \ - hash_PeRlHaSh = hash_PeRlHaSh * 33 + *s_PeRlHaSh++; \ - (hash) = hash_PeRlHaSh; \ - } STMT_END -#endif - -#ifndef PERLIO_FUNCS_DECL -# ifdef PERLIO_FUNCS_CONST -# define PERLIO_FUNCS_DECL(funcs) const PerlIO_funcs funcs -# define PERLIO_FUNCS_CAST(funcs) (PerlIO_funcs*)(funcs) -# else -# define PERLIO_FUNCS_DECL(funcs) PerlIO_funcs funcs -# define PERLIO_FUNCS_CAST(funcs) (funcs) -# endif -#endif - -/* provide these typedefs for older perls */ -#if (PERL_BCDVERSION < 0x5009003) - -# ifdef ARGSproto -typedef OP* (CPERLscope(*Perl_ppaddr_t))(ARGSproto); -# else -typedef OP* (CPERLscope(*Perl_ppaddr_t))(pTHX); -# endif - -typedef OP* (CPERLscope(*Perl_check_t)) (pTHX_ OP*); - -#endif -#ifndef isPSXSPC -# define isPSXSPC(c) (isSPACE(c) || (c) == '\v') -#endif - -#ifndef isBLANK -# define isBLANK(c) ((c) == ' ' || (c) == '\t') -#endif - -#ifdef EBCDIC -#ifndef isALNUMC -# define isALNUMC(c) isalnum(c) -#endif - -#ifndef isASCII -# define isASCII(c) isascii(c) -#endif - -#ifndef isCNTRL -# define isCNTRL(c) iscntrl(c) -#endif - -#ifndef isGRAPH -# define isGRAPH(c) isgraph(c) -#endif - -#ifndef isPRINT -# define isPRINT(c) isprint(c) -#endif - -#ifndef isPUNCT -# define isPUNCT(c) ispunct(c) -#endif - -#ifndef isXDIGIT -# define isXDIGIT(c) isxdigit(c) -#endif - -#else -# if (PERL_BCDVERSION < 0x5010000) -/* Hint: isPRINT - * The implementation in older perl versions includes all of the - * isSPACE() characters, which is wrong. The version provided by - * Devel::PPPort always overrides a present buggy version. - */ -# undef isPRINT -# endif -#ifndef isALNUMC -# define isALNUMC(c) (isALPHA(c) || isDIGIT(c)) -#endif - -#ifndef isASCII -# define isASCII(c) ((c) <= 127) -#endif - -#ifndef isCNTRL -# define isCNTRL(c) ((c) < ' ' || (c) == 127) -#endif - -#ifndef isGRAPH -# define isGRAPH(c) (isALNUM(c) || isPUNCT(c)) -#endif - -#ifndef isPRINT -# define isPRINT(c) (((c) >= 32 && (c) < 127)) -#endif - -#ifndef isPUNCT -# define isPUNCT(c) (((c) >= 33 && (c) <= 47) || ((c) >= 58 && (c) <= 64) || ((c) >= 91 && (c) <= 96) || ((c) >= 123 && (c) <= 126)) -#endif - -#ifndef isXDIGIT -# define isXDIGIT(c) (isDIGIT(c) || ((c) >= 'a' && (c) <= 'f') || ((c) >= 'A' && (c) <= 'F')) -#endif - -#endif - -#ifndef PERL_SIGNALS_UNSAFE_FLAG - -#define PERL_SIGNALS_UNSAFE_FLAG 0x0001 - -#if (PERL_BCDVERSION < 0x5008000) -# define D_PPP_PERL_SIGNALS_INIT PERL_SIGNALS_UNSAFE_FLAG -#else -# define D_PPP_PERL_SIGNALS_INIT 0 -#endif - -#if defined(NEED_PL_signals) -static U32 DPPP_(my_PL_signals) = D_PPP_PERL_SIGNALS_INIT; -#elif defined(NEED_PL_signals_GLOBAL) -U32 DPPP_(my_PL_signals) = D_PPP_PERL_SIGNALS_INIT; -#else -extern U32 DPPP_(my_PL_signals); -#endif -#define PL_signals DPPP_(my_PL_signals) - -#endif - -/* Hint: PL_ppaddr - * Calling an op via PL_ppaddr requires passing a context argument - * for threaded builds. Since the context argument is different for - * 5.005 perls, you can use aTHXR (supplied by ppport.h), which will - * automatically be defined as the correct argument. - */ - -#if (PERL_BCDVERSION <= 0x5005005) -/* Replace: 1 */ -# define PL_ppaddr ppaddr -# define PL_no_modify no_modify -/* Replace: 0 */ -#endif - -#if (PERL_BCDVERSION <= 0x5004005) -/* Replace: 1 */ -# define PL_DBsignal DBsignal -# define PL_DBsingle DBsingle -# define PL_DBsub DBsub -# define PL_DBtrace DBtrace -# define PL_Sv Sv -# define PL_bufend bufend -# define PL_bufptr bufptr -# define PL_compiling compiling -# define PL_copline copline -# define PL_curcop curcop -# define PL_curstash curstash -# define PL_debstash debstash -# define PL_defgv defgv -# define PL_diehook diehook -# define PL_dirty dirty -# define PL_dowarn dowarn -# define PL_errgv errgv -# define PL_error_count error_count -# define PL_expect expect -# define PL_hexdigit hexdigit -# define PL_hints hints -# define PL_in_my in_my -# define PL_laststatval laststatval -# define PL_lex_state lex_state -# define PL_lex_stuff lex_stuff -# define PL_linestr linestr -# define PL_na na -# define PL_perl_destruct_level perl_destruct_level -# define PL_perldb perldb -# define PL_rsfp_filters rsfp_filters -# define PL_rsfp rsfp -# define PL_stack_base stack_base -# define PL_stack_sp stack_sp -# define PL_statcache statcache -# define PL_stdingv stdingv -# define PL_sv_arenaroot sv_arenaroot -# define PL_sv_no sv_no -# define PL_sv_undef sv_undef -# define PL_sv_yes sv_yes -# define PL_tainted tainted -# define PL_tainting tainting -# define PL_tokenbuf tokenbuf -/* Replace: 0 */ -#endif - -/* Warning: PL_parser - * For perl versions earlier than 5.9.5, this is an always - * non-NULL dummy. Also, it cannot be dereferenced. Don't - * use it if you can avoid is and unless you absolutely know - * what you're doing. - * If you always check that PL_parser is non-NULL, you can - * define DPPP_PL_parser_NO_DUMMY to avoid the creation of - * a dummy parser structure. - */ - -#if (PERL_BCDVERSION >= 0x5009005) -# ifdef DPPP_PL_parser_NO_DUMMY -# define D_PPP_my_PL_parser_var(var) ((PL_parser ? PL_parser : \ - (croak("panic: PL_parser == NULL in %s:%d", \ - __FILE__, __LINE__), (yy_parser *) NULL))->var) -# else -# ifdef DPPP_PL_parser_NO_DUMMY_WARNING -# define D_PPP_parser_dummy_warning(var) -# else -# define D_PPP_parser_dummy_warning(var) \ - warn("warning: dummy PL_" #var " used in %s:%d", __FILE__, __LINE__), -# endif -# define D_PPP_my_PL_parser_var(var) ((PL_parser ? PL_parser : \ - (D_PPP_parser_dummy_warning(var) &DPPP_(dummy_PL_parser)))->var) -#if defined(NEED_PL_parser) -static yy_parser DPPP_(dummy_PL_parser); -#elif defined(NEED_PL_parser_GLOBAL) -yy_parser DPPP_(dummy_PL_parser); -#else -extern yy_parser DPPP_(dummy_PL_parser); -#endif - -# endif - -/* PL_expect, PL_copline, PL_rsfp, PL_rsfp_filters, PL_linestr, PL_bufptr, PL_bufend, PL_lex_state, PL_lex_stuff, PL_tokenbuf depends on PL_parser */ -/* Warning: PL_expect, PL_copline, PL_rsfp, PL_rsfp_filters, PL_linestr, PL_bufptr, PL_bufend, PL_lex_state, PL_lex_stuff, PL_tokenbuf - * Do not use this variable unless you know exactly what you're - * doint. It is internal to the perl parser and may change or even - * be removed in the future. As of perl 5.9.5, you have to check - * for (PL_parser != NULL) for this variable to have any effect. - * An always non-NULL PL_parser dummy is provided for earlier - * perl versions. - * If PL_parser is NULL when you try to access this variable, a - * dummy is being accessed instead and a warning is issued unless - * you define DPPP_PL_parser_NO_DUMMY_WARNING. - * If DPPP_PL_parser_NO_DUMMY is defined, the code trying to access - * this variable will croak with a panic message. - */ - -# define PL_expect D_PPP_my_PL_parser_var(expect) -# define PL_copline D_PPP_my_PL_parser_var(copline) -# define PL_rsfp D_PPP_my_PL_parser_var(rsfp) -# define PL_rsfp_filters D_PPP_my_PL_parser_var(rsfp_filters) -# define PL_linestr D_PPP_my_PL_parser_var(linestr) -# define PL_bufptr D_PPP_my_PL_parser_var(bufptr) -# define PL_bufend D_PPP_my_PL_parser_var(bufend) -# define PL_lex_state D_PPP_my_PL_parser_var(lex_state) -# define PL_lex_stuff D_PPP_my_PL_parser_var(lex_stuff) -# define PL_tokenbuf D_PPP_my_PL_parser_var(tokenbuf) -# define PL_in_my D_PPP_my_PL_parser_var(in_my) -# define PL_in_my_stash D_PPP_my_PL_parser_var(in_my_stash) -# define PL_error_count D_PPP_my_PL_parser_var(error_count) - - -#else - -/* ensure that PL_parser != NULL and cannot be dereferenced */ -# define PL_parser ((void *) 1) - -#endif -#ifndef mPUSHs -# define mPUSHs(s) PUSHs(sv_2mortal(s)) -#endif - -#ifndef PUSHmortal -# define PUSHmortal PUSHs(sv_newmortal()) -#endif - -#ifndef mPUSHp -# define mPUSHp(p,l) sv_setpvn(PUSHmortal, (p), (l)) -#endif - -#ifndef mPUSHn -# define mPUSHn(n) sv_setnv(PUSHmortal, (NV)(n)) -#endif - -#ifndef mPUSHi -# define mPUSHi(i) sv_setiv(PUSHmortal, (IV)(i)) -#endif - -#ifndef mPUSHu -# define mPUSHu(u) sv_setuv(PUSHmortal, (UV)(u)) -#endif -#ifndef mXPUSHs -# define mXPUSHs(s) XPUSHs(sv_2mortal(s)) -#endif - -#ifndef XPUSHmortal -# define XPUSHmortal XPUSHs(sv_newmortal()) -#endif - -#ifndef mXPUSHp -# define mXPUSHp(p,l) STMT_START { EXTEND(sp,1); sv_setpvn(PUSHmortal, (p), (l)); } STMT_END -#endif - -#ifndef mXPUSHn -# define mXPUSHn(n) STMT_START { EXTEND(sp,1); sv_setnv(PUSHmortal, (NV)(n)); } STMT_END -#endif - -#ifndef mXPUSHi -# define mXPUSHi(i) STMT_START { EXTEND(sp,1); sv_setiv(PUSHmortal, (IV)(i)); } STMT_END -#endif - -#ifndef mXPUSHu -# define mXPUSHu(u) STMT_START { EXTEND(sp,1); sv_setuv(PUSHmortal, (UV)(u)); } STMT_END -#endif - -/* Replace: 1 */ -#ifndef call_sv -# define call_sv perl_call_sv -#endif - -#ifndef call_pv -# define call_pv perl_call_pv -#endif - -#ifndef call_argv -# define call_argv perl_call_argv -#endif - -#ifndef call_method -# define call_method perl_call_method -#endif -#ifndef eval_sv -# define eval_sv perl_eval_sv -#endif - -/* Replace: 0 */ -#ifndef PERL_LOADMOD_DENY -# define PERL_LOADMOD_DENY 0x1 -#endif - -#ifndef PERL_LOADMOD_NOIMPORT -# define PERL_LOADMOD_NOIMPORT 0x2 -#endif - -#ifndef PERL_LOADMOD_IMPORT_OPS -# define PERL_LOADMOD_IMPORT_OPS 0x4 -#endif - -#ifndef G_METHOD -# define G_METHOD 64 -# ifdef call_sv -# undef call_sv -# endif -# if (PERL_BCDVERSION < 0x5006000) -# define call_sv(sv, flags) ((flags) & G_METHOD ? perl_call_method((char *) SvPV_nolen_const(sv), \ - (flags) & ~G_METHOD) : perl_call_sv(sv, flags)) -# else -# define call_sv(sv, flags) ((flags) & G_METHOD ? Perl_call_method(aTHX_ (char *) SvPV_nolen_const(sv), \ - (flags) & ~G_METHOD) : Perl_call_sv(aTHX_ sv, flags)) -# endif -#endif - -/* Replace perl_eval_pv with eval_pv */ - -#ifndef eval_pv -#if defined(NEED_eval_pv) -static SV* DPPP_(my_eval_pv)(char *p, I32 croak_on_error); -static -#else -extern SV* DPPP_(my_eval_pv)(char *p, I32 croak_on_error); -#endif - -#ifdef eval_pv -# undef eval_pv -#endif -#define eval_pv(a,b) DPPP_(my_eval_pv)(aTHX_ a,b) -#define Perl_eval_pv DPPP_(my_eval_pv) - -#if defined(NEED_eval_pv) || defined(NEED_eval_pv_GLOBAL) - -SV* -DPPP_(my_eval_pv)(char *p, I32 croak_on_error) -{ - dSP; - SV* sv = newSVpv(p, 0); - - PUSHMARK(sp); - eval_sv(sv, G_SCALAR); - SvREFCNT_dec(sv); - - SPAGAIN; - sv = POPs; - PUTBACK; - - if (croak_on_error && SvTRUE(GvSV(errgv))) - croak(SvPVx(GvSV(errgv), na)); - - return sv; -} - -#endif -#endif - -#ifndef vload_module -#if defined(NEED_vload_module) -static void DPPP_(my_vload_module)(U32 flags, SV *name, SV *ver, va_list *args); -static -#else -extern void DPPP_(my_vload_module)(U32 flags, SV *name, SV *ver, va_list *args); -#endif - -#ifdef vload_module -# undef vload_module -#endif -#define vload_module(a,b,c,d) DPPP_(my_vload_module)(aTHX_ a,b,c,d) -#define Perl_vload_module DPPP_(my_vload_module) - -#if defined(NEED_vload_module) || defined(NEED_vload_module_GLOBAL) - -void -DPPP_(my_vload_module)(U32 flags, SV *name, SV *ver, va_list *args) -{ - dTHR; - dVAR; - OP *veop, *imop; - - OP * const modname = newSVOP(OP_CONST, 0, name); - /* 5.005 has a somewhat hacky force_normal that doesn't croak on - SvREADONLY() if PL_compling is true. Current perls take care in - ck_require() to correctly turn off SvREADONLY before calling - force_normal_flags(). This seems a better fix than fudging PL_compling - */ - SvREADONLY_off(((SVOP*)modname)->op_sv); - modname->op_private |= OPpCONST_BARE; - if (ver) { - veop = newSVOP(OP_CONST, 0, ver); - } - else - veop = NULL; - if (flags & PERL_LOADMOD_NOIMPORT) { - imop = sawparens(newNULLLIST()); - } - else if (flags & PERL_LOADMOD_IMPORT_OPS) { - imop = va_arg(*args, OP*); - } - else { - SV *sv; - imop = NULL; - sv = va_arg(*args, SV*); - while (sv) { - imop = append_elem(OP_LIST, imop, newSVOP(OP_CONST, 0, sv)); - sv = va_arg(*args, SV*); - } - } - { - const line_t ocopline = PL_copline; - COP * const ocurcop = PL_curcop; - const int oexpect = PL_expect; - -#if (PERL_BCDVERSION >= 0x5004000) - utilize(!(flags & PERL_LOADMOD_DENY), start_subparse(FALSE, 0), - veop, modname, imop); -#else - utilize(!(flags & PERL_LOADMOD_DENY), start_subparse(), - modname, imop); -#endif - PL_expect = oexpect; - PL_copline = ocopline; - PL_curcop = ocurcop; - } -} - -#endif -#endif - -#ifndef load_module -#if defined(NEED_load_module) -static void DPPP_(my_load_module)(U32 flags, SV *name, SV *ver, ...); -static -#else -extern void DPPP_(my_load_module)(U32 flags, SV *name, SV *ver, ...); -#endif - -#ifdef load_module -# undef load_module -#endif -#define load_module DPPP_(my_load_module) -#define Perl_load_module DPPP_(my_load_module) - -#if defined(NEED_load_module) || defined(NEED_load_module_GLOBAL) - -void -DPPP_(my_load_module)(U32 flags, SV *name, SV *ver, ...) -{ - va_list args; - va_start(args, ver); - vload_module(flags, name, ver, &args); - va_end(args); -} - -#endif -#endif -#ifndef newRV_inc -# define newRV_inc(sv) newRV(sv) /* Replace */ -#endif - -#ifndef newRV_noinc -#if defined(NEED_newRV_noinc) -static SV * DPPP_(my_newRV_noinc)(SV *sv); -static -#else -extern SV * DPPP_(my_newRV_noinc)(SV *sv); -#endif - -#ifdef newRV_noinc -# undef newRV_noinc -#endif -#define newRV_noinc(a) DPPP_(my_newRV_noinc)(aTHX_ a) -#define Perl_newRV_noinc DPPP_(my_newRV_noinc) - -#if defined(NEED_newRV_noinc) || defined(NEED_newRV_noinc_GLOBAL) -SV * -DPPP_(my_newRV_noinc)(SV *sv) -{ - SV *rv = (SV *)newRV(sv); - SvREFCNT_dec(sv); - return rv; -} -#endif -#endif - -/* Hint: newCONSTSUB - * Returns a CV* as of perl-5.7.1. This return value is not supported - * by Devel::PPPort. - */ - -/* newCONSTSUB from IO.xs is in the core starting with 5.004_63 */ -#if (PERL_BCDVERSION < 0x5004063) && (PERL_BCDVERSION != 0x5004005) -#if defined(NEED_newCONSTSUB) -static void DPPP_(my_newCONSTSUB)(HV *stash, const char *name, SV *sv); -static -#else -extern void DPPP_(my_newCONSTSUB)(HV *stash, const char *name, SV *sv); -#endif - -#ifdef newCONSTSUB -# undef newCONSTSUB -#endif -#define newCONSTSUB(a,b,c) DPPP_(my_newCONSTSUB)(aTHX_ a,b,c) -#define Perl_newCONSTSUB DPPP_(my_newCONSTSUB) - -#if defined(NEED_newCONSTSUB) || defined(NEED_newCONSTSUB_GLOBAL) - -/* This is just a trick to avoid a dependency of newCONSTSUB on PL_parser */ -/* (There's no PL_parser in perl < 5.005, so this is completely safe) */ -#define D_PPP_PL_copline PL_copline - -void -DPPP_(my_newCONSTSUB)(HV *stash, const char *name, SV *sv) -{ - U32 oldhints = PL_hints; - HV *old_cop_stash = PL_curcop->cop_stash; - HV *old_curstash = PL_curstash; - line_t oldline = PL_curcop->cop_line; - PL_curcop->cop_line = D_PPP_PL_copline; - - PL_hints &= ~HINT_BLOCK_SCOPE; - if (stash) - PL_curstash = PL_curcop->cop_stash = stash; - - newSUB( - -#if (PERL_BCDVERSION < 0x5003022) - start_subparse(), -#elif (PERL_BCDVERSION == 0x5003022) - start_subparse(0), -#else /* 5.003_23 onwards */ - start_subparse(FALSE, 0), -#endif - - newSVOP(OP_CONST, 0, newSVpv((char *) name, 0)), - newSVOP(OP_CONST, 0, &PL_sv_no), /* SvPV(&PL_sv_no) == "" -- GMB */ - newSTATEOP(0, Nullch, newSVOP(OP_CONST, 0, sv)) - ); - - PL_hints = oldhints; - PL_curcop->cop_stash = old_cop_stash; - PL_curstash = old_curstash; - PL_curcop->cop_line = oldline; -} -#endif -#endif - -/* - * Boilerplate macros for initializing and accessing interpreter-local - * data from C. All statics in extensions should be reworked to use - * this, if you want to make the extension thread-safe. See ext/re/re.xs - * for an example of the use of these macros. - * - * Code that uses these macros is responsible for the following: - * 1. #define MY_CXT_KEY to a unique string, e.g. "DynaLoader_guts" - * 2. Declare a typedef named my_cxt_t that is a structure that contains - * all the data that needs to be interpreter-local. - * 3. Use the START_MY_CXT macro after the declaration of my_cxt_t. - * 4. Use the MY_CXT_INIT macro such that it is called exactly once - * (typically put in the BOOT: section). - * 5. Use the members of the my_cxt_t structure everywhere as - * MY_CXT.member. - * 6. Use the dMY_CXT macro (a declaration) in all the functions that - * access MY_CXT. - */ - -#if defined(MULTIPLICITY) || defined(PERL_OBJECT) || \ - defined(PERL_CAPI) || defined(PERL_IMPLICIT_CONTEXT) - -#ifndef START_MY_CXT - -/* This must appear in all extensions that define a my_cxt_t structure, - * right after the definition (i.e. at file scope). The non-threads - * case below uses it to declare the data as static. */ -#define START_MY_CXT - -#if (PERL_BCDVERSION < 0x5004068) -/* Fetches the SV that keeps the per-interpreter data. */ -#define dMY_CXT_SV \ - SV *my_cxt_sv = get_sv(MY_CXT_KEY, FALSE) -#else /* >= perl5.004_68 */ -#define dMY_CXT_SV \ - SV *my_cxt_sv = *hv_fetch(PL_modglobal, MY_CXT_KEY, \ - sizeof(MY_CXT_KEY)-1, TRUE) -#endif /* < perl5.004_68 */ - -/* This declaration should be used within all functions that use the - * interpreter-local data. */ -#define dMY_CXT \ - dMY_CXT_SV; \ - my_cxt_t *my_cxtp = INT2PTR(my_cxt_t*,SvUV(my_cxt_sv)) - -/* Creates and zeroes the per-interpreter data. - * (We allocate my_cxtp in a Perl SV so that it will be released when - * the interpreter goes away.) */ -#define MY_CXT_INIT \ - dMY_CXT_SV; \ - /* newSV() allocates one more than needed */ \ - my_cxt_t *my_cxtp = (my_cxt_t*)SvPVX(newSV(sizeof(my_cxt_t)-1));\ - Zero(my_cxtp, 1, my_cxt_t); \ - sv_setuv(my_cxt_sv, PTR2UV(my_cxtp)) - -/* This macro must be used to access members of the my_cxt_t structure. - * e.g. MYCXT.some_data */ -#define MY_CXT (*my_cxtp) - -/* Judicious use of these macros can reduce the number of times dMY_CXT - * is used. Use is similar to pTHX, aTHX etc. */ -#define pMY_CXT my_cxt_t *my_cxtp -#define pMY_CXT_ pMY_CXT, -#define _pMY_CXT ,pMY_CXT -#define aMY_CXT my_cxtp -#define aMY_CXT_ aMY_CXT, -#define _aMY_CXT ,aMY_CXT - -#endif /* START_MY_CXT */ - -#ifndef MY_CXT_CLONE -/* Clones the per-interpreter data. */ -#define MY_CXT_CLONE \ - dMY_CXT_SV; \ - my_cxt_t *my_cxtp = (my_cxt_t*)SvPVX(newSV(sizeof(my_cxt_t)-1));\ - Copy(INT2PTR(my_cxt_t*, SvUV(my_cxt_sv)), my_cxtp, 1, my_cxt_t);\ - sv_setuv(my_cxt_sv, PTR2UV(my_cxtp)) -#endif - -#else /* single interpreter */ - -#ifndef START_MY_CXT - -#define START_MY_CXT static my_cxt_t my_cxt; -#define dMY_CXT_SV dNOOP -#define dMY_CXT dNOOP -#define MY_CXT_INIT NOOP -#define MY_CXT my_cxt - -#define pMY_CXT void -#define pMY_CXT_ -#define _pMY_CXT -#define aMY_CXT -#define aMY_CXT_ -#define _aMY_CXT - -#endif /* START_MY_CXT */ - -#ifndef MY_CXT_CLONE -#define MY_CXT_CLONE NOOP -#endif - -#endif - -#ifndef IVdf -# if IVSIZE == LONGSIZE -# define IVdf "ld" -# define UVuf "lu" -# define UVof "lo" -# define UVxf "lx" -# define UVXf "lX" -# else -# if IVSIZE == INTSIZE -# define IVdf "d" -# define UVuf "u" -# define UVof "o" -# define UVxf "x" -# define UVXf "X" -# endif -# endif -#endif - -#ifndef NVef -# if defined(USE_LONG_DOUBLE) && defined(HAS_LONG_DOUBLE) && \ - defined(PERL_PRIfldbl) && (PERL_BCDVERSION != 0x5006000) - /* Not very likely, but let's try anyway. */ -# define NVef PERL_PRIeldbl -# define NVff PERL_PRIfldbl -# define NVgf PERL_PRIgldbl -# else -# define NVef "e" -# define NVff "f" -# define NVgf "g" -# endif -#endif - -#ifndef SvREFCNT_inc -# ifdef PERL_USE_GCC_BRACE_GROUPS -# define SvREFCNT_inc(sv) \ - ({ \ - SV * const _sv = (SV*)(sv); \ - if (_sv) \ - (SvREFCNT(_sv))++; \ - _sv; \ - }) -# else -# define SvREFCNT_inc(sv) \ - ((PL_Sv=(SV*)(sv)) ? (++(SvREFCNT(PL_Sv)),PL_Sv) : NULL) -# endif -#endif - -#ifndef SvREFCNT_inc_simple -# ifdef PERL_USE_GCC_BRACE_GROUPS -# define SvREFCNT_inc_simple(sv) \ - ({ \ - if (sv) \ - (SvREFCNT(sv))++; \ - (SV *)(sv); \ - }) -# else -# define SvREFCNT_inc_simple(sv) \ - ((sv) ? (SvREFCNT(sv)++,(SV*)(sv)) : NULL) -# endif -#endif - -#ifndef SvREFCNT_inc_NN -# ifdef PERL_USE_GCC_BRACE_GROUPS -# define SvREFCNT_inc_NN(sv) \ - ({ \ - SV * const _sv = (SV*)(sv); \ - SvREFCNT(_sv)++; \ - _sv; \ - }) -# else -# define SvREFCNT_inc_NN(sv) \ - (PL_Sv=(SV*)(sv),++(SvREFCNT(PL_Sv)),PL_Sv) -# endif -#endif - -#ifndef SvREFCNT_inc_void -# ifdef PERL_USE_GCC_BRACE_GROUPS -# define SvREFCNT_inc_void(sv) \ - ({ \ - SV * const _sv = (SV*)(sv); \ - if (_sv) \ - (void)(SvREFCNT(_sv)++); \ - }) -# else -# define SvREFCNT_inc_void(sv) \ - (void)((PL_Sv=(SV*)(sv)) ? ++(SvREFCNT(PL_Sv)) : 0) -# endif -#endif -#ifndef SvREFCNT_inc_simple_void -# define SvREFCNT_inc_simple_void(sv) STMT_START { if (sv) SvREFCNT(sv)++; } STMT_END -#endif - -#ifndef SvREFCNT_inc_simple_NN -# define SvREFCNT_inc_simple_NN(sv) (++SvREFCNT(sv), (SV*)(sv)) -#endif - -#ifndef SvREFCNT_inc_void_NN -# define SvREFCNT_inc_void_NN(sv) (void)(++SvREFCNT((SV*)(sv))) -#endif - -#ifndef SvREFCNT_inc_simple_void_NN -# define SvREFCNT_inc_simple_void_NN(sv) (void)(++SvREFCNT((SV*)(sv))) -#endif - -#ifndef newSV_type - -#if defined(NEED_newSV_type) -static SV* DPPP_(my_newSV_type)(pTHX_ svtype const t); -static -#else -extern SV* DPPP_(my_newSV_type)(pTHX_ svtype const t); -#endif - -#ifdef newSV_type -# undef newSV_type -#endif -#define newSV_type(a) DPPP_(my_newSV_type)(aTHX_ a) -#define Perl_newSV_type DPPP_(my_newSV_type) - -#if defined(NEED_newSV_type) || defined(NEED_newSV_type_GLOBAL) - -SV* -DPPP_(my_newSV_type)(pTHX_ svtype const t) -{ - SV* const sv = newSV(0); - sv_upgrade(sv, t); - return sv; -} - -#endif - -#endif - -#if (PERL_BCDVERSION < 0x5006000) -# define D_PPP_CONSTPV_ARG(x) ((char *) (x)) -#else -# define D_PPP_CONSTPV_ARG(x) (x) -#endif -#ifndef newSVpvn -# define newSVpvn(data,len) ((data) \ - ? ((len) ? newSVpv((data), (len)) : newSVpv("", 0)) \ - : newSV(0)) -#endif -#ifndef newSVpvn_utf8 -# define newSVpvn_utf8(s, len, u) newSVpvn_flags((s), (len), (u) ? SVf_UTF8 : 0) -#endif -#ifndef SVf_UTF8 -# define SVf_UTF8 0 -#endif - -#ifndef newSVpvn_flags - -#if defined(NEED_newSVpvn_flags) -static SV * DPPP_(my_newSVpvn_flags)(pTHX_ const char *s, STRLEN len, U32 flags); -static -#else -extern SV * DPPP_(my_newSVpvn_flags)(pTHX_ const char *s, STRLEN len, U32 flags); -#endif - -#ifdef newSVpvn_flags -# undef newSVpvn_flags -#endif -#define newSVpvn_flags(a,b,c) DPPP_(my_newSVpvn_flags)(aTHX_ a,b,c) -#define Perl_newSVpvn_flags DPPP_(my_newSVpvn_flags) - -#if defined(NEED_newSVpvn_flags) || defined(NEED_newSVpvn_flags_GLOBAL) - -SV * -DPPP_(my_newSVpvn_flags)(pTHX_ const char *s, STRLEN len, U32 flags) -{ - SV *sv = newSVpvn(D_PPP_CONSTPV_ARG(s), len); - SvFLAGS(sv) |= (flags & SVf_UTF8); - return (flags & SVs_TEMP) ? sv_2mortal(sv) : sv; -} - -#endif - -#endif - -/* Backwards compatibility stuff... :-( */ -#if !defined(NEED_sv_2pv_flags) && defined(NEED_sv_2pv_nolen) -# define NEED_sv_2pv_flags -#endif -#if !defined(NEED_sv_2pv_flags_GLOBAL) && defined(NEED_sv_2pv_nolen_GLOBAL) -# define NEED_sv_2pv_flags_GLOBAL -#endif - -/* Hint: sv_2pv_nolen - * Use the SvPV_nolen() or SvPV_nolen_const() macros instead of sv_2pv_nolen(). - */ -#ifndef sv_2pv_nolen -# define sv_2pv_nolen(sv) SvPV_nolen(sv) -#endif - -#ifdef SvPVbyte - -/* Hint: SvPVbyte - * Does not work in perl-5.6.1, ppport.h implements a version - * borrowed from perl-5.7.3. - */ - -#if (PERL_BCDVERSION < 0x5007000) - -#if defined(NEED_sv_2pvbyte) -static char * DPPP_(my_sv_2pvbyte)(pTHX_ SV *sv, STRLEN *lp); -static -#else -extern char * DPPP_(my_sv_2pvbyte)(pTHX_ SV *sv, STRLEN *lp); -#endif - -#ifdef sv_2pvbyte -# undef sv_2pvbyte -#endif -#define sv_2pvbyte(a,b) DPPP_(my_sv_2pvbyte)(aTHX_ a,b) -#define Perl_sv_2pvbyte DPPP_(my_sv_2pvbyte) - -#if defined(NEED_sv_2pvbyte) || defined(NEED_sv_2pvbyte_GLOBAL) - -char * -DPPP_(my_sv_2pvbyte)(pTHX_ SV *sv, STRLEN *lp) -{ - sv_utf8_downgrade(sv,0); - return SvPV(sv,*lp); -} - -#endif - -/* Hint: sv_2pvbyte - * Use the SvPVbyte() macro instead of sv_2pvbyte(). - */ - -#undef SvPVbyte - -#define SvPVbyte(sv, lp) \ - ((SvFLAGS(sv) & (SVf_POK|SVf_UTF8)) == (SVf_POK) \ - ? ((lp = SvCUR(sv)), SvPVX(sv)) : sv_2pvbyte(sv, &lp)) - -#endif - -#else - -# define SvPVbyte SvPV -# define sv_2pvbyte sv_2pv - -#endif -#ifndef sv_2pvbyte_nolen -# define sv_2pvbyte_nolen(sv) sv_2pv_nolen(sv) -#endif - -/* Hint: sv_pvn - * Always use the SvPV() macro instead of sv_pvn(). - */ - -/* Hint: sv_pvn_force - * Always use the SvPV_force() macro instead of sv_pvn_force(). - */ - -/* If these are undefined, they're not handled by the core anyway */ -#ifndef SV_IMMEDIATE_UNREF -# define SV_IMMEDIATE_UNREF 0 -#endif - -#ifndef SV_GMAGIC -# define SV_GMAGIC 0 -#endif - -#ifndef SV_COW_DROP_PV -# define SV_COW_DROP_PV 0 -#endif - -#ifndef SV_UTF8_NO_ENCODING -# define SV_UTF8_NO_ENCODING 0 -#endif - -#ifndef SV_NOSTEAL -# define SV_NOSTEAL 0 -#endif - -#ifndef SV_CONST_RETURN -# define SV_CONST_RETURN 0 -#endif - -#ifndef SV_MUTABLE_RETURN -# define SV_MUTABLE_RETURN 0 -#endif - -#ifndef SV_SMAGIC -# define SV_SMAGIC 0 -#endif - -#ifndef SV_HAS_TRAILING_NUL -# define SV_HAS_TRAILING_NUL 0 -#endif - -#ifndef SV_COW_SHARED_HASH_KEYS -# define SV_COW_SHARED_HASH_KEYS 0 -#endif - -#if (PERL_BCDVERSION < 0x5007002) - -#if defined(NEED_sv_2pv_flags) -static char * DPPP_(my_sv_2pv_flags)(pTHX_ SV *sv, STRLEN *lp, I32 flags); -static -#else -extern char * DPPP_(my_sv_2pv_flags)(pTHX_ SV *sv, STRLEN *lp, I32 flags); -#endif - -#ifdef sv_2pv_flags -# undef sv_2pv_flags -#endif -#define sv_2pv_flags(a,b,c) DPPP_(my_sv_2pv_flags)(aTHX_ a,b,c) -#define Perl_sv_2pv_flags DPPP_(my_sv_2pv_flags) - -#if defined(NEED_sv_2pv_flags) || defined(NEED_sv_2pv_flags_GLOBAL) - -char * -DPPP_(my_sv_2pv_flags)(pTHX_ SV *sv, STRLEN *lp, I32 flags) -{ - STRLEN n_a = (STRLEN) flags; - return sv_2pv(sv, lp ? lp : &n_a); -} - -#endif - -#if defined(NEED_sv_pvn_force_flags) -static char * DPPP_(my_sv_pvn_force_flags)(pTHX_ SV *sv, STRLEN *lp, I32 flags); -static -#else -extern char * DPPP_(my_sv_pvn_force_flags)(pTHX_ SV *sv, STRLEN *lp, I32 flags); -#endif - -#ifdef sv_pvn_force_flags -# undef sv_pvn_force_flags -#endif -#define sv_pvn_force_flags(a,b,c) DPPP_(my_sv_pvn_force_flags)(aTHX_ a,b,c) -#define Perl_sv_pvn_force_flags DPPP_(my_sv_pvn_force_flags) - -#if defined(NEED_sv_pvn_force_flags) || defined(NEED_sv_pvn_force_flags_GLOBAL) - -char * -DPPP_(my_sv_pvn_force_flags)(pTHX_ SV *sv, STRLEN *lp, I32 flags) -{ - STRLEN n_a = (STRLEN) flags; - return sv_pvn_force(sv, lp ? lp : &n_a); -} - -#endif - -#endif - -#if (PERL_BCDVERSION < 0x5008008) || ( (PERL_BCDVERSION >= 0x5009000) && (PERL_BCDVERSION < 0x5009003) ) -# define DPPP_SVPV_NOLEN_LP_ARG &PL_na -#else -# define DPPP_SVPV_NOLEN_LP_ARG 0 -#endif -#ifndef SvPV_const -# define SvPV_const(sv, lp) SvPV_flags_const(sv, lp, SV_GMAGIC) -#endif - -#ifndef SvPV_mutable -# define SvPV_mutable(sv, lp) SvPV_flags_mutable(sv, lp, SV_GMAGIC) -#endif -#ifndef SvPV_flags -# define SvPV_flags(sv, lp, flags) \ - ((SvFLAGS(sv) & (SVf_POK)) == SVf_POK \ - ? ((lp = SvCUR(sv)), SvPVX(sv)) : sv_2pv_flags(sv, &lp, flags)) -#endif -#ifndef SvPV_flags_const -# define SvPV_flags_const(sv, lp, flags) \ - ((SvFLAGS(sv) & (SVf_POK)) == SVf_POK \ - ? ((lp = SvCUR(sv)), SvPVX_const(sv)) : \ - (const char*) sv_2pv_flags(sv, &lp, flags|SV_CONST_RETURN)) -#endif -#ifndef SvPV_flags_const_nolen -# define SvPV_flags_const_nolen(sv, flags) \ - ((SvFLAGS(sv) & (SVf_POK)) == SVf_POK \ - ? SvPVX_const(sv) : \ - (const char*) sv_2pv_flags(sv, DPPP_SVPV_NOLEN_LP_ARG, flags|SV_CONST_RETURN)) -#endif -#ifndef SvPV_flags_mutable -# define SvPV_flags_mutable(sv, lp, flags) \ - ((SvFLAGS(sv) & (SVf_POK)) == SVf_POK \ - ? ((lp = SvCUR(sv)), SvPVX_mutable(sv)) : \ - sv_2pv_flags(sv, &lp, flags|SV_MUTABLE_RETURN)) -#endif -#ifndef SvPV_force -# define SvPV_force(sv, lp) SvPV_force_flags(sv, lp, SV_GMAGIC) -#endif - -#ifndef SvPV_force_nolen -# define SvPV_force_nolen(sv) SvPV_force_flags_nolen(sv, SV_GMAGIC) -#endif - -#ifndef SvPV_force_mutable -# define SvPV_force_mutable(sv, lp) SvPV_force_flags_mutable(sv, lp, SV_GMAGIC) -#endif - -#ifndef SvPV_force_nomg -# define SvPV_force_nomg(sv, lp) SvPV_force_flags(sv, lp, 0) -#endif - -#ifndef SvPV_force_nomg_nolen -# define SvPV_force_nomg_nolen(sv) SvPV_force_flags_nolen(sv, 0) -#endif -#ifndef SvPV_force_flags -# define SvPV_force_flags(sv, lp, flags) \ - ((SvFLAGS(sv) & (SVf_POK|SVf_THINKFIRST)) == SVf_POK \ - ? ((lp = SvCUR(sv)), SvPVX(sv)) : sv_pvn_force_flags(sv, &lp, flags)) -#endif -#ifndef SvPV_force_flags_nolen -# define SvPV_force_flags_nolen(sv, flags) \ - ((SvFLAGS(sv) & (SVf_POK|SVf_THINKFIRST)) == SVf_POK \ - ? SvPVX(sv) : sv_pvn_force_flags(sv, DPPP_SVPV_NOLEN_LP_ARG, flags)) -#endif -#ifndef SvPV_force_flags_mutable -# define SvPV_force_flags_mutable(sv, lp, flags) \ - ((SvFLAGS(sv) & (SVf_POK|SVf_THINKFIRST)) == SVf_POK \ - ? ((lp = SvCUR(sv)), SvPVX_mutable(sv)) \ - : sv_pvn_force_flags(sv, &lp, flags|SV_MUTABLE_RETURN)) -#endif -#ifndef SvPV_nolen -# define SvPV_nolen(sv) \ - ((SvFLAGS(sv) & (SVf_POK)) == SVf_POK \ - ? SvPVX(sv) : sv_2pv_flags(sv, DPPP_SVPV_NOLEN_LP_ARG, SV_GMAGIC)) -#endif -#ifndef SvPV_nolen_const -# define SvPV_nolen_const(sv) \ - ((SvFLAGS(sv) & (SVf_POK)) == SVf_POK \ - ? SvPVX_const(sv) : sv_2pv_flags(sv, DPPP_SVPV_NOLEN_LP_ARG, SV_GMAGIC|SV_CONST_RETURN)) -#endif -#ifndef SvPV_nomg -# define SvPV_nomg(sv, lp) SvPV_flags(sv, lp, 0) -#endif - -#ifndef SvPV_nomg_const -# define SvPV_nomg_const(sv, lp) SvPV_flags_const(sv, lp, 0) -#endif - -#ifndef SvPV_nomg_const_nolen -# define SvPV_nomg_const_nolen(sv) SvPV_flags_const_nolen(sv, 0) -#endif -#ifndef SvPV_renew -# define SvPV_renew(sv,n) STMT_START { SvLEN_set(sv, n); \ - SvPV_set((sv), (char *) saferealloc( \ - (Malloc_t)SvPVX(sv), (MEM_SIZE)((n)))); \ - } STMT_END -#endif -#ifndef SvMAGIC_set -# define SvMAGIC_set(sv, val) \ - STMT_START { assert(SvTYPE(sv) >= SVt_PVMG); \ - (((XPVMG*) SvANY(sv))->xmg_magic = (val)); } STMT_END -#endif - -#if (PERL_BCDVERSION < 0x5009003) -#ifndef SvPVX_const -# define SvPVX_const(sv) ((const char*) (0 + SvPVX(sv))) -#endif - -#ifndef SvPVX_mutable -# define SvPVX_mutable(sv) (0 + SvPVX(sv)) -#endif -#ifndef SvRV_set -# define SvRV_set(sv, val) \ - STMT_START { assert(SvTYPE(sv) >= SVt_RV); \ - (((XRV*) SvANY(sv))->xrv_rv = (val)); } STMT_END -#endif - -#else -#ifndef SvPVX_const -# define SvPVX_const(sv) ((const char*)((sv)->sv_u.svu_pv)) -#endif - -#ifndef SvPVX_mutable -# define SvPVX_mutable(sv) ((sv)->sv_u.svu_pv) -#endif -#ifndef SvRV_set -# define SvRV_set(sv, val) \ - STMT_START { assert(SvTYPE(sv) >= SVt_RV); \ - ((sv)->sv_u.svu_rv = (val)); } STMT_END -#endif - -#endif -#ifndef SvSTASH_set -# define SvSTASH_set(sv, val) \ - STMT_START { assert(SvTYPE(sv) >= SVt_PVMG); \ - (((XPVMG*) SvANY(sv))->xmg_stash = (val)); } STMT_END -#endif - -#if (PERL_BCDVERSION < 0x5004000) -#ifndef SvUV_set -# define SvUV_set(sv, val) \ - STMT_START { assert(SvTYPE(sv) == SVt_IV || SvTYPE(sv) >= SVt_PVIV); \ - (((XPVIV*) SvANY(sv))->xiv_iv = (IV) (val)); } STMT_END -#endif - -#else -#ifndef SvUV_set -# define SvUV_set(sv, val) \ - STMT_START { assert(SvTYPE(sv) == SVt_IV || SvTYPE(sv) >= SVt_PVIV); \ - (((XPVUV*) SvANY(sv))->xuv_uv = (val)); } STMT_END -#endif - -#endif - -#if (PERL_BCDVERSION >= 0x5004000) && !defined(vnewSVpvf) -#if defined(NEED_vnewSVpvf) -static SV * DPPP_(my_vnewSVpvf)(pTHX_ const char *pat, va_list *args); -static -#else -extern SV * DPPP_(my_vnewSVpvf)(pTHX_ const char *pat, va_list *args); -#endif - -#ifdef vnewSVpvf -# undef vnewSVpvf -#endif -#define vnewSVpvf(a,b) DPPP_(my_vnewSVpvf)(aTHX_ a,b) -#define Perl_vnewSVpvf DPPP_(my_vnewSVpvf) - -#if defined(NEED_vnewSVpvf) || defined(NEED_vnewSVpvf_GLOBAL) - -SV * -DPPP_(my_vnewSVpvf)(pTHX_ const char *pat, va_list *args) -{ - register SV *sv = newSV(0); - sv_vsetpvfn(sv, pat, strlen(pat), args, Null(SV**), 0, Null(bool*)); - return sv; -} - -#endif -#endif - -#if (PERL_BCDVERSION >= 0x5004000) && !defined(sv_vcatpvf) -# define sv_vcatpvf(sv, pat, args) sv_vcatpvfn(sv, pat, strlen(pat), args, Null(SV**), 0, Null(bool*)) -#endif - -#if (PERL_BCDVERSION >= 0x5004000) && !defined(sv_vsetpvf) -# define sv_vsetpvf(sv, pat, args) sv_vsetpvfn(sv, pat, strlen(pat), args, Null(SV**), 0, Null(bool*)) -#endif - -#if (PERL_BCDVERSION >= 0x5004000) && !defined(sv_catpvf_mg) -#if defined(NEED_sv_catpvf_mg) -static void DPPP_(my_sv_catpvf_mg)(pTHX_ SV *sv, const char *pat, ...); -static -#else -extern void DPPP_(my_sv_catpvf_mg)(pTHX_ SV *sv, const char *pat, ...); -#endif - -#define Perl_sv_catpvf_mg DPPP_(my_sv_catpvf_mg) - -#if defined(NEED_sv_catpvf_mg) || defined(NEED_sv_catpvf_mg_GLOBAL) - -void -DPPP_(my_sv_catpvf_mg)(pTHX_ SV *sv, const char *pat, ...) -{ - va_list args; - va_start(args, pat); - sv_vcatpvfn(sv, pat, strlen(pat), &args, Null(SV**), 0, Null(bool*)); - SvSETMAGIC(sv); - va_end(args); -} - -#endif -#endif - -#ifdef PERL_IMPLICIT_CONTEXT -#if (PERL_BCDVERSION >= 0x5004000) && !defined(sv_catpvf_mg_nocontext) -#if defined(NEED_sv_catpvf_mg_nocontext) -static void DPPP_(my_sv_catpvf_mg_nocontext)(SV *sv, const char *pat, ...); -static -#else -extern void DPPP_(my_sv_catpvf_mg_nocontext)(SV *sv, const char *pat, ...); -#endif - -#define sv_catpvf_mg_nocontext DPPP_(my_sv_catpvf_mg_nocontext) -#define Perl_sv_catpvf_mg_nocontext DPPP_(my_sv_catpvf_mg_nocontext) - -#if defined(NEED_sv_catpvf_mg_nocontext) || defined(NEED_sv_catpvf_mg_nocontext_GLOBAL) - -void -DPPP_(my_sv_catpvf_mg_nocontext)(SV *sv, const char *pat, ...) -{ - dTHX; - va_list args; - va_start(args, pat); - sv_vcatpvfn(sv, pat, strlen(pat), &args, Null(SV**), 0, Null(bool*)); - SvSETMAGIC(sv); - va_end(args); -} - -#endif -#endif -#endif - -/* sv_catpvf_mg depends on sv_catpvf_mg_nocontext */ -#ifndef sv_catpvf_mg -# ifdef PERL_IMPLICIT_CONTEXT -# define sv_catpvf_mg Perl_sv_catpvf_mg_nocontext -# else -# define sv_catpvf_mg Perl_sv_catpvf_mg -# endif -#endif - -#if (PERL_BCDVERSION >= 0x5004000) && !defined(sv_vcatpvf_mg) -# define sv_vcatpvf_mg(sv, pat, args) \ - STMT_START { \ - sv_vcatpvfn(sv, pat, strlen(pat), args, Null(SV**), 0, Null(bool*)); \ - SvSETMAGIC(sv); \ - } STMT_END -#endif - -#if (PERL_BCDVERSION >= 0x5004000) && !defined(sv_setpvf_mg) -#if defined(NEED_sv_setpvf_mg) -static void DPPP_(my_sv_setpvf_mg)(pTHX_ SV *sv, const char *pat, ...); -static -#else -extern void DPPP_(my_sv_setpvf_mg)(pTHX_ SV *sv, const char *pat, ...); -#endif - -#define Perl_sv_setpvf_mg DPPP_(my_sv_setpvf_mg) - -#if defined(NEED_sv_setpvf_mg) || defined(NEED_sv_setpvf_mg_GLOBAL) - -void -DPPP_(my_sv_setpvf_mg)(pTHX_ SV *sv, const char *pat, ...) -{ - va_list args; - va_start(args, pat); - sv_vsetpvfn(sv, pat, strlen(pat), &args, Null(SV**), 0, Null(bool*)); - SvSETMAGIC(sv); - va_end(args); -} - -#endif -#endif - -#ifdef PERL_IMPLICIT_CONTEXT -#if (PERL_BCDVERSION >= 0x5004000) && !defined(sv_setpvf_mg_nocontext) -#if defined(NEED_sv_setpvf_mg_nocontext) -static void DPPP_(my_sv_setpvf_mg_nocontext)(SV *sv, const char *pat, ...); -static -#else -extern void DPPP_(my_sv_setpvf_mg_nocontext)(SV *sv, const char *pat, ...); -#endif - -#define sv_setpvf_mg_nocontext DPPP_(my_sv_setpvf_mg_nocontext) -#define Perl_sv_setpvf_mg_nocontext DPPP_(my_sv_setpvf_mg_nocontext) - -#if defined(NEED_sv_setpvf_mg_nocontext) || defined(NEED_sv_setpvf_mg_nocontext_GLOBAL) - -void -DPPP_(my_sv_setpvf_mg_nocontext)(SV *sv, const char *pat, ...) -{ - dTHX; - va_list args; - va_start(args, pat); - sv_vsetpvfn(sv, pat, strlen(pat), &args, Null(SV**), 0, Null(bool*)); - SvSETMAGIC(sv); - va_end(args); -} - -#endif -#endif -#endif - -/* sv_setpvf_mg depends on sv_setpvf_mg_nocontext */ -#ifndef sv_setpvf_mg -# ifdef PERL_IMPLICIT_CONTEXT -# define sv_setpvf_mg Perl_sv_setpvf_mg_nocontext -# else -# define sv_setpvf_mg Perl_sv_setpvf_mg -# endif -#endif - -#if (PERL_BCDVERSION >= 0x5004000) && !defined(sv_vsetpvf_mg) -# define sv_vsetpvf_mg(sv, pat, args) \ - STMT_START { \ - sv_vsetpvfn(sv, pat, strlen(pat), args, Null(SV**), 0, Null(bool*)); \ - SvSETMAGIC(sv); \ - } STMT_END -#endif - -#ifndef newSVpvn_share - -#if defined(NEED_newSVpvn_share) -static SV * DPPP_(my_newSVpvn_share)(pTHX_ const char *src, I32 len, U32 hash); -static -#else -extern SV * DPPP_(my_newSVpvn_share)(pTHX_ const char *src, I32 len, U32 hash); -#endif - -#ifdef newSVpvn_share -# undef newSVpvn_share -#endif -#define newSVpvn_share(a,b,c) DPPP_(my_newSVpvn_share)(aTHX_ a,b,c) -#define Perl_newSVpvn_share DPPP_(my_newSVpvn_share) - -#if defined(NEED_newSVpvn_share) || defined(NEED_newSVpvn_share_GLOBAL) - -SV * -DPPP_(my_newSVpvn_share)(pTHX_ const char *src, I32 len, U32 hash) -{ - SV *sv; - if (len < 0) - len = -len; - if (!hash) - PERL_HASH(hash, (char*) src, len); - sv = newSVpvn((char *) src, len); - sv_upgrade(sv, SVt_PVIV); - SvIVX(sv) = hash; - SvREADONLY_on(sv); - SvPOK_on(sv); - return sv; -} - -#endif - -#endif -#ifndef SvSHARED_HASH -# define SvSHARED_HASH(sv) (0 + SvUVX(sv)) -#endif -#ifndef HvNAME_get -# define HvNAME_get(hv) HvNAME(hv) -#endif -#ifndef HvNAMELEN_get -# define HvNAMELEN_get(hv) (HvNAME_get(hv) ? (I32)strlen(HvNAME_get(hv)) : 0) -#endif -#ifndef GvSVn -# define GvSVn(gv) GvSV(gv) -#endif - -#ifndef isGV_with_GP -# define isGV_with_GP(gv) isGV(gv) -#endif -#ifndef WARN_ALL -# define WARN_ALL 0 -#endif - -#ifndef WARN_CLOSURE -# define WARN_CLOSURE 1 -#endif - -#ifndef WARN_DEPRECATED -# define WARN_DEPRECATED 2 -#endif - -#ifndef WARN_EXITING -# define WARN_EXITING 3 -#endif - -#ifndef WARN_GLOB -# define WARN_GLOB 4 -#endif - -#ifndef WARN_IO -# define WARN_IO 5 -#endif - -#ifndef WARN_CLOSED -# define WARN_CLOSED 6 -#endif - -#ifndef WARN_EXEC -# define WARN_EXEC 7 -#endif - -#ifndef WARN_LAYER -# define WARN_LAYER 8 -#endif - -#ifndef WARN_NEWLINE -# define WARN_NEWLINE 9 -#endif - -#ifndef WARN_PIPE -# define WARN_PIPE 10 -#endif - -#ifndef WARN_UNOPENED -# define WARN_UNOPENED 11 -#endif - -#ifndef WARN_MISC -# define WARN_MISC 12 -#endif - -#ifndef WARN_NUMERIC -# define WARN_NUMERIC 13 -#endif - -#ifndef WARN_ONCE -# define WARN_ONCE 14 -#endif - -#ifndef WARN_OVERFLOW -# define WARN_OVERFLOW 15 -#endif - -#ifndef WARN_PACK -# define WARN_PACK 16 -#endif - -#ifndef WARN_PORTABLE -# define WARN_PORTABLE 17 -#endif - -#ifndef WARN_RECURSION -# define WARN_RECURSION 18 -#endif - -#ifndef WARN_REDEFINE -# define WARN_REDEFINE 19 -#endif - -#ifndef WARN_REGEXP -# define WARN_REGEXP 20 -#endif - -#ifndef WARN_SEVERE -# define WARN_SEVERE 21 -#endif - -#ifndef WARN_DEBUGGING -# define WARN_DEBUGGING 22 -#endif - -#ifndef WARN_INPLACE -# define WARN_INPLACE 23 -#endif - -#ifndef WARN_INTERNAL -# define WARN_INTERNAL 24 -#endif - -#ifndef WARN_MALLOC -# define WARN_MALLOC 25 -#endif - -#ifndef WARN_SIGNAL -# define WARN_SIGNAL 26 -#endif - -#ifndef WARN_SUBSTR -# define WARN_SUBSTR 27 -#endif - -#ifndef WARN_SYNTAX -# define WARN_SYNTAX 28 -#endif - -#ifndef WARN_AMBIGUOUS -# define WARN_AMBIGUOUS 29 -#endif - -#ifndef WARN_BAREWORD -# define WARN_BAREWORD 30 -#endif - -#ifndef WARN_DIGIT -# define WARN_DIGIT 31 -#endif - -#ifndef WARN_PARENTHESIS -# define WARN_PARENTHESIS 32 -#endif - -#ifndef WARN_PRECEDENCE -# define WARN_PRECEDENCE 33 -#endif - -#ifndef WARN_PRINTF -# define WARN_PRINTF 34 -#endif - -#ifndef WARN_PROTOTYPE -# define WARN_PROTOTYPE 35 -#endif - -#ifndef WARN_QW -# define WARN_QW 36 -#endif - -#ifndef WARN_RESERVED -# define WARN_RESERVED 37 -#endif - -#ifndef WARN_SEMICOLON -# define WARN_SEMICOLON 38 -#endif - -#ifndef WARN_TAINT -# define WARN_TAINT 39 -#endif - -#ifndef WARN_THREADS -# define WARN_THREADS 40 -#endif - -#ifndef WARN_UNINITIALIZED -# define WARN_UNINITIALIZED 41 -#endif - -#ifndef WARN_UNPACK -# define WARN_UNPACK 42 -#endif - -#ifndef WARN_UNTIE -# define WARN_UNTIE 43 -#endif - -#ifndef WARN_UTF8 -# define WARN_UTF8 44 -#endif - -#ifndef WARN_VOID -# define WARN_VOID 45 -#endif - -#ifndef WARN_ASSERTIONS -# define WARN_ASSERTIONS 46 -#endif -#ifndef packWARN -# define packWARN(a) (a) -#endif - -#ifndef ckWARN -# ifdef G_WARN_ON -# define ckWARN(a) (PL_dowarn & G_WARN_ON) -# else -# define ckWARN(a) PL_dowarn -# endif -#endif - -#if (PERL_BCDVERSION >= 0x5004000) && !defined(warner) -#if defined(NEED_warner) -static void DPPP_(my_warner)(U32 err, const char *pat, ...); -static -#else -extern void DPPP_(my_warner)(U32 err, const char *pat, ...); -#endif - -#define Perl_warner DPPP_(my_warner) - -#if defined(NEED_warner) || defined(NEED_warner_GLOBAL) - -void -DPPP_(my_warner)(U32 err, const char *pat, ...) -{ - SV *sv; - va_list args; - - PERL_UNUSED_ARG(err); - - va_start(args, pat); - sv = vnewSVpvf(pat, &args); - va_end(args); - sv_2mortal(sv); - warn("%s", SvPV_nolen(sv)); -} - -#define warner Perl_warner - -#define Perl_warner_nocontext Perl_warner - -#endif -#endif - -/* concatenating with "" ensures that only literal strings are accepted as argument - * note that STR_WITH_LEN() can't be used as argument to macros or functions that - * under some configurations might be macros - */ -#ifndef STR_WITH_LEN -# define STR_WITH_LEN(s) (s ""), (sizeof(s)-1) -#endif -#ifndef newSVpvs -# define newSVpvs(str) newSVpvn(str "", sizeof(str) - 1) -#endif - -#ifndef newSVpvs_flags -# define newSVpvs_flags(str, flags) newSVpvn_flags(str "", sizeof(str) - 1, flags) -#endif - -#ifndef sv_catpvs -# define sv_catpvs(sv, str) sv_catpvn(sv, str "", sizeof(str) - 1) -#endif - -#ifndef sv_setpvs -# define sv_setpvs(sv, str) sv_setpvn(sv, str "", sizeof(str) - 1) -#endif - -#ifndef hv_fetchs -# define hv_fetchs(hv, key, lval) hv_fetch(hv, key "", sizeof(key) - 1, lval) -#endif - -#ifndef hv_stores -# define hv_stores(hv, key, val) hv_store(hv, key "", sizeof(key) - 1, val, 0) -#endif -#ifndef gv_fetchpvn_flags -# define gv_fetchpvn_flags(name, len, flags, svt) gv_fetchpv(name, flags, svt) -#endif - -#ifndef gv_fetchpvs -# define gv_fetchpvs(name, flags, svt) gv_fetchpvn_flags(name "", sizeof(name) - 1, flags, svt) -#endif - -#ifndef gv_stashpvs -# define gv_stashpvs(name, flags) gv_stashpvn(name "", sizeof(name) - 1, flags) -#endif -#ifndef SvGETMAGIC -# define SvGETMAGIC(x) STMT_START { if (SvGMAGICAL(x)) mg_get(x); } STMT_END -#endif -#ifndef PERL_MAGIC_sv -# define PERL_MAGIC_sv '\0' -#endif - -#ifndef PERL_MAGIC_overload -# define PERL_MAGIC_overload 'A' -#endif - -#ifndef PERL_MAGIC_overload_elem -# define PERL_MAGIC_overload_elem 'a' -#endif - -#ifndef PERL_MAGIC_overload_table -# define PERL_MAGIC_overload_table 'c' -#endif - -#ifndef PERL_MAGIC_bm -# define PERL_MAGIC_bm 'B' -#endif - -#ifndef PERL_MAGIC_regdata -# define PERL_MAGIC_regdata 'D' -#endif - -#ifndef PERL_MAGIC_regdatum -# define PERL_MAGIC_regdatum 'd' -#endif - -#ifndef PERL_MAGIC_env -# define PERL_MAGIC_env 'E' -#endif - -#ifndef PERL_MAGIC_envelem -# define PERL_MAGIC_envelem 'e' -#endif - -#ifndef PERL_MAGIC_fm -# define PERL_MAGIC_fm 'f' -#endif - -#ifndef PERL_MAGIC_regex_global -# define PERL_MAGIC_regex_global 'g' -#endif - -#ifndef PERL_MAGIC_isa -# define PERL_MAGIC_isa 'I' -#endif - -#ifndef PERL_MAGIC_isaelem -# define PERL_MAGIC_isaelem 'i' -#endif - -#ifndef PERL_MAGIC_nkeys -# define PERL_MAGIC_nkeys 'k' -#endif - -#ifndef PERL_MAGIC_dbfile -# define PERL_MAGIC_dbfile 'L' -#endif - -#ifndef PERL_MAGIC_dbline -# define PERL_MAGIC_dbline 'l' -#endif - -#ifndef PERL_MAGIC_mutex -# define PERL_MAGIC_mutex 'm' -#endif - -#ifndef PERL_MAGIC_shared -# define PERL_MAGIC_shared 'N' -#endif - -#ifndef PERL_MAGIC_shared_scalar -# define PERL_MAGIC_shared_scalar 'n' -#endif - -#ifndef PERL_MAGIC_collxfrm -# define PERL_MAGIC_collxfrm 'o' -#endif - -#ifndef PERL_MAGIC_tied -# define PERL_MAGIC_tied 'P' -#endif - -#ifndef PERL_MAGIC_tiedelem -# define PERL_MAGIC_tiedelem 'p' -#endif - -#ifndef PERL_MAGIC_tiedscalar -# define PERL_MAGIC_tiedscalar 'q' -#endif - -#ifndef PERL_MAGIC_qr -# define PERL_MAGIC_qr 'r' -#endif - -#ifndef PERL_MAGIC_sig -# define PERL_MAGIC_sig 'S' -#endif - -#ifndef PERL_MAGIC_sigelem -# define PERL_MAGIC_sigelem 's' -#endif - -#ifndef PERL_MAGIC_taint -# define PERL_MAGIC_taint 't' -#endif - -#ifndef PERL_MAGIC_uvar -# define PERL_MAGIC_uvar 'U' -#endif - -#ifndef PERL_MAGIC_uvar_elem -# define PERL_MAGIC_uvar_elem 'u' -#endif - -#ifndef PERL_MAGIC_vstring -# define PERL_MAGIC_vstring 'V' -#endif - -#ifndef PERL_MAGIC_vec -# define PERL_MAGIC_vec 'v' -#endif - -#ifndef PERL_MAGIC_utf8 -# define PERL_MAGIC_utf8 'w' -#endif - -#ifndef PERL_MAGIC_substr -# define PERL_MAGIC_substr 'x' -#endif - -#ifndef PERL_MAGIC_defelem -# define PERL_MAGIC_defelem 'y' -#endif - -#ifndef PERL_MAGIC_glob -# define PERL_MAGIC_glob '*' -#endif - -#ifndef PERL_MAGIC_arylen -# define PERL_MAGIC_arylen '#' -#endif - -#ifndef PERL_MAGIC_pos -# define PERL_MAGIC_pos '.' -#endif - -#ifndef PERL_MAGIC_backref -# define PERL_MAGIC_backref '<' -#endif - -#ifndef PERL_MAGIC_ext -# define PERL_MAGIC_ext '~' -#endif - -/* That's the best we can do... */ -#ifndef sv_catpvn_nomg -# define sv_catpvn_nomg sv_catpvn -#endif - -#ifndef sv_catsv_nomg -# define sv_catsv_nomg sv_catsv -#endif - -#ifndef sv_setsv_nomg -# define sv_setsv_nomg sv_setsv -#endif - -#ifndef sv_pvn_nomg -# define sv_pvn_nomg sv_pvn -#endif - -#ifndef SvIV_nomg -# define SvIV_nomg SvIV -#endif - -#ifndef SvUV_nomg -# define SvUV_nomg SvUV -#endif - -#ifndef sv_catpv_mg -# define sv_catpv_mg(sv, ptr) \ - STMT_START { \ - SV *TeMpSv = sv; \ - sv_catpv(TeMpSv,ptr); \ - SvSETMAGIC(TeMpSv); \ - } STMT_END -#endif - -#ifndef sv_catpvn_mg -# define sv_catpvn_mg(sv, ptr, len) \ - STMT_START { \ - SV *TeMpSv = sv; \ - sv_catpvn(TeMpSv,ptr,len); \ - SvSETMAGIC(TeMpSv); \ - } STMT_END -#endif - -#ifndef sv_catsv_mg -# define sv_catsv_mg(dsv, ssv) \ - STMT_START { \ - SV *TeMpSv = dsv; \ - sv_catsv(TeMpSv,ssv); \ - SvSETMAGIC(TeMpSv); \ - } STMT_END -#endif - -#ifndef sv_setiv_mg -# define sv_setiv_mg(sv, i) \ - STMT_START { \ - SV *TeMpSv = sv; \ - sv_setiv(TeMpSv,i); \ - SvSETMAGIC(TeMpSv); \ - } STMT_END -#endif - -#ifndef sv_setnv_mg -# define sv_setnv_mg(sv, num) \ - STMT_START { \ - SV *TeMpSv = sv; \ - sv_setnv(TeMpSv,num); \ - SvSETMAGIC(TeMpSv); \ - } STMT_END -#endif - -#ifndef sv_setpv_mg -# define sv_setpv_mg(sv, ptr) \ - STMT_START { \ - SV *TeMpSv = sv; \ - sv_setpv(TeMpSv,ptr); \ - SvSETMAGIC(TeMpSv); \ - } STMT_END -#endif - -#ifndef sv_setpvn_mg -# define sv_setpvn_mg(sv, ptr, len) \ - STMT_START { \ - SV *TeMpSv = sv; \ - sv_setpvn(TeMpSv,ptr,len); \ - SvSETMAGIC(TeMpSv); \ - } STMT_END -#endif - -#ifndef sv_setsv_mg -# define sv_setsv_mg(dsv, ssv) \ - STMT_START { \ - SV *TeMpSv = dsv; \ - sv_setsv(TeMpSv,ssv); \ - SvSETMAGIC(TeMpSv); \ - } STMT_END -#endif - -#ifndef sv_setuv_mg -# define sv_setuv_mg(sv, i) \ - STMT_START { \ - SV *TeMpSv = sv; \ - sv_setuv(TeMpSv,i); \ - SvSETMAGIC(TeMpSv); \ - } STMT_END -#endif - -#ifndef sv_usepvn_mg -# define sv_usepvn_mg(sv, ptr, len) \ - STMT_START { \ - SV *TeMpSv = sv; \ - sv_usepvn(TeMpSv,ptr,len); \ - SvSETMAGIC(TeMpSv); \ - } STMT_END -#endif -#ifndef SvVSTRING_mg -# define SvVSTRING_mg(sv) (SvMAGICAL(sv) ? mg_find(sv, PERL_MAGIC_vstring) : NULL) -#endif - -/* Hint: sv_magic_portable - * This is a compatibility function that is only available with - * Devel::PPPort. It is NOT in the perl core. - * Its purpose is to mimic the 5.8.0 behaviour of sv_magic() when - * it is being passed a name pointer with namlen == 0. In that - * case, perl 5.8.0 and later store the pointer, not a copy of it. - * The compatibility can be provided back to perl 5.004. With - * earlier versions, the code will not compile. - */ - -#if (PERL_BCDVERSION < 0x5004000) - - /* code that uses sv_magic_portable will not compile */ - -#elif (PERL_BCDVERSION < 0x5008000) - -# define sv_magic_portable(sv, obj, how, name, namlen) \ - STMT_START { \ - SV *SvMp_sv = (sv); \ - char *SvMp_name = (char *) (name); \ - I32 SvMp_namlen = (namlen); \ - if (SvMp_name && SvMp_namlen == 0) \ - { \ - MAGIC *mg; \ - sv_magic(SvMp_sv, obj, how, 0, 0); \ - mg = SvMAGIC(SvMp_sv); \ - mg->mg_len = -42; /* XXX: this is the tricky part */ \ - mg->mg_ptr = SvMp_name; \ - } \ - else \ - { \ - sv_magic(SvMp_sv, obj, how, SvMp_name, SvMp_namlen); \ - } \ - } STMT_END - -#else - -# define sv_magic_portable(a, b, c, d, e) sv_magic(a, b, c, d, e) - -#endif - -#ifdef USE_ITHREADS -#ifndef CopFILE -# define CopFILE(c) ((c)->cop_file) -#endif - -#ifndef CopFILEGV -# define CopFILEGV(c) (CopFILE(c) ? gv_fetchfile(CopFILE(c)) : Nullgv) -#endif - -#ifndef CopFILE_set -# define CopFILE_set(c,pv) ((c)->cop_file = savepv(pv)) -#endif - -#ifndef CopFILESV -# define CopFILESV(c) (CopFILE(c) ? GvSV(gv_fetchfile(CopFILE(c))) : Nullsv) -#endif - -#ifndef CopFILEAV -# define CopFILEAV(c) (CopFILE(c) ? GvAV(gv_fetchfile(CopFILE(c))) : Nullav) -#endif - -#ifndef CopSTASHPV -# define CopSTASHPV(c) ((c)->cop_stashpv) -#endif - -#ifndef CopSTASHPV_set -# define CopSTASHPV_set(c,pv) ((c)->cop_stashpv = ((pv) ? savepv(pv) : Nullch)) -#endif - -#ifndef CopSTASH -# define CopSTASH(c) (CopSTASHPV(c) ? gv_stashpv(CopSTASHPV(c),GV_ADD) : Nullhv) -#endif - -#ifndef CopSTASH_set -# define CopSTASH_set(c,hv) CopSTASHPV_set(c, (hv) ? HvNAME(hv) : Nullch) -#endif - -#ifndef CopSTASH_eq -# define CopSTASH_eq(c,hv) ((hv) && (CopSTASHPV(c) == HvNAME(hv) \ - || (CopSTASHPV(c) && HvNAME(hv) \ - && strEQ(CopSTASHPV(c), HvNAME(hv))))) -#endif - -#else -#ifndef CopFILEGV -# define CopFILEGV(c) ((c)->cop_filegv) -#endif - -#ifndef CopFILEGV_set -# define CopFILEGV_set(c,gv) ((c)->cop_filegv = (GV*)SvREFCNT_inc(gv)) -#endif - -#ifndef CopFILE_set -# define CopFILE_set(c,pv) CopFILEGV_set((c), gv_fetchfile(pv)) -#endif - -#ifndef CopFILESV -# define CopFILESV(c) (CopFILEGV(c) ? GvSV(CopFILEGV(c)) : Nullsv) -#endif - -#ifndef CopFILEAV -# define CopFILEAV(c) (CopFILEGV(c) ? GvAV(CopFILEGV(c)) : Nullav) -#endif - -#ifndef CopFILE -# define CopFILE(c) (CopFILESV(c) ? SvPVX(CopFILESV(c)) : Nullch) -#endif - -#ifndef CopSTASH -# define CopSTASH(c) ((c)->cop_stash) -#endif - -#ifndef CopSTASH_set -# define CopSTASH_set(c,hv) ((c)->cop_stash = (hv)) -#endif - -#ifndef CopSTASHPV -# define CopSTASHPV(c) (CopSTASH(c) ? HvNAME(CopSTASH(c)) : Nullch) -#endif - -#ifndef CopSTASHPV_set -# define CopSTASHPV_set(c,pv) CopSTASH_set((c), gv_stashpv(pv,GV_ADD)) -#endif - -#ifndef CopSTASH_eq -# define CopSTASH_eq(c,hv) (CopSTASH(c) == (hv)) -#endif - -#endif /* USE_ITHREADS */ -#ifndef IN_PERL_COMPILETIME -# define IN_PERL_COMPILETIME (PL_curcop == &PL_compiling) -#endif - -#ifndef IN_LOCALE_RUNTIME -# define IN_LOCALE_RUNTIME (PL_curcop->op_private & HINT_LOCALE) -#endif - -#ifndef IN_LOCALE_COMPILETIME -# define IN_LOCALE_COMPILETIME (PL_hints & HINT_LOCALE) -#endif - -#ifndef IN_LOCALE -# define IN_LOCALE (IN_PERL_COMPILETIME ? IN_LOCALE_COMPILETIME : IN_LOCALE_RUNTIME) -#endif -#ifndef IS_NUMBER_IN_UV -# define IS_NUMBER_IN_UV 0x01 -#endif - -#ifndef IS_NUMBER_GREATER_THAN_UV_MAX -# define IS_NUMBER_GREATER_THAN_UV_MAX 0x02 -#endif - -#ifndef IS_NUMBER_NOT_INT -# define IS_NUMBER_NOT_INT 0x04 -#endif - -#ifndef IS_NUMBER_NEG -# define IS_NUMBER_NEG 0x08 -#endif - -#ifndef IS_NUMBER_INFINITY -# define IS_NUMBER_INFINITY 0x10 -#endif - -#ifndef IS_NUMBER_NAN -# define IS_NUMBER_NAN 0x20 -#endif -#ifndef GROK_NUMERIC_RADIX -# define GROK_NUMERIC_RADIX(sp, send) grok_numeric_radix(sp, send) -#endif -#ifndef PERL_SCAN_GREATER_THAN_UV_MAX -# define PERL_SCAN_GREATER_THAN_UV_MAX 0x02 -#endif - -#ifndef PERL_SCAN_SILENT_ILLDIGIT -# define PERL_SCAN_SILENT_ILLDIGIT 0x04 -#endif - -#ifndef PERL_SCAN_ALLOW_UNDERSCORES -# define PERL_SCAN_ALLOW_UNDERSCORES 0x01 -#endif - -#ifndef PERL_SCAN_DISALLOW_PREFIX -# define PERL_SCAN_DISALLOW_PREFIX 0x02 -#endif - -#ifndef grok_numeric_radix -#if defined(NEED_grok_numeric_radix) -static bool DPPP_(my_grok_numeric_radix)(pTHX_ const char ** sp, const char * send); -static -#else -extern bool DPPP_(my_grok_numeric_radix)(pTHX_ const char ** sp, const char * send); -#endif - -#ifdef grok_numeric_radix -# undef grok_numeric_radix -#endif -#define grok_numeric_radix(a,b) DPPP_(my_grok_numeric_radix)(aTHX_ a,b) -#define Perl_grok_numeric_radix DPPP_(my_grok_numeric_radix) - -#if defined(NEED_grok_numeric_radix) || defined(NEED_grok_numeric_radix_GLOBAL) -bool -DPPP_(my_grok_numeric_radix)(pTHX_ const char **sp, const char *send) -{ -#ifdef USE_LOCALE_NUMERIC -#ifdef PL_numeric_radix_sv - if (PL_numeric_radix_sv && IN_LOCALE) { - STRLEN len; - char* radix = SvPV(PL_numeric_radix_sv, len); - if (*sp + len <= send && memEQ(*sp, radix, len)) { - *sp += len; - return TRUE; - } - } -#else - /* older perls don't have PL_numeric_radix_sv so the radix - * must manually be requested from locale.h - */ -#include - dTHR; /* needed for older threaded perls */ - struct lconv *lc = localeconv(); - char *radix = lc->decimal_point; - if (radix && IN_LOCALE) { - STRLEN len = strlen(radix); - if (*sp + len <= send && memEQ(*sp, radix, len)) { - *sp += len; - return TRUE; - } - } -#endif -#endif /* USE_LOCALE_NUMERIC */ - /* always try "." if numeric radix didn't match because - * we may have data from different locales mixed */ - if (*sp < send && **sp == '.') { - ++*sp; - return TRUE; - } - return FALSE; -} -#endif -#endif - -#ifndef grok_number -#if defined(NEED_grok_number) -static int DPPP_(my_grok_number)(pTHX_ const char * pv, STRLEN len, UV * valuep); -static -#else -extern int DPPP_(my_grok_number)(pTHX_ const char * pv, STRLEN len, UV * valuep); -#endif - -#ifdef grok_number -# undef grok_number -#endif -#define grok_number(a,b,c) DPPP_(my_grok_number)(aTHX_ a,b,c) -#define Perl_grok_number DPPP_(my_grok_number) - -#if defined(NEED_grok_number) || defined(NEED_grok_number_GLOBAL) -int -DPPP_(my_grok_number)(pTHX_ const char *pv, STRLEN len, UV *valuep) -{ - const char *s = pv; - const char *send = pv + len; - const UV max_div_10 = UV_MAX / 10; - const char max_mod_10 = UV_MAX % 10; - int numtype = 0; - int sawinf = 0; - int sawnan = 0; - - while (s < send && isSPACE(*s)) - s++; - if (s == send) { - return 0; - } else if (*s == '-') { - s++; - numtype = IS_NUMBER_NEG; - } - else if (*s == '+') - s++; - - if (s == send) - return 0; - - /* next must be digit or the radix separator or beginning of infinity */ - if (isDIGIT(*s)) { - /* UVs are at least 32 bits, so the first 9 decimal digits cannot - overflow. */ - UV value = *s - '0'; - /* This construction seems to be more optimiser friendly. - (without it gcc does the isDIGIT test and the *s - '0' separately) - With it gcc on arm is managing 6 instructions (6 cycles) per digit. - In theory the optimiser could deduce how far to unroll the loop - before checking for overflow. */ - if (++s < send) { - int digit = *s - '0'; - if (digit >= 0 && digit <= 9) { - value = value * 10 + digit; - if (++s < send) { - digit = *s - '0'; - if (digit >= 0 && digit <= 9) { - value = value * 10 + digit; - if (++s < send) { - digit = *s - '0'; - if (digit >= 0 && digit <= 9) { - value = value * 10 + digit; - if (++s < send) { - digit = *s - '0'; - if (digit >= 0 && digit <= 9) { - value = value * 10 + digit; - if (++s < send) { - digit = *s - '0'; - if (digit >= 0 && digit <= 9) { - value = value * 10 + digit; - if (++s < send) { - digit = *s - '0'; - if (digit >= 0 && digit <= 9) { - value = value * 10 + digit; - if (++s < send) { - digit = *s - '0'; - if (digit >= 0 && digit <= 9) { - value = value * 10 + digit; - if (++s < send) { - digit = *s - '0'; - if (digit >= 0 && digit <= 9) { - value = value * 10 + digit; - if (++s < send) { - /* Now got 9 digits, so need to check - each time for overflow. */ - digit = *s - '0'; - while (digit >= 0 && digit <= 9 - && (value < max_div_10 - || (value == max_div_10 - && digit <= max_mod_10))) { - value = value * 10 + digit; - if (++s < send) - digit = *s - '0'; - else - break; - } - if (digit >= 0 && digit <= 9 - && (s < send)) { - /* value overflowed. - skip the remaining digits, don't - worry about setting *valuep. */ - do { - s++; - } while (s < send && isDIGIT(*s)); - numtype |= - IS_NUMBER_GREATER_THAN_UV_MAX; - goto skip_value; - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - } - numtype |= IS_NUMBER_IN_UV; - if (valuep) - *valuep = value; - - skip_value: - if (GROK_NUMERIC_RADIX(&s, send)) { - numtype |= IS_NUMBER_NOT_INT; - while (s < send && isDIGIT(*s)) /* optional digits after the radix */ - s++; - } - } - else if (GROK_NUMERIC_RADIX(&s, send)) { - numtype |= IS_NUMBER_NOT_INT | IS_NUMBER_IN_UV; /* valuep assigned below */ - /* no digits before the radix means we need digits after it */ - if (s < send && isDIGIT(*s)) { - do { - s++; - } while (s < send && isDIGIT(*s)); - if (valuep) { - /* integer approximation is valid - it's 0. */ - *valuep = 0; - } - } - else - return 0; - } else if (*s == 'I' || *s == 'i') { - s++; if (s == send || (*s != 'N' && *s != 'n')) return 0; - s++; if (s == send || (*s != 'F' && *s != 'f')) return 0; - s++; if (s < send && (*s == 'I' || *s == 'i')) { - s++; if (s == send || (*s != 'N' && *s != 'n')) return 0; - s++; if (s == send || (*s != 'I' && *s != 'i')) return 0; - s++; if (s == send || (*s != 'T' && *s != 't')) return 0; - s++; if (s == send || (*s != 'Y' && *s != 'y')) return 0; - s++; - } - sawinf = 1; - } else if (*s == 'N' || *s == 'n') { - /* XXX TODO: There are signaling NaNs and quiet NaNs. */ - s++; if (s == send || (*s != 'A' && *s != 'a')) return 0; - s++; if (s == send || (*s != 'N' && *s != 'n')) return 0; - s++; - sawnan = 1; - } else - return 0; - - if (sawinf) { - numtype &= IS_NUMBER_NEG; /* Keep track of sign */ - numtype |= IS_NUMBER_INFINITY | IS_NUMBER_NOT_INT; - } else if (sawnan) { - numtype &= IS_NUMBER_NEG; /* Keep track of sign */ - numtype |= IS_NUMBER_NAN | IS_NUMBER_NOT_INT; - } else if (s < send) { - /* we can have an optional exponent part */ - if (*s == 'e' || *s == 'E') { - /* The only flag we keep is sign. Blow away any "it's UV" */ - numtype &= IS_NUMBER_NEG; - numtype |= IS_NUMBER_NOT_INT; - s++; - if (s < send && (*s == '-' || *s == '+')) - s++; - if (s < send && isDIGIT(*s)) { - do { - s++; - } while (s < send && isDIGIT(*s)); - } - else - return 0; - } - } - while (s < send && isSPACE(*s)) - s++; - if (s >= send) - return numtype; - if (len == 10 && memEQ(pv, "0 but true", 10)) { - if (valuep) - *valuep = 0; - return IS_NUMBER_IN_UV; - } - return 0; -} -#endif -#endif - -/* - * The grok_* routines have been modified to use warn() instead of - * Perl_warner(). Also, 'hexdigit' was the former name of PL_hexdigit, - * which is why the stack variable has been renamed to 'xdigit'. - */ - -#ifndef grok_bin -#if defined(NEED_grok_bin) -static UV DPPP_(my_grok_bin)(pTHX_ const char * start, STRLEN * len_p, I32 * flags, NV * result); -static -#else -extern UV DPPP_(my_grok_bin)(pTHX_ const char * start, STRLEN * len_p, I32 * flags, NV * result); -#endif - -#ifdef grok_bin -# undef grok_bin -#endif -#define grok_bin(a,b,c,d) DPPP_(my_grok_bin)(aTHX_ a,b,c,d) -#define Perl_grok_bin DPPP_(my_grok_bin) - -#if defined(NEED_grok_bin) || defined(NEED_grok_bin_GLOBAL) -UV -DPPP_(my_grok_bin)(pTHX_ const char *start, STRLEN *len_p, I32 *flags, NV *result) -{ - const char *s = start; - STRLEN len = *len_p; - UV value = 0; - NV value_nv = 0; - - const UV max_div_2 = UV_MAX / 2; - bool allow_underscores = *flags & PERL_SCAN_ALLOW_UNDERSCORES; - bool overflowed = FALSE; - - if (!(*flags & PERL_SCAN_DISALLOW_PREFIX)) { - /* strip off leading b or 0b. - for compatibility silently suffer "b" and "0b" as valid binary - numbers. */ - if (len >= 1) { - if (s[0] == 'b') { - s++; - len--; - } - else if (len >= 2 && s[0] == '0' && s[1] == 'b') { - s+=2; - len-=2; - } - } - } - - for (; len-- && *s; s++) { - char bit = *s; - if (bit == '0' || bit == '1') { - /* Write it in this wonky order with a goto to attempt to get the - compiler to make the common case integer-only loop pretty tight. - With gcc seems to be much straighter code than old scan_bin. */ - redo: - if (!overflowed) { - if (value <= max_div_2) { - value = (value << 1) | (bit - '0'); - continue; - } - /* Bah. We're just overflowed. */ - warn("Integer overflow in binary number"); - overflowed = TRUE; - value_nv = (NV) value; - } - value_nv *= 2.0; - /* If an NV has not enough bits in its mantissa to - * represent a UV this summing of small low-order numbers - * is a waste of time (because the NV cannot preserve - * the low-order bits anyway): we could just remember when - * did we overflow and in the end just multiply value_nv by the - * right amount. */ - value_nv += (NV)(bit - '0'); - continue; - } - if (bit == '_' && len && allow_underscores && (bit = s[1]) - && (bit == '0' || bit == '1')) - { - --len; - ++s; - goto redo; - } - if (!(*flags & PERL_SCAN_SILENT_ILLDIGIT)) - warn("Illegal binary digit '%c' ignored", *s); - break; - } - - if ( ( overflowed && value_nv > 4294967295.0) -#if UVSIZE > 4 - || (!overflowed && value > 0xffffffff ) -#endif - ) { - warn("Binary number > 0b11111111111111111111111111111111 non-portable"); - } - *len_p = s - start; - if (!overflowed) { - *flags = 0; - return value; - } - *flags = PERL_SCAN_GREATER_THAN_UV_MAX; - if (result) - *result = value_nv; - return UV_MAX; -} -#endif -#endif - -#ifndef grok_hex -#if defined(NEED_grok_hex) -static UV DPPP_(my_grok_hex)(pTHX_ const char * start, STRLEN * len_p, I32 * flags, NV * result); -static -#else -extern UV DPPP_(my_grok_hex)(pTHX_ const char * start, STRLEN * len_p, I32 * flags, NV * result); -#endif - -#ifdef grok_hex -# undef grok_hex -#endif -#define grok_hex(a,b,c,d) DPPP_(my_grok_hex)(aTHX_ a,b,c,d) -#define Perl_grok_hex DPPP_(my_grok_hex) - -#if defined(NEED_grok_hex) || defined(NEED_grok_hex_GLOBAL) -UV -DPPP_(my_grok_hex)(pTHX_ const char *start, STRLEN *len_p, I32 *flags, NV *result) -{ - const char *s = start; - STRLEN len = *len_p; - UV value = 0; - NV value_nv = 0; - - const UV max_div_16 = UV_MAX / 16; - bool allow_underscores = *flags & PERL_SCAN_ALLOW_UNDERSCORES; - bool overflowed = FALSE; - const char *xdigit; - - if (!(*flags & PERL_SCAN_DISALLOW_PREFIX)) { - /* strip off leading x or 0x. - for compatibility silently suffer "x" and "0x" as valid hex numbers. - */ - if (len >= 1) { - if (s[0] == 'x') { - s++; - len--; - } - else if (len >= 2 && s[0] == '0' && s[1] == 'x') { - s+=2; - len-=2; - } - } - } - - for (; len-- && *s; s++) { - xdigit = strchr((char *) PL_hexdigit, *s); - if (xdigit) { - /* Write it in this wonky order with a goto to attempt to get the - compiler to make the common case integer-only loop pretty tight. - With gcc seems to be much straighter code than old scan_hex. */ - redo: - if (!overflowed) { - if (value <= max_div_16) { - value = (value << 4) | ((xdigit - PL_hexdigit) & 15); - continue; - } - warn("Integer overflow in hexadecimal number"); - overflowed = TRUE; - value_nv = (NV) value; - } - value_nv *= 16.0; - /* If an NV has not enough bits in its mantissa to - * represent a UV this summing of small low-order numbers - * is a waste of time (because the NV cannot preserve - * the low-order bits anyway): we could just remember when - * did we overflow and in the end just multiply value_nv by the - * right amount of 16-tuples. */ - value_nv += (NV)((xdigit - PL_hexdigit) & 15); - continue; - } - if (*s == '_' && len && allow_underscores && s[1] - && (xdigit = strchr((char *) PL_hexdigit, s[1]))) - { - --len; - ++s; - goto redo; - } - if (!(*flags & PERL_SCAN_SILENT_ILLDIGIT)) - warn("Illegal hexadecimal digit '%c' ignored", *s); - break; - } - - if ( ( overflowed && value_nv > 4294967295.0) -#if UVSIZE > 4 - || (!overflowed && value > 0xffffffff ) -#endif - ) { - warn("Hexadecimal number > 0xffffffff non-portable"); - } - *len_p = s - start; - if (!overflowed) { - *flags = 0; - return value; - } - *flags = PERL_SCAN_GREATER_THAN_UV_MAX; - if (result) - *result = value_nv; - return UV_MAX; -} -#endif -#endif - -#ifndef grok_oct -#if defined(NEED_grok_oct) -static UV DPPP_(my_grok_oct)(pTHX_ const char * start, STRLEN * len_p, I32 * flags, NV * result); -static -#else -extern UV DPPP_(my_grok_oct)(pTHX_ const char * start, STRLEN * len_p, I32 * flags, NV * result); -#endif - -#ifdef grok_oct -# undef grok_oct -#endif -#define grok_oct(a,b,c,d) DPPP_(my_grok_oct)(aTHX_ a,b,c,d) -#define Perl_grok_oct DPPP_(my_grok_oct) - -#if defined(NEED_grok_oct) || defined(NEED_grok_oct_GLOBAL) -UV -DPPP_(my_grok_oct)(pTHX_ const char *start, STRLEN *len_p, I32 *flags, NV *result) -{ - const char *s = start; - STRLEN len = *len_p; - UV value = 0; - NV value_nv = 0; - - const UV max_div_8 = UV_MAX / 8; - bool allow_underscores = *flags & PERL_SCAN_ALLOW_UNDERSCORES; - bool overflowed = FALSE; - - for (; len-- && *s; s++) { - /* gcc 2.95 optimiser not smart enough to figure that this subtraction - out front allows slicker code. */ - int digit = *s - '0'; - if (digit >= 0 && digit <= 7) { - /* Write it in this wonky order with a goto to attempt to get the - compiler to make the common case integer-only loop pretty tight. - */ - redo: - if (!overflowed) { - if (value <= max_div_8) { - value = (value << 3) | digit; - continue; - } - /* Bah. We're just overflowed. */ - warn("Integer overflow in octal number"); - overflowed = TRUE; - value_nv = (NV) value; - } - value_nv *= 8.0; - /* If an NV has not enough bits in its mantissa to - * represent a UV this summing of small low-order numbers - * is a waste of time (because the NV cannot preserve - * the low-order bits anyway): we could just remember when - * did we overflow and in the end just multiply value_nv by the - * right amount of 8-tuples. */ - value_nv += (NV)digit; - continue; - } - if (digit == ('_' - '0') && len && allow_underscores - && (digit = s[1] - '0') && (digit >= 0 && digit <= 7)) - { - --len; - ++s; - goto redo; - } - /* Allow \octal to work the DWIM way (that is, stop scanning - * as soon as non-octal characters are seen, complain only iff - * someone seems to want to use the digits eight and nine). */ - if (digit == 8 || digit == 9) { - if (!(*flags & PERL_SCAN_SILENT_ILLDIGIT)) - warn("Illegal octal digit '%c' ignored", *s); - } - break; - } - - if ( ( overflowed && value_nv > 4294967295.0) -#if UVSIZE > 4 - || (!overflowed && value > 0xffffffff ) -#endif - ) { - warn("Octal number > 037777777777 non-portable"); - } - *len_p = s - start; - if (!overflowed) { - *flags = 0; - return value; - } - *flags = PERL_SCAN_GREATER_THAN_UV_MAX; - if (result) - *result = value_nv; - return UV_MAX; -} -#endif -#endif - -#if !defined(my_snprintf) -#if defined(NEED_my_snprintf) -static int DPPP_(my_my_snprintf)(char * buffer, const Size_t len, const char * format, ...); -static -#else -extern int DPPP_(my_my_snprintf)(char * buffer, const Size_t len, const char * format, ...); -#endif - -#define my_snprintf DPPP_(my_my_snprintf) -#define Perl_my_snprintf DPPP_(my_my_snprintf) - -#if defined(NEED_my_snprintf) || defined(NEED_my_snprintf_GLOBAL) - -int -DPPP_(my_my_snprintf)(char *buffer, const Size_t len, const char *format, ...) -{ - dTHX; - int retval; - va_list ap; - va_start(ap, format); -#ifdef HAS_VSNPRINTF - retval = vsnprintf(buffer, len, format, ap); -#else - retval = vsprintf(buffer, format, ap); -#endif - va_end(ap); - if (retval < 0 || (len > 0 && (Size_t)retval >= len)) - Perl_croak(aTHX_ "panic: my_snprintf buffer overflow"); - return retval; -} - -#endif -#endif - -#if !defined(my_sprintf) -#if defined(NEED_my_sprintf) -static int DPPP_(my_my_sprintf)(char * buffer, const char * pat, ...); -static -#else -extern int DPPP_(my_my_sprintf)(char * buffer, const char * pat, ...); -#endif - -#define my_sprintf DPPP_(my_my_sprintf) -#define Perl_my_sprintf DPPP_(my_my_sprintf) - -#if defined(NEED_my_sprintf) || defined(NEED_my_sprintf_GLOBAL) - -int -DPPP_(my_my_sprintf)(char *buffer, const char* pat, ...) -{ - va_list args; - va_start(args, pat); - vsprintf(buffer, pat, args); - va_end(args); - return strlen(buffer); -} - -#endif -#endif - -#ifdef NO_XSLOCKS -# ifdef dJMPENV -# define dXCPT dJMPENV; int rEtV = 0 -# define XCPT_TRY_START JMPENV_PUSH(rEtV); if (rEtV == 0) -# define XCPT_TRY_END JMPENV_POP; -# define XCPT_CATCH if (rEtV != 0) -# define XCPT_RETHROW JMPENV_JUMP(rEtV) -# else -# define dXCPT Sigjmp_buf oldTOP; int rEtV = 0 -# define XCPT_TRY_START Copy(top_env, oldTOP, 1, Sigjmp_buf); rEtV = Sigsetjmp(top_env, 1); if (rEtV == 0) -# define XCPT_TRY_END Copy(oldTOP, top_env, 1, Sigjmp_buf); -# define XCPT_CATCH if (rEtV != 0) -# define XCPT_RETHROW Siglongjmp(top_env, rEtV) -# endif -#endif - -#if !defined(my_strlcat) -#if defined(NEED_my_strlcat) -static Size_t DPPP_(my_my_strlcat)(char * dst, const char * src, Size_t size); -static -#else -extern Size_t DPPP_(my_my_strlcat)(char * dst, const char * src, Size_t size); -#endif - -#define my_strlcat DPPP_(my_my_strlcat) -#define Perl_my_strlcat DPPP_(my_my_strlcat) - -#if defined(NEED_my_strlcat) || defined(NEED_my_strlcat_GLOBAL) - -Size_t -DPPP_(my_my_strlcat)(char *dst, const char *src, Size_t size) -{ - Size_t used, length, copy; - - used = strlen(dst); - length = strlen(src); - if (size > 0 && used < size - 1) { - copy = (length >= size - used) ? size - used - 1 : length; - memcpy(dst + used, src, copy); - dst[used + copy] = '\0'; - } - return used + length; -} -#endif -#endif - -#if !defined(my_strlcpy) -#if defined(NEED_my_strlcpy) -static Size_t DPPP_(my_my_strlcpy)(char * dst, const char * src, Size_t size); -static -#else -extern Size_t DPPP_(my_my_strlcpy)(char * dst, const char * src, Size_t size); -#endif - -#define my_strlcpy DPPP_(my_my_strlcpy) -#define Perl_my_strlcpy DPPP_(my_my_strlcpy) - -#if defined(NEED_my_strlcpy) || defined(NEED_my_strlcpy_GLOBAL) - -Size_t -DPPP_(my_my_strlcpy)(char *dst, const char *src, Size_t size) -{ - Size_t length, copy; - - length = strlen(src); - if (size > 0) { - copy = (length >= size) ? size - 1 : length; - memcpy(dst, src, copy); - dst[copy] = '\0'; - } - return length; -} - -#endif -#endif -#ifndef PERL_PV_ESCAPE_QUOTE -# define PERL_PV_ESCAPE_QUOTE 0x0001 -#endif - -#ifndef PERL_PV_PRETTY_QUOTE -# define PERL_PV_PRETTY_QUOTE PERL_PV_ESCAPE_QUOTE -#endif - -#ifndef PERL_PV_PRETTY_ELLIPSES -# define PERL_PV_PRETTY_ELLIPSES 0x0002 -#endif - -#ifndef PERL_PV_PRETTY_LTGT -# define PERL_PV_PRETTY_LTGT 0x0004 -#endif - -#ifndef PERL_PV_ESCAPE_FIRSTCHAR -# define PERL_PV_ESCAPE_FIRSTCHAR 0x0008 -#endif - -#ifndef PERL_PV_ESCAPE_UNI -# define PERL_PV_ESCAPE_UNI 0x0100 -#endif - -#ifndef PERL_PV_ESCAPE_UNI_DETECT -# define PERL_PV_ESCAPE_UNI_DETECT 0x0200 -#endif - -#ifndef PERL_PV_ESCAPE_ALL -# define PERL_PV_ESCAPE_ALL 0x1000 -#endif - -#ifndef PERL_PV_ESCAPE_NOBACKSLASH -# define PERL_PV_ESCAPE_NOBACKSLASH 0x2000 -#endif - -#ifndef PERL_PV_ESCAPE_NOCLEAR -# define PERL_PV_ESCAPE_NOCLEAR 0x4000 -#endif - -#ifndef PERL_PV_ESCAPE_RE -# define PERL_PV_ESCAPE_RE 0x8000 -#endif - -#ifndef PERL_PV_PRETTY_NOCLEAR -# define PERL_PV_PRETTY_NOCLEAR PERL_PV_ESCAPE_NOCLEAR -#endif -#ifndef PERL_PV_PRETTY_DUMP -# define PERL_PV_PRETTY_DUMP PERL_PV_PRETTY_ELLIPSES|PERL_PV_PRETTY_QUOTE -#endif - -#ifndef PERL_PV_PRETTY_REGPROP -# define PERL_PV_PRETTY_REGPROP PERL_PV_PRETTY_ELLIPSES|PERL_PV_PRETTY_LTGT|PERL_PV_ESCAPE_RE -#endif - -/* Hint: pv_escape - * Note that unicode functionality is only backported to - * those perl versions that support it. For older perl - * versions, the implementation will fall back to bytes. - */ - -#ifndef pv_escape -#if defined(NEED_pv_escape) -static char * DPPP_(my_pv_escape)(pTHX_ SV * dsv, char const * const str, const STRLEN count, const STRLEN max, STRLEN * const escaped, const U32 flags); -static -#else -extern char * DPPP_(my_pv_escape)(pTHX_ SV * dsv, char const * const str, const STRLEN count, const STRLEN max, STRLEN * const escaped, const U32 flags); -#endif - -#ifdef pv_escape -# undef pv_escape -#endif -#define pv_escape(a,b,c,d,e,f) DPPP_(my_pv_escape)(aTHX_ a,b,c,d,e,f) -#define Perl_pv_escape DPPP_(my_pv_escape) - -#if defined(NEED_pv_escape) || defined(NEED_pv_escape_GLOBAL) - -char * -DPPP_(my_pv_escape)(pTHX_ SV *dsv, char const * const str, - const STRLEN count, const STRLEN max, - STRLEN * const escaped, const U32 flags) -{ - const char esc = flags & PERL_PV_ESCAPE_RE ? '%' : '\\'; - const char dq = flags & PERL_PV_ESCAPE_QUOTE ? '"' : esc; - char octbuf[32] = "%123456789ABCDF"; - STRLEN wrote = 0; - STRLEN chsize = 0; - STRLEN readsize = 1; -#if defined(is_utf8_string) && defined(utf8_to_uvchr) - bool isuni = flags & PERL_PV_ESCAPE_UNI ? 1 : 0; -#endif - const char *pv = str; - const char * const end = pv + count; - octbuf[0] = esc; - - if (!(flags & PERL_PV_ESCAPE_NOCLEAR)) - sv_setpvs(dsv, ""); - -#if defined(is_utf8_string) && defined(utf8_to_uvchr) - if ((flags & PERL_PV_ESCAPE_UNI_DETECT) && is_utf8_string((U8*)pv, count)) - isuni = 1; -#endif - - for (; pv < end && (!max || wrote < max) ; pv += readsize) { - const UV u = -#if defined(is_utf8_string) && defined(utf8_to_uvchr) - isuni ? utf8_to_uvchr((U8*)pv, &readsize) : -#endif - (U8)*pv; - const U8 c = (U8)u & 0xFF; - - if (u > 255 || (flags & PERL_PV_ESCAPE_ALL)) { - if (flags & PERL_PV_ESCAPE_FIRSTCHAR) - chsize = my_snprintf(octbuf, sizeof octbuf, - "%"UVxf, u); - else - chsize = my_snprintf(octbuf, sizeof octbuf, - "%cx{%"UVxf"}", esc, u); - } else if (flags & PERL_PV_ESCAPE_NOBACKSLASH) { - chsize = 1; - } else { - if (c == dq || c == esc || !isPRINT(c)) { - chsize = 2; - switch (c) { - case '\\' : /* fallthrough */ - case '%' : if (c == esc) - octbuf[1] = esc; - else - chsize = 1; - break; - case '\v' : octbuf[1] = 'v'; break; - case '\t' : octbuf[1] = 't'; break; - case '\r' : octbuf[1] = 'r'; break; - case '\n' : octbuf[1] = 'n'; break; - case '\f' : octbuf[1] = 'f'; break; - case '"' : if (dq == '"') - octbuf[1] = '"'; - else - chsize = 1; - break; - default: chsize = my_snprintf(octbuf, sizeof octbuf, - pv < end && isDIGIT((U8)*(pv+readsize)) - ? "%c%03o" : "%c%o", esc, c); - } - } else { - chsize = 1; - } - } - if (max && wrote + chsize > max) { - break; - } else if (chsize > 1) { - sv_catpvn(dsv, octbuf, chsize); - wrote += chsize; - } else { - char tmp[2]; - my_snprintf(tmp, sizeof tmp, "%c", c); - sv_catpvn(dsv, tmp, 1); - wrote++; - } - if (flags & PERL_PV_ESCAPE_FIRSTCHAR) - break; - } - if (escaped != NULL) - *escaped= pv - str; - return SvPVX(dsv); -} - -#endif -#endif - -#ifndef pv_pretty -#if defined(NEED_pv_pretty) -static char * DPPP_(my_pv_pretty)(pTHX_ SV * dsv, char const * const str, const STRLEN count, const STRLEN max, char const * const start_color, char const * const end_color, const U32 flags); -static -#else -extern char * DPPP_(my_pv_pretty)(pTHX_ SV * dsv, char const * const str, const STRLEN count, const STRLEN max, char const * const start_color, char const * const end_color, const U32 flags); -#endif - -#ifdef pv_pretty -# undef pv_pretty -#endif -#define pv_pretty(a,b,c,d,e,f,g) DPPP_(my_pv_pretty)(aTHX_ a,b,c,d,e,f,g) -#define Perl_pv_pretty DPPP_(my_pv_pretty) - -#if defined(NEED_pv_pretty) || defined(NEED_pv_pretty_GLOBAL) - -char * -DPPP_(my_pv_pretty)(pTHX_ SV *dsv, char const * const str, const STRLEN count, - const STRLEN max, char const * const start_color, char const * const end_color, - const U32 flags) -{ - const U8 dq = (flags & PERL_PV_PRETTY_QUOTE) ? '"' : '%'; - STRLEN escaped; - - if (!(flags & PERL_PV_PRETTY_NOCLEAR)) - sv_setpvs(dsv, ""); - - if (dq == '"') - sv_catpvs(dsv, "\""); - else if (flags & PERL_PV_PRETTY_LTGT) - sv_catpvs(dsv, "<"); - - if (start_color != NULL) - sv_catpv(dsv, D_PPP_CONSTPV_ARG(start_color)); - - pv_escape(dsv, str, count, max, &escaped, flags | PERL_PV_ESCAPE_NOCLEAR); - - if (end_color != NULL) - sv_catpv(dsv, D_PPP_CONSTPV_ARG(end_color)); - - if (dq == '"') - sv_catpvs(dsv, "\""); - else if (flags & PERL_PV_PRETTY_LTGT) - sv_catpvs(dsv, ">"); - - if ((flags & PERL_PV_PRETTY_ELLIPSES) && escaped < count) - sv_catpvs(dsv, "..."); - - return SvPVX(dsv); -} - -#endif -#endif - -#ifndef pv_display -#if defined(NEED_pv_display) -static char * DPPP_(my_pv_display)(pTHX_ SV * dsv, const char * pv, STRLEN cur, STRLEN len, STRLEN pvlim); -static -#else -extern char * DPPP_(my_pv_display)(pTHX_ SV * dsv, const char * pv, STRLEN cur, STRLEN len, STRLEN pvlim); -#endif - -#ifdef pv_display -# undef pv_display -#endif -#define pv_display(a,b,c,d,e) DPPP_(my_pv_display)(aTHX_ a,b,c,d,e) -#define Perl_pv_display DPPP_(my_pv_display) - -#if defined(NEED_pv_display) || defined(NEED_pv_display_GLOBAL) - -char * -DPPP_(my_pv_display)(pTHX_ SV *dsv, const char *pv, STRLEN cur, STRLEN len, STRLEN pvlim) -{ - pv_pretty(dsv, pv, cur, pvlim, NULL, NULL, PERL_PV_PRETTY_DUMP); - if (len > cur && pv[cur] == '\0') - sv_catpvs(dsv, "\\0"); - return SvPVX(dsv); -} - -#endif -#endif - -#endif /* _P_P_PORTABILITY_H_ */ - -/* End of File ppport.h */ diff --git a/xs/src/xsinit.h b/xs/src/xsinit.h deleted file mode 100644 index dcf56a6d49..0000000000 --- a/xs/src/xsinit.h +++ /dev/null @@ -1,262 +0,0 @@ -#ifndef _xsinit_h_ -#define _xsinit_h_ - -#ifdef _MSC_VER -// Disable some obnoxious warnings given by Visual Studio with the default warning level 4. -#pragma warning(disable: 4100 4127 4189 4244 4267 4700 4702 4800) -#endif - -// undef some macros set by Perl which cause compilation errors on Win32 -#undef read -#undef seekdir -#undef bind -#undef send -#undef connect -#undef wait -#undef accept -#undef close -#undef open -#undef write -#undef socket -#undef listen -#undef shutdown -#undef ioctl -#undef getpeername -#undef rect -#undef setsockopt -#undef getsockopt -#undef getsockname -#undef gethostname -#undef select -#undef socketpair -#undef recvfrom -#undef sendto -#undef pause - -// these need to be included early for Win32 (listing it in Build.PL is not enough) -#include -#include -#include -// #include - -#ifdef SLIC3RXS -// extern "C" { -#include "EXTERN.h" -#include "perl.h" -#include "XSUB.h" -#include "ppport.h" -#undef do_open -#undef do_close -#undef bind -#undef seed -#undef push -#undef pop -#ifdef _MSC_VER - // Undef some of the macros set by Perl , which cause compilation errors on Win32 - #undef connect - #undef link - #undef unlink - #undef seek - #undef send - #undef write - #undef open - #undef close - #undef seekdir - #undef setbuf - #undef fread - #undef fseek - #undef fputc - #undef fwrite - #undef fclose - #undef sleep - #undef snprintf - #undef vsnprintf - #undef strerror - #undef test - #undef times - #undef accept - #undef wait - #undef abort - #undef pause - - // Breaks compilation with Eigen matrices embedded into Slic3r::Point. - #undef malloc - #undef realloc - #undef free - #undef select - - // Because of TBB - #undef _WIN32_WINNT // To avoid compiler warnings - #define _WIN32_WINNT 0x0502 -#endif /* _MSC_VER */ -#undef Zero -#undef Packet -#undef _ -// } -#endif - -#include -#include -#include -#include -#include -#include -#include -#include - -namespace Slic3r { - -template -struct ClassTraits { - // Name of a Perl alias of a C++ class type, owned by Perl, reference counted. - static const char* name; - // Name of a Perl alias of a C++ class type, owned by the C++ code. - // The references shall be enumerated at the end of XS.pm, where the desctructor is undefined with sub DESTROY {}, - // so Perl will never delete the object instance. - static const char* name_ref; -}; - -// use this for typedefs for which the forward prototype -// in REGISTER_CLASS won't work -#define __REGISTER_CLASS(cname, perlname) \ - template <>const char* ClassTraits::name = "Slic3r::" perlname; \ - template <>const char* ClassTraits::name_ref = "Slic3r::" perlname "::Ref"; - -#define REGISTER_CLASS(cname,perlname) \ - class cname; \ - __REGISTER_CLASS(cname, perlname); - -// Return Perl alias to a C++ class name. -template -const char* perl_class_name(const T*) { return ClassTraits::name; } -// Return Perl alias to a C++ class name, suffixed with ::Ref. -// Such a C++ class instance will not be destroyed by Perl, the instance destruction is left to the C++ code. -template -const char* perl_class_name_ref(const T*) { return ClassTraits::name_ref; } - -// Mark the Perl SV (Scalar Value) as owning a "blessed" pointer to an object reference. -// Perl will never release the C++ instance. -template -SV* perl_to_SV_ref(T &t) { - SV* sv = newSV(0); - sv_setref_pv( sv, perl_class_name_ref(&t), &t ); - return sv; -} - -// Mark the Perl SV (Scalar Value) as owning a "blessed" pointer to an object instance. -// Perl will own the C++ instance, therefore it will also release it. -template -SV* perl_to_SV_clone_ref(const T &t) { - SV* sv = newSV(0); - sv_setref_pv( sv, perl_class_name(&t), new T(t) ); - return sv; -} - -// Reference wrapper to provide a C++ instance to Perl while keeping Perl from destroying the instance. -// The instance is created temporarily by XS.cpp just to provide Perl with a CLASS name and a object instance pointer. -template -class Ref { - T* val; -public: - Ref() : val(NULL) {} - Ref(T* t) : val(t) {} - Ref(const T* t) : val(const_cast(t)) {} - // Called by XS.cpp to convert the referenced object instance to a Perl SV, before it is blessed with the name - // returned by CLASS() - operator T*() const { return val; } - // Name to bless the Perl SV with. The name ends with a "::Ref" suffix to keep Perl from destroying the object instance. - static const char* CLASS() { return ClassTraits::name_ref; } -}; - -// Wrapper to clone a C++ object instance before passing it to Perl for ownership. -// This wrapper instance is created temporarily by XS.cpp to provide Perl with a CLASS name and a object instance pointer. -template -class Clone { - T* val; -public: - Clone() : val(NULL) {} - Clone(T* t) : val(new T(*t)) {} - Clone(const T& t) : val(new T(t)) {} - // Called by XS.cpp to convert the cloned object instance to a Perl SV, before it is blessed with the name - // returned by CLASS() - operator T*() const { return val; } - // Name to bless the Perl SV with. If there is a destructor registered in the XSP file for this class, then Perl will - // call this destructor when the reference counter of this SV drops to zero. - static const char* CLASS() { return ClassTraits::name; } -}; - -SV* ConfigBase__as_hash(ConfigBase* THIS); -SV* ConfigOption_to_SV(const ConfigOption &opt, const ConfigOptionDef &def); -SV* ConfigBase__get(ConfigBase* THIS, const t_config_option_key &opt_key); -SV* ConfigBase__get_at(ConfigBase* THIS, const t_config_option_key &opt_key, size_t i); -bool ConfigBase__set(ConfigBase* THIS, const t_config_option_key &opt_key, SV* value); -bool ConfigBase__set_deserialize(ConfigBase* THIS, const t_config_option_key &opt_key, SV* str); -void ConfigBase__set_ifndef(ConfigBase* THIS, const t_config_option_key &opt_key, SV* value, bool deserialize = false); -bool StaticConfig__set(StaticConfig* THIS, const t_config_option_key &opt_key, SV* value); -SV* to_AV(ExPolygon* expolygon); -SV* to_SV_pureperl(const ExPolygon* expolygon); -void from_SV(SV* expoly_sv, ExPolygon* expolygon); -void from_SV_check(SV* expoly_sv, ExPolygon* expolygon); -void from_SV(SV* line_sv, Line* THIS); -void from_SV_check(SV* line_sv, Line* THIS); -SV* to_AV(Line* THIS); -SV* to_SV_pureperl(const Line* THIS); -void from_SV(SV* poly_sv, MultiPoint* THIS); -void from_SV_check(SV* poly_sv, MultiPoint* THIS); -SV* to_AV(MultiPoint* THIS); -SV* to_SV_pureperl(const MultiPoint* THIS); -void from_SV_check(SV* poly_sv, Polygon* THIS); -void from_SV_check(SV* poly_sv, Polyline* THIS); -SV* to_SV_pureperl(const Point* THIS); -void from_SV(SV* point_sv, Point* point); -void from_SV_check(SV* point_sv, Point* point); -SV* to_SV_pureperl(const Vec2d* point); -bool from_SV(SV* point_sv, Vec2d* point); -bool from_SV_check(SV* point_sv, Vec2d* point); -void from_SV_check(SV* surface_sv, Surface* THIS); -SV* to_SV(TriangleMesh* THIS); - -} - -// Defined in wxPerlIface.cpp -// Return a pointer to the associated wxWidgets object instance given by classname. -extern void* wxPli_sv_2_object( pTHX_ SV* scalar, const char* classname ); - -inline void confess_at(const char *file, int line, const char *func, const char *pat, ...) -{ - #ifdef SLIC3RXS - va_list args; - SV *error_sv = newSVpvf("Error in function %s at %s:%d: ", func, - file, line); - - va_start(args, pat); - sv_vcatpvf(error_sv, pat, &args); - va_end(args); - - sv_catpvn(error_sv, "\n\t", 2); - - dSP; - ENTER; - SAVETMPS; - PUSHMARK(SP); - XPUSHs( sv_2mortal(error_sv) ); - PUTBACK; - call_pv("Carp::confess", G_DISCARD); - FREETMPS; - LEAVE; - #endif -} - -#ifndef CONFESS -/* Implementation of CONFESS("foo"): */ -#ifdef _MSC_VER - #define CONFESS(...) confess_at(__FILE__, __LINE__, __FUNCTION__, __VA_ARGS__) -#else - #define CONFESS(...) confess_at(__FILE__, __LINE__, __func__, __VA_ARGS__) -#endif -/* End implementation of CONFESS("foo"): */ -#endif /* CONFESS */ - -using namespace Slic3r; - -#endif diff --git a/xs/t/15_config.t b/xs/t/15_config.t deleted file mode 100644 index 4d032019c2..0000000000 --- a/xs/t/15_config.t +++ /dev/null @@ -1,252 +0,0 @@ -#!/usr/bin/perl - -use strict; -use warnings; - -use Slic3r::XS; -use Test::More tests => 143; - -foreach my $config (Slic3r::Config->new, Slic3r::Config::Static::new_FullPrintConfig) { - $config->set('layer_height', 0.3); - ok abs($config->get('layer_height') - 0.3) < 1e-4, 'set/get float'; - is $config->opt_serialize('layer_height'), '0.3', 'serialize float'; - - $config->set('perimeters', 2); - is $config->get('perimeters'), 2, 'set/get int'; - is $config->opt_serialize('perimeters'), '2', 'serialize int'; - - $config->set('extrusion_axis', 'A'); - is $config->get('extrusion_axis'), 'A', 'set/get string'; - is $config->opt_serialize('extrusion_axis'), 'A', 'serialize string'; - - $config->set('notes', "foo\nbar"); - is $config->get('notes'), "foo\nbar", 'set/get string with newline'; - is $config->opt_serialize('notes'), 'foo\nbar', 'serialize string with newline'; - $config->set_deserialize('notes', 'bar\nbaz'); - is $config->get('notes'), "bar\nbaz", 'deserialize string with newline'; - - foreach my $test_data ( - { - name => 'empty', - values => [], - serialized => '' - }, - { - name => 'single empty', - values => [''], - serialized => '""' - }, - { - name => 'single noempty, simple', - values => ['RGB'], - serialized => 'RGB' - }, - { - name => 'multiple noempty, simple', - values => ['ABC', 'DEF', '09182745@!#$*(&'], - serialized => 'ABC;DEF;09182745@!#$*(&' - }, - { - name => 'multiple, simple, some empty', - values => ['ABC', 'DEF', '', '09182745@!#$*(&', ''], - serialized => 'ABC;DEF;;09182745@!#$*(&;' - }, - { - name => 'complex', - values => ['some "quoted" notes', "yet\n some notes", "whatever \n notes", ''], - serialized => '"some \"quoted\" notes";"yet\n some notes";"whatever \n notes";' - } - ) - { - $config->set('filament_notes', $test_data->{values}); - is $config->opt_serialize('filament_notes'), $test_data->{serialized}, 'serialize multi-string value ' . $test_data->{name}; - $config->set_deserialize('filament_notes', ''); - is_deeply $config->get('filament_notes'), [], 'deserialize multi-string value - empty ' . $test_data->{name}; - $config->set_deserialize('filament_notes', $test_data->{serialized}); - is_deeply $config->get('filament_notes'), $test_data->{values}, 'deserialize complex multi-string value ' . $test_data->{name}; - } - - $config->set('first_layer_height', 0.3); - ok abs($config->get('first_layer_height') - 0.3) < 1e-4, 'set/get absolute floatOrPercent'; - is $config->opt_serialize('first_layer_height'), '0.3', 'serialize absolute floatOrPercent'; - -# This is no more supported after first_layer_height was moved from PrintObjectConfig to PrintConfig. -# $config->set('first_layer_height', $config->get('layer_height')); -# $config->get_abs_value('first_layer_height'); -# ok abs($config->get_abs_value('first_layer_height') - 0.15) < 1e-4, 'set/get relative floatOrPercent'; -# is $config->opt_serialize('first_layer_height'), '50%', 'serialize relative floatOrPercent'; - - # Uh-oh, we have no point option to test at the moment - #ok $config->set('print_center', [50,80]), 'valid point coordinates'; - #is_deeply $config->get('print_center'), [50,80], 'set/get point'; - #is $config->serialize('print_center'), '50,80', 'serialize point'; - #$config->set_deserialize('print_center', '20,10'); - #is_deeply $config->get('print_center'), [20,10], 'deserialize point'; - #ok !$config->set('print_center', ['t',80]), 'invalid point X'; - #ok !$config->set('print_center', [50,'t']), 'invalid point Y'; - - $config->set('use_relative_e_distances', 1); - is $config->get('use_relative_e_distances'), 1, 'set/get bool'; - is $config->opt_serialize('use_relative_e_distances'), '1', 'serialize bool'; - $config->set('gcode_flavor', 'teacup'); - is $config->get('gcode_flavor'), 'teacup', 'set/get enum'; - is $config->opt_serialize('gcode_flavor'), 'teacup', 'serialize enum'; - $config->set_deserialize('gcode_flavor', 'mach3'); - is $config->get('gcode_flavor'), 'mach3', 'deserialize enum (gcode_flavor)'; - $config->set_deserialize('gcode_flavor', 'machinekit'); - is $config->get('gcode_flavor'), 'machinekit', 'deserialize enum (gcode_flavor)'; - - $config->set_deserialize('fill_pattern', 'line'); - is $config->get('fill_pattern'), 'line', 'deserialize enum (fill_pattern)'; - - $config->set_deserialize('support_material_pattern', 'rectilinear'); - is $config->get('support_material_pattern'), 'rectilinear', 'deserialize enum (support_material_pattern)'; - - $config->set('extruder_offset', [[10,20],[30,45]]); - is_deeply [ map $_->pp, @{$config->get('extruder_offset')} ], [[10,20],[30,45]], 'set/get points'; - $config->set('extruder_offset', [Slic3r::Pointf->new(10,20),Slic3r::Pointf->new(30,45)]); - is_deeply [ map $_->pp, @{$config->get('extruder_offset')} ], [[10,20],[30,45]], 'set/get points'; - is $config->opt_serialize('extruder_offset'), '10x20,30x45', 'serialize points'; - $config->set_deserialize('extruder_offset', '20x10'); - is_deeply [ map $_->pp, @{$config->get('extruder_offset')} ], [[20,10]], 'deserialize points'; - $config->set_deserialize('extruder_offset', '0x0'); - is_deeply [ map $_->pp, @{$config->get('extruder_offset')} ], [[0,0]], 'deserialize points'; - { - my @values = ([10,20]); - $values[2] = [10,20]; # implicitely extend array; this is not the same as explicitely assigning undef to second item - ok !$config->set('extruder_offset', \@values), 'reject undef points'; - } - - # truncate ->get() to first decimal digit - $config->set('nozzle_diameter', [0.2,3]); - is_deeply [ map int($_*10)/10, @{$config->get('nozzle_diameter')} ], [0.2,3], 'set/get floats'; - is $config->opt_serialize('nozzle_diameter'), '0.2,3', 'serialize floats'; - $config->set_deserialize('nozzle_diameter', '0.1,0.4'); - is_deeply [ map int($_*10)/10, @{$config->get('nozzle_diameter')} ], [0.1,0.4], 'deserialize floats'; - $config->set_deserialize('nozzle_diameter', '3'); - is_deeply [ map int($_*10)/10, @{$config->get('nozzle_diameter')} ], [3], 'deserialize a single float'; - { - my @values = (0.4); - $values[2] = 2; # implicitely extend array; this is not the same as explicitely assigning undef to second item - ok !$config->set('nozzle_diameter', \@values), 'reject undef floats'; - } - - $config->set('temperature', [180,210]); - is_deeply $config->get('temperature'), [180,210], 'set/get ints'; - is $config->opt_serialize('temperature'), '180,210', 'serialize ints'; - $config->set_deserialize('temperature', '195,220'); - is_deeply $config->get('temperature'), [195,220], 'deserialize ints'; - { - my @values = (180); - $values[2] = 200; # implicitely extend array; this is not the same as explicitely assigning undef to second item - ok !$config->set('temperature', \@values), 'reject undef ints'; - } - - $config->set('wipe', [1,0]); - is_deeply $config->get('wipe'), [1,0], 'set/get bools'; - is $config->get_at('wipe', 0), 1, 'get_at bools'; - is $config->get_at('wipe', 1), 0, 'get_at bools'; - is $config->get_at('wipe', 9), 1, 'get_at bools'; - is $config->opt_serialize('wipe'), '1,0', 'serialize bools'; - $config->set_deserialize('wipe', '0,1,1'); - is_deeply $config->get('wipe'), [0,1,1], 'deserialize bools'; - $config->set_deserialize('wipe', ''); - is_deeply $config->get('wipe'), [], 'deserialize bools from empty string'; - $config->set_deserialize('retract_layer_change', 0); - is_deeply $config->get('retract_layer_change'), [0], 'deserialize bools from non-string value'; - { - my @values = (1); - $values[2] = 1; # implicitely extend array; this is not the same as explicitely assigning undef to second item - ok !$config->set('wipe', \@values), 'reject undef bools'; - } - - $config->set('post_process', ['foo','bar']); - is_deeply $config->get('post_process'), ['foo','bar'], 'set/get strings'; - is $config->opt_serialize('post_process'), 'foo;bar', 'serialize strings'; - $config->set_deserialize('post_process', 'bar;baz'); - is_deeply $config->get('post_process'), ['bar','baz'], 'deserialize strings'; - { - my @values = ('foo'); - $values[2] = 'bar'; # implicitely extend array; this is not the same as explicitely assigning undef to second item - ok !$config->set('post_process', \@values), 'reject undef strings'; - } - - is_deeply [ sort @{$config->get_keys} ], [ sort keys %{$config->as_hash} ], 'get_keys and as_hash'; -} - -{ - my $config = Slic3r::Config->new; - $config->set('perimeters', 2); - - # test that no crash happens when using set_deserialize() with a key that hasn't been set() yet - $config->set_deserialize('filament_diameter', '3'); - - my $config2 = Slic3r::Config::Static::new_FullPrintConfig; - $config2->apply_dynamic($config); - is $config2->get('perimeters'), 2, 'apply_dynamic'; -} - -{ - my $config = Slic3r::Config::Static::new_FullPrintConfig; - my $config2 = Slic3r::Config->new; - $config2->apply_static($config); - is $config2->get('perimeters'), Slic3r::Config::print_config_def()->{perimeters}{default}, 'apply_static and print_config_def'; - - $config->set('top_solid_infill_speed', 70); - is $config->get_abs_value('top_solid_infill_speed'), 70, 'get_abs_value() works when ratio_over references a floatOrPercent option'; -} - -{ - my $config = Slic3r::Config->new; - $config->set('fill_pattern', 'line'); - - my $config2 = Slic3r::Config->new; - $config2->set('fill_pattern', 'hilbertcurve'); - - is $config->get('fill_pattern'), 'line', 'no interferences between DynamicConfig objects'; -} - -{ - my $config = Slic3r::Config->new; - # the pair [0,0] is part of the test, since it checks whether the 0x0 serialized value is correctly parsed - $config->set('extruder_offset', [ [0,0], [20,0], [0,20] ]); - my $config2 = Slic3r::Config->new; - $config2->apply($config); - is_deeply [ map $_->pp, @{$config->get('extruder_offset')} ], [ map $_->pp, @{$config2->get('extruder_offset')} ], - 'apply dynamic over dynamic'; -} - -{ - my $config = Slic3r::Config->new; - $config->set('extruder', 2); - $config->set('perimeter_extruder', 3); - $config->normalize_fdm; - ok !$config->has('extruder'), 'extruder option is removed after normalize()'; - is $config->get('infill_extruder'), 2, 'undefined extruder is populated with default extruder'; - is $config->get('perimeter_extruder'), 3, 'defined extruder is not overwritten by default extruder'; -} - -{ - my $config = Slic3r::Config->new; - $config->set('infill_extruder', 2); - $config->normalize_fdm; - is $config->get('solid_infill_extruder'), 2, 'undefined solid infill extruder is populated with infill extruder'; -} - -{ - my $config = Slic3r::Config->new; - $config->set('spiral_vase', 1); - $config->set('retract_layer_change', [1,0]); - $config->normalize_fdm; - is_deeply $config->get('retract_layer_change'), [0,0], 'retract_layer_change is disabled with spiral_vase'; -} - -{ - use Cwd qw(abs_path); - use File::Basename qw(dirname); - my $path = abs_path($0); - my $config = Slic3r::Config::load(dirname($path)."/inc/22_config_bad_config_options.ini"); - ok 1, 'did not crash on reading invalid items in config'; -} - -__END__ diff --git a/xs/t/inc/22_config_bad_config_options.ini b/xs/t/inc/22_config_bad_config_options.ini deleted file mode 100644 index b28c624792..0000000000 --- a/xs/t/inc/22_config_bad_config_options.ini +++ /dev/null @@ -1,7 +0,0 @@ -# generated by Slic3r 1.1.7 on Tue Aug 19 21:49:50 2014 -avoid_crossing_perimeters = 1 -bed_size = 200,180 -g0 = 0 -perimeter_acceleration = 0 -support_material_extruder = 1 -support_material_extrusion_width = 0 diff --git a/xs/xsp/Config.xsp b/xs/xsp/Config.xsp deleted file mode 100644 index 3c3ed5bb4d..0000000000 --- a/xs/xsp/Config.xsp +++ /dev/null @@ -1,218 +0,0 @@ -%module{Slic3r::XS}; - -%{ -#include -#include "libslic3r/PrintConfig.hpp" -%} - -%name{Slic3r::Config} class DynamicPrintConfig { - DynamicPrintConfig(); - ~DynamicPrintConfig(); - static DynamicPrintConfig* new_from_defaults() - %code{% RETVAL = DynamicPrintConfig::new_from_defaults_keys(FullPrintConfig::defaults().keys()); %}; - static DynamicPrintConfig* new_from_defaults_keys(std::vector keys); - DynamicPrintConfig* clone() %code{% RETVAL = new DynamicPrintConfig(*THIS); %}; - DynamicPrintConfig* clone_only(std::vector keys) - %code{% RETVAL = new DynamicPrintConfig(); RETVAL->apply_only(*THIS, keys, true); %}; - bool has(t_config_option_key opt_key); - SV* as_hash() - %code{% RETVAL = ConfigBase__as_hash(THIS); %}; - SV* get(t_config_option_key opt_key) - %code{% RETVAL = ConfigBase__get(THIS, opt_key); %}; - SV* get_at(t_config_option_key opt_key, int i) - %code{% RETVAL = ConfigBase__get_at(THIS, opt_key, i); %}; - SV* get_value(t_config_option_key opt_key) - %code{% - const ConfigOptionDef *def = THIS->def()->get(opt_key); - RETVAL = (def != nullptr && ! def->ratio_over.empty()) ? - newSVnv(THIS->get_abs_value(opt_key)) : - ConfigBase__get(THIS, opt_key); - %}; - bool set(t_config_option_key opt_key, SV* value) - %code{% RETVAL = ConfigBase__set(THIS, opt_key, value); %}; - bool set_deserialize(t_config_option_key opt_key, SV* str) - %code{% RETVAL = ConfigBase__set_deserialize(THIS, opt_key, str); %}; - void set_ifndef(t_config_option_key opt_key, SV* value, bool deserialize = false) - %code{% ConfigBase__set_ifndef(THIS, opt_key, value, deserialize); %}; - std::string opt_serialize(t_config_option_key opt_key); - double get_abs_value(t_config_option_key opt_key); - %name{get_abs_value_over} - double get_abs_value(t_config_option_key opt_key, double ratio_over); - void apply(DynamicPrintConfig* other) - %code{% THIS->apply(*other, true); %}; - std::vector diff(DynamicPrintConfig* other) - %code{% RETVAL = THIS->diff(*other); %}; - bool equals(DynamicPrintConfig* other) - %code{% RETVAL = THIS->equals(*other); %}; - void apply_static(StaticPrintConfig* other) - %code{% THIS->apply(*other, true); %}; - %name{get_keys} std::vector keys(); - void erase(t_config_option_key opt_key); - void normalize_fdm(); - %name{setenv} void setenv_(); - double min_object_distance() %code{% RETVAL = Slic3r::min_object_distance(*THIS); %}; - static DynamicPrintConfig* load(char *path) - %code%{ - auto config = new DynamicPrintConfig(); - try { - config->load(path, ForwardCompatibilitySubstitutionRule::Disable); - RETVAL = config; - } catch (std::exception& e) { - delete config; - croak("Error extracting configuration from %s:\n%s\n", path, e.what()); - } - %}; - void save(std::string file); - int validate() %code%{ - std::string err = THIS->validate(); - if (! err.empty()) - croak("Configuration is not valid: %s\n", err.c_str()); - RETVAL = 1; - %}; -}; - -%name{Slic3r::Config::Static} class StaticPrintConfig { - static StaticPrintConfig* new_GCodeConfig() - %code{% RETVAL = new GCodeConfig(); %}; - static StaticPrintConfig* new_PrintConfig() - %code{% RETVAL = static_cast(new PrintConfig()); %}; - static StaticPrintConfig* new_FullPrintConfig() - %code{% RETVAL = static_cast(new FullPrintConfig()); %}; - ~StaticPrintConfig(); - bool has(t_config_option_key opt_key); - SV* as_hash() - %code{% RETVAL = ConfigBase__as_hash(THIS); %}; - SV* get(t_config_option_key opt_key) - %code{% RETVAL = ConfigBase__get(THIS, opt_key); %}; - SV* get_at(t_config_option_key opt_key, int i) - %code{% RETVAL = ConfigBase__get_at(THIS, opt_key, i); %}; - bool set(t_config_option_key opt_key, SV* value) - %code{% RETVAL = StaticConfig__set(THIS, opt_key, value); %}; - bool set_deserialize(t_config_option_key opt_key, SV* str) - %code{% RETVAL = ConfigBase__set_deserialize(THIS, opt_key, str); %}; - void set_ifndef(t_config_option_key opt_key, SV* value, bool deserialize = false) - %code{% ConfigBase__set_ifndef(THIS, opt_key, value, deserialize); %}; - std::string opt_serialize(t_config_option_key opt_key); - double get_abs_value(t_config_option_key opt_key); - %name{get_abs_value_over} - double get_abs_value(t_config_option_key opt_key, double ratio_over); - void apply_static(StaticPrintConfig* other) - %code{% THIS->apply(*other, true); %}; - void apply_dynamic(DynamicPrintConfig* other) - %code{% THIS->apply(*other, true); %}; - %name{get_keys} std::vector keys(); - std::string get_extrusion_axis() - %code{% - if (GCodeConfig* config = dynamic_cast(THIS)) { - RETVAL = get_extrusion_axis(*config); - } else { - CONFESS("This StaticConfig object does not provide get_extrusion_axis()"); - } - %}; - %name{setenv} void setenv_(); - double min_object_distance() %code{% RETVAL = Slic3r::min_object_distance(*THIS); %}; - static StaticPrintConfig* load(char *path) - %code%{ - auto config = new FullPrintConfig(); - try { - config->load(path, ForwardCompatibilitySubstitutionRule::Disable); - RETVAL = static_cast(config); - } catch (std::exception& e) { - delete config; - croak("Error extracting configuration from %s:\n%s\n", path, e.what()); - } - %}; - - void save(std::string file); -}; - -%package{Slic3r::Config}; - -%{ -PROTOTYPES: DISABLE - -SV* -print_config_def() - CODE: - t_optiondef_map &def = *const_cast(&Slic3r::print_config_def.options); - - HV* options_hv = newHV(); - for (t_optiondef_map::iterator oit = def.begin(); oit != def.end(); ++oit) { - HV* hv = newHV(); - - t_config_option_key opt_key = oit->first; - ConfigOptionDef* optdef = &oit->second; - - const char* opt_type; - if (optdef->type == coFloat || optdef->type == coFloats || optdef->type == coFloatOrPercent || optdef->type == coFloatsOrPercents) { - opt_type = "f"; - } else if (optdef->type == coPercent || optdef->type == coPercents) { - opt_type = "percent"; - } else if (optdef->type == coInt || optdef->type == coInts) { - opt_type = "i"; - } else if (optdef->type == coString) { - opt_type = "s"; - } else if (optdef->type == coStrings) { - opt_type = "s@"; - } else if (optdef->type == coPoint || optdef->type == coPoints) { - opt_type = "point"; - } else if (optdef->type == coPoint3) { - opt_type = "point3"; - } else if (optdef->type == coBool || optdef->type == coBools) { - opt_type = "bool"; - } else if (optdef->type == coEnum) { - opt_type = "select"; - } else { - throw "Unknown option type"; - } - (void)hv_stores( hv, "type", newSVpv(opt_type, 0) ); - (void)hv_stores( hv, "height", newSViv(optdef->height) ); - (void)hv_stores( hv, "width", newSViv(optdef->width) ); - (void)hv_stores( hv, "min", newSViv(optdef->min) ); - (void)hv_stores( hv, "max", newSViv(optdef->max) ); - - // aliases - if (!optdef->aliases.empty()) { - AV* av = newAV(); - av_fill(av, optdef->aliases.size()-1); - for (std::vector::iterator it = optdef->aliases.begin(); it != optdef->aliases.end(); ++it) - av_store(av, it - optdef->aliases.begin(), newSVpvn(it->c_str(), it->length())); - (void)hv_stores( hv, "aliases", newRV_noinc((SV*)av) ); - } - - // shortcut - if (!optdef->shortcut.empty()) { - AV* av = newAV(); - av_fill(av, optdef->shortcut.size()-1); - for (std::vector::iterator it = optdef->shortcut.begin(); it != optdef->shortcut.end(); ++it) - av_store(av, it - optdef->shortcut.begin(), newSVpvn(it->c_str(), it->length())); - (void)hv_stores( hv, "shortcut", newRV_noinc((SV*)av) ); - } - - // enum_values - if (optdef->enum_def && !optdef->enum_def->values().empty()) { - AV* av = newAV(); - av_fill(av, optdef->enum_def->values().size()-1); - for (std::vector::const_iterator it = optdef->enum_def->values().begin(); it != optdef->enum_def->values().end(); ++it) - av_store(av, it - optdef->enum_def->values().begin(), newSVpvn(it->c_str(), it->length())); - (void)hv_stores( hv, "values", newRV_noinc((SV*)av) ); - } - - // enum_labels - if (optdef->enum_def && !optdef->enum_def->labels().empty()) { - AV* av = newAV(); - av_fill(av, optdef->enum_def->labels().size()-1); - for (std::vector::const_iterator it = optdef->enum_def->labels().begin(); it != optdef->enum_def->labels().end(); ++it) - av_store(av, it - optdef->enum_def->labels().begin(), newSVpvn_utf8(it->c_str(), it->length(), true)); - (void)hv_stores( hv, "labels", newRV_noinc((SV*)av) ); - } - - if (optdef->default_value) - (void)hv_stores( hv, "default", ConfigOption_to_SV(*optdef->default_value.get(), *optdef) ); - (void)hv_store( options_hv, opt_key.c_str(), opt_key.length(), newRV_noinc((SV*)hv), 0 ); - } - - RETVAL = newRV_noinc((SV*)options_hv); - OUTPUT: - RETVAL -%} diff --git a/xs/xsp/ExPolygon.xsp b/xs/xsp/ExPolygon.xsp deleted file mode 100644 index 50b32544ee..0000000000 --- a/xs/xsp/ExPolygon.xsp +++ /dev/null @@ -1,57 +0,0 @@ -%module{Slic3r::XS}; - -%{ -#include -#include "libslic3r/ExPolygon.hpp" -%} - -%name{Slic3r::ExPolygon} class ExPolygon { - ~ExPolygon(); - Clone clone() - %code{% RETVAL = THIS; %}; - SV* arrayref() - %code{% RETVAL = to_AV(THIS); %}; - SV* pp() - %code{% RETVAL = to_SV_pureperl(THIS); %}; - Ref contour() - %code{% RETVAL = &(THIS->contour); %}; - Polygons* holes() - %code{% RETVAL = &(THIS->holes); %}; - void scale(double factor); - void translate(double x, double y); - double area(); - bool is_valid(); - bool contains_line(Line* line) - %code{% RETVAL = THIS->contains(*line); %}; - bool contains_polyline(Polyline* polyline) - %code{% RETVAL = THIS->contains(*polyline); %}; - bool contains_point(Point* point) - %code{% RETVAL = THIS->contains(*point); %}; - ExPolygons simplify(double tolerance); - Polygons simplify_p(double tolerance); -%{ - -ExPolygon* -ExPolygon::new(...) - CODE: - RETVAL = new ExPolygon (); - // ST(0) is class name, ST(1) is contour and others are holes - from_SV_check(ST(1), &RETVAL->contour); - RETVAL->holes.resize(items-2); - for (unsigned int i = 2; i < items; i++) { - from_SV_check(ST(i), &RETVAL->holes[i-2]); - } - OUTPUT: - RETVAL - -void -ExPolygon::rotate(angle, center_sv) - double angle; - SV* center_sv; - CODE: - Point center; - from_SV_check(center_sv, ¢er); - THIS->rotate(angle, center); - -%} -}; diff --git a/xs/xsp/Geometry.xsp b/xs/xsp/Geometry.xsp deleted file mode 100644 index d31438c0ac..0000000000 --- a/xs/xsp/Geometry.xsp +++ /dev/null @@ -1,51 +0,0 @@ -%module{Slic3r::XS}; - -%{ -#include -#include "libslic3r/Geometry.hpp" -#include "libslic3r/Geometry/ConvexHull.hpp" -#include "libslic3r/ShortestPath.hpp" -%} - - -%package{Slic3r::Geometry}; - -%{ - -Clone -convex_hull(points) - Points points - CODE: - RETVAL = Slic3r::Geometry::convex_hull(points); - OUTPUT: - RETVAL - -double -rad2deg(angle) - double angle - CODE: - RETVAL = Slic3r::Geometry::rad2deg(angle); - OUTPUT: - RETVAL - -double -deg2rad(angle) - double angle - CODE: - RETVAL = Slic3r::Geometry::deg2rad(angle); - OUTPUT: - RETVAL - -IV -_constant() - ALIAS: - X = X - Y = Y - Z = Z - PROTOTYPE: - CODE: - RETVAL = ix; - OUTPUT: RETVAL - -%} - diff --git a/xs/xsp/Line.xsp b/xs/xsp/Line.xsp deleted file mode 100644 index 67308721a3..0000000000 --- a/xs/xsp/Line.xsp +++ /dev/null @@ -1,78 +0,0 @@ -%module{Slic3r::XS}; - -%{ -#include -#include "libslic3r/Line.hpp" -#include "libslic3r/Polyline.hpp" -%} - -%name{Slic3r::Line} class Line { - ~Line(); - Clone clone() - %code{% RETVAL = THIS; %}; - SV* arrayref() - %code{% RETVAL = to_AV(THIS); %}; - SV* pp() - %code{% RETVAL = to_SV_pureperl(THIS); %}; - Ref a() - %code{% RETVAL=&THIS->a; %}; - Ref b() - %code{% RETVAL=&THIS->b; %}; - void reverse(); - void scale(double factor); - void translate(double x, double y); - double length(); - double atan2_(); - double orientation(); - double direction(); - bool parallel_to(double angle); - bool parallel_to_line(Line* line) - %code{% RETVAL = THIS->parallel_to(*line); %}; - Clone midpoint(); - Clone intersection_infinite(Line* other) - %code{% - Point p; - bool res = THIS->intersection_infinite(*other, &p); - if (!res) CONFESS("Intersection failed"); - RETVAL = p; - %}; - Polyline* as_polyline() - %code{% RETVAL = new Polyline(THIS->a, THIS->b); %}; - Clone normal(); - Clone vector(); - double ccw(Point* point) - %code{% RETVAL = cross2((THIS->a - *point).cast(), (THIS->b - THIS->a).cast()); %}; -%{ - -Line* -Line::new(...) - CODE: - RETVAL = new Line (); - // ST(0) is class name, ST(1) and ST(2) are endpoints - from_SV_check(ST(1), &RETVAL->a); - from_SV_check(ST(2), &RETVAL->b); - OUTPUT: - RETVAL - -void -Line::rotate(angle, center_sv) - double angle; - SV* center_sv; - CODE: - Point center; - from_SV_check(center_sv, ¢er); - THIS->rotate(angle, center); - -bool -Line::coincides_with(line_sv) - SV* line_sv; - CODE: - Line line; - from_SV_check(line_sv, &line); - RETVAL = (*THIS) == line; - OUTPUT: - RETVAL - -%} -}; - diff --git a/xs/xsp/Model.xsp b/xs/xsp/Model.xsp deleted file mode 100644 index 9763c55904..0000000000 --- a/xs/xsp/Model.xsp +++ /dev/null @@ -1,286 +0,0 @@ -%module{Slic3r::XS}; - -%{ -#include -#include "libslic3r/Model.hpp" -#include "libslic3r/ModelArrange.hpp" -#include "libslic3r/Print.hpp" -#include "libslic3r/PrintConfig.hpp" -#include "libslic3r/Slicing.hpp" -#include "libslic3r/Format/AMF.hpp" -#include "libslic3r/Format/3mf.hpp" -#include "libslic3r/Format/OBJ.hpp" -#include "libslic3r/Format/STL.hpp" -#include "libslic3r/PresetBundle.hpp" -%} - -%name{Slic3r::Model} class Model { - Model(); - ~Model(); - - %name{read_from_file} Model(std::string input_file, bool add_default_instances = true) - %code%{ - try { - RETVAL = new Model(Model::read_from_file(input_file, nullptr, nullptr, only_if(add_default_instances, Model::LoadAttribute::AddDefaultInstances))); - } catch (std::exception& e) { - croak("Error while opening %s: %s\n", input_file.c_str(), e.what()); - } - %}; - - Clone clone() - %code%{ RETVAL = THIS; %}; - - %name{_add_object} Ref add_object(); - Ref _add_object_clone(ModelObject* other, bool copy_volumes = true) - %code%{ auto ptr = THIS->add_object(*other); if (! copy_volumes) ptr->clear_volumes(); RETVAL = ptr; %}; - void delete_object(size_t idx); - void clear_objects(); - size_t objects_count() - %code%{ RETVAL = THIS->objects.size(); %}; - Ref get_object(int idx) - %code%{ RETVAL = THIS->objects.at(idx); %}; - - Ref get_material(t_model_material_id material_id) - %code%{ - RETVAL = THIS->get_material(material_id); - if (RETVAL == NULL) { - XSRETURN_UNDEF; - } - %}; - - %name{add_material} Ref add_material(t_model_material_id material_id); - Ref add_material_clone(t_model_material_id material_id, ModelMaterial* other) - %code%{ RETVAL = THIS->add_material(material_id, *other); %}; - bool has_material(t_model_material_id material_id) const - %code%{ - RETVAL = (THIS->get_material(material_id) != NULL); - %}; - void delete_material(t_model_material_id material_id); - void clear_materials(); - - std::vector material_names() const - %code%{ - for (ModelMaterialMap::iterator i = THIS->materials.begin(); - i != THIS->materials.end(); ++i) - { - RETVAL.push_back(i->first); - } - %}; - - size_t material_count() const - %code%{ RETVAL = THIS->materials.size(); %}; - - bool add_default_instances(); - void center_instances_around_point(Vec2d* point) - %code%{ THIS->center_instances_around_point(*point); %}; - void translate(double x, double y, double z); - Clone mesh(); - - ModelObjectPtrs* objects() - %code%{ RETVAL = &THIS->objects; %}; - - bool arrange_objects(double dist) %code%{ arrange_objects(*THIS, arr2::InfiniteBed{}, arr2::ArrangeSettings{}.set_distance_from_objects(dist) ); %}; - void duplicate(unsigned int copies_num, double dist) %code%{ duplicate(*THIS, copies_num, arr2::InfiniteBed{}, arr2::ArrangeSettings{}.set_distance_from_objects(dist) ); %}; - bool looks_like_multipart_object() const; - void convert_multipart_object(unsigned int max_extruders); - - bool store_stl(char *path, bool binary) - %code%{ TriangleMesh mesh = THIS->mesh(); RETVAL = Slic3r::store_stl(path, &mesh, binary); %}; - -%{ - -Model* -load_stl(CLASS, path, object_name) - char* CLASS; - char* path; - char* object_name; - CODE: - RETVAL = new Model(); - if (! load_stl(path, RETVAL, object_name)) { - delete RETVAL; - RETVAL = NULL; - } - OUTPUT: - RETVAL - -%} -}; - -%name{Slic3r::Model::Material} class ModelMaterial { - Ref model() - %code%{ RETVAL = THIS->get_model(); %}; - - Ref config() - %code%{ RETVAL = &const_cast(THIS->config.get()); %}; - - std::string get_attribute(std::string name) - %code%{ if (THIS->attributes.find(name) != THIS->attributes.end()) RETVAL = THIS->attributes[name]; %}; - - void set_attribute(std::string name, std::string value) - %code%{ THIS->attributes[name] = value; %}; - -%{ - -SV* -ModelMaterial::attributes() - CODE: - HV* hv = newHV(); - for (t_model_material_attributes::const_iterator attr = THIS->attributes.begin(); attr != THIS->attributes.end(); ++attr) { - (void)hv_store( hv, attr->first.c_str(), attr->first.length(), newSVpv(attr->second.c_str(), attr->second.length()), 0 ); - } - RETVAL = (SV*)newRV_noinc((SV*)hv); - OUTPUT: - RETVAL -%} - -}; - - -%name{Slic3r::Model::Object} class ModelObject { - ModelVolumePtrs* volumes() - %code%{ RETVAL = &THIS->volumes; %}; - - ModelInstancePtrs* instances() - %code%{ RETVAL = &THIS->instances; %}; - - void invalidate_bounding_box(); - Clone mesh(); - Clone raw_mesh(); - - %name{_add_volume} Ref add_volume(TriangleMesh* mesh) - %code%{ RETVAL = THIS->add_volume(*mesh); %}; - Ref _add_volume_clone(ModelVolume* other) - %code%{ RETVAL = THIS->add_volume(*other); %}; - - void delete_volume(size_t idx); - void clear_volumes(); - int volumes_count() - %code%{ RETVAL = THIS->volumes.size(); %}; - Ref get_volume(int idx) - %code%{ RETVAL = THIS->volumes.at(idx); %}; - bool move_volume_up(int idx) - %code%{ - if (idx > 0 && idx < int(THIS->volumes.size())) { - std::swap(THIS->volumes[idx-1], THIS->volumes[idx]); - RETVAL = true; - } else - RETVAL = false; - %}; - bool move_volume_down(int idx) - %code%{ - if (idx >= 0 && idx + 1 < int(THIS->volumes.size())) { - std::swap(THIS->volumes[idx+1], THIS->volumes[idx]); - RETVAL = true; - } else - RETVAL = false; - %}; - - %name{_add_instance} Ref add_instance(); - Ref _add_instance_clone(ModelInstance* other) - %code%{ RETVAL = THIS->add_instance(*other); %}; - void delete_last_instance(); - void clear_instances(); - int instances_count() - %code%{ RETVAL = THIS->instances.size(); %}; - - std::string name() - %code%{ RETVAL = THIS->name; %}; - void set_name(std::string value) - %code%{ THIS->name = value; %}; - std::string input_file() - %code%{ RETVAL = THIS->input_file; %}; - void set_input_file(std::string value) - %code%{ THIS->input_file = value; %}; - Ref config() - %code%{ RETVAL = &const_cast(THIS->config.get()); %}; - - Ref model() - %code%{ RETVAL = THIS->get_model(); %}; - - Ref origin_translation() - %code%{ RETVAL = &THIS->origin_translation; %}; - void set_origin_translation(Vec3d* point) - %code%{ THIS->origin_translation = *point; %}; - - void ensure_on_bed(); - int materials_count() const; - int facets_count(); - void center_around_origin(); - void translate(double x, double y, double z); - void scale_xyz(Vec3d* versor) - %code{% THIS->scale(*versor); %}; - void rotate(float angle, Vec3d* axis) - %code{% THIS->rotate(angle, *axis); %}; - void mirror(Axis axis); - -}; - - -%name{Slic3r::Model::Volume} class ModelVolume { - Ref object() - %code%{ RETVAL = THIS->get_object(); %}; - - std::string name() - %code%{ RETVAL = THIS->name; %}; - void set_name(std::string value) - %code%{ THIS->name = value; %}; - t_model_material_id material_id(); - void set_material_id(t_model_material_id material_id) - %code%{ THIS->set_material_id(material_id); %}; - Ref material(); - - Ref config() - %code%{ RETVAL = &const_cast(THIS->config.get()); %}; - Ref mesh() - %code%{ RETVAL = &THIS->mesh(); %}; - - bool modifier() - %code%{ RETVAL = THIS->is_modifier(); %}; - void set_modifier(bool modifier) - %code%{ THIS->set_type(modifier ? ModelVolumeType::PARAMETER_MODIFIER : ModelVolumeType::MODEL_PART); %}; - bool model_part() - %code%{ RETVAL = THIS->is_model_part(); %}; - bool support_enforcer() - %code%{ RETVAL = THIS->is_support_enforcer(); %}; - void set_support_enforcer() - %code%{ THIS->set_type(ModelVolumeType::SUPPORT_ENFORCER); %}; - bool support_blocker() - %code%{ RETVAL = THIS->is_support_blocker(); %}; - void set_support_blocker() - %code%{ THIS->set_type(ModelVolumeType::SUPPORT_BLOCKER); %}; - - size_t split(unsigned int max_extruders); -}; - - -%name{Slic3r::Model::Instance} class ModelInstance { - Ref object() - %code%{ RETVAL = THIS->get_object(); %}; - - Vec3d* rotation() - %code%{ RETVAL = new Vec3d(THIS->get_rotation(X), THIS->get_rotation(Y), THIS->get_rotation(Z)); %}; - - Vec3d* scaling_factor() - %code%{ RETVAL = new Vec3d(THIS->get_scaling_factor(X), THIS->get_scaling_factor(Y), THIS->get_scaling_factor(Z)); %}; - - Vec2d* offset() - %code%{ RETVAL = new Vec2d(THIS->get_offset(X), THIS->get_offset(Y)); %}; - - void set_rotation(double val) - %code%{ THIS->set_rotation(Z, val); THIS->get_object()->invalidate_bounding_box(); %}; - - void set_rotations(Vec3d *rotation) - %code%{ THIS->set_rotation(*rotation); THIS->get_object()->invalidate_bounding_box(); %}; - - void set_scaling_factor(double val) - %code%{ THIS->set_scaling_factor(X, val); THIS->set_scaling_factor(Y, val); THIS->set_scaling_factor(Z, val); THIS->get_object()->invalidate_bounding_box(); %}; - - void set_scaling_factors(Vec3d *scale) - %code%{ THIS->set_scaling_factor(*scale); THIS->get_object()->invalidate_bounding_box(); %}; - - void set_offset(Vec2d *offset) - %code%{ - THIS->set_offset(X, (*offset)(0)); - THIS->set_offset(Y, (*offset)(1)); - %}; -}; diff --git a/xs/xsp/Point.xsp b/xs/xsp/Point.xsp deleted file mode 100644 index 0d44ea3644..0000000000 --- a/xs/xsp/Point.xsp +++ /dev/null @@ -1,129 +0,0 @@ -%module{Slic3r::XS}; - -%{ -#include -#include "libslic3r/Point.hpp" -#include "libslic3r/Line.hpp" -#include "libslic3r/Polygon.hpp" -#include "libslic3r/Polyline.hpp" -%} - -%name{Slic3r::Point} class Point { - Point(int _x = 0, int _y = 0); - ~Point(); - Clone clone() - %code{% RETVAL=THIS; %}; - void scale(double factor) - %code{% *THIS *= factor; %}; - void translate(double x, double y) - %code{% *THIS += Point(x, y); %}; - SV* arrayref() - %code{% RETVAL = to_SV_pureperl(THIS); %}; - SV* pp() - %code{% RETVAL = to_SV_pureperl(THIS); %}; - int x() - %code{% RETVAL = (*THIS)(0); %}; - int y() - %code{% RETVAL = (*THIS)(1); %}; - void set_x(int val) - %code{% (*THIS)(0) = val; %}; - void set_y(int val) - %code{% (*THIS)(1) = val; %}; - Clone nearest_point(Points points) - %code{% RETVAL = nearest_point(points, *THIS).first; %}; - double distance_to(Point* point) - %code{% RETVAL = (*point - *THIS).cast().norm(); %}; - double distance_to_line(Line* line) - %code{% RETVAL = line->distance_to(*THIS); %}; - double perp_distance_to_line(Line* line) - %code{% RETVAL = line->perp_distance_to(*THIS); %}; - double ccw(Point* p1, Point* p2) - %code{% RETVAL = cross2((*p1 - *THIS).cast(), (*p2 - *p1).cast()); %}; - Point* negative() - %code{% RETVAL = new Point(- *THIS); %}; - std::string serialize() %code{% char buf[2048]; sprintf(buf, "%ld,%ld", (*THIS)(0), (*THIS)(1)); RETVAL = buf; %}; - -%{ - -void -Point::rotate(angle, center_sv) - double angle; - SV* center_sv; - CODE: - Point center; - from_SV_check(center_sv, ¢er); - THIS->rotate(angle, center); - -bool -Point::coincides_with(point_sv) - SV* point_sv; - CODE: - Point point; - from_SV_check(point_sv, &point); - RETVAL = (*THIS) == point; - OUTPUT: - RETVAL - -%} - -}; - -%name{Slic3r::Pointf} class Vec2d { - Vec2d(double _x = 0, double _y = 0); - ~Vec2d(); - Clone clone() - %code{% RETVAL = THIS; %}; - SV* arrayref() - %code{% RETVAL = to_SV_pureperl(THIS); %}; - SV* pp() - %code{% RETVAL = to_SV_pureperl(THIS); %}; - double x() - %code{% RETVAL = (*THIS)(0); %}; - double y() - %code{% RETVAL = (*THIS)(1); %}; - void set_x(double val) - %code{% (*THIS)(0) = val; %}; - void set_y(double val) - %code{% (*THIS)(1) = val; %}; - void translate(double x, double y) - %code{% *THIS += Vec2d(x, y); %}; - void scale(double factor) - %code{% *THIS *= factor; %}; - void rotate(double angle, Vec2d* center) - %code{% *THIS = Eigen::Translation2d(*center) * Eigen::Rotation2Dd(angle) * Eigen::Translation2d(- *center) * Eigen::Vector2d((*THIS)(0), (*THIS)(1)); %}; - Vec2d* negative() - %code{% RETVAL = new Vec2d(- *THIS); %}; - Vec2d* vector_to(Vec2d* point) - %code{% RETVAL = new Vec2d(*point - *THIS); %}; - std::string serialize() %code{% char buf[2048]; sprintf(buf, "%lf,%lf", (*THIS)(0), (*THIS)(1)); RETVAL = buf; %}; -}; - -%name{Slic3r::Pointf3} class Vec3d { - Vec3d(double _x = 0, double _y = 0, double _z = 0); - ~Vec3d(); - Clone clone() - %code{% RETVAL = THIS; %}; - double x() - %code{% RETVAL = (*THIS)(0); %}; - double y() - %code{% RETVAL = (*THIS)(1); %}; - double z() - %code{% RETVAL = (*THIS)(2); %}; - void set_x(double val) - %code{% (*THIS)(0) = val; %}; - void set_y(double val) - %code{% (*THIS)(1) = val; %}; - void set_z(double val) - %code{% (*THIS)(2) = val; %}; - void translate(double x, double y, double z) - %code{% *THIS += Vec3d(x, y, z); %}; - void scale(double factor) - %code{% *THIS *= factor; %}; - double distance_to(Vec3d* point) - %code{% RETVAL = (*point - *THIS).norm(); %}; - Vec3d* negative() - %code{% RETVAL = new Vec3d(- *THIS); %}; - Vec3d* vector_to(Vec3d* point) - %code{% RETVAL = new Vec3d(*point - *THIS); %}; - std::string serialize() %code{% char buf[2048]; sprintf(buf, "%lf,%lf,%lf", (*THIS)(0), (*THIS)(1), (*THIS)(2)); RETVAL = buf; %}; -}; diff --git a/xs/xsp/Polygon.xsp b/xs/xsp/Polygon.xsp deleted file mode 100644 index 95c1d2da3d..0000000000 --- a/xs/xsp/Polygon.xsp +++ /dev/null @@ -1,65 +0,0 @@ -%module{Slic3r::XS}; - -%{ -#include -#include "libslic3r/Polygon.hpp" -%} - -%name{Slic3r::Polygon} class Polygon { - ~Polygon(); - Clone clone() - %code{% RETVAL = THIS; %}; - SV* arrayref() - %code{% RETVAL = to_AV(THIS); %}; - SV* pp() - %code{% RETVAL = to_SV_pureperl(THIS); %}; - void scale(double factor); - void translate(double x, double y); - void reverse(); - Lines lines(); - Clone split_at_vertex(Point* point) - %code{% RETVAL = THIS->split_at_vertex(*point); %}; - Clone split_at_first_point(); - double length(); - double area(); - bool is_counter_clockwise(); - bool is_clockwise(); - bool make_counter_clockwise(); - bool make_clockwise(); - bool is_valid(); - Clone first_point(); - bool contains_point(Point* point) - %code{% RETVAL = THIS->contains(*point); %}; - Polygons simplify(double tolerance); - Clone centroid(); - Clone first_intersection(Line* line) - %code{% - Point p; - (void)THIS->first_intersection(*line, &p); - RETVAL = p; - %}; -%{ - -Polygon* -Polygon::new(...) - CODE: - RETVAL = new Polygon (); - // ST(0) is class name, ST(1) is first point - RETVAL->points.resize(items-1); - for (unsigned int i = 1; i < items; i++) { - from_SV_check(ST(i), &RETVAL->points[i-1]); - } - OUTPUT: - RETVAL - -void -Polygon::rotate(angle, center_sv) - double angle; - SV* center_sv; - CODE: - Point center; - from_SV_check(center_sv, ¢er); - THIS->rotate(angle, center); - -%} -}; diff --git a/xs/xsp/Polyline.xsp b/xs/xsp/Polyline.xsp deleted file mode 100644 index 595d54ec33..0000000000 --- a/xs/xsp/Polyline.xsp +++ /dev/null @@ -1,74 +0,0 @@ -%module{Slic3r::XS}; - -%{ -#include -#include "libslic3r/Polyline.hpp" -%} - -%name{Slic3r::Polyline} class Polyline { - ~Polyline(); - Clone clone() - %code{% RETVAL = THIS; %}; - SV* arrayref() - %code{% RETVAL = to_AV(THIS); %}; - SV* pp() - %code{% RETVAL = to_SV_pureperl(THIS); %}; - void scale(double factor); - void translate(double x, double y); - void pop_back() - %code{% THIS->points.pop_back(); %}; - void reverse(); - Lines lines(); - Clone first_point(); - Clone last_point(); - double length(); - bool is_valid(); - void clip_end(double distance); - void clip_start(double distance); - void extend_end(double distance); - void extend_start(double distance); - void simplify(double tolerance); - void split_at(Point* point, Polyline* p1, Polyline* p2) - %code{% THIS->split_at(*point, p1, p2); %}; -%{ - -Polyline* -Polyline::new(...) - CODE: - RETVAL = new Polyline (); - // ST(0) is class name, ST(1) is first point - RETVAL->points.resize(items-1); - for (unsigned int i = 1; i < items; i++) { - from_SV_check(ST(i), &RETVAL->points[i-1]); - } - OUTPUT: - RETVAL - -void -Polyline::append(...) - CODE: - for (unsigned int i = 1; i < items; i++) { - Point p; - from_SV_check(ST(i), &p); - THIS->points.push_back(p); - } - -void -Polyline::append_polyline(polyline) - Polyline* polyline; - CODE: - for (Points::const_iterator it = polyline->points.begin(); it != polyline->points.end(); ++it) { - THIS->points.push_back((*it)); - } - -void -Polyline::rotate(angle, center_sv) - double angle; - SV* center_sv; - CODE: - Point center; - from_SV_check(center_sv, ¢er); - THIS->rotate(angle, center); - -%} -}; diff --git a/xs/xsp/Print.xsp b/xs/xsp/Print.xsp deleted file mode 100644 index 584a2c1003..0000000000 --- a/xs/xsp/Print.xsp +++ /dev/null @@ -1,68 +0,0 @@ -%module{Slic3r::XS}; - -%{ -#include -#include "libslic3r/Print.hpp" -%} - -%name{Slic3r::Print} class Print { - Print(); - ~Print(); - - Ref model() - %code%{ RETVAL = const_cast(&THIS->model()); %}; - Ref config() - %code%{ RETVAL = const_cast(static_cast(&THIS->config())); %}; - double total_used_filament() - %code%{ RETVAL = THIS->print_statistics().total_used_filament; %}; - - void auto_assign_extruders(ModelObject* model_object); - std::string output_filepath(std::string path = "") - %code%{ - try { - RETVAL = THIS->output_filepath(path); - } catch (std::exception& e) { - croak("%s\n", e.what()); - } - %}; - - bool apply(Model *model, DynamicPrintConfig* config) - %code%{ - // Touching every config as the Perl bindings does not correctly export ModelConfig, - // therefore the configs have often invalid timestamps. - for (auto obj : model->objects) { - obj->config.touch(); - for (auto vol : obj->volumes) - vol->config.touch(); - } - for (auto mat : model->materials) - mat.second->config.touch(); - RETVAL = THIS->apply(*model, *config); - %}; - std::vector extruders() const; - int validate() %code%{ - std::string err = THIS->validate(); - if (! err.empty()) - croak("Configuration is not valid: %s\n", err.c_str()); - RETVAL = 1; - %}; - - void set_status_silent(); - - void process() %code%{ - try { - THIS->process(); - } catch (std::exception& e) { - croak("%s\n", e.what()); - } - %}; - - void export_gcode(char *path_template) %code%{ - try { - THIS->export_gcode(path_template, nullptr); - } catch (std::exception& e) { - croak("%s\n", e.what()); - } - %}; - -}; diff --git a/xs/xsp/TriangleMesh.xsp b/xs/xsp/TriangleMesh.xsp deleted file mode 100644 index 5dc0df7465..0000000000 --- a/xs/xsp/TriangleMesh.xsp +++ /dev/null @@ -1,115 +0,0 @@ -%module{Slic3r::XS}; - -%{ -#include -#include "libslic3r/TriangleMesh.hpp" -#include "libslic3r/TriangleMeshSlicer.hpp" -%} - -%name{Slic3r::TriangleMesh} class TriangleMesh { - TriangleMesh(); - ~TriangleMesh(); - Clone clone() - %code{% RETVAL = THIS; %}; - void write_ascii(char* output_file); - void write_binary(char* output_file); - void scale(float factor); - void scale_xyz(Vec3d* versor) - %code{% THIS->scale(versor->cast()); %}; - void translate(float x, float y, float z); - void rotate_x(float angle); - void rotate_y(float angle); - void rotate_z(float angle); - void mirror_x(); - void mirror_y(); - void mirror_z(); - void align_to_origin(); - void rotate(double angle, Point* center); - void merge(TriangleMesh* mesh) - %code{% THIS->merge(*mesh); %}; - Clone convex_hull(); - Clone center() - %code{% RETVAL = THIS->bounding_box().center(); %}; - int facets_count(); - -%{ - -void -TriangleMesh::ReadFromPerl(vertices, facets) - SV* vertices - SV* facets - CODE: - std::vector out_vertices; - { - AV* vertices_av = (AV*)SvRV(vertices); - int number_of_vertices = av_len(vertices_av) + 1; - out_vertices.reserve(number_of_vertices); - for (int i = 0; i < number_of_vertices; ++ i) { - AV* vertex_av = (AV*)SvRV(*av_fetch(vertices_av, i, 0)); - out_vertices.push_back(Slic3r::Vec3f(SvNV(*av_fetch(vertex_av, 0, 0)), SvNV(*av_fetch(vertex_av, 1, 0)), SvNV(*av_fetch(vertex_av, 2, 0)))); - } - } - std::vector out_indices; - { - AV* facets_av = (AV*)SvRV(facets); - int number_of_facets = av_len(facets_av) + 1; - out_indices.reserve(number_of_facets); - for (int i = 0; i < number_of_facets; ++ i) { - AV* facet_av = (AV*)SvRV(*av_fetch(facets_av, i, 0)); - out_indices.push_back(Slic3r::Vec3i(SvIV(*av_fetch(facet_av, 0, 0)), SvIV(*av_fetch(facet_av, 1, 0)), SvIV(*av_fetch(facet_av, 2, 0)))); - } - } - *THIS = TriangleMesh(std::move(out_vertices), std::move(out_indices)); - -SV* -TriangleMesh::vertices() - CODE: - // vertices - AV* vertices = newAV(); - av_extend(vertices, THIS->its.vertices.size()); - for (size_t i = 0; i < THIS->its.vertices.size(); i++) { - AV* vertex = newAV(); - av_store(vertices, i, newRV_noinc((SV*)vertex)); - av_extend(vertex, 2); - av_store(vertex, 0, newSVnv(THIS->its.vertices[i](0))); - av_store(vertex, 1, newSVnv(THIS->its.vertices[i](1))); - av_store(vertex, 2, newSVnv(THIS->its.vertices[i](2))); - } - - RETVAL = newRV_noinc((SV*)vertices); - OUTPUT: - RETVAL - -SV* -TriangleMesh::facets() - CODE: - // facets - AV* facets = newAV(); - av_extend(facets, THIS->facets_count()); - for (int i = 0; i < THIS->facets_count(); i++) { - AV* facet = newAV(); - av_store(facets, i, newRV_noinc((SV*)facet)); - av_extend(facet, 2); - av_store(facet, 0, newSVnv(THIS->its.indices[i][0])); - av_store(facet, 1, newSVnv(THIS->its.indices[i][1])); - av_store(facet, 2, newSVnv(THIS->its.indices[i][2])); - } - - RETVAL = newRV_noinc((SV*)facets); - OUTPUT: - RETVAL - -SV* -TriangleMesh::size() - CODE: - AV* size = newAV(); - av_extend(size, 2); - av_store(size, 0, newSVnv(THIS->stats().size(0))); - av_store(size, 1, newSVnv(THIS->stats().size(1))); - av_store(size, 2, newSVnv(THIS->stats().size(2))); - RETVAL = newRV_noinc((SV*)size); - OUTPUT: - RETVAL - -%} -}; diff --git a/xs/xsp/XS.xsp b/xs/xsp/XS.xsp deleted file mode 100644 index 66a35366bd..0000000000 --- a/xs/xsp/XS.xsp +++ /dev/null @@ -1,38 +0,0 @@ -%module{Slic3r::XS}; -%package{Slic3r::XS}; - -#include -#include "Utils.hpp" - -%{ - -%} - -%package{Slic3r}; -%{ - -SV* -VERSION() - CODE: - RETVAL = newSVpv(SLIC3R_VERSION, 0); - OUTPUT: RETVAL - -SV* -BUILD() - CODE: - RETVAL = newSVpv(SLIC3R_BUILD_ID, 0); - OUTPUT: RETVAL - -SV* -FORK_NAME() - CODE: - RETVAL = newSVpv(SLIC3R_APP_NAME, 0); - OUTPUT: RETVAL - -void -set_logging_level(level) - unsigned int level; - CODE: - Slic3r::set_logging_level(level); - -%} diff --git a/xs/xsp/my.map b/xs/xsp/my.map deleted file mode 100644 index ba5ed6e046..0000000000 --- a/xs/xsp/my.map +++ /dev/null @@ -1,344 +0,0 @@ -coordf_t T_NV - -std::string T_STD_STRING -t_config_option_key T_STD_STRING -t_model_material_id T_STD_STRING - -std::vector T_STD_VECTOR_STD_STRING - -std::vector T_STD_VECTOR_INT -std::vector T_STD_VECTOR_INT -std::vector T_STD_VECTOR_INT - -std::vector T_STD_VECTOR_UINT - -std::vector T_STD_VECTOR_DOUBLE - -DynamicPrintConfig* O_OBJECT_SLIC3R -Ref O_OBJECT_SLIC3R_T -Clone O_OBJECT_SLIC3R_T - -StaticPrintConfig* O_OBJECT_SLIC3R -Ref O_OBJECT_SLIC3R_T - -GCodeConfig* O_OBJECT_SLIC3R -Ref O_OBJECT_SLIC3R_T - -PrintConfig* O_OBJECT_SLIC3R -Ref O_OBJECT_SLIC3R_T - -FullPrintConfig* O_OBJECT_SLIC3R -Ref O_OBJECT_SLIC3R_T - -TriangleMesh* O_OBJECT_SLIC3R -Ref O_OBJECT_SLIC3R_T -Clone O_OBJECT_SLIC3R_T - -Point* O_OBJECT_SLIC3R -Ref O_OBJECT_SLIC3R_T -Clone O_OBJECT_SLIC3R_T - -Point3* O_OBJECT_SLIC3R -Ref O_OBJECT_SLIC3R_T -Clone O_OBJECT_SLIC3R_T - -Vec2d* O_OBJECT_SLIC3R -Ref O_OBJECT_SLIC3R_T -Clone O_OBJECT_SLIC3R_T - -Vec3d* O_OBJECT_SLIC3R -Ref O_OBJECT_SLIC3R_T -Clone O_OBJECT_SLIC3R_T - -Line* O_OBJECT_SLIC3R -Ref O_OBJECT_SLIC3R_T -Clone O_OBJECT_SLIC3R_T - -Polyline* O_OBJECT_SLIC3R -Ref O_OBJECT_SLIC3R_T -Clone O_OBJECT_SLIC3R_T - -Polygon* O_OBJECT_SLIC3R -Ref O_OBJECT_SLIC3R_T -Clone O_OBJECT_SLIC3R_T - -ExPolygon* O_OBJECT_SLIC3R -Ref O_OBJECT_SLIC3R_T -Clone O_OBJECT_SLIC3R_T - -Model* O_OBJECT_SLIC3R -Ref O_OBJECT_SLIC3R_T -Clone O_OBJECT_SLIC3R_T - -ModelMaterial* O_OBJECT_SLIC3R -Ref O_OBJECT_SLIC3R_T -Clone O_OBJECT_SLIC3R_T - -ModelObject* O_OBJECT_SLIC3R -Ref O_OBJECT_SLIC3R_T -Clone O_OBJECT_SLIC3R_T - -ModelVolume* O_OBJECT_SLIC3R -Ref O_OBJECT_SLIC3R_T -Clone O_OBJECT_SLIC3R_T - -ModelInstance* O_OBJECT_SLIC3R -Ref O_OBJECT_SLIC3R_T -Clone O_OBJECT_SLIC3R_T - -Print* O_OBJECT_SLIC3R -Ref O_OBJECT_SLIC3R_T -Clone O_OBJECT_SLIC3R_T - -Axis T_UV -ExtrusionLoopRole T_UV -ExtrusionRole T_UV -SurfaceType T_UV - -# we return these types whenever we want the items to be cloned -Points T_ARRAYREF -Pointfs T_ARRAYREF -Lines T_ARRAYREF -Polygons T_ARRAYREF -Polylines T_ARRAYREF -ExPolygons T_ARRAYREF - -# we return these types whenever we want the items to be returned -# by reference and marked ::Ref because they're contained in another -# Perl object -Polygons* T_ARRAYREF_PTR -ModelObjectPtrs* T_PTR_ARRAYREF_PTR -ModelVolumePtrs* T_PTR_ARRAYREF_PTR -ModelInstancePtrs* T_PTR_ARRAYREF_PTR - -# we return these types whenever we want the items to be returned -# by reference and not marked ::Ref because they're newly allocated -# and not referenced by any Perl object - - -INPUT - -T_STD_STRING - { - size_t len; - // const char * c = SvPV($arg, len); - // Always convert strings to UTF-8 before passing them to XS - const char * c = SvPVutf8($arg, len); - $var = std::string(c, len); - } - -T_STD_VECTOR_STD_STRING - if (SvROK($arg) && SvTYPE(SvRV($arg))==SVt_PVAV) { - AV* av = (AV*)SvRV($arg); - const unsigned int alen = av_len(av)+1; - $var = std::vector(alen); - STRLEN len; - char* tmp; - SV** elem; - for (unsigned int i = 0; i < alen; i++) { - elem = av_fetch(av, i, 0); - if (elem != NULL) { - tmp = SvPV(*elem, len); - ${var}[i] = std::string(tmp, len); - } - else - ${var}[i] = std::string(\"\"); - } - } - else - Perl_croak(aTHX_ \"%s: %s is not an array reference\", - ${$ALIAS?\q[GvNAME(CvGV(cv))]:\qq[\"$pname\"]}, - \"$var\"); - -T_STD_VECTOR_INT - if (SvROK($arg) && SvTYPE(SvRV($arg))==SVt_PVAV) { - AV* av = (AV*)SvRV($arg); - const unsigned int len = av_len(av)+1; - $var = std::vector(len); - SV** elem; - for (unsigned int i = 0; i < len; i++) { - elem = av_fetch(av, i, 0); - if (elem != NULL) - ${var}[i] = SvIV(*elem); - else - ${var}[i] = 0; - } - } - else - Perl_croak(aTHX_ \"%s: %s is not an array reference\", - ${$ALIAS?\q[GvNAME(CvGV(cv))]:\qq[\"$pname\"]}, - \"$var\"); - -T_STD_VECTOR_UINT - if (SvROK($arg) && SvTYPE(SvRV($arg))==SVt_PVAV) { - AV* av = (AV*)SvRV($arg); - const unsigned int len = av_len(av)+1; - $var = std::vector(len); - SV** elem; - for (unsigned int i = 0; i < len; i++) { - elem = av_fetch(av, i, 0); - if (elem != NULL) - ${var}[i] = SvUV(*elem); - else - ${var}[i] = 0; - } - } - else - Perl_croak(aTHX_ \"%s: %s is not an array reference\", - ${$ALIAS?\q[GvNAME(CvGV(cv))]:\qq[\"$pname\"]}, - \"$var\"); - -T_STD_VECTOR_DOUBLE - if (SvROK($arg) && SvTYPE(SvRV($arg))==SVt_PVAV) { - AV* av = (AV*)SvRV($arg); - const unsigned int len = av_len(av)+1; - $var = std::vector(len); - SV** elem; - for (unsigned int i = 0; i < len; i++) { - elem = av_fetch(av, i, 0); - if (elem != NULL) - ${var}[i] = SvNV(*elem); - else - ${var}[i] = 0.; - } - } - else - Perl_croak(aTHX_ \"%s: %s is not an array reference\", - ${$ALIAS?\q[GvNAME(CvGV(cv))]:\qq[\"$pname\"]}, - \"$var\"); - -O_OBJECT_SLIC3R - if( sv_isobject($arg) && (SvTYPE(SvRV($arg)) == SVt_PVMG) ) { - if ( sv_isa($arg, Slic3r::perl_class_name($var) ) || sv_isa($arg, Slic3r::perl_class_name_ref($var) )) { - $var = ($type)SvIV((SV*)SvRV( $arg )); - } else { - croak(\"$var is not of type %s (got %s)\", Slic3r::perl_class_name($var), HvNAME(SvSTASH(SvRV($arg)))); - XSRETURN_UNDEF; - } - } else { - warn( \"${Package}::$func_name() -- $var is not a blessed SV reference\" ); - XSRETURN_UNDEF; - } - -T_ARRAYREF - if (SvROK($arg) && SvTYPE(SvRV($arg)) == SVt_PVAV) { - AV* av = (AV*)SvRV($arg); - const unsigned int len = av_len(av)+1; - $var.resize(len); - for (unsigned int i = 0; i < len; i++) { - SV** elem = av_fetch(av, i, 0); - from_SV_check(*elem, &$var\[i]); - } - } else - Perl_croak(aTHX_ \"%s: %s is not an array reference\", - ${$ALIAS?\q[GvNAME(CvGV(cv))]:\qq[\"$pname\"]}, - \"$var\"); - -OUTPUT - -T_STD_STRING - $arg = newSVpvn_utf8( $var.c_str(), $var.length(), true ); - -T_STD_VECTOR_STD_STRING - AV* av = newAV(); - $arg = newRV_noinc((SV*)av); - sv_2mortal($arg); - const unsigned int len = $var.size(); - if (len) - av_extend(av, len-1); - for (unsigned int i = 0; i < len; i++) { - const std::string& str = ${var}[i]; - STRLEN len = str.length(); - av_store(av, i, newSVpvn_utf8(str.c_str(), len, true)); - } - -T_STD_VECTOR_INT - AV* av = newAV(); - $arg = newRV_noinc((SV*)av); - sv_2mortal($arg); - const unsigned int len = $var.size(); - if (len) - av_extend(av, len-1); - for (unsigned int i = 0; i < len; i++) { - av_store(av, i, newSViv(${var}[i])); - } - -T_STD_VECTOR_UINT - AV* av = newAV(); - $arg = newRV_noinc((SV*)av); - sv_2mortal($arg); - const unsigned int len = $var.size(); - if (len) - av_extend(av, len-1); - for (unsigned int i = 0; i < len; i++) { - av_store(av, i, newSVuv(${var}[i])); - } - -T_STD_VECTOR_DOUBLE - AV* av = newAV(); - $arg = newRV_noinc((SV*)av); - sv_2mortal($arg); - const unsigned int len = $var.size(); - if (len) - av_extend(av, len-1); - for (unsigned int i = 0; i < len; i++) { - av_store(av, i, newSVnv(${var}[i])); - } - -# return object from pointer -O_OBJECT_SLIC3R - if ($var == NULL) - XSRETURN_UNDEF; - sv_setref_pv( $arg, Slic3r::perl_class_name($var), (void*)$var ); - -# return value handled by template class -O_OBJECT_SLIC3R_T - if ($var == NULL) - XSRETURN_UNDEF; - sv_setref_pv( $arg, $type\::CLASS(), (void*)$var ); - - -T_ARRAYREF - AV* av = newAV(); - $arg = newRV_noinc((SV*)av); - sv_2mortal($arg); - const unsigned int len = $var.size(); - if (len > 0) av_extend(av, len-1); - int i = 0; - for (${type}::const_iterator it = $var.begin(); it != $var.end(); ++it) { - av_store(av, i++, perl_to_SV_clone_ref(*it)); - } - -T_ARRAYREF_PTR - AV* av = newAV(); - $arg = newRV_noinc((SV*)av); - sv_2mortal($arg); - const unsigned int len = $var->size(); - if (len > 0) av_extend(av, len-1); - int i = 0; - for (${ my $t = $type; $t =~ s/\*$//; \$t }::iterator it = $var->begin(); it != $var->end(); ++it) { - av_store(av, i++, perl_to_SV_ref(*it)); - } - -T_PTR_ARRAYREF_PTR - AV* av = newAV(); - $arg = newRV_noinc((SV*)av); - sv_2mortal($arg); - const unsigned int len = $var->size(); - if (len > 0) av_extend(av, len-1); - int i = 0; - for (${ my $t = $type; $t =~ s/\*$//; \$t }::iterator it = $var->begin(); it != $var->end(); ++it) { - av_store(av, i++, perl_to_SV_ref(**it)); - } - -T_PTR_ARRAYREF - AV* av = newAV(); - $arg = newRV_noinc((SV*)av); - sv_2mortal($arg); - const unsigned int len = $var.size(); - if (len > 0) av_extend(av, len-1); - int i = 0; - for (${type}::iterator it = $var.begin(); it != $var.end(); ++it) { - av_store(av, i++, to_SV(*it)); - } - diff --git a/xs/xsp/mytype.map b/xs/xsp/mytype.map deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/xs/xsp/typemap.xspt b/xs/xsp/typemap.xspt deleted file mode 100644 index 7b9c02319d..0000000000 --- a/xs/xsp/typemap.xspt +++ /dev/null @@ -1,99 +0,0 @@ -%typemap{bool}{simple}; -%typemap{size_t}{simple}; -%typemap{coordf_t}{simple}; -%typemap{std::string}; -%typemap{t_config_option_key}; -%typemap{t_model_material_id}; -%typemap{std::vector}; -%typemap{std::vector}; -%typemap{std::vector*}; -%typemap{std::vector}; -%typemap{std::vector*}; -%typemap{std::vector}; -%typemap{std::vector*}; -%typemap{std::vector}; -%typemap{void*}; -%typemap{SV*}; -%typemap{AV*}; -%typemap{Point*}; -%typemap{Ref}{simple}; -%typemap{Clone}{simple}; -%typemap{Point3*}; -%typemap{Ref}{simple}; -%typemap{Clone}{simple}; -%typemap{Vec2d*}; -%typemap{Ref}{simple}; -%typemap{Clone}{simple}; -%typemap{Vec3d*}; -%typemap{Ref}{simple}; -%typemap{Clone}{simple}; -%typemap{DynamicPrintConfig*}; -%typemap{Ref}{simple}; -%typemap{Clone}{simple}; -%typemap{StaticPrintConfig*}; -%typemap{Ref}{simple}; -%typemap{GCodeConfig*}; -%typemap{Ref}{simple}; -%typemap{PrintConfig*}; -%typemap{Ref}{simple}; -%typemap{FullPrintConfig*}; -%typemap{Ref}{simple}; -%typemap{ExPolygon*}; -%typemap{Ref}{simple}; -%typemap{Clone}{simple}; -%typemap{Line*}; -%typemap{Ref}{simple}; -%typemap{Clone}{simple}; -%typemap{Polyline*}; -%typemap{Ref}{simple}; -%typemap{Clone}{simple}; -%typemap{Polygon*}; -%typemap{Ref}{simple}; -%typemap{Clone}{simple}; -%typemap{TriangleMesh*}; -%typemap{Ref}{simple}; -%typemap{Clone}{simple}; - -%typemap{Print*}; -%typemap{Ref}{simple}; -%typemap{Clone}{simple}; - -%typemap{Points}; -%typemap{Pointfs}; -%typemap{Lines}; -%typemap{Polygons}; -%typemap{Polylines}; -%typemap{ExPolygons}; -%typemap{Polygons*}; -%typemap{TriangleMesh*}; -%typemap{Model*}; -%typemap{Ref}{simple}; -%typemap{Clone}{simple}; -%typemap{ModelMaterial*}; -%typemap{Ref}{simple}; -%typemap{Clone}{simple}; -%typemap{ModelObject*}; -%typemap{Ref}{simple}; -%typemap{Clone}{simple}; -%typemap{ModelObjectPtrs*}; -%typemap{Ref}{simple}; -%typemap{Clone}{simple}; -%typemap{ModelVolume*}; -%typemap{Ref}{simple}; -%typemap{Clone}{simple}; -%typemap{ModelVolumePtrs*}; -%typemap{Ref}{simple}; -%typemap{Clone}{simple}; -%typemap{ModelInstance*}; -%typemap{Ref}{simple}; -%typemap{Clone}{simple}; -%typemap{ModelInstancePtrs*}; -%typemap{Ref}{simple}; -%typemap{Clone}{simple}; - -%typemap{Axis}{parsed}{ - %cpp_type{Axis}; - %precall_code{% - $CVar = (Axis)SvUV($PerlVar); - %}; -}; From 6b0dcc658d08164998929e56f9ed00fb186c451f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20=C5=A0ach?= Date: Thu, 4 Jan 2024 16:09:06 +0100 Subject: [PATCH 41/91] Fix narrowing conversion and memory leak in tests --- tests/fff_print/test_gcode.cpp | 4 ++-- tests/libslic3r/test_config.cpp | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/tests/fff_print/test_gcode.cpp b/tests/fff_print/test_gcode.cpp index a61ca2dd8a..593723a272 100644 --- a/tests/fff_print/test_gcode.cpp +++ b/tests/fff_print/test_gcode.cpp @@ -280,8 +280,8 @@ TEST_CASE("M73s have correct percent values", "[GCode]") { Print print; Model model; TriangleMesh test_mesh{mesh(TestMesh::cube_20x20x20)}; - const double layer_height = config.opt_float("layer_height"); - test_mesh.scale(Vec3f{1, 1, layer_height/20}); + const auto layer_height = static_cast(config.opt_float("layer_height")); + test_mesh.scale(Vec3f{1.0F, 1.0F, layer_height/20.0F}); Test::init_print({test_mesh}, print, model, config); check_m73s(print); diff --git a/tests/libslic3r/test_config.cpp b/tests/libslic3r/test_config.cpp index 229edeebae..721d0561a4 100644 --- a/tests/libslic3r/test_config.cpp +++ b/tests/libslic3r/test_config.cpp @@ -110,6 +110,7 @@ TEST_CASE("Config apply dynamic to static", "[Config]") { config2->apply(config, true); CHECK(config2->opt_int("perimeters") == 2); + delete config2; } TEST_CASE("Config apply static to dynamic", "[Config]") { @@ -118,11 +119,13 @@ TEST_CASE("Config apply static to dynamic", "[Config]") { DynamicPrintConfig config2; config2.apply(*config, true); + delete config; CHECK( config2.opt_int("perimeters") == DynamicPrintConfig::full_print_config().opt_int("perimeters") ); + } TEST_CASE("Config apply dynamic to dynamic", "[Config]") { @@ -144,6 +147,7 @@ TEST_CASE("Get abs value on percent", "[Config]") { config->set_deserialize_strict("solid_infill_speed", "60"); config->set_deserialize_strict("top_solid_infill_speed", "10%"); CHECK(config->get_abs_value("top_solid_infill_speed") == 6); + delete config; } TEST_CASE("No interference between DynamicConfig objects", "[Config]") { From a21e442e4fb8d859e4dd7ca041ef7e2d508ebc4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20=C5=A0ach?= Date: Fri, 5 Jan 2024 12:57:05 +0100 Subject: [PATCH 42/91] Remove note about perl from readme --- README.md | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/README.md b/README.md index 7fdf11bbb4..8ae1ea3d06 100644 --- a/README.md +++ b/README.md @@ -19,10 +19,7 @@ the [documentation directory](doc/) for more information. ### What language is it written in? -All user facing code is written in C++, and some legacy code as well as unit -tests are written in Perl. Perl is not required for either development or use -of PrusaSlicer. - +All user facing code is written in C++. The slicing core is the `libslic3r` library, which can be built and used in a standalone way. The command line interface is a thin wrapper over `libslic3r`. From 1f88b49afbc905fb6a5a98f476592881826cce84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20=C5=A0ach?= Date: Fri, 5 Jan 2024 12:59:52 +0100 Subject: [PATCH 43/91] Remove legacy perl code in lib/Slic3r --- lib/Slic3r/Config.pm | 46 ------- lib/Slic3r/GCode/Reader.pm | 95 ------------- lib/Slic3r/Geometry.pm | 46 ------- lib/Slic3r/Line.pm | 13 -- lib/Slic3r/Model.pm | 141 -------------------- lib/Slic3r/Point.pm | 33 ----- lib/Slic3r/Polygon.pm | 14 -- lib/Slic3r/Polyline.pm | 19 --- lib/Slic3r/Test.pm | 267 ------------------------------------- 9 files changed, 674 deletions(-) delete mode 100644 lib/Slic3r/Config.pm delete mode 100644 lib/Slic3r/GCode/Reader.pm delete mode 100644 lib/Slic3r/Geometry.pm delete mode 100644 lib/Slic3r/Line.pm delete mode 100644 lib/Slic3r/Model.pm delete mode 100644 lib/Slic3r/Point.pm delete mode 100644 lib/Slic3r/Polygon.pm delete mode 100644 lib/Slic3r/Polyline.pm delete mode 100644 lib/Slic3r/Test.pm diff --git a/lib/Slic3r/Config.pm b/lib/Slic3r/Config.pm deleted file mode 100644 index 2ca8e75825..0000000000 --- a/lib/Slic3r/Config.pm +++ /dev/null @@ -1,46 +0,0 @@ -#/|/ Copyright (c) Prusa Research 2016 - 2022 VojtÄ›ch Bubník @bubnikv -#/|/ Copyright (c) 2017 Joseph Lenox @lordofhyphens -#/|/ Copyright (c) Slic3r 2011 - 2016 Alessandro Ranellucci @alranel -#/|/ Copyright (c) 2015 Alexander Rössler @machinekoder -#/|/ Copyright (c) 2012 Henrik Brix Andersen @henrikbrixandersen -#/|/ Copyright (c) 2012 Mark Hindess -#/|/ Copyright (c) 2012 Josh McCullough -#/|/ Copyright (c) 2011 - 2012 Michael Moon -#/|/ Copyright (c) 2012 Simon George -#/|/ Copyright (c) 2012 Johannes Reinhardt -#/|/ Copyright (c) 2011 Clarence Risher -#/|/ -#/|/ PrusaSlicer is released under the terms of the AGPLv3 or higher -#/|/ -# Extends C++ class Slic3r::DynamicPrintConfig -# This perl class does not keep any perl class variables, -# all the storage is handled by the underlying C++ code. -package Slic3r::Config; -use strict; -use warnings; -use utf8; - -use List::Util qw(first max); - -# C++ Slic3r::PrintConfigDef exported as a Perl hash of hashes. -# The C++ counterpart is a constant singleton. -our $Options = print_config_def(); - -# Generate accessors. -{ - no strict 'refs'; - for my $opt_key (keys %$Options) { - *{$opt_key} = sub { - #print "Slic3r::Config::accessor $opt_key\n"; - $_[0]->get($opt_key) - }; - } -} - -package Slic3r::Config::Static; -use parent 'Slic3r::Config'; - -sub Slic3r::Config::GCode::new { Slic3r::Config::Static::new_GCodeConfig } -sub Slic3r::Config::Print::new { Slic3r::Config::Static::new_PrintConfig } - -1; diff --git a/lib/Slic3r/GCode/Reader.pm b/lib/Slic3r/GCode/Reader.pm deleted file mode 100644 index d19619ff86..0000000000 --- a/lib/Slic3r/GCode/Reader.pm +++ /dev/null @@ -1,95 +0,0 @@ -#/|/ Copyright (c) Prusa Research 2016 - 2017 VojtÄ›ch Bubník @bubnikv -#/|/ Copyright (c) Slic3r 2013 - 2015 Alessandro Ranellucci @alranel -#/|/ -#/|/ PrusaSlicer is released under the terms of the AGPLv3 or higher -#/|/ -# Helper module to parse and interpret a G-code file, -# invoking a callback for each move extracted from the G-code. -# Currently used by the automatic tests only. -package Slic3r::GCode::Reader; -use Moo; - -has 'config' => (is => 'ro', default => sub { Slic3r::Config::GCode->new }); -has 'X' => (is => 'rw', default => sub {0}); -has 'Y' => (is => 'rw', default => sub {0}); -has 'Z' => (is => 'rw', default => sub {0}); -has 'E' => (is => 'rw', default => sub {0}); -has 'F' => (is => 'rw', default => sub {0}); -has '_extrusion_axis' => (is => 'rw', default => sub {"E"}); - -our $Verbose = 0; -my @AXES = qw(X Y Z E); - -sub apply_print_config { - my ($self, $print_config) = @_; - - $self->config->apply_static($print_config); - $self->_extrusion_axis($self->config->get_extrusion_axis); -} - -sub clone { - my $self = shift; - return (ref $self)->new( - map { $_ => $self->$_ } (@AXES, 'F', '_extrusion_axis', 'config'), - ); -} - -sub parse { - my $self = shift; - my ($gcode, $cb) = @_; - - foreach my $raw_line (split /\R+/, $gcode) { - print "$raw_line\n" if $Verbose || $ENV{SLIC3R_TESTS_GCODE}; - my $line = $raw_line; - $line =~ s/\s*;(.*)//; # strip comment - my %info = (comment => $1, raw => $raw_line); - - # parse command - my ($command, @args) = split /\s+/, $line; - $command //= ''; - my %args = map { /([A-Z])(.*)/; ($1 => $2) } @args; - - # convert extrusion axis - if (exists $args{ $self->_extrusion_axis }) { - $args{E} = $args{ $self->_extrusion_axis }; - } - - # check motion - if ($command =~ /^G[01]$/) { - foreach my $axis (@AXES) { - if (exists $args{$axis}) { - $self->$axis(0) if $axis eq 'E' && $self->config->use_relative_e_distances; - $info{"dist_$axis"} = $args{$axis} - $self->$axis; - $info{"new_$axis"} = $args{$axis}; - } else { - $info{"dist_$axis"} = 0; - $info{"new_$axis"} = $self->$axis; - } - } - $info{dist_XY} = sqrt(($info{dist_X}**2) + ($info{dist_Y}**2)); - if (exists $args{E}) { - if ($info{dist_E} > 0) { - $info{extruding} = 1; - } elsif ($info{dist_E} < 0) { - $info{retracting} = 1 - } - } else { - $info{travel} = 1; - } - } - - # run callback - $cb->($self, $command, \%args, \%info); - - # update coordinates - if ($command =~ /^(?:G[01]|G92)$/) { - for my $axis (@AXES, 'F') { - $self->$axis($args{$axis}) if exists $args{$axis}; - } - } - - # TODO: update temperatures - } -} - -1; diff --git a/lib/Slic3r/Geometry.pm b/lib/Slic3r/Geometry.pm deleted file mode 100644 index 0f8b376442..0000000000 --- a/lib/Slic3r/Geometry.pm +++ /dev/null @@ -1,46 +0,0 @@ -#/|/ Copyright (c) Prusa Research 2017 - 2022 VojtÄ›ch Bubník @bubnikv -#/|/ Copyright (c) Slic3r 2011 - 2015 Alessandro Ranellucci @alranel -#/|/ Copyright (c) 2013 Jose Luis Perez Diez -#/|/ Copyright (c) 2013 Anders Sundman -#/|/ Copyright (c) 2013 Jesse Vincent -#/|/ Copyright (c) 2012 Mike Sheldrake @mesheldrake -#/|/ Copyright (c) 2012 Mark Hindess -#/|/ -#/|/ PrusaSlicer is released under the terms of the AGPLv3 or higher -#/|/ -package Slic3r::Geometry; -use strict; -use warnings; - -require Exporter; -our @ISA = qw(Exporter); - -# Exported by this module. The last section starting with convex_hull is exported by Geometry.xsp -our @EXPORT_OK = qw( - PI epsilon - - scale - unscale - scaled_epsilon - - X Y Z - convex_hull - deg2rad - rad2deg -); - -use constant PI => 4 * atan2(1, 1); -use constant A => 0; -use constant B => 1; -use constant X1 => 0; -use constant Y1 => 1; -use constant X2 => 2; -use constant Y2 => 3; - -sub epsilon () { 1E-4 } -sub scaled_epsilon () { epsilon / &Slic3r::SCALING_FACTOR } - -sub scale ($) { $_[0] / &Slic3r::SCALING_FACTOR } -sub unscale ($) { $_[0] * &Slic3r::SCALING_FACTOR } - -1; diff --git a/lib/Slic3r/Line.pm b/lib/Slic3r/Line.pm deleted file mode 100644 index 1b1c3db10c..0000000000 --- a/lib/Slic3r/Line.pm +++ /dev/null @@ -1,13 +0,0 @@ -#/|/ Copyright (c) Prusa Research 2022 VojtÄ›ch Bubník @bubnikv -#/|/ Copyright (c) Slic3r 2011 - 2014 Alessandro Ranellucci @alranel -#/|/ -#/|/ PrusaSlicer is released under the terms of the AGPLv3 or higher -#/|/ -package Slic3r::Line; -use strict; -use warnings; - -# a line is a two-points line -use parent 'Slic3r::Polyline'; - -1; diff --git a/lib/Slic3r/Model.pm b/lib/Slic3r/Model.pm deleted file mode 100644 index ffbba9b861..0000000000 --- a/lib/Slic3r/Model.pm +++ /dev/null @@ -1,141 +0,0 @@ -#/|/ Copyright (c) Prusa Research 2016 - 2022 VojtÄ›ch Bubník @bubnikv, Enrico Turri @enricoturri1966 -#/|/ Copyright (c) Slic3r 2012 - 2016 Alessandro Ranellucci @alranel -#/|/ -#/|/ PrusaSlicer is released under the terms of the AGPLv3 or higher -#/|/ -# extends C++ class Slic3r::Model -package Slic3r::Model; - -use List::Util qw(first max any); - -sub merge { - my $class = shift; - my @models = @_; - - my $new_model = ref($class) - ? $class - : $class->new; - - $new_model->add_object($_) for map @{$_->objects}, @models; - return $new_model; -} - -sub add_object { - my $self = shift; - - if (@_ == 1) { - # we have a Model::Object - my ($object) = @_; - return $self->_add_object_clone($object); - } else { - my (%args) = @_; - - my $new_object = $self->_add_object; - - $new_object->set_name($args{name}) - if defined $args{name}; - $new_object->set_input_file($args{input_file}) - if defined $args{input_file}; - $new_object->config->apply($args{config}) - if defined $args{config}; - $new_object->set_layer_height_ranges($args{layer_height_ranges}) - if defined $args{layer_height_ranges}; - $new_object->set_origin_translation($args{origin_translation}) - if defined $args{origin_translation}; - - return $new_object; - } -} - -sub set_material { - my $self = shift; - my ($material_id, $attributes) = @_; - - my $material = $self->add_material($material_id); - $material->apply($attributes // {}); - return $material; -} - -# Extends C++ class Slic3r::ModelMaterial -package Slic3r::Model::Material; - -sub apply { - my ($self, $attributes) = @_; - $self->set_attribute($_, $attributes{$_}) for keys %$attributes; -} - -# Extends C++ class Slic3r::ModelObject -package Slic3r::Model::Object; - -use List::Util qw(first sum); - -sub add_volume { - my $self = shift; - - my $new_volume; - if (@_ == 1) { - # we have a Model::Volume - my ($volume) = @_; - - $new_volume = $self->_add_volume_clone($volume); - - if ($volume->material_id ne '') { - # merge material attributes and config (should we rename materials in case of duplicates?) - if (my $material = $volume->object->model->get_material($volume->material_id)) { - my %attributes = %{ $material->attributes }; - if ($self->model->has_material($volume->material_id)) { - %attributes = (%attributes, %{ $self->model->get_material($volume->material_id)->attributes }) - } - my $new_material = $self->model->set_material($volume->material_id, {%attributes}); - $new_material->config->apply($material->config); - } - } - } else { - my %args = @_; - - $new_volume = $self->_add_volume($args{mesh}); - - $new_volume->set_name($args{name}) - if defined $args{name}; - $new_volume->set_material_id($args{material_id}) - if defined $args{material_id}; - $new_volume->set_modifier($args{modifier}) - if defined $args{modifier}; - $new_volume->config->apply($args{config}) - if defined $args{config}; - } - - if ($new_volume->material_id ne '' && !defined $self->model->get_material($new_volume->material_id)) { - # TODO: this should be a trigger on Volume::material_id - $self->model->set_material($new_volume->material_id); - } - - $self->invalidate_bounding_box; - - return $new_volume; -} - -sub add_instance { - my $self = shift; - - if (@_ == 1) { - # we have a Model::Instance - my ($instance) = @_; - return $self->_add_instance_clone($instance); - } else { - my (%args) = @_; - - my $new_instance = $self->_add_instance; - - $new_instance->set_rotations($args{rotation}) - if defined $args{rotation}; - $new_instance->set_scaling_factors($args{scaling_factor}) - if defined $args{scaling_factor}; - $new_instance->set_offset($args{offset}) - if defined $args{offset}; - - return $new_instance; - } -} - -1; diff --git a/lib/Slic3r/Point.pm b/lib/Slic3r/Point.pm deleted file mode 100644 index 60df2b54f9..0000000000 --- a/lib/Slic3r/Point.pm +++ /dev/null @@ -1,33 +0,0 @@ -#/|/ Copyright (c) Prusa Research 2018 VojtÄ›ch Bubník @bubnikv -#/|/ Copyright (c) Slic3r 2011 - 2015 Alessandro Ranellucci @alranel -#/|/ -#/|/ PrusaSlicer is released under the terms of the AGPLv3 or higher -#/|/ -package Slic3r::Point; -use strict; -use warnings; - -sub new_scale { - my $class = shift; - return $class->new(map Slic3r::Geometry::scale($_), @_); -} - -package Slic3r::Pointf; -use strict; -use warnings; - -sub new_unscale { - my $class = shift; - return $class->new(map Slic3r::Geometry::unscale($_), @_); -} - -package Slic3r::Pointf3; -use strict; -use warnings; - -sub new_unscale { - my $class = shift; - return $class->new(map Slic3r::Geometry::unscale($_), @_); -} - -1; diff --git a/lib/Slic3r/Polygon.pm b/lib/Slic3r/Polygon.pm deleted file mode 100644 index 6b4ce05dd2..0000000000 --- a/lib/Slic3r/Polygon.pm +++ /dev/null @@ -1,14 +0,0 @@ -#/|/ Copyright (c) Prusa Research 2017 - 2022 VojtÄ›ch Bubník @bubnikv -#/|/ Copyright (c) Slic3r 2011 - 2014 Alessandro Ranellucci @alranel -#/|/ Copyright (c) 2012 Mark Hindess -#/|/ -#/|/ PrusaSlicer is released under the terms of the AGPLv3 or higher -#/|/ -package Slic3r::Polygon; -use strict; -use warnings; - -# a polygon is a closed polyline. -use parent 'Slic3r::Polyline'; - -1; diff --git a/lib/Slic3r/Polyline.pm b/lib/Slic3r/Polyline.pm deleted file mode 100644 index f071397670..0000000000 --- a/lib/Slic3r/Polyline.pm +++ /dev/null @@ -1,19 +0,0 @@ -#/|/ Copyright (c) Prusa Research 2018 VojtÄ›ch Bubník @bubnikv -#/|/ Copyright (c) Slic3r 2011 - 2014 Alessandro Ranellucci @alranel -#/|/ Copyright (c) 2012 Mark Hindess -#/|/ -#/|/ PrusaSlicer is released under the terms of the AGPLv3 or higher -#/|/ -package Slic3r::Polyline; -use strict; -use warnings; - -use Slic3r::Geometry qw(X Y); - -sub new_scale { - my $class = shift; - my @points = map { ref($_) eq 'Slic3r::Point' ? $_->pp : $_ } @_; - return $class->new(map [ Slic3r::Geometry::scale($_->[X]), Slic3r::Geometry::scale($_->[Y]) ], @points); -} - -1; diff --git a/lib/Slic3r/Test.pm b/lib/Slic3r/Test.pm deleted file mode 100644 index 644920c0bd..0000000000 --- a/lib/Slic3r/Test.pm +++ /dev/null @@ -1,267 +0,0 @@ -#/|/ Copyright (c) Prusa Research 2016 - 2021 VojtÄ›ch Bubník @bubnikv, Lukáš MatÄ›na @lukasmatena, Enrico Turri @enricoturri1966 -#/|/ Copyright (c) 2016 Joseph Lenox @lordofhyphens -#/|/ Copyright (c) Slic3r 2012 - 2016 Alessandro Ranellucci @alranel -#/|/ -#/|/ PrusaSlicer is released under the terms of the AGPLv3 or higher -#/|/ -package Slic3r::Test; -use strict; -use warnings; -use Cwd 'abs_path'; - -require Exporter; -our @ISA = qw(Exporter); -our @EXPORT_OK = qw(_eq); - -use List::Util qw(first); -use Slic3r::Geometry qw(epsilon X Y Z); - -my %cuboids = ( - '20mm_cube' => [20,20,20], - '2x20x10' => [2, 20,10], -); - -sub mesh { - my ($name, %params) = @_; - - my ($vertices, $facets); - if ($cuboids{$name}) { - my ($x, $y, $z) = @{ $cuboids{$name} }; - $vertices = [ - [$x,$y,0], [$x,0,0], [0,0,0], [0,$y,0], [$x,$y,$z], [0,$y,$z], [0,0,$z], [$x,0,$z], - ]; - $facets = [ - [0,1,2], [0,2,3], [4,5,6], [4,6,7], [0,4,7], [0,7,1], [1,7,6], [1,6,2], [2,6,5], [2,5,3], [4,0,3], [4,3,5], - ], - } elsif ($name eq 'box') { - my ($x, $y, $z) = @{ $params{"dim"} }; - $vertices = [ - [$x,$y,0], [$x,0,0], [0,0,0], [0,$y,0], [$x,$y,$z], [0,$y,$z], [0,0,$z], [$x,0,$z], - ]; - $facets = [ - [0,1,2], [0,2,3], [4,5,6], [4,6,7], [0,4,7], [0,7,1], [1,7,6], [1,6,2], [2,6,5], [2,5,3], [4,0,3], [4,3,5], - ], - } elsif ($name eq 'cube_with_hole') { - $vertices = [ - [0,0,0],[0,0,10],[0,20,0],[0,20,10],[20,0,0],[20,0,10],[5,5,0],[15,5,0],[5,15,0],[20,20,0],[15,15,0],[20,20,10],[5,5,10],[5,15,10],[15,5,10],[15,15,10] - ]; - $facets = [ - [0,1,2],[2,1,3],[1,0,4],[5,1,4],[6,7,4],[8,2,9],[0,2,8],[10,8,9],[0,8,6],[0,6,4],[4,7,9],[7,10,9],[2,3,9],[9,3,11],[12,1,5],[13,3,12],[14,12,5],[3,1,12],[11,3,13],[11,15,5],[11,13,15],[15,14,5],[5,4,9],[11,5,9],[8,13,12],[6,8,12],[10,15,13],[8,10,13],[15,10,14],[14,10,7],[14,7,12],[12,7,6] - ], - } elsif ($name eq 'cube_with_concave_hole') { - $vertices = [ - [-10,-10,-5],[-10,-10,5],[-10,10,-5],[-10,10,5],[10,-10,-5],[10,-10,5],[-5,-5,-5],[5,-5,-5],[5,5,-5],[5,10,-5],[-5,5,-5],[3.06161699911402e-16,5,-5],[5,0,-5],[0,0,-5],[10,5,-5],[5,10,5],[-5,-5,5],[5,0,5],[5,-5,5],[-5,5,5],[10,5,5],[5,5,5],[3.06161699911402e-16,5,5],[0,0,5] - ]; - $facets = [ - [0,1,2],[2,1,3],[1,0,4],[5,1,4],[6,7,4],[8,2,9],[10,2,11],[11,12,13],[0,2,10],[0,10,6],[0,6,4],[11,2,8],[4,7,12],[4,12,8],[12,11,8],[14,4,8],[2,3,9],[9,3,15],[16,1,5],[17,18,5],[19,3,16],[20,21,5],[18,16,5],[3,1,16],[22,3,19],[21,3,22],[21,17,5],[21,22,17],[21,15,3],[23,17,22],[5,4,14],[20,5,14],[20,14,21],[21,14,8],[9,15,21],[8,9,21],[10,19,16],[6,10,16],[11,22,19],[10,11,19],[13,23,11],[11,23,22],[23,13,12],[17,23,12],[17,12,18],[18,12,7],[18,7,16],[16,7,6] - ], - } elsif ($name eq 'V') { - $vertices = [ - [-14,0,20],[-14,15,20],[0,0,0],[0,15,0],[-4,0,20],[-4,15,20],[5,0,7.14286],[10,0,0],[24,0,20],[14,0,20],[10,15,0],[5,15,7.14286],[14,15,20],[24,15,20] - ]; - $facets = [ - [0,1,2],[2,1,3],[1,0,4],[5,1,4],[4,0,2],[6,4,2],[7,6,2],[8,9,7],[9,6,7],[2,3,7],[7,3,10],[1,5,3],[3,5,11],[11,12,13],[11,13,3],[3,13,10],[5,4,6],[11,5,6],[6,9,11],[11,9,12],[12,9,8],[13,12,8],[8,7,10],[13,8,10] - ], - } elsif ($name eq 'L') { - $vertices = [ - [0,10,0],[0,10,10],[0,20,0],[0,20,10],[10,10,0],[10,10,10],[20,20,0],[20,0,0],[10,0,0],[20,20,10],[10,0,10],[20,0,10] - ]; - $facets = [ - [0,1,2],[2,1,3],[4,5,1],[0,4,1],[0,2,4],[4,2,6],[4,6,7],[4,7,8],[2,3,6],[6,3,9],[3,1,5],[9,3,5],[10,11,5],[11,9,5],[5,4,10],[10,4,8],[10,8,7],[11,10,7],[11,7,6],[9,11,6] - ], - } elsif ($name eq 'overhang') { - $vertices = [ - [1364.68505859375,614.398010253906,20.002498626709],[1389.68505859375,614.398010253906,20.002498626709],[1377.18505859375,589.398986816406,20.002498626709],[1389.68505859375,589.398986816406,20.002498626709],[1389.68505859375,564.398986816406,20.0014991760254],[1364.68505859375,589.398986816406,20.002498626709],[1364.68505859375,564.398986816406,20.0014991760254],[1360.93505859375,589.398986816406,17.0014991760254],[1360.93505859375,585.64697265625,17.0014991760254],[1357.18505859375,564.398986816406,17.0014991760254],[1364.68505859375,589.398986816406,17.0014991760254],[1364.68505859375,571.899963378906,17.0014991760254],[1364.68505859375,564.398986816406,17.0014991760254],[1348.43603515625,564.398986816406,17.0014991760254],[1352.80908203125,589.398986816406,17.0014991760254],[1357.18408203125,589.398986816406,17.0014991760254],[1357.18310546875,614.398010253906,17.0014991760254],[1364.68505859375,606.89599609375,17.0014991760254],[1364.68505859375,614.398010253906,17.0014991760254],[1352.18603515625,564.398986816406,20.0014991760254],[1363.65405273438,589.398986816406,23.3004989624023],[1359.46704101562,589.398986816406,23.3004989624023],[1358.37109375,564.398986816406,23.3004989624023],[1385.56103515625,564.398986816406,23.3004989624023],[1373.06311035156,589.398986816406,23.3004989624023],[1368.80810546875,564.398986816406,23.3004989624023],[1387.623046875,589.398986816406,23.3004989624023],[1387.623046875,585.276000976562,23.3004989624023],[1389.68505859375,589.398986816406,23.3004989624023],[1389.68505859375,572.64599609375,23.3004989624023],[1389.68505859375,564.398986816406,23.3004989624023],[1367.77709960938,589.398986816406,23.3004989624023],[1366.7470703125,564.398986816406,23.3004989624023],[1354.31201171875,589.398986816406,23.3004989624023],[1352.18603515625,564.398986816406,23.3004989624023],[1389.68505859375,614.398010253906,23.3004989624023],[1377.31701660156,614.398010253906,23.3004989624023],[1381.43908691406,589.398986816406,23.3004989624023],[1368.80700683594,614.398010253906,23.3004989624023],[1368.80810546875,589.398986816406,23.3004989624023],[1356.43908691406,614.398010253906,23.3004989624023],[1357.40502929688,589.398986816406,23.3004989624023],[1360.56201171875,614.398010253906,23.3004989624023],[1348.705078125,614.398010253906,23.3004989624023],[1350.44506835938,589.398986816406,23.3004989624023],[1389.68505859375,606.153015136719,23.3004989624023],[1347.35205078125,589.398986816406,23.3004989624023],[1346.56005859375,589.398986816406,23.3004989624023],[1346.56005859375,594.159912109375,17.0014991760254],[1346.56005859375,589.398986816406,17.0014991760254],[1346.56005859375,605.250427246094,23.3004989624023],[1346.56005859375,614.398010253906,23.3004989624023],[1346.56005859375,614.398010253906,20.8258285522461],[1346.56005859375,614.398010253906,17.0014991760254],[1346.56005859375,564.398986816406,19.10133934021],[1346.56005859375,567.548583984375,23.3004989624023],[1346.56005859375,564.398986816406,17.0020332336426],[1346.56005859375,564.398986816406,23.0018501281738],[1346.56005859375,564.398986816406,23.3004989624023],[1346.56005859375,575.118957519531,17.0014991760254],[1346.56005859375,574.754028320312,23.3004989624023] - ]; - $facets = [ - [0,1,2],[2,3,4],[2,5,0],[4,6,2],[2,6,5],[2,1,3],[7,8,9],[10,9,8],[11,9,10],[12,9,11],[9,13,14],[7,15,16],[10,17,0],[10,0,5],[12,11,6],[18,16,0],[6,19,13],[6,13,9],[9,12,6],[17,18,0],[11,10,5],[11,5,6],[14,16,15],[17,7,18],[16,18,7],[14,15,9],[7,9,15],[7,17,8],[10,8,17],[20,21,22],[23,24,25],[26,23,27],[28,27,23],[29,28,23],[30,29,23],[25,31,32],[22,33,34],[35,36,37],[24,38,39],[21,40,41],[38,42,20],[33,43,44],[6,4,23],[6,23,25],[36,35,1],[1,0,38],[1,38,36],[29,30,4],[25,32,6],[40,42,0],[35,45,1],[4,3,28],[4,28,29],[3,1,45],[3,45,28],[22,34,19],[19,6,32],[19,32,22],[42,38,0],[30,23,4],[0,16,43],[0,43,40],[24,37,36],[38,24,36],[24,23,37],[37,23,26],[22,32,20],[20,32,31],[33,41,40],[43,33,40],[45,35,26],[37,26,35],[33,44,34],[44,43,46],[20,42,21],[40,21,42],[31,39,38],[20,31,38],[33,22,41],[21,41,22],[31,25,39],[24,39,25],[26,27,45],[28,45,27],[47,48,49],[47,50,48],[51,48,50],[52,48,51],[53,48,52],[54,55,56],[57,55,54],[58,55,57],[49,59,47],[60,56,55],[59,56,60],[60,47,59],[48,53,16],[56,13,19],[54,56,19],[56,59,13],[59,49,14],[59,14,13],[49,48,16],[49,16,14],[44,46,60],[44,60,55],[51,50,43],[19,34,58],[19,58,57],[53,52,16],[43,16,52],[43,52,51],[57,54,19],[47,60,46],[55,58,34],[55,34,44],[50,47,46],[50,46,43] - ], - } elsif ($name eq '40x10') { - $vertices = [ - [12.8680295944214,29.5799007415771,12],[11.7364797592163,29.8480796813965,12],[11.1571502685547,29.5300102233887,12],[10.5814504623413,29.9830799102783,12],[10,29.6000003814697,12],[9.41855144500732,29.9830799102783,12],[8.84284687042236,29.5300102233887,12],[8.26351833343506,29.8480796813965,12],[7.70256900787354,29.3210391998291,12],[7.13196802139282,29.5799007415771,12],[6.59579277038574,28.9761600494385,12],[6.03920221328735,29.1821594238281,12],[5.53865718841553,28.5003795623779,12],[5,28.6602592468262,12],[4.54657793045044,27.9006500244141,12],[4.02841377258301,28.0212306976318,12],[3.63402199745178,27.1856994628906,12],[3.13758301734924,27.2737407684326,12],[2.81429696083069,26.3659801483154,12],[2.33955597877502,26.4278793334961,12],[2.0993549823761,25.4534206390381,12],[1.64512205123901,25.4950904846191,12],[1.49962198734283,24.4613399505615,12],[1.0636739730835,24.4879894256592,12],[1.02384400367737,23.4042091369629,12],[0.603073298931122,23.4202003479004,12],[0.678958415985107,22.2974300384521,12],[0.269550800323486,22.3061599731445,12],[0.469994693994522,21.1571502685547,12],[0.067615881562233,21.1609306335449,12],[0.399999290704727,20,12],[0,20,12],[0.399999290704727,5,12],[0,5,12],[0.456633001565933,4.2804012298584,12],[0.0615576282143593,4.21782684326172,12],[0.625140011310577,3.5785219669342,12],[0.244717106223106,3.45491504669189,12],[0.901369392871857,2.91164398193359,12],[0.544967114925385,2.73004698753357,12],[1.27852201461792,2.29618692398071,12],[0.954914808273315,2.06107401847839,12],[1.74730801582336,1.74730801582336,12],[1.46446597576141,1.46446597576141,12],[2.29618692398071,1.27852201461792,12],[2.06107401847839,0.954914808273315,12],[2.91164398193359,0.901369392871857,12],[2.73004698753357,0.544967114925385,12],[3.5785219669342,0.625140011310577,12],[3.45491504669189,0.244717106223106,12],[4.2804012298584,0.456633001565933,12],[4.21782684326172,0.0615576282143593,12],[5,0.399999290704727,12],[5,0,12],[19.6000003814697,0.399999290704727,12],[20,0,12],[19.6000003814697,20,12],[20,20,12],[19.5300102233887,21.1571502685547,12],[19.9323806762695,21.1609306335449,12],[19.3210391998291,22.2974300384521,12],[19.7304496765137,22.3061599731445,12],[18.9761600494385,23.4042091369629,12],[19.3969306945801,23.4202003479004,12],[18.5003795623779,24.4613399505615,12],[18.9363307952881,24.4879894256592,12],[17.9006500244141,25.4534206390381,12],[18.3548793792725,25.4950904846191,12],[17.1856994628906,26.3659801483154,12],[17.6604404449463,26.4278793334961,12],[16.3659801483154,27.1856994628906,12],[16.862419128418,27.2737407684326,12],[15.4534196853638,27.9006500244141,12],[15.9715900421143,28.0212306976318,12],[14.4613399505615,28.5003795623779,12],[15,28.6602592468262,12],[13.4042100906372,28.9761600494385,12],[13.9608001708984,29.1821594238281,12],[12.2974300384521,29.3210391998291,12],[7.13196802139282,29.5799007415771,0],[8.26351833343506,29.8480796813965,0],[8.84284687042236,29.5300102233887,0],[9.41855144500732,29.9830799102783,0],[10,29.6000003814697,0],[10.5814504623413,29.9830799102783,0],[11.1571502685547,29.5300102233887,0],[11.7364797592163,29.8480796813965,0],[12.2974300384521,29.3210391998291,0],[12.8680295944214,29.5799007415771,0],[13.4042100906372,28.9761600494385,0],[13.9608001708984,29.1821594238281,0],[14.4613399505615,28.5003795623779,0],[15,28.6602592468262,0],[15.4534196853638,27.9006500244141,0],[15.9715900421143,28.0212306976318,0],[16.3659801483154,27.1856994628906,0],[16.862419128418,27.2737407684326,0],[17.1856994628906,26.3659801483154,0],[17.6604404449463,26.4278793334961,0],[17.9006500244141,25.4534206390381,0],[18.3548793792725,25.4950904846191,0],[18.5003795623779,24.4613399505615,0],[18.9363307952881,24.4879894256592,0],[18.9761600494385,23.4042091369629,0],[19.3969306945801,23.4202003479004,0],[19.3210391998291,22.2974300384521,0],[19.7304496765137,22.3061599731445,0],[19.5300102233887,21.1571502685547,0],[19.9323806762695,21.1609306335449,0],[19.6000003814697,20,0],[20,20,0],[19.6000003814697,0.399999290704727,0],[20,0,0],[5,0.399999290704727,0],[5,0,0],[4.2804012298584,0.456633001565933,0],[4.21782684326172,0.0615576282143593,0],[3.5785219669342,0.625140011310577,0],[3.45491504669189,0.244717106223106,0],[2.91164398193359,0.901369392871857,0],[2.73004698753357,0.544967114925385,0],[2.29618692398071,1.27852201461792,0],[2.06107401847839,0.954914808273315,0],[1.74730801582336,1.74730801582336,0],[1.46446597576141,1.46446597576141,0],[1.27852201461792,2.29618692398071,0],[0.954914808273315,2.06107401847839,0],[0.901369392871857,2.91164398193359,0],[0.544967114925385,2.73004698753357,0],[0.625140011310577,3.5785219669342,0],[0.244717106223106,3.45491504669189,0],[0.456633001565933,4.2804012298584,0],[0.0615576282143593,4.21782684326172,0],[0.399999290704727,5,0],[0,5,0],[0.399999290704727,20,0],[0,20,0],[0.469994693994522,21.1571502685547,0],[0.067615881562233,21.1609306335449,0],[0.678958415985107,22.2974300384521,0],[0.269550800323486,22.3061599731445,0],[1.02384400367737,23.4042091369629,0],[0.603073298931122,23.4202003479004,0],[1.49962198734283,24.4613399505615,0],[1.0636739730835,24.4879894256592,0],[2.0993549823761,25.4534206390381,0],[1.64512205123901,25.4950904846191,0],[2.81429696083069,26.3659801483154,0],[2.33955597877502,26.4278793334961,0],[3.63402199745178,27.1856994628906,0],[3.13758301734924,27.2737407684326,0],[4.54657793045044,27.9006500244141,0],[4.02841377258301,28.0212306976318,0],[5.53865718841553,28.5003795623779,0],[5,28.6602592468262,0],[6.59579277038574,28.9761600494385,0],[6.03920221328735,29.1821594238281,0],[7.70256900787354,29.3210391998291,0] - ]; - $facets = [ - [0,1,2],[2,1,3],[2,3,4],[4,3,5],[4,5,6],[6,5,7],[6,7,8],[8,7,9],[8,9,10],[10,9,11],[10,11,12],[12,11,13],[12,13,14],[14,13,15],[14,15,16],[16,15,17],[16,17,18],[18,17,19],[18,19,20],[20,19,21],[20,21,22],[22,21,23],[22,23,24],[24,23,25],[24,25,26],[26,25,27],[26,27,28],[28,27,29],[28,29,30],[30,29,31],[30,31,32],[32,31,33],[32,33,34],[34,33,35],[34,35,36],[36,35,37],[36,37,38],[38,37,39],[38,39,40],[40,39,41],[40,41,42],[42,41,43],[42,43,44],[44,43,45],[44,45,46],[46,45,47],[46,47,48],[48,47,49],[48,49,50],[50,49,51],[50,51,52],[52,51,53],[52,53,54],[54,53,55],[54,55,56],[56,55,57],[56,57,58],[58,57,59],[58,59,60],[60,59,61],[60,61,62],[62,61,63],[62,63,64],[64,63,65],[64,65,66],[66,65,67],[66,67,68],[68,67,69],[68,69,70],[70,69,71],[70,71,72],[72,71,73],[72,73,74],[74,73,75],[74,75,76],[76,75,77],[76,77,78],[78,77,0],[78,0,2],[79,80,81],[81,80,82],[81,82,83],[83,82,84],[83,84,85],[85,84,86],[85,86,87],[87,86,88],[87,88,89],[89,88,90],[89,90,91],[91,90,92],[91,92,93],[93,92,94],[93,94,95],[95,94,96],[95,96,97],[97,96,98],[97,98,99],[99,98,100],[99,100,101],[101,100,102],[101,102,103],[103,102,104],[103,104,105],[105,104,106],[105,106,107],[107,106,108],[107,108,109],[109,108,110],[109,110,111],[111,110,112],[111,112,113],[113,112,114],[113,114,115],[115,114,116],[115,116,117],[117,116,118],[117,118,119],[119,118,120],[119,120,121],[121,120,122],[121,122,123],[123,122,124],[123,124,125],[125,124,126],[125,126,127],[127,126,128],[127,128,129],[129,128,130],[129,130,131],[131,130,132],[131,132,133],[133,132,134],[133,134,135],[135,134,136],[135,136,137],[137,136,138],[137,138,139],[139,138,140],[139,140,141],[141,140,142],[141,142,143],[143,142,144],[143,144,145],[145,144,146],[145,146,147],[147,146,148],[147,148,149],[149,148,150],[149,150,151],[151,150,152],[151,152,153],[153,152,154],[153,154,155],[155,154,156],[155,156,157],[157,156,79],[157,79,81],[57,110,108],[57,108,59],[59,108,106],[59,106,61],[61,106,104],[61,104,63],[63,104,102],[63,102,65],[65,102,100],[65,100,67],[67,100,98],[67,98,69],[69,98,96],[69,96,71],[71,96,94],[71,94,73],[73,94,92],[73,92,75],[75,92,90],[75,90,77],[77,90,88],[77,88,0],[0,88,86],[0,86,1],[1,86,84],[1,84,3],[3,84,82],[3,82,5],[5,82,80],[5,80,7],[7,80,79],[7,79,9],[9,79,156],[9,156,11],[11,156,154],[11,154,13],[13,154,152],[13,152,15],[15,152,150],[15,150,17],[17,150,148],[17,148,19],[19,148,146],[19,146,21],[21,146,144],[21,144,23],[23,144,142],[23,142,25],[25,142,140],[25,140,27],[27,140,138],[27,138,29],[29,138,136],[29,136,31],[33,31,134],[134,31,136],[33,134,132],[33,132,35],[35,132,130],[35,130,37],[37,130,128],[37,128,39],[39,128,126],[39,126,41],[41,126,124],[41,124,43],[43,124,122],[43,122,45],[45,122,120],[45,120,47],[47,120,118],[47,118,49],[49,118,116],[49,116,51],[51,116,114],[51,114,53],[55,53,112],[112,53,114],[57,55,110],[110,55,112],[30,135,137],[30,137,28],[28,137,139],[28,139,26],[26,139,141],[26,141,24],[24,141,143],[24,143,22],[22,143,145],[22,145,20],[20,145,147],[20,147,18],[18,147,149],[18,149,16],[16,149,151],[16,151,14],[14,151,153],[14,153,12],[12,153,155],[12,155,10],[10,155,157],[10,157,8],[8,157,81],[8,81,6],[6,81,83],[6,83,4],[4,83,85],[4,85,2],[2,85,87],[2,87,78],[78,87,89],[78,89,76],[76,89,91],[76,91,74],[74,91,93],[74,93,72],[72,93,95],[72,95,70],[70,95,97],[70,97,68],[68,97,99],[68,99,66],[66,99,101],[66,101,64],[64,101,103],[64,103,62],[62,103,105],[62,105,60],[60,105,107],[60,107,58],[58,107,109],[58,109,56],[30,32,135],[135,32,133],[52,113,115],[52,115,50],[50,115,117],[50,117,48],[48,117,119],[48,119,46],[46,119,121],[46,121,44],[44,121,123],[44,123,42],[42,123,125],[42,125,40],[40,125,127],[40,127,38],[38,127,129],[38,129,36],[36,129,131],[36,131,34],[34,131,133],[34,133,32],[52,54,113],[113,54,111],[54,56,111],[111,56,109] - ], - } elsif ($name eq 'sloping_hole') { - $vertices = [ - [-20,-20,-5],[-20,-20,5],[-20,20,-5],[-20,20,5],[20,-20,-5],[20,-20,5],[4.46294021606445,7.43144989013672,-5],[20,20,-5],[-19.1420993804932,0,-5],[-18.8330993652344,-2.07911992073059,-5],[-17.9195003509521,-4.06736993789673,-5],[-16.4412002563477,-5.87785005569458,-5],[-14.4629001617432,-7.43144989013672,-5],[-12.0711002349854,-8.66024971008301,-5],[-9.37016010284424,-9.51056003570557,-5],[-3.5217399597168,-9.94521999359131,-5],[-6.4782600402832,-9.94521999359131,-5],[-0.629840016365051,-9.51056003570557,-5],[2.07106995582581,-8.66024971008301,-5],[6.44122982025146,-5.87785005569458,-5],[4.46294021606445,-7.43144989013672,-5],[-12.0711002349854,8.66024971008301,-5],[-9.37016010284424,9.51056003570557,-5],[7.91947984695435,-4.06736993789673,-5],[8.83310031890869,-2.07911992073059,-5],[-6.4782600402832,9.94521999359131,-5],[-0.629840016365051,9.51056003570557,-5],[2.07106995582581,8.66024971008301,-5],[9.14214038848877,0,-5],[8.83310031890869,2.07911992073059,-5],[-3.5217399597168,9.94521999359131,-5],[7.91947984695435,4.06736993789673,-5],[6.44122982025146,5.87785005569458,-5],[-14.4629001617432,7.43144989013672,-5],[-16.4412002563477,5.87785005569458,-5],[-17.9195003509521,4.06736993789673,-5],[-18.8330993652344,2.07911992073059,-5],[20,20,5],[3.5217399597168,-9.94521999359131,5],[-8.83310031890869,-2.07911992073059,5],[-9.14214038848877,0,5],[-8.83310031890869,2.07911992073059,5],[6.4782600402832,-9.94521999359131,5],[-7.91947984695435,4.06736993789673,5],[-6.44122982025146,5.87785005569458,5],[-4.46294021606445,7.43144989013672,5],[-2.07106995582581,8.66024971008301,5],[0.629840016365051,9.51056003570557,5],[12.0711002349854,-8.66024971008301,5],[9.37016010284424,-9.51056003570557,5],[3.5217399597168,9.94521999359131,5],[6.4782600402832,9.94521999359131,5],[9.37016010284424,9.51056003570557,5],[12.0711002349854,8.66024971008301,5],[14.4629001617432,7.43144989013672,5],[16.4412002563477,-5.87785005569458,5],[14.4629001617432,-7.43144989013672,5],[16.4412002563477,5.87785005569458,5],[17.9195003509521,4.06736993789673,5],[18.8330993652344,-2.07911992073059,5],[17.9195003509521,-4.06736993789673,5],[18.8330993652344,2.07911992073059,5],[19.1420993804932,0,5],[0.629840016365051,-9.51056003570557,5],[-2.07106995582581,-8.66024971008301,5],[-4.46294021606445,-7.43144989013672,5],[-6.44122982025146,-5.87785005569458,5],[-7.91947984695435,-4.06736993789673,5] - ]; - $facets = [ - [0,1,2],[2,1,3],[1,0,4],[5,1,4],[6,2,7],[0,2,8],[0,8,9],[0,9,10],[0,10,11],[0,11,12],[0,12,13],[0,13,4],[13,14,4],[15,4,16],[17,4,15],[18,4,17],[19,4,20],[18,20,4],[21,2,22],[4,19,23],[4,23,7],[23,24,7],[22,2,25],[26,2,27],[28,29,7],[25,2,30],[29,31,7],[30,2,26],[31,32,7],[27,2,6],[32,6,7],[28,7,24],[33,2,21],[34,2,33],[35,2,34],[36,2,35],[8,2,36],[16,4,14],[2,3,7],[7,3,37],[38,1,5],[3,1,39],[3,39,40],[3,40,41],[42,38,5],[3,41,43],[3,43,44],[37,3,45],[37,45,46],[37,46,47],[48,49,5],[37,47,50],[49,42,5],[37,50,51],[37,51,52],[37,52,53],[37,53,54],[55,56,5],[37,54,57],[37,57,58],[59,60,5],[37,58,61],[37,62,5],[37,61,62],[62,59,5],[60,55,5],[63,1,38],[64,1,63],[65,1,64],[66,1,65],[67,1,66],[39,1,67],[44,45,3],[56,48,5],[5,4,7],[37,5,7],[41,40,36],[36,40,8],[39,9,40],[40,9,8],[43,41,35],[35,41,36],[44,43,34],[34,43,35],[33,45,44],[34,33,44],[21,46,45],[33,21,45],[22,47,46],[21,22,46],[25,50,47],[22,25,47],[30,51,50],[25,30,50],[26,52,51],[30,26,51],[27,53,52],[26,27,52],[6,54,53],[27,6,53],[32,57,54],[6,32,54],[31,58,57],[32,31,57],[29,61,58],[31,29,58],[28,62,61],[29,28,61],[59,62,28],[24,59,28],[60,59,24],[23,60,24],[55,60,23],[19,55,23],[55,19,56],[56,19,20],[56,20,48],[48,20,18],[48,18,49],[49,18,17],[49,17,42],[42,17,15],[42,15,38],[38,15,16],[38,16,63],[63,16,14],[63,14,64],[64,14,13],[64,13,65],[65,13,12],[65,12,66],[66,12,11],[66,11,67],[67,11,10],[67,10,39],[39,10,9] - ], - } elsif ($name eq 'ipadstand') { - $vertices = [ - [17.4344673156738,-2.69879599481136e-16,9.5],[14.2814798355103,10,9.5],[0,0,9.5],[31.7159481048584,10,9.5],[62.2344741821289,2.06667568800577e-16,20],[31.7159481048584,10,20],[17.4344673156738,-2.69879599481136e-16,20],[62.2344741821289,10,20],[98.2079696655273,10,0],[98.2079696655273,8.56525380796383e-16,10],[98.2079696655273,0,0],[98.2079696655273,10,20],[98.2079696655273,0,20],[81.6609649658203,-4.39753856997999e-16,10],[90.0549850463867,10,10],[78.5079803466797,10,10],[93.2079696655273,8.56525380796383e-16,10],[14.2814798355103,10,20],[0,0,20],[87.4344711303711,2.81343962782118e-15,20],[84.2814788818359,10,20],[0,10,20],[0,0,0],[0,10,0],[62.2344741821289,2.06667568800577e-16,30],[66.9609756469727,10,30],[62.2344741821289,10,30],[70.1139602661133,8.5525763717214e-16,30],[67.7053375244141,10,28.7107200622559],[71.6787109375,1.24046736339707e-15,27.2897701263428] - ]; - $facets = [ - [0,1,2],[1,0,3],[4,5,6],[5,4,7],[8,9,10],[9,11,12],[11,9,8],[13,14,15],[14,13,16],[17,2,1],[2,17,18],[19,11,20],[11,19,12],[17,21,18],[21,2,18],[2,21,22],[22,21,23],[8,22,23],[22,8,10],[24,25,26],[25,24,27],[23,1,8],[1,23,21],[1,21,17],[5,15,3],[15,5,7],[15,7,28],[28,7,26],[28,26,25],[8,14,11],[14,8,3],[3,8,1],[14,3,15],[11,14,20],[26,4,24],[4,26,7],[12,16,9],[16,12,19],[29,4,13],[4,29,24],[24,29,27],[9,22,10],[22,9,0],[0,9,16],[0,16,13],[0,13,6],[6,13,4],[2,22,0],[19,14,16],[14,19,20],[15,29,13],[29,25,27],[25,29,15],[25,15,28],[6,3,0],[3,6,5] - ]; - } elsif ($name eq 'A') { - $vertices = [ - [513.075988769531,51.6074333190918,36.0009002685547],[516.648803710938,51.7324333190918,36.0009002685547],[513.495178222656,51.7324333190918,36.0009002685547],[489.391204833984,51.4824333190918,24.0011005401611],[488.928588867188,51.7324333190918,24.0011005401611],[492.06201171875,51.7324333190918,24.0011005401611],[496.840393066406,51.2324333190918,24.0011005401611],[495.195404052734,51.7324333190918,24.0011005401611],[498.981994628906,51.7324333190918,24.0011005401611],[506.966613769531,51.6074333190918,24.0011005401611],[510.342010498047,51.7324333190918,24.0011005401611],[507.163818359375,51.6074333190918,24.0011005401611],[512.515380859375,54.7190322875977,36.0009002685547],[514.161987304688,54.5058326721191,36.0009002685547],[493.06201171875,54.7190322875977,36.0009002685547],[495.195404052734,51.7324333190918,36.0009002685547],[496.195404052734,54.7190322875977,36.0009002685547],[497.195404052734,57.7058334350586,36.0009002685547],[500.851989746094,60.2658309936523,36.0009002685547],[498.915405273438,62.8258323669434,36.0009002685547],[506.701995849609,62.8258323669434,36.0009002685547],[503.648590087891,60.2658309936523,36.0009002685547],[508.381805419922,57.7058334350586,36.0009002685547],[496.418792724609,60.052433013916,36.0009002685547],[506.515197753906,72.2124328613281,36.0009002685547],[502.808807373047,74.5324325561523,36.0009002685547],[503.781982421875,71.6058349609375,36.0009002685547],[515.358764648438,55.4658317565918,36.0009002685547],[499.375183105469,76.9058380126953,36.0009002685547],[501.168792724609,78.0658340454102,36.0009002685547],[504.568786621094,78.0658340454102,36.0009002685547],[506.32861328125,81.599235534668,36.0009002685547],[502.928588867188,81.599235534668,36.0009002685547],[499.528594970703,81.599235534668,36.0009002685547],[498.20361328125,77.8658294677734,36.0009002685547],[495.195404052734,51.7324333190918,30.0011005401611],[498.981994628906,51.7324333190918,27.0011005401611],[506.555206298828,51.7324333190918,33.0009002685547],[506.555206298828,51.7324333190918,36.0009002685547],[510.342010498047,51.7324333190918,36.0009002685547],[512.515380859375,54.7190322875977,24.0011005401611],[509.361999511719,54.7190322875977,24.0011005401611],[508.381805419922,57.7058334350586,24.0011005401611],[506.701995849609,62.8258323669434,24.0011005401611],[509.188812255859,60.052433013916,24.0011005401611],[493.06201171875,54.7190322875977,24.0011005401611],[503.648590087891,60.2658309936523,24.0011005401611],[500.851989746094,60.2658309936523,24.0011005401611],[498.915405273438,62.8258323669434,24.0011005401611],[502.808807373047,62.8258323669434,24.0011005401611],[491.425201416016,54.5058326721191,24.0011005401611],[506.421813964844,76.9058380126953,24.0011005401611],[502.808807373047,74.5324325561523,24.0011005401611],[504.568786621094,78.0658340454102,24.0011005401611],[506.32861328125,81.599235534668,24.0011005401611],[507.618804931641,77.8658294677734,24.0011005401611],[499.221801757812,72.2124328613281,24.0011005401611],[501.835388183594,71.6058349609375,24.0011005401611],[501.168792724609,78.0658340454102,24.0011005401611],[499.528594970703,81.599235534668,24.0011005401611],[502.048583984375,79.8324356079102,24.0011005401611],[490.253601074219,55.4658317565918,24.0011005401611],[488.928588867188,51.7324333190918,30.0011005401611],[488.928588867188,51.7324333190918,36.0009002685547],[490.253601074219,55.4658317565918,31.5009002685547],[498.20361328125,77.8658294677734,34.5009002685547],[508.381805419922,57.7058334350586,30.0011005401611],[505.585388183594,57.7058334350586,27.0011005401611],[502.788818359375,57.7058334350586,36.0009002685547],[499.992004394531,57.7058334350586,33.0009002685547],[509.851989746094,53.2258338928223,33.0009002685547],[509.361999511719,54.7190322875977,36.0009002685547],[508.871795654297,56.2124328613281,27.0011005401611],[496.695404052734,56.2124328613281,33.0009002685547],[495.695404052734,53.2258338928223,27.0011005401611],[506.32861328125,81.599235534668,30.0011005401611],[507.618804931641,77.8658294677734,25.5011005401611],[515.358764648438,55.4658317565918,34.5009002685547],[501.228607177734,81.599235534668,33.0009002685547],[504.628601074219,81.599235534668,27.0011005401611],[503.781982421875,71.6058349609375,33.0009002685547],[502.808807373047,74.5324325561523,30.0011005401611],[498.915405273438,62.8258323669434,30.0011005401611],[500.861999511719,62.8258323669434,27.0011005401611],[502.808807373047,62.8258323669434,36.0009002685547],[504.755187988281,62.8258323669434,33.0009002685547],[501.835388183594,71.6058349609375,33.0009002685547],[499.888793945312,65.7524337768555,33.0009002685547],[499.888793945312,65.7524337768555,36.0009002685547],[513.128601074219,51.4824333190918,36.0009002685547],[513.075988769531,51.6074333190918,24.0011005401611],[516.648803710938,51.7324333190918,24.0011005401611],[513.128601074219,51.4824333190918,24.0011005401611],[513.495178222656,51.7324333190918,24.0011005401611],[506.966613769531,51.6074333190918,36.0009002685547],[507.163818359375,51.6074333190918,36.0009002685547],[490.337799072266,51.4824333190918,24.0011005401611],[489.391204833984,51.4824333190918,36.0009002685547],[492.06201171875,51.7324333190918,36.0009002685547],[490.337799072266,51.4824333190918,36.0009002685547],[513.233764648438,51.2324333190918,24.0011005401611],[513.233764648438,51.2324333190918,36.0009002685547],[504.773803710938,51.4824333190918,36.0009002685547],[504.773803710938,51.4824333190918,24.0011005401611],[489.266998291016,51.2324333190918,24.0011005401611],[489.266998291016,51.2324333190918,36.0009002685547],[490.253601074219,55.4658317565918,25.5011005401611],[499.528594970703,81.599235534668,30.0011005401611],[498.20361328125,77.8658294677734,31.5009002685547],[515.358764648438,55.4658317565918,28.5011005401611],[515.358764648438,55.4658317565918,25.5011005401611],[495.246795654297,61.0124320983887,36.0009002685547],[490.253601074219,55.4658317565918,34.5009002685547],[490.253601074219,55.4658317565918,36.0009002685547],[494.228607177734,66.6658325195312,24.0011005401611],[499.068786621094,67.5192337036133,24.0011005401611],[498.20361328125,77.8658294677734,25.5011005401611],[498.20361328125,77.8658294677734,24.0011005401611],[506.608795166016,67.5192337036133,36.0009002685547],[509.09521484375,64.7458343505859,36.0009002685547],[507.618804931641,77.8658294677734,34.5009002685547],[507.618804931641,77.8658294677734,36.0009002685547],[510.385406494141,61.0124320983887,24.0011005401611],[515.358764648438,55.4658317565918,24.0011005401611],[489.32861328125,47.7324333190918,31.5009002685547],[492.95361328125,47.7324333190918,33.5634994506836],[489.32861328125,47.7324333190918,34.5009002685547],[489.32861328125,47.7324333190918,28.5011005401611],[489.32861328125,47.7324333190918,25.5011005401611],[492.95361328125,47.7324333190918,26.4385013580322],[492.95361328125,47.7324333190918,30.5635013580322],[492.95361328125,47.7324333190918,32.0634994506836],[492.95361328125,47.7324333190918,31.3135013580322],[492.95361328125,47.7324333190918,35.4384994506836],[489.32861328125,47.7324333190918,36.0009002685547],[492.95361328125,47.7324333190918,34.3134994506836],[492.95361328125,47.7324333190918,34.6884994506836],[492.95361328125,47.7324333190918,27.9385013580322],[492.95361328125,47.7324333190918,28.6885013580322],[492.95361328125,47.7324333190918,29.0635013580322],[489.32861328125,47.7324333190918,24.0011005401611],[492.95361328125,47.7324333190918,24.5635013580322],[492.95361328125,47.7324333190918,25.6885013580322],[492.95361328125,47.7324333190918,25.3135013580322],[492.95361328125,47.7324333190918,24.1885013580322],[492.95361328125,47.7324333190918,24.0011005401611],[513.443786621094,50.7324333190918,24.0011005401611],[492.95361328125,47.7324333190918,35.8134994506836],[492.95361328125,47.7324333190918,36.0009002685547],[513.443786621094,50.7324333190918,36.0009002685547],[506.350402832031,51.4824333190918,36.0009002685547],[506.350402832031,51.4824333190918,24.0011005401611],[492.743804931641,48.2324333190918,24.0011005401611],[492.638793945312,48.4824333190918,24.0011005401611],[492.743804931641,48.2324333190918,36.0009002685547],[492.638793945312,48.4824333190918,36.0009002685547],[490.089599609375,50.9824333190918,36.0009002685547],[490.089599609375,50.9824333190918,24.0011005401611],[510.342010498047,51.7324333190918,30.0011005401611],[499.068786621094,67.5192337036133,36.0009002685547],[494.228607177734,66.6658325195312,36.0009002685547],[499.375183105469,76.9058380126953,24.0011005401611],[506.421813964844,76.9058380126953,36.0009002685547],[506.608795166016,67.5192337036133,24.0011005401611],[505.728607177734,65.7524337768555,24.0011005401611],[509.09521484375,64.7458343505859,24.0011005401611],[506.701995849609,62.8258323669434,30.0011005401611],[505.728607177734,65.7524337768555,27.0011005401611],[501.835388183594,71.6058349609375,27.0011005401611],[499.888793945312,65.7524337768555,27.0011005401611],[494.228607177734,66.6658325195312,30.0011005401611],[495.553588867188,70.3992309570312,28.5011005401611],[492.903594970703,62.9324340820312,28.5011005401611],[495.553588867188,70.3992309570312,31.5009002685547],[492.903594970703,62.9324340820312,31.5009002685547],[511.488800048828,66.6658325195312,24.0011005401611],[511.488800048828,66.6658325195312,30.0011005401611],[512.778564453125,62.9324340820312,28.5011005401611],[515.358764648438,55.4658317565918,31.5009002685547],[507.618804931641,77.8658294677734,31.5009002685547],[510.198791503906,70.3992309570312,28.5011005401611],[511.488800048828,66.6658325195312,36.0009002685547],[512.778564453125,62.9324340820312,31.5009002685547],[510.198791503906,70.3992309570312,31.5009002685547],[502.788818359375,57.7058334350586,24.0011005401611],[497.195404052734,57.7058334350586,30.0011005401611],[492.903594970703,62.9324340820312,34.5009002685547],[492.903594970703,62.9324340820312,36.0009002685547],[495.553588867188,70.3992309570312,24.0011005401611],[496.725189208984,69.4392318725586,24.0011005401611],[495.553588867188,70.3992309570312,25.5011005401611],[495.246795654297,61.0124320983887,24.0011005401611],[492.903594970703,62.9324340820312,25.5011005401611],[492.903594970703,62.9324340820312,24.0011005401611],[495.553588867188,70.3992309570312,36.0009002685547],[496.725189208984,69.4392318725586,36.0009002685547],[495.553588867188,70.3992309570312,34.5009002685547],[510.198791503906,70.3992309570312,36.0009002685547],[509.002014160156,69.4392318725586,36.0009002685547],[510.198791503906,70.3992309570312,34.5009002685547],[512.778564453125,62.9324340820312,25.5011005401611],[512.778564453125,62.9324340820312,24.0011005401611],[510.198791503906,70.3992309570312,24.0011005401611],[509.002014160156,69.4392318725586,24.0011005401611],[510.198791503906,70.3992309570312,25.5011005401611],[510.385406494141,61.0124320983887,36.0009002685547],[512.778564453125,62.9324340820312,34.5009002685547],[512.778564453125,62.9324340820312,36.0009002685547],[496.840393066406,51.2324333190918,36.0009002685547],[498.981994628906,51.7324333190918,36.0009002685547],[498.981994628906,51.7324333190918,33.0009002685547],[506.555206298828,51.7324333190918,24.0011005401611],[506.555206298828,51.7324333190918,27.0011005401611],[503.82861328125,47.7324333190918,30.7509002685547],[507.45361328125,47.7324333190918,32.8134994506836],[503.82861328125,47.7324333190918,33.7509002685547],[503.82861328125,47.7324333190918,29.2511005401611],[503.82861328125,47.7324333190918,26.2511005401611],[507.45361328125,47.7324333190918,27.1885013580322],[493.921813964844,57.2792320251465,36.0009002685547],[491.425201416016,54.5058326721191,36.0009002685547],[497.195404052734,57.7058334350586,24.0011005401611],[496.418792724609,60.052433013916,24.0011005401611],[509.188812255859,60.052433013916,36.0009002685547],[511.675415039062,57.2792320251465,24.0011005401611],[514.161987304688,54.5058326721191,24.0011005401611],[507.45361328125,47.7324333190918,34.3134994506836],[503.82861328125,47.7324333190918,35.2509002685547],[507.45361328125,47.7324333190918,25.6885013580322],[503.82861328125,47.7324333190918,24.7511005401611],[500.20361328125,47.7324333190918,31.6885013580322],[500.20361328125,47.7324333190918,28.3135013580322],[500.20361328125,47.7324333190918,30.1885013580322],[507.45361328125,47.7324333190918,29.8135013580322],[507.45361328125,47.7324333190918,31.3135013580322],[507.45361328125,47.7324333190918,30.5635013580322],[503.82861328125,47.7324333190918,36.0009002685547],[507.45361328125,47.7324333190918,35.4384994506836],[507.45361328125,47.7324333190918,35.0634994506836],[507.45361328125,47.7324333190918,28.6885013580322],[507.45361328125,47.7324333190918,29.4385013580322],[503.82861328125,47.7324333190918,24.0011005401611],[507.45361328125,47.7324333190918,24.5635013580322],[507.45361328125,47.7324333190918,24.9385013580322],[500.20361328125,47.7324333190918,34.6884994506836],[500.20361328125,47.7324333190918,33.1884994506836],[500.20361328125,47.7324333190918,33.9384994506836],[500.20361328125,47.7324333190918,25.3135013580322],[500.20361328125,47.7324333190918,26.8135013580322],[500.20361328125,47.7324333190918,26.0635013580322],[500.20361328125,47.7324333190918,30.9385013580322],[500.20361328125,47.7324333190918,35.0634994506836],[500.20361328125,47.7324333190918,35.4384994506836],[500.20361328125,47.7324333190918,29.0635013580322],[500.20361328125,47.7324333190918,29.4385013580322],[500.20361328125,47.7324333190918,24.9385013580322],[500.20361328125,47.7324333190918,24.5635013580322],[507.45361328125,47.7324333190918,24.1885013580322],[507.45361328125,47.7324333190918,24.0011005401611],[513.86376953125,49.7324333190918,24.0011005401611],[507.45361328125,47.7324333190918,35.8134994506836],[507.45361328125,47.7324333190918,36.0009002685547],[513.86376953125,49.7324333190918,36.0009002685547],[500.20361328125,47.7324333190918,24.1885013580322],[500.20361328125,47.7324333190918,24.0011005401611],[502.988800048828,49.7324333190918,24.0011005401611],[500.20361328125,47.7324333190918,35.8134994506836],[500.20361328125,47.7324333190918,36.0009002685547],[502.988800048828,49.7324333190918,36.0009002685547],[504.755187988281,62.8258323669434,27.0011005401611],[499.205383300781,51.2324333190918,36.0009002685547],[498.786193847656,51.1074333190918,36.0009002685547],[502.358795166016,51.2324333190918,36.0009002685547],[499.205383300781,51.2324333190918,24.0011005401611],[502.358795166016,51.2324333190918,24.0011005401611],[498.786193847656,51.1074333190918,24.0011005401611],[502.568786621094,50.7324333190918,24.0011005401611],[505.931213378906,51.3574333190918,24.0011005401611],[509.503601074219,51.4824333190918,24.0011005401611],[502.568786621094,50.7324333190918,36.0009002685547],[505.931213378906,51.3574333190918,36.0009002685547],[509.503601074219,51.4824333190918,36.0009002685547],[499.048583984375,50.4824333190918,36.0009002685547],[492.428588867188,48.9824333190918,36.0009002685547],[499.048583984375,50.4824333190918,24.0011005401611],[492.428588867188,48.9824333190918,24.0011005401611],[506.088806152344,50.9824333190918,24.0011005401611],[506.036010742188,51.1074333190918,24.0011005401611],[506.088806152344,50.9824333190918,36.0009002685547],[506.036010742188,51.1074333190918,36.0009002685547],[498.891204833984,50.8574333190918,36.0009002685547],[498.943786621094,50.7324333190918,36.0009002685547],[498.891204833984,50.8574333190918,24.0011005401611],[498.943786621094,50.7324333190918,24.0011005401611],[499.573608398438,49.2324333190918,24.0011005401611],[499.783813476562,48.7324333190918,24.0011005401611],[499.573608398438,49.2324333190918,36.0009002685547],[499.783813476562,48.7324333190918,36.0009002685547],[506.403594970703,50.2324333190918,24.0011005401611],[506.298797607422,50.4824333190918,24.0011005401611],[506.403594970703,50.2324333190918,36.0009002685547],[506.298797607422,50.4824333190918,36.0009002685547],[501.228607177734,81.599235534668,27.0011005401611],[502.928588867188,81.599235534668,24.0011005401611],[499.2587890625,49.9824333190918,36.0009002685547],[499.363800048828,49.7324333190918,36.0009002685547],[499.2587890625,49.9824333190918,24.0011005401611],[499.363800048828,49.7324333190918,24.0011005401611],[496.695404052734,56.2124328613281,27.0011005401611],[496.195404052734,54.7190322875977,24.0011005401611],[509.851989746094,53.2258338928223,27.0011005401611],[493.464782714844,51.1074333190918,36.0009002685547],[493.464782714844,51.1074333190918,24.0011005401611],[502.768798828125,51.7324333190918,24.0011005401611],[500.215789794922,51.3574333190918,24.0011005401611],[497.628601074219,51.2324333190918,24.0011005401611],[502.768798828125,51.7324333190918,36.0009002685547],[500.215789794922,51.3574333190918,36.0009002685547],[497.628601074219,51.2324333190918,36.0009002685547],[507.033813476562,48.7324333190918,24.0011005401611],[506.823791503906,49.2324333190918,24.0011005401611],[507.033813476562,48.7324333190918,36.0009002685547],[506.823791503906,49.2324333190918,36.0009002685547],[494.4501953125,51.1074333190918,24.0011005401611],[494.4501953125,51.1074333190918,36.0009002685547],[500.807006835938,51.3574333190918,36.0009002685547],[503.591186523438,51.4824333190918,36.0009002685547],[503.591186523438,51.4824333190918,24.0011005401611],[500.807006835938,51.3574333190918,24.0011005401611],[505.728607177734,65.7524337768555,36.0009002685547],[505.728607177734,65.7524337768555,33.0009002685547],[499.221801757812,72.2124328613281,36.0009002685547],[501.835388183594,71.6058349609375,36.0009002685547],[506.515197753906,72.2124328613281,24.0011005401611],[503.781982421875,71.6058349609375,24.0011005401611],[503.781982421875,71.6058349609375,27.0011005401611],[499.888793945312,65.7524337768555,24.0011005401611],[495.695404052734,53.2258338928223,33.0009002685547],[516.648803710938,51.7324333190918,30.0011005401611],[498.20361328125,77.8658294677734,28.5011005401611],[505.585388183594,57.7058334350586,33.0009002685547],[508.871795654297,56.2124328613281,33.0009002685547],[499.992004394531,57.7058334350586,27.0011005401611],[504.628601074219,81.599235534668,33.0009002685547],[500.861999511719,62.8258323669434,33.0009002685547],[496.878601074219,74.1324310302734,27.0011005401611],[496.878601074219,74.1324310302734,33.0009002685547],[491.57861328125,59.199031829834,27.0011005401611],[490.253601074219,55.4658317565918,28.5011005401611],[491.57861328125,59.199031829834,33.0009002685547],[514.068786621094,59.199031829834,27.0011005401611],[514.068786621094,59.199031829834,33.0009002685547],[508.908813476562,74.1324310302734,27.0011005401611],[507.618804931641,77.8658294677734,28.5011005401611],[508.908813476562,74.1324310302734,33.0009002685547],[491.271789550781,50.9824333190918,36.0009002685547],[490.877807617188,50.9824333190918,36.0009002685547],[491.271789550781,50.9824333190918,24.0011005401611],[490.877807617188,50.9824333190918,24.0011005401611],[495.213806152344,50.9824333190918,36.0009002685547],[493.636993408203,50.9824333190918,36.0009002685547],[495.213806152344,50.9824333190918,24.0011005401611],[493.636993408203,50.9824333190918,24.0011005401611],[503.985412597656,51.4824333190918,36.0009002685547],[503.985412597656,51.4824333190918,24.0011005401611],[511.675415039062,57.2792320251465,36.0009002685547],[493.921813964844,57.2792320251465,24.0011005401611],[502.768798828125,51.7324333190918,30.0011005401611],[506.555206298828,51.7324333190918,30.0011005401611],[498.981994628906,51.7324333190918,30.0011005401611],[492.848815917969,50.9824333190918,24.0011005401611],[492.848815917969,50.9824333190918,36.0009002685547],[500.861999511719,68.6792297363281,36.0009002685547],[500.861999511719,68.6792297363281,24.0011005401611],[496.878601074219,74.1324310302734,24.0011005401611],[496.878601074219,74.1324310302734,36.0009002685547],[504.755187988281,68.6792297363281,24.0011005401611],[504.755187988281,68.6792297363281,36.0009002685547],[508.908813476562,74.1324310302734,36.0009002685547],[508.908813476562,74.1324310302734,24.0011005401611],[505.728607177734,65.7524337768555,30.0011005401611],[504.755187988281,68.6792297363281,30.0011005401611],[503.781982421875,71.6058349609375,30.0011005401611],[500.861999511719,68.6792297363281,30.0011005401611],[499.888793945312,65.7524337768555,30.0011005401611],[501.835388183594,71.6058349609375,30.0011005401611],[491.57861328125,59.199031829834,24.0011005401611],[491.57861328125,59.199031829834,36.0009002685547],[514.068786621094,59.199031829834,36.0009002685547],[514.068786621094,59.199031829834,24.0011005401611],[511.07861328125,47.7324333190918,34.8759002685547],[511.07861328125,47.7324333190918,31.8759002685547],[514.70361328125,47.7324333190918,33.9384994506836],[511.07861328125,47.7324333190918,25.1261005401611],[514.70361328125,47.7324333190918,26.0635013580322],[511.07861328125,47.7324333190918,28.1261005401611],[502.788818359375,57.7058334350586,30.0011005401611],[502.048583984375,79.8324356079102,36.0009002685547],[514.70361328125,47.7324333190918,30.9385013580322],[511.07861328125,47.7324333190918,30.3759002685547],[514.70361328125,47.7324333190918,29.0635013580322],[511.07861328125,47.7324333190918,29.6261005401611],[496.57861328125,47.7324333190918,31.1259002685547],[496.57861328125,47.7324333190918,32.6259002685547],[496.57861328125,47.7324333190918,34.1259002685547],[496.57861328125,47.7324333190918,28.8761005401611],[496.57861328125,47.7324333190918,27.3761005401611],[496.57861328125,47.7324333190918,25.8761005401611],[496.57861328125,47.7324333190918,29.6261005401611],[514.70361328125,47.7324333190918,35.4384994506836],[511.07861328125,47.7324333190918,35.6259002685547],[514.70361328125,47.7324333190918,24.5635013580322],[511.07861328125,47.7324333190918,24.3761005401611],[496.57861328125,47.7324333190918,34.8759002685547],[496.57861328125,47.7324333190918,25.1261005401611],[496.57861328125,47.7324333190918,35.6259002685547],[496.57861328125,47.7324333190918,24.3761005401611],[511.07861328125,47.7324333190918,36.0009002685547],[511.07861328125,47.7324333190918,24.0011005401611],[514.70361328125,47.7324333190918,30.1885013580322],[514.70361328125,47.7324333190918,35.8134994506836],[514.70361328125,47.7324333190918,29.8135013580322],[514.70361328125,47.7324333190918,24.1885013580322],[496.57861328125,47.7324333190918,36.0009002685547],[496.57861328125,47.7324333190918,24.0011005401611],[510.238800048828,49.7324333190918,24.0011005401611],[510.238800048828,49.7324333190918,36.0009002685547],[514.70361328125,47.7324333190918,24.0011005401611],[514.70361328125,47.7324333190918,36.0009002685547],[496.158813476562,48.7324333190918,36.0009002685547],[496.158813476562,48.7324333190918,24.0011005401611],[502.808807373047,62.8258323669434,30.0011005401611],[509.608795166016,51.2324333190918,24.0011005401611],[509.608795166016,51.2324333190918,36.0009002685547],[491.641204833984,50.8574333190918,24.0011005401611],[495.423797607422,50.4824333190918,36.0009002685547],[495.423797607422,50.4824333190918,24.0011005401611],[491.641204833984,50.8574333190918,36.0009002685547],[495.528594970703,50.2324333190918,24.0011005401611],[492.0087890625,49.9824333190918,24.0011005401611],[509.818786621094,50.7324333190918,24.0011005401611],[495.948608398438,49.2324333190918,36.0009002685547],[495.528594970703,50.2324333190918,36.0009002685547],[495.948608398438,49.2324333190918,24.0011005401611],[509.818786621094,50.7324333190918,36.0009002685547],[492.0087890625,49.9824333190918,36.0009002685547],[491.956207275391,50.1074333190918,24.0011005401611],[491.956207275391,50.1074333190918,36.0009002685547],[502.928588867188,81.599235534668,30.0011005401611],[491.851013183594,50.3574333190918,36.0009002685547],[491.851013183594,50.3574333190918,24.0011005401611],[496.195404052734,54.7190322875977,30.0011005401611],[509.361999511719,54.7190322875977,30.0011005401611],[488.632598876953,51.7256317138672,30.0011005401611],[488.632598876953,51.7256317138672,29.5091018676758],[488.632598876953,51.7188339233398,24.0011005401611],[488.632598876953,51.7256317138672,27.4929008483887],[488.632598876953,51.7324333190918,30.0011005401611],[488.632598876953,51.7324333190918,29.0175018310547],[488.632598876953,51.7324333190918,24.9847011566162],[488.632598876953,51.7324333190918,24.0011005401611],[488.632598876953,51.7188339233398,30.0011005401611],[488.632598876953,51.7176322937012,24.0011005401611],[488.632598876953,51.7182312011719,30.0011005401611],[488.632598876953,51.7176322937012,30.0011005401611],[488.632598876953,51.715030670166,24.0011005401611],[488.632598876953,51.7162322998047,30.0011005401611],[488.632598876953,50.761833190918,24.0011005401611],[488.632598876953,50.7578315734863,24.0011005401611],[488.632598876953,50.7598342895508,30.0011005401611],[488.632598876953,50.7522315979004,24.0011005401611],[488.632598876953,49.7838325500488,24.0011005401611],[488.632598876953,50.2680320739746,30.0011005401611],[488.632598876953,51.7046318054199,24.0011005401611],[488.632598876953,51.709831237793,30.0011005401611],[488.632598876953,50.9120330810547,24.0011005401611],[488.632598876953,50.8882331848145,24.0011005401611],[488.632598876953,50.9002304077148,30.0011005401611],[488.632598876953,47.7324333190918,24.0370998382568],[488.632598876953,48.5612335205078,30.0011005401611],[488.632598876953,47.7324333190918,24.0011005401611],[488.632598876953,47.7324333190918,24.1091003417969],[488.632598876953,48.5612335205078,30.0189018249512],[488.632598876953,47.7324333190918,25.3211002349854],[488.632598876953,48.5612335205078,30.0551013946533],[488.632598876953,47.7324333190918,25.4651012420654],[488.632598876953,48.5612335205078,30.6609001159668],[488.632598876953,47.7324333190918,25.5371017456055],[488.632598876953,48.5612335205078,30.7329006195068],[488.632598876953,47.7324333190918,25.6091003417969],[488.632598876953,48.5612335205078,30.7689018249512],[488.632598876953,47.7324333190918,25.8971004486084],[488.632598876953,48.5612335205078,30.8051013946533],[488.632598876953,47.7324333190918,28.321102142334],[488.632598876953,48.5612335205078,30.9491004943848],[488.632598876953,47.7324333190918,28.4651012420654],[488.632598876953,48.5612335205078,32.1609001159668],[488.632598876953,47.7324333190918,28.5371017456055],[488.632598876953,48.5612335205078,32.2329025268555],[488.632598876953,47.7324333190918,28.6811008453369],[488.632598876953,48.5612335205078,32.2689018249512],[488.632598876953,47.7324333190918,31.1049003601074],[488.632598876953,48.5612335205078,32.3411026000977],[488.632598876953,47.7324333190918,31.3929004669189],[488.632598876953,49.3900299072266,36.0009002685547],[488.632598876953,47.7324333190918,31.536901473999],[488.632598876953,47.7324333190918,31.6809005737305],[488.632598876953,47.7324333190918,34.1049003601074],[488.632598876953,47.7324333190918,34.3929023742676],[488.632598876953,47.7324333190918,34.464900970459],[488.632598876953,47.7324333190918,34.5369033813477],[488.632598876953,47.7324333190918,34.6809005737305],[488.632598876953,47.7324333190918,35.8929023742676],[488.632598876953,47.7324333190918,35.964900970459],[488.632598876953,47.7324333190918,36.0009002685547],[488.632598876953,50.8816299438477,24.0011005401611],[488.632598876953,50.8850326538086,30.0011005401611],[488.632598876953,49.7480316162109,24.0011005401611],[488.632598876953,49.7426300048828,24.0011005401611],[488.632598876953,49.745231628418,30.0011005401611],[488.632598876953,49.7592315673828,24.0011005401611],[488.632598876953,49.7536315917969,30.0011005401611],[488.632598876953,49.3900299072266,24.0011005401611],[488.632598876953,49.5664329528809,30.0011005401611],[488.632598876953,50.8786315917969,24.0011005401611],[488.632598876953,50.7764320373535,24.0011005401611],[488.632598876953,50.8274307250977,30.0011005401611],[488.632598876953,50.7550315856934,30.0011005401611],[488.632598876953,50.7692337036133,30.0011005401611],[488.632598876953,50.9284324645996,24.0011005401611],[488.632598876953,50.9202308654785,30.0011005401611],[488.632598876953,51.1788330078125,24.0011005401611],[488.632598876953,51.139232635498,24.0011005401611],[488.632598876953,51.1590309143066,30.0011005401611],[488.632598876953,51.2324333190918,24.0011005401611],[488.632598876953,51.2056312561035,30.0011005401611],[488.632598876953,51.4340324401855,24.0011005401611],[488.632598876953,51.3946304321289,24.0011005401611],[488.632598876953,51.4142303466797,30.0011005401611],[488.632598876953,51.4498329162598,24.0011005401611],[488.632598876953,51.5772323608398,30.0011005401611],[488.632598876953,51.4418334960938,30.0011005401611],[488.632598876953,51.3136329650879,30.0011005401611],[488.632598876953,49.7714309692383,30.0011005401611],[488.632598876953,51.0338325500488,30.0011005401611],[488.632598876953,50.8816299438477,30.0011005401611],[488.632598876953,50.8800315856934,30.0011005401611],[488.632598876953,51.7188339233398,36.0009002685547],[488.632598876953,51.7176322937012,36.0009002685547],[488.632598876953,49.3900299072266,30.0011005401611],[488.632598876953,50.7522315979004,30.0011005401611],[488.632598876953,50.7522315979004,36.0009002685547],[488.632598876953,49.7426300048828,30.0011005401611],[488.632598876953,49.7426300048828,36.0009002685547],[488.632598876953,49.7480316162109,30.0011005401611],[488.632598876953,49.7480316162109,36.0009002685547],[488.632598876953,51.715030670166,30.0011005401611],[488.632598876953,51.715030670166,36.0009002685547],[488.632598876953,50.7578315734863,30.0011005401611],[488.632598876953,50.7578315734863,36.0009002685547],[488.632598876953,50.761833190918,30.0011005401611],[488.632598876953,50.761833190918,36.0009002685547],[488.632598876953,50.8882331848145,30.0011005401611],[488.632598876953,50.8882331848145,36.0009002685547],[488.632598876953,49.7592315673828,30.0011005401611],[488.632598876953,49.7592315673828,36.0009002685547],[488.632598876953,51.1788330078125,30.0011005401611],[488.632598876953,51.1788330078125,36.0009002685547],[488.632598876953,50.9120330810547,30.0011005401611],[488.632598876953,50.9120330810547,36.0009002685547],[488.632598876953,51.4498329162598,30.0011005401611],[488.632598876953,51.4498329162598,36.0009002685547],[488.632598876953,51.7046318054199,30.0011005401611],[488.632598876953,51.7046318054199,36.0009002685547],[488.632598876953,51.2324333190918,30.0011005401611],[488.632598876953,51.2324333190918,36.0009002685547],[488.632598876953,51.3946304321289,30.0011005401611],[488.632598876953,51.3946304321289,36.0009002685547],[488.632598876953,51.4340324401855,30.0011005401611],[488.632598876953,51.4340324401855,36.0009002685547],[488.632598876953,49.7838325500488,30.0011005401611],[488.632598876953,49.7838325500488,36.0009002685547],[488.632598876953,50.7764320373535,30.0011005401611],[488.632598876953,50.7764320373535,36.0009002685547],[488.632598876953,51.139232635498,30.0011005401611],[488.632598876953,51.139232635498,36.0009002685547],[488.632598876953,50.9284324645996,30.0011005401611],[488.632598876953,50.9284324645996,36.0009002685547],[488.632598876953,50.8816299438477,36.0009002685547],[488.632598876953,50.8786315917969,30.0011005401611],[488.632598876953,50.8786315917969,36.0009002685547],[488.632598876953,51.7324333190918,35.0173034667969],[488.632598876953,51.7324333190918,36.0009002685547],[488.632598876953,51.7324333190918,30.9847011566162],[517.188415527344,51.7140884399414,24.0011005401611],[517.188415527344,51.7140884399414,36.0009002685547],[517.188415527344,50.4475173950195,24.0011005401611],[517.188415527344,51.7324333190918,35.3734130859375],[517.188415527344,51.7324333190918,36.0009002685547],[517.188415527344,51.7324333190918,34.1185760498047],[517.188415527344,51.7324333190918,31.88330078125],[517.188415527344,51.7324333190918,30.0011005401611],[517.188415527344,51.7324333190918,28.1187744140625],[517.188415527344,51.7324333190918,25.8834266662598],[517.188415527344,51.7324333190918,24.6285915374756],[517.188415527344,51.7324333190918,24.0011005401611],[517.188415527344,47.7324333190918,24.0600452423096],[517.188415527344,47.7324333190918,24.0011005401611],[517.188415527344,50.4475173950195,36.0009002685547],[517.188415527344,47.7324333190918,24.1779975891113],[517.188415527344,47.7324333190918,24.6498031616211],[517.188415527344,47.7324333190918,28.7625770568848],[517.188415527344,47.7324333190918,29.7061901092529],[517.188415527344,47.7324333190918,29.9420928955078],[517.188415527344,47.7324333190918,30.0600452423096],[517.188415527344,47.7324333190918,30.2959480285645],[517.188415527344,47.7324333190918,31.2395629882812],[517.188415527344,47.7324333190918,35.3521995544434],[517.188415527344,47.7324333190918,35.8240051269531],[517.188415527344,47.7324333190918,35.9419555664062],[517.188415527344,47.7324333190918,36.0009002685547] - ]; - $facets = [ - [0,1,2],[3,4,5],[6,7,8],[9,10,11],[12,2,1],[12,1,13],[14,15,16],[17,18,19],[20,21,22],[17,19,23],[24,25,26],[27,13,1],[28,25,29],[30,31,32],[28,33,34],[35,36,7],[37,38,39],[40,10,41],[42,43,44],[45,5,4],[46,47,48],[46,48,49],[45,4,50],[51,52,53],[51,54,55],[56,52,57],[58,59,60],[61,50,4],[62,63,64],[65,34,33],[66,67,42],[68,17,69],[70,71,22],[66,42,72],[73,16,15],[35,7,74],[75,76,54],[77,27,1],[78,32,31],[75,54,79],[80,26,25],[81,80,25],[82,83,48],[84,20,85],[81,25,86],[87,88,19],[0,89,1],[90,91,92],[90,10,93],[38,94,39],[94,95,39],[3,7,96],[97,15,98],[97,99,15],[92,91,100],[89,101,1],[102,39,95],[103,11,10],[104,96,7],[105,15,99],[106,61,4],[107,108,33],[76,55,54],[109,91,110],[111,23,19],[112,63,113],[114,115,48],[116,59,117],[118,20,119],[120,31,121],[122,44,43],[110,91,123],[124,125,126],[127,128,129],[127,130,124],[131,124,132],[126,133,134],[135,136,126],[137,138,127],[139,127,138],[128,140,141],[142,128,143],[144,140,145],[100,91,146],[147,148,134],[101,149,1],[102,150,39],[103,10,151],[145,140,152],[152,140,153],[148,154,134],[154,155,134],[156,15,105],[157,104,7],[36,8,7],[158,37,39],[159,19,88],[160,19,159],[161,59,58],[161,117,59],[162,31,30],[162,121,31],[163,43,164],[163,165,43],[166,167,43],[167,164,43],[168,57,52],[82,48,169],[114,170,171],[108,65,33],[64,63,112],[114,172,170],[160,173,170],[171,170,173],[172,174,170],[160,170,174],[175,176,177],[178,77,1],[179,31,120],[175,180,176],[181,182,176],[177,176,182],[180,183,176],[181,176,183],[184,42,67],[185,69,17],[160,111,19],[186,187,160],[188,189,114],[190,188,114],[114,48,191],[192,114,193],[194,160,195],[196,160,194],[197,198,181],[199,197,181],[122,43,165],[200,201,175],[202,175,203],[204,175,202],[205,119,20],[206,181,207],[208,209,15],[210,15,209],[211,10,9],[212,10,211],[213,214,215],[216,217,218],[219,14,17],[113,63,220],[221,222,48],[191,48,222],[22,223,20],[205,20,223],[224,40,42],[123,91,225],[214,226,215],[227,215,226],[218,217,228],[229,228,217],[215,230,213],[125,135,126],[217,216,231],[129,128,142],[216,213,232],[130,132,124],[213,216,233],[234,213,235],[236,227,237],[238,237,227],[239,240,216],[233,216,240],[241,242,229],[243,229,242],[215,227,244],[245,215,246],[217,247,229],[248,249,217],[232,213,250],[230,250,213],[133,147,134],[244,227,251],[236,252,227],[251,227,252],[231,216,253],[254,253,216],[141,140,144],[247,255,229],[241,229,256],[255,256,229],[257,241,258],[259,146,91],[260,261,236],[262,1,149],[263,264,241],[265,241,264],[266,236,267],[268,267,236],[49,48,83],[166,43,269],[270,271,272],[273,274,275],[276,274,277],[278,151,10],[279,280,272],[281,39,150],[272,282,279],[155,283,134],[274,276,284],[153,140,285],[286,276,287],[265,276,286],[288,289,279],[268,288,279],[290,291,272],[271,290,272],[292,274,293],[275,274,292],[294,265,295],[276,265,294],[296,297,268],[279,296,268],[241,265,298],[298,265,299],[236,300,268],[300,301,268],[107,33,78],[302,303,59],[304,305,279],[282,304,279],[306,276,307],[284,276,306],[185,17,73],[308,309,221],[158,39,70],[310,41,10],[15,311,208],[7,6,312],[313,314,6],[315,6,314],[316,208,317],[318,317,208],[258,241,319],[319,241,320],[261,321,236],[321,322,236],[6,315,323],[208,324,318],[270,325,318],[326,318,325],[327,328,315],[273,315,328],[118,329,20],[330,20,329],[331,332,25],[86,25,332],[333,334,52],[335,52,334],[115,336,48],[169,48,336],[62,106,4],[35,15,210],[35,337,15],[158,10,212],[158,310,10],[338,178,1],[339,59,116],[107,302,59],[66,22,340],[66,341,22],[185,221,342],[185,308,221],[75,31,179],[75,343,31],[166,20,330],[166,85,20],[81,52,335],[81,168,52],[82,19,344],[82,87,19],[108,339,345],[346,108,345],[64,347,348],[349,347,64],[178,109,350],[351,178,350],[179,352,353],[354,352,179],[355,208,356],[356,208,311],[357,358,6],[358,312,6],[68,22,21],[68,340,22],[221,48,47],[184,342,221],[359,270,360],[318,360,270],[361,362,273],[315,273,362],[272,102,270],[363,270,102],[274,273,103],[364,103,273],[21,19,18],[21,20,84],[184,46,42],[43,42,46],[12,22,71],[365,22,12],[14,98,15],[14,220,63],[40,93,10],[40,225,91],[45,221,309],[366,221,45],[313,367,212],[212,367,368],[36,369,367],[313,36,367],[316,37,367],[37,368,367],[210,367,369],[316,367,210],[362,370,315],[370,323,315],[360,318,371],[371,318,324],[372,331,159],[159,195,160],[373,115,56],[115,114,189],[52,56,161],[374,161,56],[25,28,331],[375,331,28],[376,333,163],[163,203,175],[377,118,24],[118,181,198],[25,24,162],[378,162,24],[52,51,333],[379,333,51],[167,380,381],[376,167,381],[377,381,330],[330,381,380],[335,381,382],[376,381,335],[373,383,169],[169,383,384],[168,385,383],[373,168,383],[372,87,383],[87,384,383],[377,80,381],[80,382,381],[86,383,385],[372,383,86],[106,348,347],[386,106,347],[375,65,346],[108,346,65],[64,112,349],[387,349,112],[171,190,114],[346,345,171],[374,190,345],[171,345,190],[349,172,347],[172,114,192],[386,347,192],[172,192,347],[173,160,196],[171,173,346],[375,346,196],[173,196,346],[172,349,174],[174,186,160],[387,186,349],[174,349,186],[64,348,62],[106,62,348],[108,107,339],[59,339,107],[374,345,116],[339,116,345],[76,353,352],[379,76,352],[388,77,351],[178,351,77],[179,120,354],[378,354,120],[177,200,175],[351,350,177],[389,200,350],[177,350,200],[354,180,352],[180,175,204],[379,352,204],[180,204,352],[182,181,206],[177,182,351],[388,351,206],[182,206,351],[180,354,183],[183,199,181],[378,199,354],[183,354,199],[91,109,338],[178,338,109],[76,75,353],[179,353,75],[389,350,110],[109,110,350],[390,391,392],[393,394,395],[224,122,389],[122,175,201],[365,388,205],[205,207,181],[66,340,396],[68,396,340],[184,396,342],[185,342,396],[66,396,67],[184,67,396],[68,69,396],[185,396,69],[219,111,387],[111,160,187],[366,386,191],[191,193,114],[150,272,280],[102,272,150],[151,277,274],[103,151,274],[161,374,117],[116,117,374],[366,61,386],[106,386,61],[111,187,387],[186,387,187],[56,188,374],[190,374,188],[191,386,193],[192,193,386],[331,375,194],[196,194,375],[28,34,375],[65,375,34],[219,387,113],[112,113,387],[224,389,123],[110,123,389],[51,55,379],[76,379,55],[24,197,378],[199,378,197],[122,201,389],[200,389,201],[333,379,202],[204,202,379],[205,388,207],[206,207,388],[365,27,388],[77,388,27],[162,378,121],[120,121,378],[162,30,25],[30,29,25],[51,53,54],[303,60,59],[28,29,33],[29,397,33],[161,58,52],[53,52,58],[21,84,19],[84,344,19],[46,49,43],[49,269,43],[208,316,209],[210,209,316],[327,313,211],[212,211,313],[36,35,369],[210,369,35],[37,158,368],[212,368,158],[6,8,313],[36,313,8],[326,38,316],[37,316,38],[392,391,398],[399,398,391],[394,400,395],[401,395,400],[390,214,391],[214,213,234],[393,395,218],[218,239,216],[402,230,403],[230,215,245],[125,124,131],[404,125,403],[405,406,231],[231,248,217],[129,137,127],[407,406,129],[130,127,139],[402,130,408],[194,195,331],[159,331,195],[115,189,56],[188,56,189],[14,219,220],[113,220,219],[45,50,366],[61,366,50],[221,366,222],[191,222,366],[17,23,219],[111,219,23],[118,198,24],[197,24,198],[202,203,333],[163,333,203],[40,224,225],[123,225,224],[12,13,365],[27,365,13],[22,365,223],[205,223,365],[42,44,224],[122,224,44],[399,391,234],[214,234,391],[401,239,395],[218,395,239],[214,390,226],[226,238,227],[218,228,393],[228,229,243],[401,399,233],[233,235,213],[392,409,390],[410,390,409],[394,393,411],[412,411,393],[402,403,131],[125,131,403],[405,137,406],[129,406,137],[405,408,139],[130,139,408],[230,245,403],[404,403,245],[231,406,248],[407,248,406],[232,254,216],[402,408,232],[413,404,244],[244,246,215],[414,247,407],[247,217,249],[133,126,136],[415,133,413],[141,143,128],[416,414,141],[410,238,390],[226,390,238],[412,393,243],[228,243,393],[233,399,235],[234,235,399],[237,260,236],[238,410,237],[417,260,410],[237,410,260],[239,401,240],[233,240,401],[242,241,257],[243,242,412],[418,412,257],[242,257,412],[401,419,399],[398,399,419],[417,410,420],[409,420,410],[400,421,401],[419,401,421],[418,422,412],[411,412,422],[413,135,404],[125,404,135],[414,407,142],[129,142,407],[130,402,132],[131,132,402],[133,136,413],[135,413,136],[423,147,415],[133,415,147],[137,405,138],[139,138,405],[141,414,143],[142,143,414],[424,416,144],[141,144,416],[405,254,408],[232,408,254],[244,404,246],[245,246,404],[247,249,407],[248,407,249],[232,250,402],[230,402,250],[415,413,251],[244,251,413],[252,236,266],[251,252,415],[423,415,266],[252,266,415],[231,253,405],[254,405,253],[416,255,414],[247,414,255],[256,263,241],[255,416,256],[424,263,416],[256,416,263],[257,258,418],[425,418,258],[260,417,261],[426,261,417],[422,418,427],[427,259,91],[420,428,417],[428,1,262],[147,423,148],[429,148,423],[263,424,264],[264,295,265],[266,267,423],[267,268,297],[144,145,424],[430,424,145],[49,431,269],[166,269,431],[82,431,83],[49,83,431],[84,85,431],[166,431,85],[82,344,431],[84,431,344],[432,278,90],[10,90,278],[433,0,281],[39,281,0],[362,361,434],[435,271,359],[270,359,271],[436,361,275],[273,275,361],[360,437,359],[277,287,276],[151,278,277],[280,279,289],[150,280,281],[436,438,439],[439,285,140],[90,92,432],[440,432,92],[282,272,291],[441,282,442],[284,293,274],[443,438,284],[278,432,286],[286,299,265],[281,288,433],[288,268,301],[0,433,89],[444,89,433],[435,445,442],[445,134,283],[439,446,436],[361,436,446],[442,290,435],[271,435,290],[438,436,292],[275,292,436],[445,435,447],[359,447,435],[286,287,278],[277,278,287],[288,281,289],[280,289,281],[145,152,430],[443,430,152],[148,429,154],[441,154,429],[424,430,294],[294,307,276],[423,296,429],[296,279,305],[425,440,100],[92,100,440],[290,442,291],[282,291,442],[292,293,438],[284,438,293],[298,320,241],[432,440,298],[300,236,322],[433,300,444],[426,101,444],[89,444,101],[107,448,302],[302,79,54],[78,31,343],[107,78,448],[75,79,448],[302,448,79],[78,343,448],[75,448,343],[427,418,259],[425,259,418],[428,262,417],[426,417,262],[437,449,359],[447,359,449],[434,361,450],[446,450,361],[32,33,397],[78,33,32],[53,303,54],[302,54,303],[152,153,443],[438,443,153],[429,304,441],[282,441,304],[430,443,306],[284,306,443],[154,441,155],[442,155,441],[298,299,432],[286,432,299],[300,433,301],[288,301,433],[185,451,308],[308,74,7],[73,15,337],[185,73,451],[35,74,451],[308,451,74],[73,337,451],[35,451,337],[158,452,310],[310,72,42],[70,22,341],[158,70,452],[66,72,452],[310,452,72],[70,341,452],[66,452,341],[313,327,314],[315,314,327],[316,317,326],[318,326,317],[15,156,311],[356,311,156],[7,312,157],[358,157,312],[211,9,327],[364,327,9],[38,326,94],[363,94,326],[294,295,424],[264,424,295],[296,423,297],[267,297,423],[262,149,426],[101,426,149],[258,319,425],[440,425,319],[261,426,321],[444,321,426],[259,425,146],[100,146,425],[306,307,430],[294,430,307],[304,429,305],[296,305,429],[319,320,440],[298,440,320],[321,444,322],[300,322,444],[445,283,442],[155,442,283],[439,438,285],[153,285,438],[17,68,18],[21,18,68],[46,184,47],[221,47,184],[102,95,363],[94,363,95],[9,11,364],[103,364,11],[6,323,357],[370,357,323],[371,324,355],[208,355,324],[270,363,325],[326,325,363],[327,364,328],[273,328,364],[0,2,39],[12,39,2],[90,93,91],[40,91,93],[14,16,17],[73,17,16],[45,309,7],[308,7,309],[12,71,39],[70,39,71],[40,41,42],[310,42,41],[97,98,63],[14,63,98],[3,5,7],[45,7,5],[118,377,329],[330,329,377],[331,372,332],[86,332,372],[333,376,334],[335,334,376],[115,373,336],[169,336,373],[167,166,380],[330,380,166],[80,81,382],[335,382,81],[86,385,81],[168,81,385],[169,384,82],[87,82,384],[159,88,372],[87,372,88],[163,164,376],[167,376,164],[24,26,377],[80,377,26],[56,57,373],[168,373,57],[32,397,30],[29,30,397],[58,60,53],[303,53,60],[205,181,119],[118,119,181],[163,175,165],[122,165,175],[453,454,455],[454,456,455],[457,455,456],[458,455,457],[459,455,458],[460,455,459],[461,462,463],[464,465,466],[467,468,469],[470,471,472],[465,473,474],[475,476,477],[478,479,480],[481,482,478],[483,484,481],[485,486,483],[487,488,485],[489,490,487],[491,492,489],[493,494,491],[495,496,493],[497,498,495],[499,500,497],[501,502,499],[503,504,501],[505,504,503],[506,504,505],[507,504,506],[508,504,507],[509,504,508],[510,504,509],[511,504,510],[512,504,511],[513,504,512],[514,504,513],[476,515,516],[517,518,519],[520,517,521],[518,522,523],[522,480,479],[524,525,526],[468,470,527],[525,467,528],[529,475,530],[531,532,533],[534,531,535],[536,537,538],[473,539,540],[539,536,541],[537,534,542],[471,520,543],[532,529,544],[545,524,546],[453,461,547],[463,464,548],[523,549,504],[527,550,551],[519,552,553],[521,554,555],[466,556,557],[469,558,559],[528,560,561],[477,562,563],[543,564,565],[535,566,567],[530,568,569],[540,570,571],[474,572,573],[542,574,575],[538,576,577],[541,578,579],[472,580,581],[526,582,583],[533,584,585],[544,586,587],[516,545,588],[588,589,590],[455,460,4],[591,592,63],[462,455,4],[592,547,63],[547,548,63],[465,462,4],[548,557,63],[127,124,501],[127,501,499],[505,503,124],[124,126,507],[124,507,506],[509,508,126],[126,134,512],[126,512,511],[510,509,126],[128,127,493],[128,493,491],[497,495,127],[489,487,128],[140,128,483],[140,483,481],[487,485,128],[478,480,140],[480,522,140],[514,513,134],[504,514,134],[551,581,437],[471,470,434],[445,447,555],[445,555,553],[134,445,553],[134,553,504],[446,439,518],[446,518,517],[439,140,522],[439,522,518],[515,476,358],[563,588,356],[557,573,63],[473,465,4],[437,360,559],[437,559,551],[360,371,561],[360,561,559],[362,434,470],[362,470,468],[370,362,468],[370,468,467],[499,497,127],[506,505,124],[495,493,127],[513,512,134],[481,478,140],[447,449,565],[447,565,555],[450,446,517],[450,517,520],[356,156,569],[356,569,563],[157,358,476],[157,476,475],[357,370,467],[357,467,525],[371,355,583],[371,583,561],[460,459,4],[63,62,593],[63,593,591],[62,4,459],[62,459,458],[532,531,104],[531,534,104],[567,585,105],[575,567,105],[4,3,539],[4,539,473],[536,539,3],[97,63,573],[97,573,571],[571,579,97],[99,97,579],[99,579,577],[105,99,577],[105,577,575],[96,104,534],[96,534,537],[3,96,537],[3,537,536],[503,501,124],[508,507,126],[491,489,128],[511,510,126],[485,483,128],[434,450,520],[434,520,471],[449,437,581],[449,581,565],[156,105,585],[156,585,587],[587,569,156],[104,157,529],[104,529,532],[475,529,157],[590,583,355],[355,356,588],[355,588,590],[358,357,524],[358,524,515],[525,524,357],[458,457,62],[457,593,62],[479,478,482],[479,504,549],[479,482,504],[482,481,484],[472,551,550],[581,551,472],[482,484,504],[484,483,486],[523,553,552],[504,553,523],[540,573,572],[571,573,540],[544,585,584],[587,585,544],[542,577,576],[575,577,542],[526,590,589],[583,590,526],[535,575,574],[567,575,535],[533,567,566],[585,567,533],[538,579,578],[577,579,538],[543,581,580],[565,581,543],[477,569,568],[563,569,477],[530,587,586],[569,587,530],[541,571,570],[579,571,541],[528,583,582],[561,583,528],[591,453,592],[547,592,453],[521,565,564],[555,565,521],[474,557,556],[573,557,474],[516,563,562],[588,563,516],[519,555,554],[553,555,519],[527,559,558],[551,559,527],[469,561,560],[559,561,469],[462,461,455],[453,455,461],[461,463,547],[548,547,463],[465,464,462],[463,462,464],[464,466,548],[557,548,466],[469,560,467],[528,467,560],[472,550,470],[527,470,550],[474,556,465],[466,465,556],[477,568,475],[530,475,568],[516,562,476],[477,476,562],[519,554,517],[521,517,554],[521,564,520],[543,520,564],[523,552,518],[519,518,552],[479,549,522],[523,522,549],[526,589,524],[589,546,524],[527,558,468],[469,468,558],[528,582,525],[526,525,582],[530,586,529],[544,529,586],[533,566,531],[535,531,566],[535,574,534],[542,534,574],[538,578,536],[541,536,578],[540,572,473],[474,473,572],[541,570,539],[540,539,570],[542,576,537],[538,537,576],[543,580,471],[472,471,580],[544,584,532],[533,532,584],[524,545,515],[516,515,545],[545,546,588],[589,588,546],[453,591,454],[593,454,591],[484,486,504],[486,485,488],[486,488,504],[488,487,490],[488,490,504],[490,489,492],[490,492,504],[492,491,494],[492,494,504],[494,493,496],[494,496,504],[496,495,498],[496,498,504],[498,497,500],[498,500,504],[500,499,502],[500,502,504],[501,504,502],[454,593,456],[457,456,593],[594,595,596],[597,598,594],[599,597,594],[600,599,594],[601,600,594],[602,601,594],[603,602,594],[604,603,594],[605,604,594],[606,607,608],[609,606,608],[610,609,608],[611,610,608],[612,611,608],[613,612,608],[614,613,608],[615,614,608],[616,615,608],[617,616,608],[618,617,608],[619,618,608],[620,619,608],[596,608,607],[595,594,598],[608,596,595],[605,594,91],[91,338,602],[91,602,603],[598,597,1],[594,596,91],[608,595,1],[595,598,1],[616,617,392],[610,611,394],[419,421,613],[419,613,614],[422,427,607],[422,607,606],[427,91,596],[427,596,607],[428,420,619],[428,619,620],[1,428,620],[1,620,608],[420,409,618],[420,618,619],[411,422,606],[411,606,609],[398,419,614],[398,614,615],[421,400,612],[421,612,613],[409,392,617],[409,617,618],[394,411,609],[394,609,610],[604,605,91],[338,1,599],[338,599,600],[392,398,615],[392,615,616],[400,394,611],[400,611,612],[603,604,91],[601,602,338],[597,599,1],[600,601,338] - ]; - } elsif ($name eq 'gt2_teeth') { - $vertices = [ - [15.8899993896484,19.444055557251,2.67489433288574],[15.9129991531372,19.1590557098389,2.67489433288574],[15.9039993286133,19.1500549316406,2.67489433288574],[15.9489994049072,19.2490558624268,2.67489433288574],[15.9579992294312,19.3570556640625,2.67489433288574],[15.8819999694824,18.690055847168,2.67489433288574],[15.8319997787476,17.7460556030273,2.67489433288574],[15.8489999771118,18.819055557251,2.67489433288574],[15.8589992523193,17.7190551757812,2.67489433288574],[15.8769998550415,19.0490550994873,2.67489433288574],[15.7529993057251,17.8080558776855,2.67489433288574],[15.7869997024536,19.5010547637939,2.67489433288574],[14.0329990386963,18.7170543670654,2.67489433288574],[13.9599990844727,18.7460556030273,2.67489433288574],[13.9869995117188,20.2840557098389,2.67489433288574],[14.2029991149902,20.149055480957,2.67489433288574],[14.1939992904663,19.9560546875,2.67489433288574],[14.1939992904663,20.1670551300049,2.67489433288574],[14.2119998931885,20.0590553283691,2.67489433288574],[12.1899995803833,19.1840553283691,2.67489433288574],[12.096999168396,19.1950550079346,2.67489433288574],[12.1099996566772,20.6690559387207,2.67489433288574],[11.382999420166,19.9750556945801,2.67489433288574],[11.2599992752075,19.2490558624268,2.67489433288574],[11.2369995117188,19.9320545196533,2.67489433288574],[11.5349998474121,20.0640544891357,2.67489433288574],[11.6259994506836,20.1550559997559,2.67489433288574],[11.6829986572266,20.2390556335449,2.67489433288574],[11.7369995117188,20.3570556640625,2.67489433288574],[11.8449993133545,20.645055770874,2.67489433288574],[11.7729988098145,20.4640560150146,2.67489433288574],[11.7799987792969,20.5370559692383,9.41389465332031],[11.7639999389648,20.4470558166504,2.67489433288574],[11.9559993743896,20.6810550689697,2.67489433288574],[12.3079996109009,20.6020545959473,2.67489433288574],[12.1959991455078,19.1860542297363,2.67489433288574],[12.2059993743896,20.6540546417236,2.67489433288574],[12.3489990234375,20.3740558624268,2.67489433288574],[12.3579998016357,20.2750549316406,2.67489433288574],[12.3669996261597,20.266056060791,2.67489433288574],[12.3849992752075,20.1670551300049,2.67489433288574],[12.4269990921021,20.0680541992188,2.67489433288574],[12.5029993057251,19.9540557861328,2.67489433288574],[12.6169996261597,19.8550548553467,2.67489433288574],[12.7449989318848,19.7800559997559,2.67489433288574],[12.7629995346069,19.7800559997559,2.67489433288574],[12.8799991607666,19.7350559234619,2.67489433288574],[13.0369997024536,19.7250556945801,2.67489433288574],[13.0149993896484,19.0340557098389,2.67489433288574],[11.1699991226196,19.2580547332764,2.67489433288574],[11.0959987640381,19.2580547332764,2.67489433288574],[11.1209993362427,19.9230556488037,2.67489433288574],[13.0599994659424,19.024055480957,2.67489433288574],[14.9049997329712,18.3170547485352,2.67489433288574],[14.8779993057251,18.3400554656982,2.67489433288574],[14.8779993057251,19.149055480957,2.67489433288574],[13.3039989471436,19.77805519104,2.67489433288574],[13.1589994430542,18.9890556335449,2.67489433288574],[13.1559991836548,19.7350559234619,2.67489433288574],[13.4269990921021,19.8600559234619,2.67489433288574],[13.5339994430542,19.9700546264648,2.67389440536499],[13.6359996795654,20.1220550537109,2.67489433288574],[13.6359996795654,20.1400547027588,2.67489433288574],[13.6719989776611,20.2210559844971,2.67489433288574],[13.6899995803833,20.2300548553467,2.67489433288574],[13.7509994506836,20.3010559082031,2.67489433288574],[13.8539991378784,20.3180541992188,2.67489433288574],[14.8329992294312,18.3580551147461,2.67489433288574],[14.1849994659424,19.8530559539795,2.67489433288574],[14.0769996643066,18.7000541687012,2.67489433288574],[14.1099996566772,20.2400550842285,2.67489433288574],[14.2009992599487,19.6230545043945,2.67489433288574],[14.2729997634888,19.4670543670654,2.67489433288574],[14.3379993438721,19.3790550231934,2.67489433288574],[14.4549999237061,19.2770557403564,2.67489433288574],[14.5899991989136,19.2040557861328,2.67489433288574],[14.6079998016357,19.2040557861328,2.67489433288574],[14.7209997177124,19.1600551605225,2.67489433288574],[15.1379995346069,19.210054397583,2.67489433288574],[14.9949998855591,18.2680549621582,2.67489433288574],[15.0029993057251,19.1580543518066,2.67489433288574],[15.2369995117188,19.2760543823242,2.67489433288574],[15.3779993057251,19.4060554504395,2.67489433288574],[15.4539995193481,19.520055770874,2.67489433288574],[15.471999168396,19.52805519104,2.67489433288574],[15.5449991226196,19.5830554962158,2.67489433288574],[15.6529998779297,19.573055267334,2.67489433288574],[15.7059993743896,17.8360557556152,2.67489433288574],[15.9449996948242,18.5560550689697,2.67489433288574],[15.8589992523193,18.9380550384521,2.67489433288574],[14.9589996337891,18.2950553894043,2.67489433288574],[15.7779998779297,19.5100555419922,2.67489433288574],[14.0049991607666,20.2750549316406,2.67489433288574],[12.3489990234375,20.5000553131104,2.67489433288574],[13.0689992904663,19.0150547027588,2.67489433288574],[13.0999994277954,19.0100555419922,2.67489433288574],[15.9489994049072,19.3670558929443,9.41489505767822],[15.9489994049072,19.2490558624268,9.41489505767822],[15.75,17.8080558776855,9.41489505767822],[15.6639995574951,19.5710544586182,9.41489505767822],[15.5709991455078,17.9260559082031,9.41489505767822],[15.8769998550415,18.690055847168,9.41489505767822],[15.8499994277954,18.8170547485352,9.41489505767822],[15.9459991455078,18.5520553588867,9.41489505767822],[15.914999961853,17.6890544891357,9.41489505767822],[15.3999996185303,19.4290542602539,9.41489505767822],[15.3099994659424,19.339054107666,9.41489505767822],[15.3729991912842,18.0440559387207,9.41489505767822],[15.4579992294312,19.5170555114746,9.41489505767822],[15.5469999313354,19.5820541381836,9.41489505767822],[13.2309989929199,19.7610549926758,9.41489505767822],[13.168999671936,19.7360553741455,9.41489505767822],[13.096999168396,19.0140552520752,9.41489505767822],[13.1999988555908,18.9870548248291,9.41489505767822],[15.1399993896484,19.2080554962158,9.41489505767822],[15.0159997940063,19.1600551605225,9.41489505767822],[14.9859991073608,18.2770557403564,9.41489505767822],[15.1749992370605,18.1690559387207,9.41489505767822],[15.9039993286133,19.1320552825928,9.41489505767822],[15.8949995040894,19.4460544586182,9.41489505767822],[15.8769998550415,19.0420551300049,9.41489505767822],[12.2169990539551,20.6500549316406,9.41489505767822],[11.9379997253418,20.6810550689697,9.41489505767822],[11.8629989624023,19.2130546569824,9.41489505767822],[12.096999168396,19.1950550079346,9.41489505767822],[14.1669998168945,18.6640548706055,9.41489505767822],[14.1039991378784,20.2460556030273,9.41489505767822],[13.9849996566772,18.7360553741455,9.41489505767822],[14.7349996566772,19.1590557098389,9.41489505767822],[14.5849990844727,19.2050552368164,9.41489505767822],[14.5719995498657,18.4850559234619,9.41489505767822],[14.1939992904663,19.6760559082031,9.41489505767822],[14.1849994659424,19.9330558776855,9.41489505767822],[14.1759996414185,18.6640548706055,9.41489505767822],[14.261999130249,19.4890556335449,9.41489505767822],[14.3539991378784,19.3610553741455,9.41489505767822],[14.3559989929199,18.5830554962158,9.41489505767822],[11.6039991378784,20.1250553131104,9.41489505767822],[11.5209999084473,20.0520553588867,9.41489505767822],[11.4209995269775,19.2480545043945,9.41489505767822],[11.6989994049072,20.2690544128418,9.41389465332031],[11.7609996795654,20.4310550689697,9.41489505767822],[11.8359994888306,19.2130546569824,9.41489505767822],[14.1889991760254,20.1710548400879,9.41489505767822],[13.9689998626709,20.2840557098389,9.41489505767822],[13.8739995956421,20.315055847168,9.41489505767822],[13.7799997329712,18.8080558776855,9.41489505767822],[13.9869995117188,20.2750549316406,9.41489505767822],[12.3129997253418,20.5980548858643,9.41489505767822],[12.3399991989136,20.5090560913086,9.41489505767822],[12.3489990234375,20.3830547332764,9.41489505767822],[12.3599996566772,20.2680549621582,9.41489505767822],[12.3849992752075,20.1850547790527,9.41489505767822],[12.3849992752075,20.1670551300049,9.41489505767822],[12.4249992370605,20.065055847168,9.41489505767822],[12.4729995727539,19.1350555419922,9.41489505767822],[14.4399995803833,19.2900543212891,9.41489505767822],[14.3649997711182,18.5740547180176,9.41489505767822],[13.5729999542236,20.0310554504395,9.41489505767822],[13.4889993667603,19.9140548706055,9.41489505767822],[13.5639991760254,18.8710556030273,9.41489505767822],[13.6389999389648,20.1310558319092,9.41489505767822],[13.6719989776611,20.2130546569824,9.41489505767822],[13.75,20.3020553588867,9.41489505767822],[12.7399997711182,19.7810554504395,9.41489505767822],[12.6189994812012,19.8520545959473,9.41489505767822],[12.5799999237061,19.1200542449951,9.41489505767822],[12.8349990844727,19.069055557251,9.41489505767822],[11.2669992446899,19.9350547790527,9.41489505767822],[11.1029987335205,19.9230556488037,9.41489505767822],[11.0209999084473,19.2600555419922,9.41489505767822],[11.3819999694824,19.9710559844971,9.41489505767822],[13.418999671936,19.8530559539795,9.41489505767822],[13.4329996109009,18.9160556793213,9.41489505767822],[11.8399991989136,20.6430549621582,9.41489505767822],[13.3119993209839,19.7800559997559,9.41489505767822],[15.2189998626709,19.2600555419922,9.41489505767822],[15.1839990615845,18.1600551605225,9.41489505767822],[15.3639993667603,18.0520553588867,9.41489505767822],[13.0189990997314,19.7250556945801,9.41489505767822],[12.8949995040894,19.7350559234619,9.41489505767822],[15.9039993286133,19.1500549316406,9.41489505767822],[15.7699995040894,19.5140552520752,9.41489505767822],[15.8589992523193,18.9340553283691,9.41489505767822],[14.1939992904663,19.9510555267334,9.41489505767822],[14.2119998931885,20.0630550384521,9.41489505767822],[14.8589992523193,19.149055480957,9.41489505767822],[14.8159999847412,18.3670558929443,9.41489505767822],[14.8959999084473,18.3220558166504,9.41489505767822],[12.5189990997314,19.9360542297363,9.41489505767822],[11.0209999084473,19.9290542602539,9.41489505767822],[11.0209999084473,19.2530555725098,2.67489433288574],[11.0209999084473,19.9300556182861,2.67489433288574],[15.9799995422363,18.505931854248,5.58724021911621],[15.9799995422363,18.5044555664062,9.41489505767822],[15.9799995422363,18.5041732788086,2.67489433288574],[15.9799995422363,18.1684837341309,2.67489433288574],[15.9799995422363,18.1288299560547,9.41489505767822],[15.9799995422363,17.9876575469971,2.67489433288574],[15.9799995422363,17.6247596740723,3.91620373725891],[15.9799995422363,17.6247596740723,2.67489433288574],[15.9799995422363,17.6254329681396,4.32245063781738],[15.9799995422363,17.8920269012451,9.41489505767822],[15.9799995422363,17.8795108795166,2.67489433288574],[15.9799995422363,17.629810333252,4.58585262298584],[15.9799995422363,17.6336059570312,5.27938556671143],[15.9799995422363,17.8311748504639,2.67489433288574],[15.9799995422363,17.638355255127,9.41489505767822],[15.9799995422363,17.6346111297607,5.98653984069824],[15.9799995422363,17.8728256225586,2.67489433288574],[15.9799995422363,18.2221603393555,2.67489433288574] - ]; - $facets = [ - [0,1,2],[0,3,1],[0,4,3],[5,6,7],[8,6,5],[2,9,0],[6,10,11],[12,13,14],[15,16,17],[18,16,15],[19,20,21],[22,23,24],[25,23,22],[26,23,25],[27,23,26],[28,23,27],[29,30,31],[29,32,30],[29,28,32],[33,28,29],[33,23,28],[21,23,33],[20,23,21],[34,35,36],[37,35,34],[38,35,37],[39,35,38],[40,35,39],[41,35,40],[42,35,41],[43,35,42],[44,35,43],[45,35,44],[46,35,45],[47,35,46],[48,35,47],[49,50,51],[52,48,47],[23,49,24],[53,54,55],[56,57,58],[59,57,56],[60,57,59],[61,57,60],[62,57,61],[63,57,62],[64,57,63],[65,57,64],[66,57,65],[13,57,66],[54,67,55],[68,69,70],[71,69,68],[72,69,71],[73,69,72],[74,69,73],[75,69,74],[76,69,75],[77,69,76],[67,69,77],[70,16,68],[70,17,16],[78,79,80],[81,79,78],[82,79,81],[83,79,82],[84,79,83],[85,79,84],[86,79,85],[87,79,86],[88,8,5],[11,7,6],[11,89,7],[11,9,89],[11,0,9],[55,90,53],[55,79,90],[55,80,79],[91,11,10],[92,69,12],[92,70,69],[34,93,37],[47,94,52],[47,95,94],[47,57,95],[47,58,57],[51,24,49],[21,35,19],[21,36,35],[14,92,12],[86,10,87],[86,91,10],[77,55,67],[66,14,13],[96,97,4],[98,99,100],[101,102,98],[103,101,98],[104,103,98],[105,106,107],[108,105,107],[109,108,107],[100,109,107],[110,111,112],[113,110,112],[114,115,116],[117,114,116],[118,119,120],[121,122,123],[124,121,123],[125,126,127],[128,129,130],[131,132,133],[71,131,133],[134,71,133],[135,134,133],[136,135,133],[137,138,139],[140,137,139],[141,140,139],[142,31,141],[142,141,139],[143,126,132],[144,145,146],[147,144,146],[127,147,146],[148,121,124],[149,148,124],[150,149,124],[151,150,124],[152,151,124],[153,152,124],[154,153,124],[155,154,124],[129,156,157],[130,129,157],[158,159,160],[161,158,160],[162,161,160],[163,162,160],[146,163,160],[164,165,166],[167,164,166],[168,169,170],[171,168,170],[139,171,170],[159,172,173],[123,174,142],[175,110,113],[173,175,113],[106,176,177],[178,106,177],[179,180,167],[112,179,167],[175,173,172],[119,118,181],[119,181,97],[119,97,96],[182,98,102],[182,102,183],[182,183,120],[182,120,119],[143,132,184],[184,185,143],[147,127,126],[174,123,122],[159,173,160],[126,125,133],[126,133,132],[186,187,188],[186,188,116],[186,116,115],[99,98,182],[109,100,99],[106,178,107],[114,117,177],[114,177,176],[128,130,187],[128,187,186],[135,136,157],[135,157,156],[163,146,145],[164,167,180],[179,112,111],[171,139,138],[189,155,166],[189,166,165],[149,150,93],[154,155,189],[31,142,174],[114,176,78],[81,78,176],[7,89,183],[89,9,120],[89,120,183],[78,80,114],[176,106,81],[88,5,103],[183,102,7],[118,120,9],[9,2,181],[9,181,118],[115,114,80],[82,81,106],[101,103,5],[102,101,5],[5,7,102],[97,181,2],[2,1,97],[1,3,97],[80,55,115],[172,159,59],[59,56,172],[3,4,97],[4,0,96],[105,108,82],[186,115,55],[82,106,105],[83,82,108],[60,59,159],[175,172,56],[119,96,0],[0,11,119],[108,109,84],[84,83,108],[55,77,186],[56,58,110],[56,110,175],[60,159,158],[11,91,182],[182,119,11],[91,86,182],[85,84,109],[86,85,99],[128,186,77],[58,111,110],[158,161,60],[26,25,137],[138,137,25],[99,182,86],[109,99,85],[77,76,128],[58,47,111],[61,60,161],[137,140,26],[27,26,140],[25,22,138],[129,128,76],[76,75,129],[75,74,129],[74,73,156],[73,72,135],[68,16,184],[68,184,132],[16,18,185],[161,162,62],[62,61,161],[179,111,47],[171,138,22],[156,129,74],[135,156,73],[134,135,72],[72,71,134],[68,132,131],[185,184,16],[18,15,185],[63,62,162],[28,27,140],[22,24,171],[71,68,131],[15,17,143],[15,143,185],[17,70,143],[70,92,126],[162,163,64],[64,63,162],[180,179,47],[47,46,180],[140,141,28],[168,171,24],[126,143,70],[92,14,147],[147,126,92],[14,66,144],[14,144,147],[65,64,163],[66,65,145],[46,45,180],[32,28,141],[24,51,168],[145,144,66],[163,145,65],[164,180,45],[45,44,164],[44,43,164],[43,42,165],[38,37,151],[150,151,37],[37,93,150],[141,31,30],[30,32,141],[169,168,51],[165,164,43],[189,165,42],[42,41,189],[40,39,152],[40,152,153],[151,152,39],[39,38,151],[93,34,149],[154,189,41],[153,154,41],[41,40,153],[148,149,34],[34,36,148],[36,21,121],[31,174,29],[121,148,36],[21,33,122],[21,122,121],[33,29,122],[174,122,29],[116,188,53],[104,98,10],[87,10,98],[98,100,87],[79,87,100],[79,100,107],[90,79,107],[90,107,178],[178,177,90],[53,90,177],[53,177,117],[117,116,53],[54,53,188],[54,188,187],[67,54,187],[67,187,130],[69,67,130],[69,130,157],[12,69,157],[12,157,136],[136,133,12],[12,133,125],[125,127,12],[13,12,127],[127,146,13],[57,13,146],[57,146,160],[95,57,160],[95,160,173],[173,113,95],[94,95,113],[113,112,94],[52,94,112],[48,52,112],[112,167,48],[35,48,167],[35,167,166],[19,35,166],[139,170,50],[50,49,139],[166,155,19],[20,19,155],[155,124,20],[23,20,124],[23,124,123],[49,23,123],[49,123,142],[142,139,49],[190,191,170],[192,191,190],[191,192,51],[191,51,50],[170,169,190],[169,51,192],[169,192,190],[170,191,50],[193,194,195],[196,197,198],[199,200,201],[198,202,203],[204,201,200],[205,204,200],[206,207,208],[206,208,205],[206,205,200],[207,206,209],[207,209,203],[207,203,202],[202,198,197],[197,196,210],[197,210,195],[197,195,194],[8,88,195],[8,195,210],[210,196,8],[196,198,8],[198,203,8],[203,209,8],[209,206,8],[206,200,8],[202,197,104],[207,202,104],[103,104,197],[103,197,194],[193,195,88],[88,103,194],[88,194,193],[200,199,8],[199,201,8],[204,205,6],[6,8,201],[6,201,204],[10,6,205],[10,205,208],[104,10,208],[104,208,207] - ]; - } elsif ($name eq 'pyramid') { - $vertices = [ - [10,10,40],[0,0,0],[20,0,0],[20,20,0],[0,20,0], - ]; - $facets = [ - [0,1,2],[0,3,4],[3,1,4],[1,3,2],[3,0,2],[4,1,0], - ]; - } elsif ($name eq 'two_hollow_squares') { - $vertices = [ - [66.7133483886719,104.286666870117,0],[66.7133483886719,95.7133331298828,0],[65.6666870117188,94.6666717529297,0],[75.2866821289062,95.7133331298828,0],[76.3333435058594,105.333335876465,0],[76.3333435058594,94.6666717529297,0],[65.6666870117188,105.33332824707,0],[75.2866821289062,104.286666870117,0],[71.1066818237305,104.58666229248,2.79999995231628],[66.4133529663086,104.58666229248,2.79999995231628],[75.5866851806641,104.58666229248,2.79999995231628],[66.4133529663086,99.8933334350586,2.79999995231628],[66.4133529663086,95.4133377075195,2.79999995231628],[71.1066818237305,95.4133377075195,2.79999995231628],[75.5866851806641,95.4133377075195,2.79999995231628],[75.5866851806641,100.106666564941,2.79999995231628],[74.5400161743164,103.540000915527,2.79999995231628],[70.0320129394531,103.540000915527,2.79999995231628],[67.4600067138672,103.540000915527,2.79999995231628],[67.4600067138672,100.968002319336,2.79999995231628],[67.4600067138672,96.4599990844727,2.79999995231628],[74.5400161743164,99.0319976806641,2.79999995231628],[74.5400161743164,96.4599990844727,2.79999995231628],[70.0320129394531,96.4599990844727,2.79999995231628],[123.666717529297,94.6666717529297,0],[134.333312988281,94.6666717529297,0],[124.413360595703,95.4133377075195,2.79999995231628],[129.106674194336,95.4133377075195,2.79999995231628],[133.586669921875,95.4133377075195,2.79999995231628],[123.666717529297,105.33332824707,0],[124.413360595703,104.58666229248,2.79999995231628],[124.413360595703,99.8933334350586,2.79999995231628],[134.333312988281,105.33332824707,0],[129.106674194336,104.58666229248,2.79999995231628],[133.586669921875,104.58666229248,2.79999995231628],[133.586669921875,100.106666564941,2.79999995231628],[124.713317871094,104.286666870117,0],[124.713317871094,95.7133331298828,0],[133.286712646484,95.7133331298828,0],[133.286712646484,104.286666870117,0],[132.540023803711,103.540000915527,2.79999995231628],[128.032028198242,103.540008544922,2.79999995231628],[125.460006713867,103.540000915527,2.79999995231628],[125.460006713867,100.968002319336,2.79999995231628],[125.460006713867,96.4599990844727,2.79999995231628],[132.540023803711,99.0319976806641,2.79999995231628],[132.540023803711,96.4599990844727,2.79999995231628],[128.032028198242,96.4599990844727,2.79999995231628], - ]; - $facets = [ - [0,1,2],[3,4,5],[6,4,0],[6,0,2],[2,1,5],[7,4,3],[1,3,5],[0,4,7],[4,6,8],[6,9,8],[4,8,10],[6,2,9],[2,11,9],[2,12,11],[2,5,12],[5,13,12],[5,14,13],[4,10,15],[5,4,14],[4,15,14],[7,16,17],[0,7,18],[7,17,18],[1,19,20],[1,0,19],[0,18,19],[7,3,21],[3,22,21],[7,21,16],[3,23,22],[3,1,23],[1,20,23],[24,25,26],[25,27,26],[25,28,27],[29,24,30],[24,31,30],[24,26,31],[32,29,33],[29,30,33],[32,33,34],[32,34,35],[25,32,28],[32,35,28],[36,37,24],[38,32,25],[29,32,36],[29,36,24],[24,37,25],[39,32,38],[37,38,25],[36,32,39],[39,40,41],[36,39,42],[39,41,42],[37,43,44],[37,36,43],[36,42,43],[39,38,45],[38,46,45],[39,45,40],[38,47,46],[38,37,47],[37,44,47],[16,8,9],[16,10,8],[10,16,15],[15,16,21],[22,15,21],[15,22,14],[22,23,14],[23,20,14],[17,16,9],[18,17,9],[19,18,9],[19,9,11],[19,11,20],[13,14,20],[20,11,12],[13,20,12],[41,40,30],[42,41,30],[43,42,30],[43,30,31],[43,31,44],[27,28,44],[44,31,26],[27,44,26],[40,33,30],[40,34,33],[34,40,35],[35,40,45],[46,35,45],[35,46,28],[46,47,28],[47,44,28], - ]; - } elsif ($name eq 'small_dorito') { - $vertices = [ - [6.00058937072754,-22.9982089996338,0],[22.0010242462158,-49.9998741149902,0],[-9.99957847595215,-49.999870300293,0],[6.00071382522583,-32.2371635437012,28.0019245147705],[11.1670551300049,-37.9727020263672,18.9601669311523],[6.00060224533081,-26.5392456054688,10.7321853637695] - ]; - $facets = [ - [0,1,2],[3,4,5],[2,1,4],[2,4,3],[2,3,5],[2,5,0],[5,4,1],[5,1,0] - ]; - } elsif ($name eq 'bridge') { - $vertices = [ - [75,84.5,8],[125,84.5,8],[75,94.5,8],[120,84.5,5],[125,94.5,8],[75,84.5,0],[80,84.5,5],[125,84.5,0],[125,94.5,0],[80,94.5,5],[75,94.5,0],[120,94.5,5],[120,84.5,0],[80,94.5,0],[80,84.5,0],[120,94.5,0] - ]; - $facets = [ - [0,1,2],[1,0,3],[2,1,4],[2,5,0],[0,6,3],[1,3,7],[1,8,4],[4,9,2],[10,5,2],[5,6,0],[6,11,3],[3,12,7],[7,8,1],[4,8,11],[4,11,9],[9,10,2],[10,13,5],[14,6,5],[9,11,6],[11,12,3],[12,8,7],[11,8,15],[13,10,9],[5,13,14],[14,13,6],[6,13,9],[15,12,11],[15,8,12] - ]; - } else { - return undef; - } - - my $mesh = Slic3r::TriangleMesh->new; - $mesh->ReadFromPerl($vertices, $facets); - $mesh->scale_xyz(Slic3r::Pointf3->new(@{$params{scale_xyz}})) if $params{scale_xyz}; - $mesh->translate(@{$params{translate}}) if $params{translate}; - return $mesh; -} - -sub model { - my ($model_names, %params) = @_; - $model_names = [ $model_names ] if ! ref($model_names); - - my $model = Slic3r::Model->new; - - for my $model_name (@$model_names) { - my $input_file = "${model_name}.stl"; - my $mesh = mesh($model_name, %params); - # $mesh->write_ascii("out/$input_file"); - - my $object = $model->add_object(input_file => $input_file); - $model->set_material($model_name); - $object->add_volume(mesh => $mesh, material_id => $model_name); - $object->add_instance( - offset => Slic3r::Pointf->new(0,0), - # 3D full transform - rotation => Slic3r::Pointf3->new(0, 0, $params{rotation} // 0), - scaling_factor => Slic3r::Pointf3->new($params{scale} // 1, $params{scale} // 1, $params{scale} // 1), - # old transform - # rotation => $params{rotation} // 0, - # scaling_factor => $params{scale} // 1, - ); - } - return $model; -} - -sub init_print { - my ($models, %params) = @_; - my $model; - if (ref($models) eq 'ARRAY') { - $model = model($models, %params); - } elsif (ref($models)) { - $model = $models; - } else { - $model = model([$models], %params); - } - - my $config = Slic3r::Config->new; - $config->apply($params{config}) if $params{config}; - $config->set('gcode_comments', 1) if $ENV{SLIC3R_TESTS_GCODE}; - - my $print = Slic3r::Print->new; - die "Unknown model in test" if !defined $model; - if (defined $params{duplicate} && $params{duplicate} > 1) { - $model->duplicate($params{duplicate} // 1, $config->min_object_distance); - } - foreach my $model_object (@{$model->objects}) { - $model_object->ensure_on_bed; - $print->auto_assign_extruders($model_object); - } - $model->arrange_objects($config->min_object_distance); - $model->center_instances_around_point($params{print_center} ? Slic3r::Pointf->new(@{$params{print_center}}) : Slic3r::Pointf->new(100,100)); - - $print->apply($model, $config); - $print->validate; - - # We return a proxy object in order to keep $models alive as required by the Print API. - return Slic3r::Test::Print->new( - print => $print, - model => $model, - ); -} - -sub gcode { - my ($print) = @_; - - $print = $print->print if $print->isa('Slic3r::Test::Print'); - - # Write the resulting G-code into a temporary file. - my $gcode_temp_path = abs_path($0) . '.gcode.temp'; - # Remove the existing temp file. - unlink $gcode_temp_path; - $print->set_status_silent; - $print->process; - $print->export_gcode($gcode_temp_path); - # Read the temoprary G-code file. - my $gcode; - { - local $/; - open my $fh, '<', $gcode_temp_path or die "Test.pm: can't open $gcode_temp_path: $!"; - $gcode = <$fh>; - } - # Remove the temp file. - unlink $gcode_temp_path; - - return $gcode; -} - -sub _eq { - my ($a, $b) = @_; - return abs($a - $b) < epsilon; -} - -sub add_facet { - my ($facet, $vertices, $facets) = @_; - - push @$facets, []; - for my $i (0..2) { - my $v = first { $vertices->[$_][X] == $facet->[$i][X] && $vertices->[$_][Y] == $facet->[$i][Y] && $vertices->[$_][Z] == $facet->[$i][Z] } 0..$#$vertices; - if (!defined $v) { - push @$vertices, [ @{$facet->[$i]}[X,Y,Z] ]; - $v = $#$vertices; - } - $facets->[-1][$i] = $v; - } -} - -package Slic3r::Test::Print; -use Moo; - -has 'print' => (is => 'ro', required => 1, handles => [qw(process apply)]); -has 'model' => (is => 'ro', required => 1); - -1; From 6e6cf80e92712f7b4061fa28a2739b02213e832a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20=C5=A0ach?= Date: Fri, 5 Jan 2024 13:00:28 +0100 Subject: [PATCH 44/91] Remove obsolete sublime project --- PrusaSlicer.sublime-project | 103 ------------------------------------ 1 file changed, 103 deletions(-) delete mode 100644 PrusaSlicer.sublime-project diff --git a/PrusaSlicer.sublime-project b/PrusaSlicer.sublime-project deleted file mode 100644 index 785dddba41..0000000000 --- a/PrusaSlicer.sublime-project +++ /dev/null @@ -1,103 +0,0 @@ -{ - "build_systems": - [ - { - "name": "List", - //"file_regex": " at ([^-\\s]*) line ([0-9]*)", -// "file_regex": " at (D\\:\\/src\\/Slic3r\\/.*?) line ([0-9]*)", - "shell_cmd": "ls -l" - }, - { - "name": "Run", - "working_dir": "$project_path", - "file_regex": " at (.*?) line ([0-9]*)", -// "shell_cmd": "chdir & perl slic3r.pl --DataDir \"C:\\Users\\Public\\Documents\\Prusa3D\\Slic3r settings MK2\" --gui \"..\\Slic3r-tests\\gap fill torture 20 -rt.stl\"" - "shell_cmd": "chdir & perl slic3r.pl" - }, - { - "name": "full", - "file_regex": "^(..[^:]*):([0-9]+):?([0-9]+)?:? (.*)$", - "shell_cmd": "chdir & perl Build.pl" - }, - { - "name": "xs", - "working_dir": "$project_path/build", - // for Visual Studio: - "file_regex": "^(..[^:]*)\\(([0-9]+)\\)(.*)$", - // For GCC: -// "file_regex": "^(..[^:]*):([0-9]+):?([0-9]+)?:? (.*)$", - "shell_cmd": "chdir & ninja -j 6 -v", - "env": { -// "PATH": "C:\\Program Files (x86)\\MSBuild\\12.0\\bin\\amd64;C:\\Program Files (x86)\\Microsoft Visual Studio 12.0\\VC\\BIN\\amd64;C:\\Program Files (x86)\\Microsoft Visual Studio 12.0\\Common7\\IDE;C:\\Program Files (x86)\\Microsoft Visual Studio 12.0\\Common7\\Tools;%PATH%;c:\\wperl64d\\site\\bin;c:\\wperl64d\\bin", -// "PERL_CPANM_HOME": "c:\\wperl64d\\cpanm", -// "WXDIR": "D:\\src-perl\\wxWidgets-3.0.3-beta1", -// "BOOST_DIR": "D:\\src-perl\\boost_1_61_0", -// "BOOST_INCLUDEDIR": "D:\\src-perl\\boost_1_61_0", -// "BOOST_LIBRARYDIR": "D:\\src-perl\\boost_1_61_0\\stage\\x64\\lib", -// "SLIC3R_STATIC": "1" - } - }, - { - "name": "xs & run", - "working_dir": "$project_path/build", - "file_regex": "^(..[^:]*):([0-9]+):?([0-9]+)?:? (.*)$", - "shell_cmd": "chdir & ninja -j 6 & cd .. & perl slic3r.pl --gui \"..\\Slic3r-tests\\star3-big2.stl\"" - }, - { - "name": "Slic3r - clean", - "working_dir": "$project_path/build", - "file_regex": "^(..[^:]*)(?::|\\()([0-9]+)(?::|\\))(?:([0-9]+):)?\\s*(.*)", - "shell_cmd": ["chdir & ninja clean"] - }, - { - "name": "run tests", - "working_dir": "$project_path/build", - // for Visual Studio: - "file_regex": "^(..[^:]*)\\(([0-9]+)\\)(.*)$", - "shell_cmd": "chdir & ctest --verbose" - }, - { - "name": "Clean & Configure", - "working_dir": "$project_path", - // for Visual Studio: - "file_regex": "^(..[^:]*)(?::|\\()([0-9]+)(?::|\\))(?:([0-9]+):)?\\s*(.*)", - "shell_cmd": "chdir & rmdir /S /Q build & mkdir build & cd build & cmake -G Ninja .. -DCMAKE_COLOR_MAKEFILE=OFF -DCMAKE_RULE_PROGRESS=OFF -DCMAKE_RULE_MESSAGES=OFF -DCMAKE_VERBOSE_MAKEFILE=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo" - }, - { - "name": "Configure", - "working_dir": "$project_path/build", - // for Visual Studio: - "file_regex": "^(..[^:]*)(?::|\\()([0-9]+)(?::|\\))(?:([0-9]+):)?\\s*(.*)", - "shell_cmd": "cmake -G Ninja .. -DCMAKE_COLOR_MAKEFILE=OFF -DCMAKE_RULE_PROGRESS=OFF -DCMAKE_RULE_MESSAGES=OFF -DCMAKE_VERBOSE_MAKEFILE=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo" - } - ], - "folders": - [ - { - "path": ".", -// "folder_exclude_patterns": [".svn", "._d", ".metadata", ".settings"], - "file_exclude_patterns": ["XS.c", "*.pch", "*.ilk", "*.js" ] - } - ], - - "settings": - { - "sublimegdb_workingdir": "${folder:${project_path:run}}", - // NOTE: You MUST provide --interpreter=mi for the plugin to work -// "sublimegdb_commandline": "D:\\Qt\\Tools\\mingw492_32\\bin\\gdb.exe --interpreter=mi -ex 'target localhost:2345'", -// "sublimegdb_commandline": "D:\\Qt\\Tools\\mingw492_32\\bin\\gdb.exe --interpreter=mi perl --args perl slic3r.pl", -// "sublimegdb_commandline": "D:\\Qt\\Tools\\mingw492_32\\bin\\gdb.exe --interpreter=mi perl --args slic3r.pl ", -// "sublimegdb_commandline": "D:\\Qt\\Tools\\mingw492_32\\bin\\gdb.exe --interpreter=mi -e C:\\Strawberry\\perl\\bin\\perl.exe -s C:\\Strawberry\\perl\\site\\lib\\auto\\Slic3r\\XS\\XS.xs.dll --args perl slic3r.pl -j 1 --gui D:\\src\\Slic3r-tests\\star3-big.stl", - "sublimegdb_commandline": "D:\\Qt\\Tools\\mingw492_32\\bin\\gdb.exe --interpreter=mi perl.exe --args perl slic3r.pl -j 1 --gui", // D:\\src\\Slic3r-tests\\star3-big.stl", -// "sublimegdb_commandline": "D:\\Qt\\Tools\\mingw492_32\\bin\\gdb.exe --interpreter=mi -x slic3r.gdb", -// "arguments": "slic3r -j 1 --gui ../Slic3r-tests/star3-big.stl", -// "arguments": "../slic3r.pl -j 1 --gui", -// "sublimegdb_exec_cmd": "-exec-continue", - - // Add "pending breakpoints" for symbols that are dynamically loaded from - // external shared libraries - "debug_ext" : true, - "run_after_init": false, - "close_views": false - } -} From bf7901ae46ee075cba4ab0be2f73fd53171d951f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20=C5=A0ach?= Date: Fri, 5 Jan 2024 13:03:03 +0100 Subject: [PATCH 45/91] Remove Slic3r.pm --- lib/Slic3r.pm | 61 --------------------------------------------------- 1 file changed, 61 deletions(-) delete mode 100644 lib/Slic3r.pm diff --git a/lib/Slic3r.pm b/lib/Slic3r.pm deleted file mode 100644 index 271704155f..0000000000 --- a/lib/Slic3r.pm +++ /dev/null @@ -1,61 +0,0 @@ -#/|/ Copyright (c) Prusa Research 2016 - 2022 VojtÄ›ch Bubník @bubnikv, Tomáš Mészáros @tamasmeszaros, VojtÄ›ch Král @vojtechkral, Oleksandra Iushchenko @YuSanka -#/|/ Copyright (c) 2018 Martin Loidl @LoidlM -#/|/ Copyright (c) Slic3r 2011 - 2016 Alessandro Ranellucci @alranel -#/|/ Copyright (c) 2012 Henrik Brix Andersen @henrikbrixandersen -#/|/ Copyright (c) 2012 Mark Hindess -#/|/ Copyright (c) 2012 Michael Moon -#/|/ Copyright (c) 2011 Clarence Risher -#/|/ -#/|/ PrusaSlicer is released under the terms of the AGPLv3 or higher -#/|/ -# This package loads all the non-GUI Slic3r perl packages. - -package Slic3r; - -# Copyright holder: Alessandro Ranellucci -# This application is licensed under the GNU Affero General Public License, version 3 - -use strict; -use warnings; -use Config; -require v5.10; - -our $VERSION = VERSION(); -our $BUILD = BUILD(); -our $FORK_NAME = FORK_NAME(); - -our $debug = 0; -sub debugf { - printf @_ if $debug; -} - -our $loglevel = 0; - -BEGIN { - $debug = 1 if (defined($ENV{'SLIC3R_DEBUGOUT'}) && $ENV{'SLIC3R_DEBUGOUT'} == 1); - print "Debugging output enabled\n" if $debug; -} - -use FindBin; - -use Moo 1.003001; - -use Slic3r::XS; # import all symbols (constants etc.) before they get parsed -use Slic3r::Config; -use Slic3r::GCode::Reader; -use Slic3r::Line; -use Slic3r::Model; -use Slic3r::Point; -use Slic3r::Polygon; -use Slic3r::Polyline; -our $build = eval "use Slic3r::Build; 1"; - -# Scaling between the float and integer coordinates. -# Floats are in mm. -use constant SCALING_FACTOR => 0.000001; - -# Set the logging level at the Slic3r XS module. -$Slic3r::loglevel = (defined($ENV{'SLIC3R_LOGLEVEL'}) && $ENV{'SLIC3R_LOGLEVEL'} =~ /^[1-9]/) ? $ENV{'SLIC3R_LOGLEVEL'} : 0; -set_logging_level($Slic3r::loglevel); - -1; From b287bbc5dcce81f047255752e1ae4116af87b0b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20=C5=A0ach?= Date: Fri, 5 Jan 2024 13:44:55 +0100 Subject: [PATCH 46/91] Remove obsolete cmake find script and also remove Fill.hpp --- cmake/modules/FindAlienWx.cmake | 109 -------------------------- src/libslic3r/CMakeLists.txt | 1 - src/libslic3r/Fill/Fill.hpp | 37 --------- src/libslic3r/Layer.cpp | 1 - src/libslic3r/Support/TreeSupport.cpp | 1 - tests/fff_print/test_fill.cpp | 1 - 6 files changed, 150 deletions(-) delete mode 100644 cmake/modules/FindAlienWx.cmake delete mode 100644 src/libslic3r/Fill/Fill.hpp diff --git a/cmake/modules/FindAlienWx.cmake b/cmake/modules/FindAlienWx.cmake deleted file mode 100644 index 65221172be..0000000000 --- a/cmake/modules/FindAlienWx.cmake +++ /dev/null @@ -1,109 +0,0 @@ -# Find the wxWidgets module based on the information provided by the Perl Alien::wxWidgets module. - -# Check for the Perl & PerlLib modules -include(LibFindMacros) -libfind_package(AlienWx Perl) -libfind_package(AlienWx PerlLibs) - -if (AlienWx_DEBUG) - message(STATUS " AlienWx_FIND_COMPONENTS=${AlienWx_FIND_COMPONENTS}") -endif() - -# Execute an Alien::Wx module to find the relevant information regarding -# the wxWidgets used by the Perl interpreter. -# Perl specific stuff -set(AlienWx_TEMP_INCLUDE ${CMAKE_CURRENT_BINARY_DIR}/AlienWx_TEMP_INCLUDE.txt) -execute_process( - COMMAND ${PERL_EXECUTABLE} -e " -# Import Perl modules. -use strict; -use warnings; -use Text::ParseWords; - -BEGIN { - # CMake sets the environment variables CC and CXX to the detected C compiler. - # There is an issue with the Perl ExtUtils::CBuilder, which does not handle whitespaces - # in the paths correctly on Windows, so we rather drop the CMake auto-detected paths. - delete \$ENV{CC}; - delete \$ENV{CXX}; -} - -use Alien::wxWidgets; -use ExtUtils::CppGuess; - -# Test for a Visual Studio compiler -my \$cpp_guess = ExtUtils::CppGuess->new; -my \$mswin = \$^O eq 'MSWin32'; -my \$msvc = \$cpp_guess->is_msvc; - -# List of wxWidgets components to be used. -my @components = split /;/, '${AlienWx_FIND_COMPONENTS}'; - -# Query the available data from Alien::wxWidgets. -my \$version = Alien::wxWidgets->version; -my \$config = Alien::wxWidgets->config; -my \$compiler = Alien::wxWidgets->compiler; -my \$linker = Alien::wxWidgets->linker; -my \$include_path = ' ' . Alien::wxWidgets->include_path; -my \$defines = ' ' . Alien::wxWidgets->defines; -my \$cflags = Alien::wxWidgets->c_flags; -my \$linkflags = Alien::wxWidgets->link_flags; -my \$libraries = ' ' . Alien::wxWidgets->libraries(@components); -my \$gui_toolkit = Alien::wxWidgets->config->{toolkit}; -#my @libraries = Alien::wxWidgets->link_libraries(@components); -#my @implib = Alien::wxWidgets->import_libraries(@components); -#my @shrlib = Alien::wxWidgets->shared_libraries(@components); -#my @keys = Alien::wxWidgets->library_keys; # 'gl', 'adv', ... -#my \$library_path = Alien::wxWidgets->shared_library_path; -#my \$key = Alien::wxWidgets->key; -#my \$prefix = Alien::wxWidgets->prefix; - -my \$filename = '${AlienWx_TEMP_INCLUDE}'; -open(my $fh, '>', \$filename) or die \"Could not open file '\$filename' \$!\"; - -# Convert a space separated lists to CMake semicolon separated lists, -# escape the backslashes, -# export the resulting list to a temp file. -sub cmake_set_var { - my (\$varname, \$content) = @_; - # Remove line separators. - \$content =~ s/\\r|\\n//g; - # Escape the path separators. - \$content =~ s/\\\\/\\\\\\\\\\\\\\\\/g; - my @words = shellwords(\$content); - print \$fh \"set(AlienWx_\$varname \\\"\" . join(';', @words) . \"\\\")\\n\"; -} -cmake_set_var('VERSION', \$version); -\$include_path =~ s/ -I/ /g; -cmake_set_var('INCLUDE_DIRS', \$include_path); -\$libraries =~ s/ -L/ -LIBPATH:/g if \$msvc; -cmake_set_var('LIBRARIES', \$libraries); -#cmake_set_var('LIBRARY_DIRS', ); -#\$defines =~ s/ -D/ /g; -cmake_set_var('DEFINITIONS', \$defines); -#cmake_set_var('DEFINITIONS_DEBUG', ); -cmake_set_var('CXX_FLAGS', \$cflags); -cmake_set_var('GUI_TOOLKIT', \$gui_toolkit); -close \$fh; -") -include(${AlienWx_TEMP_INCLUDE}) -file(REMOVE ${AlienWx_TEMP_INCLUDE}) -unset(AlienWx_TEMP_INCLUDE) - -if (AlienWx_DEBUG) - message(STATUS " AlienWx_VERSION = ${AlienWx_VERSION}") - message(STATUS " AlienWx_INCLUDE_DIRS = ${AlienWx_INCLUDE_DIRS}") - message(STATUS " AlienWx_LIBRARIES = ${AlienWx_LIBRARIES}") - message(STATUS " AlienWx_LIBRARY_DIRS = ${AlienWx_LIBRARY_DIRS}") - message(STATUS " AlienWx_DEFINITIONS = ${AlienWx_DEFINITIONS}") - message(STATUS " AlienWx_DEFINITIONS_DEBUG = ${AlienWx_DEFINITIONS_DEBUG}") - message(STATUS " AlienWx_CXX_FLAGS = ${AlienWx_CXX_FLAGS}") - message(STATUS " AlienWx_GUI_TOOLKIT = ${AlienWx_GUI_TOOLKIT}") -endif() - -include(FindPackageHandleStandardArgs) - -find_package_handle_standard_args(AlienWx - REQUIRED_VARS AlienWx_INCLUDE_DIRS AlienWx_LIBRARIES -# HANDLE_COMPONENTS - VERSION_VAR AlienWx_VERSION) diff --git a/src/libslic3r/CMakeLists.txt b/src/libslic3r/CMakeLists.txt index 2aa9b4839e..7921fccab1 100644 --- a/src/libslic3r/CMakeLists.txt +++ b/src/libslic3r/CMakeLists.txt @@ -88,7 +88,6 @@ set(SLIC3R_SOURCES ExtrusionSimulator.hpp FileParserError.hpp Fill/Fill.cpp - Fill/Fill.hpp Fill/Fill3DHoneycomb.cpp Fill/Fill3DHoneycomb.hpp Fill/FillAdaptive.cpp diff --git a/src/libslic3r/Fill/Fill.hpp b/src/libslic3r/Fill/Fill.hpp deleted file mode 100644 index d94e253108..0000000000 --- a/src/libslic3r/Fill/Fill.hpp +++ /dev/null @@ -1,37 +0,0 @@ -///|/ Copyright (c) Prusa Research 2016 - 2020 VojtÄ›ch Bubník @bubnikv, Lukáš MatÄ›na @lukasmatena -///|/ -///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher -///|/ -#ifndef slic3r_Fill_hpp_ -#define slic3r_Fill_hpp_ - -#include -#include -#include - -#include "../libslic3r.h" -#include "../PrintConfig.hpp" - -#include "FillBase.hpp" - -namespace Slic3r { - -class ExtrusionEntityCollection; -class LayerRegion; - -// An interface class to Perl, aggregating an instance of a Fill and a FillData. -class Filler -{ -public: - Filler() : fill(nullptr) {} - ~Filler() { - delete fill; - fill = nullptr; - } - Fill *fill; - FillParams params; -}; - -} // namespace Slic3r - -#endif // slic3r_Fill_hpp_ diff --git a/src/libslic3r/Layer.cpp b/src/libslic3r/Layer.cpp index 96bfeffaa0..e4b4d6539a 100644 --- a/src/libslic3r/Layer.cpp +++ b/src/libslic3r/Layer.cpp @@ -14,7 +14,6 @@ #include "Point.hpp" #include "Polygon.hpp" #include "Print.hpp" -#include "Fill/Fill.hpp" #include "ShortestPath.hpp" #include "SVG.hpp" #include "BoundingBox.hpp" diff --git a/src/libslic3r/Support/TreeSupport.cpp b/src/libslic3r/Support/TreeSupport.cpp index d82cb58142..2f630df7cf 100644 --- a/src/libslic3r/Support/TreeSupport.cpp +++ b/src/libslic3r/Support/TreeSupport.cpp @@ -19,7 +19,6 @@ #include "../BuildVolume.hpp" #include "../ClipperUtils.hpp" #include "../EdgeGrid.hpp" -#include "../Fill/Fill.hpp" #include "../Layer.hpp" #include "../Print.hpp" #include "../MultiPoint.hpp" diff --git a/tests/fff_print/test_fill.cpp b/tests/fff_print/test_fill.cpp index 6d8422c82d..94b6cab153 100644 --- a/tests/fff_print/test_fill.cpp +++ b/tests/fff_print/test_fill.cpp @@ -6,7 +6,6 @@ #include "libslic3r/libslic3r.h" #include "libslic3r/ClipperUtils.hpp" -#include "libslic3r/Fill/Fill.hpp" #include "libslic3r/Flow.hpp" #include "libslic3r/Layer.hpp" #include "libslic3r/Geometry.hpp" From 0b3974954d9383c1694d501e374af06f154b2c04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20=C5=A0ach?= Date: Fri, 5 Jan 2024 13:50:38 +0100 Subject: [PATCH 47/91] Remove layer count in GCode.hpp --- src/libslic3r/GCode.hpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/libslic3r/GCode.hpp b/src/libslic3r/GCode.hpp index b266b8a156..8890ec6125 100644 --- a/src/libslic3r/GCode.hpp +++ b/src/libslic3r/GCode.hpp @@ -151,8 +151,6 @@ public: std::string placeholder_parser_process(const std::string &name, const std::string &templ, unsigned int current_extruder_id, const DynamicConfig *config_override = nullptr); bool enable_cooling_markers() const { return m_enable_cooling_markers; } - // For Perl bindings, to be used exclusively by unit tests. - unsigned int layer_count() const { return m_layer_count; } void set_layer_count(unsigned int value) { m_layer_count = value; } void apply_print_config(const PrintConfig &print_config); From d12146e5f0f3bea963a5ae8b6eb7030d0326942a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20=C5=A0ach?= Date: Fri, 5 Jan 2024 13:57:21 +0100 Subject: [PATCH 48/91] Remove make_fills() that was just for perl --- src/libslic3r/Layer.hpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/libslic3r/Layer.hpp b/src/libslic3r/Layer.hpp index 5e7e7835da..e66a6c8a0c 100644 --- a/src/libslic3r/Layer.hpp +++ b/src/libslic3r/Layer.hpp @@ -377,8 +377,6 @@ public: return false; } void make_perimeters(); - // Phony version of make_fills() without parameters for Perl integration only. - void make_fills() { this->make_fills(nullptr, nullptr, nullptr); } void make_fills(FillAdaptive::Octree *adaptive_fill_octree, FillAdaptive::Octree *support_fill_octree, FillLightning::Generator *lightning_generator); From 18c23383afcae1636d505ea0c7596ff442580481 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20=C5=A0ach?= Date: Fri, 5 Jan 2024 14:13:51 +0100 Subject: [PATCH 49/91] Remove various perl specific code --- src/libslic3r/Print.hpp | 4 ---- src/libslic3r/Utils.hpp | 4 ---- src/libslic3r/utils.cpp | 9 --------- src/slic3r/GUI/GUI.hpp | 1 - src/slic3r/GUI/ProgressStatusBar.cpp | 10 ---------- src/slic3r/GUI/ProgressStatusBar.hpp | 4 ---- 6 files changed, 32 deletions(-) diff --git a/src/libslic3r/Print.hpp b/src/libslic3r/Print.hpp index a43ea4dfb6..1e710272e1 100644 --- a/src/libslic3r/Print.hpp +++ b/src/libslic3r/Print.hpp @@ -639,10 +639,6 @@ public: // If zero, then the print is empty and the print shall not be executed. unsigned int num_object_instances() const; - // For Perl bindings. - PrintObjectPtrs& objects_mutable() { return m_objects; } - PrintRegionPtrs& print_regions_mutable() { return m_print_regions; } - const ExtrusionEntityCollection& skirt() const { return m_skirt; } const ExtrusionEntityCollection& brim() const { return m_brim; } // Convex hull of the 1st layer extrusions, for bed leveling and placing the initial purge line. diff --git a/src/libslic3r/Utils.hpp b/src/libslic3r/Utils.hpp index e02126d9ba..4b4be4c3ee 100644 --- a/src/libslic3r/Utils.hpp +++ b/src/libslic3r/Utils.hpp @@ -73,10 +73,6 @@ const std::string& data_dir(); // so the user knows where to search for the debugging output. std::string debug_out_path(const char *name, ...); -// A special type for strings encoded in the local Windows 8-bit code page. -// This type is only needed for Perl bindings to relay to Perl that the string is raw, not UTF-8 encoded. -typedef std::string local_encoded_string; - // Returns next utf8 sequence length. =number of bytes in string, that creates together one utf-8 character. // Starting at pos. ASCII characters returns 1. Works also if pos is in the middle of the sequence. extern size_t get_utf8_sequence_length(const std::string& text, size_t pos = 0); diff --git a/src/libslic3r/utils.cpp b/src/libslic3r/utils.cpp index f4d7c51da1..7062c2b89d 100644 --- a/src/libslic3r/utils.cpp +++ b/src/libslic3r/utils.cpp @@ -123,15 +123,6 @@ unsigned get_logging_level() } } -// Force set_logging_level(<=error) after loading of the DLL. -// This is currently only needed if libslic3r is loaded as a shared library into Perl interpreter -// to perform unit and integration tests. -static struct RunOnInit { - RunOnInit() { - set_logging_level(1); - } -} g_RunOnInit; - void disable_multi_threading() { // Disable parallelization to simplify debugging. diff --git a/src/slic3r/GUI/GUI.hpp b/src/slic3r/GUI/GUI.hpp index 0239c62bcd..50492928a7 100644 --- a/src/slic3r/GUI/GUI.hpp +++ b/src/slic3r/GUI/GUI.hpp @@ -50,7 +50,6 @@ void change_opt_value(DynamicPrintConfig& config, const t_config_option_key& opt void show_error(wxWindow* parent, const wxString& message, bool monospaced_font = false); void show_error(wxWindow* parent, const char* message, bool monospaced_font = false); inline void show_error(wxWindow* parent, const std::string& message, bool monospaced_font = false) { show_error(parent, message.c_str(), monospaced_font); } -void show_error_id(int id, const std::string& message); // For Perl 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()); } diff --git a/src/slic3r/GUI/ProgressStatusBar.cpp b/src/slic3r/GUI/ProgressStatusBar.cpp index 0857cb9275..17d38e33df 100644 --- a/src/slic3r/GUI/ProgressStatusBar.cpp +++ b/src/slic3r/GUI/ProgressStatusBar.cpp @@ -191,15 +191,5 @@ void ProgressStatusBar::set_font(const wxFont &font) self->SetFont(font); } -void ProgressStatusBar::show_cancel_button() -{ - if(m_cancelbutton) m_cancelbutton->Show(); -} - -void ProgressStatusBar::hide_cancel_button() -{ - if(m_cancelbutton) m_cancelbutton->Hide(); -} - } diff --git a/src/slic3r/GUI/ProgressStatusBar.hpp b/src/slic3r/GUI/ProgressStatusBar.hpp index 40b9aeb08b..8b159ec8be 100644 --- a/src/slic3r/GUI/ProgressStatusBar.hpp +++ b/src/slic3r/GUI/ProgressStatusBar.hpp @@ -66,10 +66,6 @@ public: wxString get_status_text() const; void set_font(const wxFont &font); - // Temporary methods to satisfy Perl side - void show_cancel_button(); - void hide_cancel_button(); - void update_dark_ui(); private: From f9bc7f37bddc3043b5cb2e51edd8fa4884c015cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20=C5=A0ach?= Date: Fri, 5 Jan 2024 16:43:51 +0100 Subject: [PATCH 50/91] Remove local-lib from .gitignore --- .gitignore | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitignore b/.gitignore index d17030cb09..a2b1bf0c78 100644 --- a/.gitignore +++ b/.gitignore @@ -12,7 +12,6 @@ xs/MANIFEST.bak xs/assertlib* .init_bundle.ini .vs/* -local-lib /src/TAGS /.vscode/ build-linux/* From d147a41dd6c4da5efbf7e2a1b2392185f1d86928 Mon Sep 17 00:00:00 2001 From: rtyr <36745189+rtyr@users.noreply.github.com> Date: Mon, 8 Jan 2024 11:12:14 +0100 Subject: [PATCH 51/91] Added M5C printer. --- resources/profiles/Anker.idx | 2 + resources/profiles/Anker.ini | 432 ++++++++++++++++++++++++++++++----- 2 files changed, 373 insertions(+), 61 deletions(-) diff --git a/resources/profiles/Anker.idx b/resources/profiles/Anker.idx index 0cf915db16..d867f38f2d 100644 --- a/resources/profiles/Anker.idx +++ b/resources/profiles/Anker.idx @@ -1,4 +1,6 @@ min_slic3r_version = 2.6.0-alpha4 +1.1.3 Fixed top solid infill extrusion width for M5C. +1.1.2 Added AnkerMake M5C. 1.1.1 Initial official version 1.0.1 Initial Version min_slic3r_version = 2.6.0-alpha1 diff --git a/resources/profiles/Anker.ini b/resources/profiles/Anker.ini index 70cb4dcf14..d5c1c46dcd 100644 --- a/resources/profiles/Anker.ini +++ b/resources/profiles/Anker.ini @@ -5,7 +5,7 @@ name = AnkerMake # 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 +config_version = 1.1.3 # Where to get the updates from? config_update_url = https://files.prusa3d.com/wp-content/uploads/repository/PrusaSlicer-settings-master/live/Anker/ # changelog_url = https://files.prusa3d.com/?latest=slicer-profiles&lng=%1% @@ -24,6 +24,18 @@ bed_texture = M5-texture_v2.svg thumbnail = M5_thumbnail_v2.png default_materials = Generic PLA+ @ANKER; Generic PLA @ANKER; Generic PET @ANKER; Generic ABS @ANKER; +# All presets starting with asterisk, for example *common*, are intermediate and they will +# not make it into the user interface. +[printer_model:M5C] +name = AnkerMake M5C +variants = 0.4 +technology = FFF +family = AnkerMake +bed_model = M5C-bed.stl +bed_texture = M5C-texture_v2.svg +thumbnail = M5C_thumbnail_v2.png +default_materials = Generic PLA+ @ANKER; Generic PLA @ANKER; Generic PET @ANKER; Generic ABS @ANKER; + # All presets starting with asterisk, for example *common*, are intermediate and they will # not make it into the user interface. @@ -166,16 +178,265 @@ top_solid_layers = 4 [print:0.10 mm HIGHDETAIL (0.4 mm nozzle) @ANKER] inherits = *0.10mm* -compatible_printers_condition = printer_model=~/(M5).*/ and nozzle_diameter[0]==0.4 +compatible_printers_condition = printer_notes=~/.*(MACHINE_M5_).*/ and nozzle_diameter[0]==0.4 [print:0.20 mm NORMAL (0.4 mm nozzle) @ANKER] inherits = *0.20mm* -compatible_printers_condition = printer_model=~/(M5).*/ and nozzle_diameter[0]==0.4 +compatible_printers_condition = printer_notes=~/.*(MACHINE_M5_).*/ and nozzle_diameter[0]==0.4 [print:0.30 mm SUPERDRAFT (0.4 mm nozzle) @ANKER] inherits = *0.30mm* -compatible_printers_condition = printer_model=~/(M5).*/ and nozzle_diameter[0]==0.4 +compatible_printers_condition = printer_notes=~/.*(MACHINE_M5_).*/ and nozzle_diameter[0]==0.4 + +[print:*common-M5C*] +avoid_crossing_curled_overhangs = 0 +avoid_crossing_perimeters = 0 +avoid_crossing_perimeters_max_detour = 0 +bottom_fill_pattern = rectilinear +bottom_solid_min_thickness = 0.8 +bridge_angle = 0 +bridge_flow_ratio = 1 +bridge_speed = 30 +brim_separation = 0.1 +brim_type = no_brim +brim_width = 8 +complete_objects = 0 +dont_support_bridges = 1 +draft_shield = disabled +elefant_foot_compensation = 0 +enable_dynamic_overhang_speeds = 1 +external_perimeter_extrusion_width = 0.44 +external_perimeter_speed = 75 +external_perimeters_first = 1 +extra_perimeters = 1 +extra_perimeters_on_overhangs = 0 +extruder_clearance_height = 20 +extruder_clearance_radius = 20 +extrusion_width = 0.4 +fill_angle = 45 +fill_density = 10% +fill_pattern = grid +first_layer_acceleration = 2500 +first_layer_acceleration_over_raft = 0 +first_layer_extrusion_width = 0.5 +first_layer_speed = 50 +first_layer_speed_over_raft = 30 +fuzzy_skin = none +fuzzy_skin_point_dist = 0.8 +fuzzy_skin_thickness = 0.3 +gap_fill_enabled = 1 +gap_fill_speed = 75 +gcode_comments = 0 +gcode_label_objects = 0 +gcode_resolution = 0.0125 +gcode_substitutions = "(G28 ;Home.*$)";"${1}\\nM4899 T3\\n";;";S-Curve" +infill_acceleration = 4000 +infill_anchor = 30 +infill_anchor_max = 60 +infill_every_layers = 1 +infill_extruder = 1 +infill_extrusion_width = 0.4 +infill_first = 0 +infill_overlap = 25% +infill_speed = 250 +interface_shells = 0 +ironing = 0 +ironing_flowrate = 15% +ironing_spacing = 0.1 +ironing_speed = 15 +ironing_type = top +max_print_speed = 500 +max_volumetric_extrusion_rate_slope_negative = 0 +max_volumetric_extrusion_rate_slope_positive = 0 +max_volumetric_speed = 0 +min_bead_width = 85% +min_feature_size = 25% +min_skirt_length = 0 +mmu_segmented_region_max_width = 0 +only_retract_when_crossing_perimeters = 0 +ooze_prevention = 0 +output_filename_format = {input_filename_base}_{layer_height}mm_{initial_filament_type}_{printer_model}.gcode +overhang_speed_0 = 25 +overhang_speed_1 = 55 +overhang_speed_2 = 55 +overhang_speed_3 = 100% +overhangs = 1 +perimeter_extruder = 1 +perimeter_extrusion_width = 0.4 +perimeter_generator = classic +perimeter_speed = 200 +post_process = +print_settings_id = +raft_contact_distance = 0.1 +raft_expansion = 1.5 +raft_first_layer_density = 90% +raft_first_layer_expansion = 0 +raft_layers = 0 +resolution = 0 +seam_position = aligned +single_extruder_multi_material_priming = 1 +skirt_distance = 6 +skirt_height = 1 +skirts = 1 +slice_closing_radius = 0.049 +slicing_mode = regular +small_perimeter_speed = 75 +solid_infill_below_area = 0 +solid_infill_every_layers = 0 +solid_infill_extruder = 1 +solid_infill_extrusion_width = 0.4 +solid_infill_speed = 100 +spiral_vase = 0 +staggered_inner_seams = 0 +standby_temperature_delta = -5 +support_material = 0 +support_material_angle = 90 +support_material_auto = 1 +support_material_bottom_contact_distance = 0 +support_material_bottom_interface_layers = -1 +support_material_buildplate_only = 0 +support_material_closing_radius = 2 +support_material_contact_distance = 0.2 +support_material_enforce_layers = 0 +support_material_extruder = 1 +support_material_extrusion_width = 0.3 +support_material_interface_contact_loops = 0 +support_material_interface_extruder = 1 +support_material_interface_layers = 0 +support_material_interface_pattern = rectilinear +support_material_interface_spacing = 0.2 +support_material_interface_speed = 100% +support_material_pattern = rectilinear +support_material_spacing = 1.333 +support_material_speed = 150 +support_material_style = grid +support_material_synchronize_layers = 0 +support_material_threshold = 30 +support_material_with_sheath = 0 +support_material_xy_spacing = 0.8 +support_tree_angle = 40 +support_tree_angle_slow = 25 +support_tree_branch_diameter = 2 +support_tree_branch_diameter_angle = 5 +support_tree_branch_distance = 1 +support_tree_tip_diameter = 0.8 +support_tree_top_rate = 15% +thick_bridges = 0 +thin_walls = 1 +threads = 10 +top_fill_pattern = rectilinear +top_infill_extrusion_width = 0.4 +top_solid_infill_speed = 50 +top_solid_min_thickness = 0.8 +travel_speed = 500 +travel_speed_z = 10 +wall_distribution_count = 1 +wall_transition_angle = 10 +wall_transition_filter_deviation = 25% +wall_transition_length = 100% +wipe_tower = 0 +wipe_tower_bridging = 10 +wipe_tower_brim_width = 2 +wipe_tower_cone_angle = 0 +wipe_tower_extra_spacing = 100% +wipe_tower_no_sparse_layers = 0 +wipe_tower_rotation_angle = 0 +wipe_tower_width = 60 +wipe_tower_x = 180 +wipe_tower_y = 140 +xy_size_compensation = 0 + +[print:Precision - M5C (0.4 mm nozzle) @ANKER] +inherits = *common-M5C* +compatible_printers_condition = printer_notes=~/.*(MACHINE_M5C_).*/ and printer_notes=~/.*(P_PRECISION).*/ and nozzle_diameter[0]==0.4 +first_layer_height = 0.14 +layer_height = 0.16 +top_solid_layers = 5 +bottom_solid_layers = 3 +perimeters = 2 +bridge_acceleration = 500 +default_acceleration = 4000 +external_perimeter_acceleration = 3000 +perimeter_acceleration = 3000 +top_solid_infill_acceleration = 2500 +travel_acceleration = 4000 +solid_infill_acceleration = 2500 + +[print:Normal - M5C (0.4 mm nozzle) @ANKER] +inherits = *common-M5C* +notes = PRINT_COMPATIBLE\n P_NORMAL\n F_PLA__Basic\n +compatible_printers_condition = printer_notes=~/.*(MACHINE_M5C_).*/ and printer_notes=~/.*(P_NORMAL).*/ and nozzle_diameter[0]==0.4 +first_layer_height = 0.14 +layer_height = 0.2 +top_solid_layers = 4 +bottom_solid_layers = 4 +perimeters = 3 +bridge_acceleration = 500 +default_acceleration = 2500 +external_perimeter_acceleration = 2500 +external_perimeter_speed = 150 +first_layer_acceleration = 2500 +first_layer_acceleration_over_raft = 0 +first_layer_speed = 50 +gap_fill_speed = 75 +infill_acceleration = 2500 +infill_speed = 250 +max_print_speed = 250 +overhang_speed_0 = 15 +overhang_speed_1 = 20 +overhang_speed_2 = 30 +overhang_speed_3 = 30 +perimeter_acceleration = 2500 +perimeter_speed = 250 +small_perimeter_speed = 75 +solid_infill_acceleration = 2500 +solid_infill_speed = 150 +top_solid_infill_acceleration = 2500 +top_solid_infill_speed = 150 +travel_acceleration = 2500 +travel_speed = 250 +travel_speed_z = 10 + +[print:Fast - M5C (0.4 mm nozzle) @ANKER] +inherits = *common-M5C* +notes = PRINT_COMPATIBLE\n P_FAST\n F_PLA__Basic\n +compatible_printers_condition = printer_notes=~/.*(MACHINE_M5C_).*/ and printer_notes=~/.*(P_FAST).*/ and nozzle_diameter[0]==0.4 +layer_height = 0.25 +first_layer_height = 0.14 +perimeters = 2 +top_solid_layers = 4 +bottom_solid_layers = 3 +external_perimeter_acceleration = 3000 +perimeter_acceleration = 5000 +top_solid_infill_acceleration = 4000 +solid_infill_acceleration = 4000 +infill_acceleration = 5000 +bridge_acceleration = 500 +first_layer_acceleration = 2500 +first_layer_acceleration_over_raft = 0 +travel_acceleration = 5000 +default_acceleration = 5000 +# Speed +perimeter_speed = 250 +small_perimeter_speed = 75 +external_perimeter_speed = 150 +infill_speed = 270 +solid_infill_speed = 100 +top_solid_infill_speed = 100 +support_material_speed = 150 +support_material_interface_speed = 100% +bridge_speed = 20 +gap_fill_speed = 75 +overhang_speed_0 = 15 +overhang_speed_1 = 20 +overhang_speed_2 = 30 +overhang_speed_3 = 30 +travel_speed = 500 +travel_speed_z = 10 +first_layer_speed = 50 +first_layer_speed_over_raft = 30 +max_print_speed = 500 # When submitting new filaments please print the following temperature tower at 0.1mm layer height: # https://www.thingiverse.com/thing:2615842 @@ -186,7 +447,7 @@ compatible_printers_condition = printer_model=~/(M5).*/ and nozzle_diameter[0]== # So having some leeway to get good bed adhesion is not a luxury for many users [filament:*common*] -cooling = 0 +cooling = 1 compatible_printers = extrusion_multiplier = 1 filament_cost = 0 @@ -218,13 +479,13 @@ temperature = 200 [filament:*PLA+*] inherits = *common* -bed_temperature = 60 +bed_temperature = 65 fan_below_layer_time = 100 filament_colour = #DDDDDD filament_type = PLA+ filament_density = 1.24 filament_cost = 20 -first_layer_bed_temperature = 60 +first_layer_bed_temperature = 65 first_layer_temperature = 230 fan_always_on = 1 max_fan_speed = 100 @@ -243,12 +504,12 @@ filament_type = PETG filament_density = 1.27 filament_cost = 30 first_layer_bed_temperature = 80 -first_layer_temperature = 260 +first_layer_temperature = 255 fan_always_on = 1 max_fan_speed = 50 min_fan_speed = 50 bridge_fan_speed = 100 -temperature = 260 +temperature = 255 [filament:*ABS*] inherits = *common* @@ -260,13 +521,13 @@ filament_type = ABS filament_density = 1.04 filament_cost = 20 first_layer_bed_temperature = 90 -first_layer_temperature = 260 +first_layer_temperature = 255 fan_always_on = 0 max_fan_speed = 0 min_fan_speed = 0 bridge_fan_speed = 30 top_fan_speed = 0 -temperature = 260 +temperature = 255 [filament:Generic PLA @ANKER] inherits = *PLA* @@ -289,61 +550,91 @@ filament_vendor = Generic # Common printer preset [printer:*common*] -printer_technology = FFF -before_layer_gcode = ;BEFORE_LAYER_CHANGE\n;{layer_z} -between_objects_gcode = -pause_print_gcode = -deretract_speed = 60 -extruder_colour = #FCE94F -extruder_offset = 0x0 -gcode_flavor = marlin -silent_mode = 1 -remaining_times = 1 -machine_max_acceleration_e = 2500 -machine_max_acceleration_extruding = 2500 -machine_max_acceleration_retracting = 2500 -machine_max_acceleration_travel = 1500,1250 -machine_max_acceleration_x = 2500 -machine_max_acceleration_y = 2500 -machine_max_acceleration_z = 2500 -machine_max_feedrate_e = 100 -machine_max_feedrate_x = 300 -machine_max_feedrate_y = 300 -machine_max_feedrate_z = 20 -machine_max_jerk_e = 3 -machine_max_jerk_x = 15 -machine_max_jerk_y = 15 -machine_max_jerk_z = 0.3 -machine_min_extruding_rate = 0 -machine_min_travel_rate = 0 -layer_gcode = ;AFTER_LAYER_CHANGE\n;{layer_z} +printer_vendor = AnkerMake +# General +## Size and coordinates max_print_height = 250 -printer_notes = -printer_settings_id = -retract_before_travel = 3 -retract_before_wipe = 0 -retract_layer_change = 1 -retract_length_toolchange = 4 +z_offset = 0 +## Capabilities +#extruders_count = 1 +single_extruder_multi_material = 0 +## Firmware +gcode_flavor = marlin2 +thumbnails = 256x256 +thumbnails_format = PNG +silent_mode = 0 +remaining_times = 1 +## Advanced +use_relative_e_distances = 1 +use_firmware_retraction = 0 +use_volumetric_e = 0 +variable_layer_height = 1 +# Custom G-code +start_gcode = M104 S{first_layer_temperature[0]} ; set final nozzle temp\nM190 S{first_layer_bed_temperature[0]} ; set and wait for bed temp to stabilize\nM109 S{first_layer_temperature[0]} ; wait for nozzle temp to stabilize\nG28 ;Home\n;LAYER_COUNT:{total_layer_count}\n +autoemit_temperature_commands = 1 +end_gcode = M104 S0\nM140 S0\n;Retract the filament\nG92 E1\nG1 E-1 F300\nG28 X0 Y0\nM84 +before_layer_gcode = ;BEFORE_LAYER_CHANGE\n;{layer_z}\n;LAYER:{layer_num+1} +layer_gcode = ;AFTER_LAYER_CHANGE\nG92 E0 +toolchange_gcode = +between_objects_gcode = +color_change_gcode = M600 +pause_print_gcode = M601 +template_custom_gcode = +# Machine limits +## General +### machine_limits_usage = emit_to_gcode time_estimate_only ignore +machine_limits_usage = time_estimate_only +## Maximum feedrates +machine_max_feedrate_e = 100 +machine_max_feedrate_x = 500 +machine_max_feedrate_y = 500 +machine_max_feedrate_z = 50 +## Maximum accelerations +machine_max_acceleration_e = 10000 +machine_max_acceleration_extruding = 10000 +machine_max_acceleration_retracting = 10000 +machine_max_acceleration_travel = 10000 +machine_max_acceleration_x = 10000 +machine_max_acceleration_y = 10000 +machine_max_acceleration_z = 10000 +## Jerk limits +machine_max_jerk_x = 15, 15 +machine_max_jerk_y = 15, 15 +machine_max_jerk_z = 0.3, 0.3 +machine_max_jerk_e = 3, 3 +machine_min_extruding_rate = 0, 0 +machine_min_travel_rate = 0, 0 +# Extruder 1 2 3 4 5 6 +## Size +nozzle_diameter = 0.4 +## Preview +extruder_colour = #9BE198 +## Layer height limits +min_layer_height = 0.08 +max_layer_height = 0.32 +## Position (for multi-extruder printers) +extruder_offset = 0x0 +## Retraction +retract_length = 3 retract_lift = 0 retract_lift_above = 0 retract_lift_below = 0 -retract_restart_extra = 0 -retract_restart_extra_toolchange = 0 retract_speed = 60 -single_extruder_multi_material = 0 -thumbnails = 64x64,256x256 -thumbnails_format = JPG -toolchange_gcode = -use_firmware_retraction = 0 -use_relative_e_distances = 0 -use_volumetric_e = 0 -variable_layer_height = 1 +deretract_speed = 0 +retract_restart_extra = 0 +retract_before_travel = 0.8 +retract_layer_change = 1 wipe = 0 -z_offset = 0 +retract_before_wipe = 0% +## Retraction when tool is disabled (advanced settings for multi-extruder setups) +retract_length_toolchange = 4 +retract_restart_extra_toolchange = 0 +# Notes +printer_notes = Base printer notes is EMPTY! +default_print_profile = default_filament_profile = Generic PLA+ @ANKER -start_gcode = M104 S{first_layer_temperature[0]} ; set final nozzle temp\nM190 S{first_layer_bed_temperature[0]} ; set and wait for bed temp to stabilize\nM109 S{first_layer_temperature[0]} ; wait for nozzle temp to stabilize\nG28 ;Home\nM420 S1; restore saved Auto Bed Leveling data\nG1 E10 F3600; push out retracted filament(fix for over retraction after prime) -end_gcode = M104 S0\nM140 S0\n;Retract the filament\nG92 E1\nG1 E-1 F300\nG28 X0 Y0\nM84 - +printer_technology = FFF +printer_settings_id = [printer:*M5*] inherits = *common* bed_shape = 0x0,235-0,235x235,0x235 @@ -354,8 +645,19 @@ retract_speed = 60 deretract_speed = 60 retract_before_travel = 3 retract_before_wipe = 0% -printer_notes = Don not remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_ANKERMAKE\nPRINTER_MODEL_M5 - +printer_notes = MACHINE_M5_\n PRINTER_VENDOR_ANKERMAKE\n PRINTER_MODEL_M5\n +[printer:*M5C*] +inherits = *common* +bed_shape = 0x0,220x0,220x220,0x220 +max_print_height = 250 +printer_model = M5C +retract_length = 0.8 +retract_speed = 60 +deretract_speed = 60 +retract_before_travel = 3 +retract_before_wipe = 0% +wipe = 1 +printer_notes = MACHINE_M5C_\n PRINTER_VENDOR_ANKERMAKE\n P_PRECISION P_NORMAL P_FAST\n [printer:AnkerMake M5 (0.4 mm nozzle)] inherits = *M5* nozzle_diameter = 0.4 @@ -364,3 +666,11 @@ min_layer_height = 0.08 max_layer_height = 0.32 retract_lift_above = 0 default_print_profile = 0.2 mm OPTIMAL (0.4 mm nozzle) @ANKER +[printer:AnkerMake M5C (0.4 mm nozzle)] +inherits = *M5C* +nozzle_diameter = 0.4 +printer_variant = 0.4 +min_layer_height = 0.08 +max_layer_height = 0.32 +retract_lift_above = 0 +default_print_profile = 0.2 mm OPTIMAL (0.4 mm nozzle) @ANKER From 8fe827b0523979dcb87492ad41557c9c788b0e77 Mon Sep 17 00:00:00 2001 From: rtyr <36745189+rtyr@users.noreply.github.com> Date: Mon, 8 Jan 2024 11:13:24 +0100 Subject: [PATCH 52/91] Added M5C resources. --- resources/profiles/Anker/M5C-bed.stl | Bin 0 -> 36084 bytes resources/profiles/Anker/M5C-texture.svg | 1 + resources/profiles/Anker/M5C-texture_v2.svg | 1 + resources/profiles/Anker/M5C_thumbnail.png | Bin 0 -> 19202 bytes resources/profiles/Anker/M5C_thumbnail_v2.png | Bin 0 -> 19202 bytes 5 files changed, 2 insertions(+) create mode 100644 resources/profiles/Anker/M5C-bed.stl create mode 100644 resources/profiles/Anker/M5C-texture.svg create mode 100644 resources/profiles/Anker/M5C-texture_v2.svg create mode 100644 resources/profiles/Anker/M5C_thumbnail.png create mode 100644 resources/profiles/Anker/M5C_thumbnail_v2.png diff --git a/resources/profiles/Anker/M5C-bed.stl b/resources/profiles/Anker/M5C-bed.stl new file mode 100644 index 0000000000000000000000000000000000000000..ea3b99845e0488133bda84ac1f5b2da0de68e851 GIT binary patch literal 36084 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 diff --git a/resources/profiles/Anker/M5C-texture_v2.svg b/resources/profiles/Anker/M5C-texture_v2.svg new file mode 100644 index 0000000000..4fcf959f66 --- /dev/null +++ b/resources/profiles/Anker/M5C-texture_v2.svg @@ -0,0 +1 @@ + diff --git a/resources/profiles/Anker/M5C_thumbnail.png b/resources/profiles/Anker/M5C_thumbnail.png new file mode 100644 index 0000000000000000000000000000000000000000..3491ec6bfa7aa74cda05e9f62bea0b2a9043742d GIT binary patch literal 19202 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 bJp=EZV5szO7gEn7t5}Q-%=N1gZZZD>yC^CI literal 0 HcmV?d00001 diff --git a/resources/profiles/Anker/M5C_thumbnail_v2.png b/resources/profiles/Anker/M5C_thumbnail_v2.png new file mode 100644 index 0000000000000000000000000000000000000000..3491ec6bfa7aa74cda05e9f62bea0b2a9043742d GIT binary patch literal 19202 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 bJp=EZV5szO7gEn7t5}Q-%=N1gZZZD>yC^CI literal 0 HcmV?d00001 From 6bd9c50c7ac050162006c4e71936fe5685f1c91d Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Wed, 10 Jan 2024 12:30:38 +0100 Subject: [PATCH 53/91] Fixed typo in a tooltip --- src/slic3r/GUI/UnsavedChangesDialog.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slic3r/GUI/UnsavedChangesDialog.cpp b/src/slic3r/GUI/UnsavedChangesDialog.cpp index 723937aafa..43239561c3 100644 --- a/src/slic3r/GUI/UnsavedChangesDialog.cpp +++ b/src/slic3r/GUI/UnsavedChangesDialog.cpp @@ -1624,7 +1624,7 @@ void DiffPresetDialog::create_edit_sizer() { // Add check box for the edit mode m_use_for_transfer = new wxCheckBox(this, wxID_ANY, _L("Transfer values from left to right")); - m_use_for_transfer->SetToolTip(_L("If enabled, this dialog can be used for transver selected values from left to right preset.")); + m_use_for_transfer->SetToolTip(_L("If checked, this dialog can be used for transferring selected values from the preset on the left to the preset on the right.")); m_use_for_transfer->Bind(wxEVT_CHECKBOX, [this](wxCommandEvent&) { bool use = m_use_for_transfer->GetValue(); m_tree->GetColumn(DiffModel::colToggle)->SetHidden(!use); From b9039c84cba331e587f1ea5475d38cdba13f6bb7 Mon Sep 17 00:00:00 2001 From: Filip Sykala - NTB T15p Date: Thu, 11 Jan 2024 10:32:45 +0100 Subject: [PATCH 54/91] Fix application of rotation and distance from surface after style change --- src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp index 6cccfa3c09..8149496c1e 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp @@ -2148,6 +2148,8 @@ void fix_transformation(const StyleManager::Style &from, const StyleManager::Sty float f_angle = f_angle_opt.value_or(.0f); float t_angle = t_angle_opt.value_or(.0f); do_local_z_rotate(canvas.get_selection(), t_angle - f_angle); + std::string no_snapshot; + canvas.do_rotate(no_snapshot); } // fix distance (Z move) when exists difference in styles @@ -2157,6 +2159,8 @@ void fix_transformation(const StyleManager::Style &from, const StyleManager::Sty float f_move = f_move_opt.value_or(.0f); float t_move = t_move_opt.value_or(.0f); do_local_z_move(canvas.get_selection(), t_move - f_move); + std::string no_snapshot; + canvas.do_move(no_snapshot); } } } // namesapce From cecbd8aef12bcca1312002d0cc724a164fd9c851 Mon Sep 17 00:00:00 2001 From: Filip Sykala - NTB T15p Date: Thu, 11 Jan 2024 12:31:52 +0100 Subject: [PATCH 55/91] Fix compare of styles to accept not exactly same floats value for style --- src/slic3r/Utils/EmbossStyleManager.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/slic3r/Utils/EmbossStyleManager.hpp b/src/slic3r/Utils/EmbossStyleManager.hpp index d36f062f48..bce87d04c8 100644 --- a/src/slic3r/Utils/EmbossStyleManager.hpp +++ b/src/slic3r/Utils/EmbossStyleManager.hpp @@ -213,8 +213,8 @@ public: { return EmbossStyle::operator==(other) && projection == other.projection && - distance == other.distance && - angle == other.angle; + is_approx(distance, other.distance) && + is_approx(angle, other.angle); } // cache for view font name with maximal width in imgui From 0ff255eadc2351a1ebf01c59b0152d8b94210d72 Mon Sep 17 00:00:00 2001 From: Filip Sykala - NTB T15p Date: Mon, 15 Jan 2024 15:05:40 +0100 Subject: [PATCH 56/91] Initialize SvgFile object in optional different way. --- src/slic3r/GUI/Gizmos/GLGizmoSVG.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSVG.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSVG.cpp index 2d08f9d7eb..106684fdfc 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSVG.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSVG.cpp @@ -1490,8 +1490,9 @@ void GLGizmoSVG::draw_filename(){ std::string new_path = choose_svg_file(); if (!new_path.empty()) { file_changed = true; - m_volume_shape.svg_file = {}; // clear data - m_volume_shape.svg_file->path = new_path; + EmbossShape::SvgFile svg_file_new; + svg_file_new.path = new_path; + m_volume_shape.svg_file = svg_file_new; // clear data } } else if (ImGui::IsItemHovered()) { ImGui::SetTooltip("%s", _u8L("Change to another .svg file").c_str()); From eff53d4dba01e62e35b09152fc3525c10e5d72f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20=C5=A0ach?= Date: Wed, 10 Jan 2024 13:44:51 +0100 Subject: [PATCH 57/91] Add option cmd option to limit the number of threads --- src/PrusaSlicer.cpp | 8 +++++++- src/libslic3r/PrintConfig.cpp | 5 +++++ src/libslic3r/Thread.cpp | 9 ++++----- src/libslic3r/Utils.hpp | 3 ++- src/libslic3r/utils.cpp | 6 +++--- 5 files changed, 21 insertions(+), 10 deletions(-) diff --git a/src/PrusaSlicer.cpp b/src/PrusaSlicer.cpp index a07256fd7b..04b481bc42 100644 --- a/src/PrusaSlicer.cpp +++ b/src/PrusaSlicer.cpp @@ -817,7 +817,13 @@ bool CLI::setup(int argc, char **argv) if (opt_loglevel != 0) set_logging_level(opt_loglevel->value); } - + + { + const ConfigOptionInt *opt_threads = m_config.opt("threads"); + if (opt_threads != nullptr) + thread_count = opt_threads->value; + } + //FIXME Validating at this stage most likely does not make sense, as the config is not fully initialized yet. std::string validity = m_config.validate(); diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 88ba446eba..02e824efe6 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -5066,6 +5066,11 @@ CLIMiscConfigDef::CLIMiscConfigDef() def->label = L("Data directory"); def->tooltip = L("Load and store settings at the given directory. This is useful for maintaining different profiles or including configurations from a network storage."); + def = this->add("threads", coInt); + def->label = L("Maximum number of threads"); + def->tooltip = L("Sets the maximum number of threads the slicing process will use. If not defined, slic3r will decide."); + def->min = 1; + def = this->add("loglevel", coInt); def->label = L("Logging level"); def->tooltip = L("Sets logging sensitivity. 0:fatal, 1:error, 2:warning, 3:info, 4:debug, 5:trace\n" diff --git a/src/libslic3r/Thread.cpp b/src/libslic3r/Thread.cpp index 338182e026..789e51da6e 100644 --- a/src/libslic3r/Thread.cpp +++ b/src/libslic3r/Thread.cpp @@ -235,12 +235,11 @@ void name_tbb_thread_pool_threads_set_locale() // const size_t nthreads_hw = std::thread::hardware_concurrency(); const size_t nthreads_hw = tbb::this_task_arena::max_concurrency(); size_t nthreads = nthreads_hw; + if (thread_count) { + nthreads = std::min(nthreads_hw, *thread_count); + } -#if 0 - // Shiny profiler is not thread safe, thus disable parallelization. - disable_multi_threading(); - nthreads = 1; -#endif + enforce_thread_count(nthreads); size_t nthreads_running(0); std::condition_variable cv; diff --git a/src/libslic3r/Utils.hpp b/src/libslic3r/Utils.hpp index 4b4be4c3ee..c9ee17235d 100644 --- a/src/libslic3r/Utils.hpp +++ b/src/libslic3r/Utils.hpp @@ -21,6 +21,7 @@ namespace boost { namespace filesystem { class directory_entry; }} namespace Slic3r { +inline std::optional thread_count; extern void set_logging_level(unsigned int level); extern unsigned get_logging_level(); // Format memory allocated, separate thousands by comma. @@ -29,7 +30,7 @@ extern std::string format_memsize_MB(size_t n); // The string is non-empty if the loglevel >= info (3) or ignore_loglevel==true. // Latter is used to get the memory info from SysInfoDialog. extern std::string log_memory_info(bool ignore_loglevel = false); -extern void disable_multi_threading(); +extern void enforce_thread_count(std::size_t count); // Returns the size of physical memory (RAM) in bytes. extern size_t total_physical_memory(); diff --git a/src/libslic3r/utils.cpp b/src/libslic3r/utils.cpp index 7062c2b89d..08f9d430d8 100644 --- a/src/libslic3r/utils.cpp +++ b/src/libslic3r/utils.cpp @@ -123,15 +123,15 @@ unsigned get_logging_level() } } -void disable_multi_threading() +void enforce_thread_count(const std::size_t count) { // Disable parallelization to simplify debugging. #ifdef TBB_HAS_GLOBAL_CONTROL { - static tbb::global_control gc(tbb::global_control::max_allowed_parallelism, 1); + static tbb::global_control gc(tbb::global_control::max_allowed_parallelism, count); } #else // TBB_HAS_GLOBAL_CONTROL - static tbb::task_scheduler_init *tbb_init = new tbb::task_scheduler_init(1); + static tbb::task_scheduler_init *tbb_init = new tbb::task_scheduler_init(count); UNUSED(tbb_init); #endif // TBB_HAS_GLOBAL_CONTROL } From 24e325469743a852704b5a68f135007542e75738 Mon Sep 17 00:00:00 2001 From: SachCZ Date: Wed, 3 Jan 2024 13:22:16 +0100 Subject: [PATCH 58/91] Smooth z-hop curve to avoid unreasonably high jerk setting. * Replace the ramping travel with a smooth ramping travel on marlin 2 under the right circumstances. --- src/libslic3r/GCode/Travels.cpp | 167 ++++++++++++++++++++----- src/libslic3r/GCode/Travels.hpp | 41 ++++++ tests/fff_print/test_gcode_travels.cpp | 19 +++ 3 files changed, 199 insertions(+), 28 deletions(-) diff --git a/src/libslic3r/GCode/Travels.cpp b/src/libslic3r/GCode/Travels.cpp index 17f4344742..c894debbf4 100644 --- a/src/libslic3r/GCode/Travels.cpp +++ b/src/libslic3r/GCode/Travels.cpp @@ -2,6 +2,45 @@ namespace Slic3r::GCode::Impl::Travels { +ElevatedTravelFormula::ElevatedTravelFormula(const ElevatedTravelParams ¶ms) + : smoothing_from(params.slope_end - params.blend_width / 2.0) + , smoothing_to(params.slope_end + params.blend_width / 2.0) + , blend_width(params.blend_width) + , lift_height(params.lift_height) + , slope_end(params.slope_end) { + if (smoothing_from < 0) { + smoothing_from = params.slope_end; + smoothing_to = params.slope_end; + } +} + +double parabola(const double x, const double a, const double b, const double c) { + return a * x * x + b * x + c; +} + +double ElevatedTravelFormula::slope_function(double distance_from_start) const { + if (distance_from_start < this->slope_end) { + const double lift_percent = distance_from_start / this->slope_end; + return lift_percent * this->lift_height; + } else { + return this->lift_height; + } +} + +double ElevatedTravelFormula::operator()(const double distance_from_start) const { + if (distance_from_start > this->smoothing_from && distance_from_start < this->smoothing_to) { + const double slope = this->lift_height / this->slope_end; + + // This is a part of a parabola going over a specific + // range and with specific end slopes. + const double a = -slope / 2.0 / this->blend_width; + const double b = slope * this->smoothing_to / this->blend_width; + const double c = this->lift_height + a * boost::math::pow<2>(this->smoothing_to); + return parabola(distance_from_start, a, b, c); + } + return slope_function(distance_from_start); +} + Points3 generate_flat_travel(tcb::span xy_path, const float elevation) { Points3 result; result.reserve(xy_path.size() - 1); @@ -52,26 +91,6 @@ std::vector slice_xy_path( return result; } -struct ElevatedTravelParams -{ - double lift_height{}; - double slope_end{}; -}; - -struct ElevatedTravelFormula -{ - double operator()(double distance_from_start) const { - if (distance_from_start < this->params.slope_end) { - const double lift_percent = distance_from_start / this->params.slope_end; - return lift_percent * this->params.lift_height; - } else { - return this->params.lift_height; - } - } - - ElevatedTravelParams params{}; -}; - Points3 generate_elevated_travel( const tcb::span xy_path, const std::vector &ensure_points_at_distances, @@ -136,8 +155,64 @@ std::optional get_obstacle_adjusted_slope_end( return *first_obstacle_distance; } +struct SmoothingParams +{ + double blend_width{}; + unsigned points_count{1}; +}; + +SmoothingParams get_smoothing_params( + const double lift_height, + const double slope_end, + unsigned extruder_id, + const double travel_length, + const FullPrintConfig &config +) { + if (config.gcode_flavor != gcfMarlinFirmware) + // Smoothing is supported only on Marlin. + return {0, 1}; + + const double slope = lift_height / slope_end; + const double max_machine_z_velocity = config.machine_max_feedrate_z.get_at(extruder_id); + const double max_xy_velocity = + Vec2d{ + config.machine_max_feedrate_x.get_at(extruder_id), + config.machine_max_feedrate_y.get_at(extruder_id)} + .norm(); + + const double xy_acceleration = config.machine_max_acceleration_travel.get_at(extruder_id); + + const double xy_acceleration_time = max_xy_velocity / xy_acceleration; + const double xy_acceleration_distance = 1.0 / 2.0 * xy_acceleration * + boost::math::pow<2>(xy_acceleration_time); + + if (travel_length < xy_acceleration_distance) { + return {0, 1}; + } + + const double max_z_velocity = std::min(max_xy_velocity * slope, max_machine_z_velocity); + const double deceleration_time = max_z_velocity / + config.machine_max_acceleration_z.get_at(extruder_id); + const double deceleration_xy_distance = deceleration_time * max_xy_velocity; + + const double blend_width = slope_end > deceleration_xy_distance / 2.0 ? deceleration_xy_distance : + slope_end * 2.0; + + const unsigned points_count = blend_width > 0 ? + std::ceil(max_z_velocity / config.machine_max_jerk_z.get_at(extruder_id)) : + 1; + + if (blend_width <= 0 // When there is no blend with, there is no need for smoothing. + || points_count > 6 // That would be way to many points. Do not do it at all. + || points_count <= 0 // Always return at least one point. + ) + return {0, 1}; + + return {blend_width, points_count}; +} + ElevatedTravelParams get_elevated_traval_params( - const Lines &xy_path, + const Polyline &xy_path, const FullPrintConfig &config, const unsigned extruder_id, const std::optional> &previous_layer_distancer @@ -146,6 +221,7 @@ ElevatedTravelParams get_elevated_traval_params( if (!config.travel_ramping_lift.get_at(extruder_id)) { elevation_params.slope_end = 0; elevation_params.lift_height = config.retract_lift.get_at(extruder_id); + elevation_params.blend_width = 0; return elevation_params; } elevation_params.lift_height = config.travel_max_lift.get_at(extruder_id); @@ -160,15 +236,45 @@ ElevatedTravelParams get_elevated_traval_params( } std::optional obstacle_adjusted_slope_end{ - get_obstacle_adjusted_slope_end(xy_path, previous_layer_distancer)}; + get_obstacle_adjusted_slope_end(xy_path.lines(), previous_layer_distancer)}; if (obstacle_adjusted_slope_end && obstacle_adjusted_slope_end < elevation_params.slope_end) { elevation_params.slope_end = *obstacle_adjusted_slope_end; } + SmoothingParams smoothing_params{get_smoothing_params( + elevation_params.lift_height, elevation_params.slope_end, extruder_id, + unscaled(xy_path.length()), config + )}; + + elevation_params.blend_width = smoothing_params.blend_width; + elevation_params.parabola_points_count = smoothing_params.points_count; return elevation_params; } +/** + * @brief Generate regulary spaced points on 1 axis. Includes both from and to. + * + * If count is 1, the point is in the middle of the range. + */ +std::vector linspace(const double from, const double to, const unsigned count) { + if (count == 0) { + return {}; + } + std::vector result; + result.reserve(count); + if (count == 1) { + result.emplace_back((from + to) / 2.0); + return result; + } + const double step = (to - from) / count; + for (unsigned i = 0; i < count - 1; ++i) { + result.emplace_back(from + i * step); + } + result.emplace_back(to); // Make sure the last value is exactly equal to the value of "to". + return result; +} + Points3 generate_travel_to_extrusion( const Polyline &xy_path, const FullPrintConfig &config, @@ -184,15 +290,20 @@ Points3 generate_travel_to_extrusion( return generate_flat_travel(xy_path.points, initial_elevation); } - Lines global_xy_path; - for (const Line &line : xy_path.lines()) { - global_xy_path.emplace_back(line.a + xy_path_coord_origin, line.b + xy_path_coord_origin); + Points global_xy_path; + for (const Point &point : xy_path.points) { + global_xy_path.emplace_back(point + xy_path_coord_origin); } - ElevatedTravelParams elevation_params{ - get_elevated_traval_params(global_xy_path, config, extruder_id, previous_layer_distancer)}; + ElevatedTravelParams elevation_params{get_elevated_traval_params( + Polyline{std::move(global_xy_path)}, config, extruder_id, previous_layer_distancer + )}; - const std::vector ensure_points_at_distances{elevation_params.slope_end}; + const std::vector ensure_points_at_distances = linspace( + elevation_params.slope_end - elevation_params.blend_width / 2.0, + elevation_params.slope_end + elevation_params.blend_width / 2.0, + elevation_params.parabola_points_count + ); Points3 result{generate_elevated_travel( xy_path.points, ensure_points_at_distances, initial_elevation, diff --git a/src/libslic3r/GCode/Travels.hpp b/src/libslic3r/GCode/Travels.hpp index eeb783d0a1..84020bb2cc 100644 --- a/src/libslic3r/GCode/Travels.hpp +++ b/src/libslic3r/GCode/Travels.hpp @@ -11,18 +11,59 @@ #include #include +#include + #include "libslic3r/Line.hpp" #include "libslic3r/Point.hpp" #include "libslic3r/AABBTreeLines.hpp" #include "libslic3r/PrintConfig.hpp" namespace Slic3r::GCode::Impl::Travels { +/** + * @brief A point on a curve with a distance from start. + */ struct DistancedPoint { Point point; double distance_from_start; }; +struct ElevatedTravelParams +{ + /** Maximal value of nozzle lift. */ + double lift_height{}; + + /** Distance from travel to the middle of the smoothing parabola. */ + double slope_end{}; + + /** Width of the smoothing parabola */ + double blend_width{}; + + /** How many points should be used to approximate the parabola */ + unsigned parabola_points_count{}; +}; + +/** + * @brief A mathematical formula for a smooth function. + * + * It starts lineary increasing than there is a parabola part and + * at the end it is flat. + */ +struct ElevatedTravelFormula +{ + ElevatedTravelFormula(const ElevatedTravelParams ¶ms); + double operator()(const double distance_from_start) const; + +private: + double slope_function(double distance_from_start) const; + + double smoothing_from; + double smoothing_to; + double blend_width; + double lift_height; + double slope_end; +}; + /** * @brief Takes a path described as a list of points and adds points to it. * diff --git a/tests/fff_print/test_gcode_travels.cpp b/tests/fff_print/test_gcode_travels.cpp index d8bbf4c0e7..a5ec848df5 100644 --- a/tests/fff_print/test_gcode_travels.cpp +++ b/tests/fff_print/test_gcode_travels.cpp @@ -1,6 +1,7 @@ #include #include #include +#include using namespace Slic3r; using namespace Slic3r::GCode::Impl::Travels; @@ -179,3 +180,21 @@ TEST_CASE("Get first crossed line distance", "[GCode]") { CHECK_FALSE(get_first_crossed_line_distance(tcb::span{travel}.subspan(6), distancer)); } + +TEST_CASE("Elevated travel formula", "[GCode]") { + const double lift_height{10}; + const double slope_end{10}; + const double blend_width{10}; + const ElevatedTravelParams params{lift_height, slope_end, blend_width}; + + ElevatedTravelFormula f{params}; + + const double distance = slope_end - blend_width / 2; + const double slope = (f(distance) - f(0)) / distance; + // At the begining it has given slope. + CHECK(slope == lift_height / slope_end); + // At the end it is flat. + CHECK(f(slope_end + blend_width / 2) == f(slope_end + blend_width)); + // Should be smoothed. + CHECK(f(slope_end) < lift_height); +} From 7f397cd7b3291a9d6a8c7d2696c07c14b2fadcb9 Mon Sep 17 00:00:00 2001 From: SachCZ Date: Fri, 5 Jan 2024 12:17:03 +0100 Subject: [PATCH 59/91] Implement ramping layer change using a tag in gcode During layer change, instead of generating the gcode, generate a placeholder tag. Then at the end of layer processing replace this tag with a ramping travel move. This solves the issue, that one does not know the starting point of the current layer where the layer change gcode would be originally generate. The ramping layer changes uses smoothing of the ramping travel. Also it is adjusted in such a way that it increases the ramp angle when the travel is too short, to always reach the next layer. --- src/libslic3r/CMakeLists.txt | 2 - src/libslic3r/GCode.cpp | 216 +++++++++++-------- src/libslic3r/GCode.hpp | 38 ++-- src/libslic3r/GCode/GCodeProcessor.cpp | 1 + src/libslic3r/GCode/GCodeProcessor.hpp | 1 + src/libslic3r/GCode/GCodeWriter.cpp | 60 ++++-- src/libslic3r/GCode/GCodeWriter.hpp | 17 +- src/libslic3r/GCode/LayerChanges.cpp | 53 ----- src/libslic3r/GCode/LayerChanges.hpp | 52 ----- src/libslic3r/GCode/Travels.cpp | 31 +-- src/libslic3r/GCode/Travels.hpp | 14 ++ src/libslic3r/GCode/WipeTowerIntegration.cpp | 20 +- tests/fff_print/CMakeLists.txt | 1 - tests/fff_print/test_gcode_layer_changes.cpp | 55 ----- 14 files changed, 241 insertions(+), 320 deletions(-) delete mode 100644 src/libslic3r/GCode/LayerChanges.cpp delete mode 100644 src/libslic3r/GCode/LayerChanges.hpp delete mode 100644 tests/fff_print/test_gcode_layer_changes.cpp diff --git a/src/libslic3r/CMakeLists.txt b/src/libslic3r/CMakeLists.txt index 7921fccab1..ce24457cd1 100644 --- a/src/libslic3r/CMakeLists.txt +++ b/src/libslic3r/CMakeLists.txt @@ -193,8 +193,6 @@ set(SLIC3R_SOURCES GCode/AvoidCrossingPerimeters.hpp GCode/Travels.cpp GCode/Travels.hpp - GCode/LayerChanges.cpp - GCode/LayerChanges.hpp GCode.cpp GCode.hpp GCodeReader.cpp diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 30df60c786..1a8efc7a35 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -35,7 +35,6 @@ #include "GCode/WipeTower.hpp" #include "GCode/WipeTowerIntegration.hpp" #include "GCode/Travels.hpp" -#include "GCode/LayerChanges.hpp" #include "Point.hpp" #include "Polygon.hpp" #include "PrintConfig.hpp" @@ -2081,6 +2080,50 @@ AABBTreeLines::LinesDistancer get_previous_layer_distancer( } } +std::string GCodeGenerator::get_layer_change_gcode(const Vec3d& from, const Vec3d& to, const unsigned extruder_id) { + const Polyline xy_path{ + this->gcode_to_point(from.head<2>()), + this->gcode_to_point(to.head<2>()) + }; + + using namespace GCode::Impl::Travels; + + ElevatedTravelParams elevation_params{ + get_elevated_traval_params(xy_path, this->m_config, extruder_id)}; + + const double initial_elevation = from.z(); + const double z_change = to.z() - from.z(); + elevation_params.lift_height = std::max(z_change, elevation_params.lift_height); + + const double path_length = unscaled(xy_path.length()); + const double lift_at_travel_end = + (elevation_params.lift_height / elevation_params.slope_end * path_length); + if (lift_at_travel_end < z_change) { + elevation_params.lift_height = z_change; + elevation_params.slope_end = path_length; + } + + const std::vector ensure_points_at_distances = linspace( + elevation_params.slope_end - elevation_params.blend_width / 2.0, + elevation_params.slope_end + elevation_params.blend_width / 2.0, + elevation_params.parabola_points_count + ); + + Points3 travel{generate_elevated_travel( + xy_path.points, ensure_points_at_distances, initial_elevation, + ElevatedTravelFormula{elevation_params} + )}; + + std::string travel_gcode; + Vec3d previous_point{this->point_to_gcode(travel.front())}; + for (const Vec3crd& point : tcb::span{travel}.subspan(1)) { + const Vec3d gcode_point{this->point_to_gcode(point)}; + travel_gcode += this->m_writer.get_travel_to_xyz_gcode(previous_point, gcode_point, "layer change"); + previous_point = gcode_point; + } + return travel_gcode; +} + // In sequential mode, process_layer is called once per each object and its copy, // therefore layers will contain a single entry and single_object_instance_idx will point to the copy of the object. // In non-sequential mode, process_layer is called per each print_z height with all object and support layers accumulated. @@ -2150,6 +2193,7 @@ LayerResult GCodeGenerator::process_layer( m_enable_loop_clipping = !enable; } + std::string gcode; assert(is_decimal_separator_point()); // for the sprintfs @@ -2168,6 +2212,7 @@ LayerResult GCodeGenerator::process_layer( m_last_layer_z = static_cast(print_z); m_max_layer_z = std::max(m_max_layer_z, m_last_layer_z); m_last_height = height; + m_current_layer_first_position = std::nullopt; // Set new layer - this will change Z and force a retraction if retract_layer_change is enabled. if (! print.config().before_layer_gcode.value.empty()) { @@ -2179,7 +2224,7 @@ LayerResult GCodeGenerator::process_layer( print.config().before_layer_gcode.value, m_writer.extruder()->id(), &config) + "\n"; } - gcode += this->change_layer(previous_layer_z, print_z, result.spiral_vase_enable); // this will increase m_layer_index + gcode += this->change_layer(previous_layer_z, print_z); // this will increase m_layer_index m_layer = &layer; if (this->line_distancer_is_required(layer_tools.extruders) && this->m_layer != nullptr && this->m_layer->lower_layer != nullptr) { this->m_previous_layer_distancer = GCode::Impl::get_previous_layer_distancer(layers, layer.lower_layer->lslices); @@ -2305,6 +2350,33 @@ LayerResult GCodeGenerator::process_layer( is_anything_overridden, false /* print_wipe_extrusions */); } + + // During layer change the starting position of next layer is now known. + // The solution is thus to emplace a temporary tag to the gcode, cache the postion and + // replace the tag later. The tag is Layer_Change_Travel, the cached position is + // m_current_layer_first_position and it is replaced here. + const std::string tag = GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Layer_Change_Travel); + std::string layer_change_gcode; + const bool do_ramping_layer_change = ( + m_previous_layer_last_position + && m_current_layer_first_position + && m_layer_change_extruder_id + && !result.spiral_vase_enable + && print_z > previous_layer_z + && EXTRUDER_CONFIG(travel_ramping_lift) + && EXTRUDER_CONFIG(travel_slope) > 0 && EXTRUDER_CONFIG(travel_slope) < 90 + ); + if (do_ramping_layer_change) { + layer_change_gcode = this->get_layer_change_gcode(*m_previous_layer_last_position, *m_current_layer_first_position, *m_layer_change_extruder_id); + } else { + if (!m_current_layer_first_position) { + throw std::runtime_error("Destination is required for layer change!"); + } + layer_change_gcode = this->writer().get_travel_to_z_gcode(m_current_layer_first_position->z(), "simple layer change"); + } + + boost::algorithm::replace_first(gcode, tag, layer_change_gcode); + BOOST_LOG_TRIVIAL(trace) << "Exported layer " << layer.id() << " print_z " << print_z << log_memory_info(); @@ -2604,63 +2676,10 @@ std::string GCodeGenerator::preamble() return gcode; } - -std::optional GCodeGenerator::get_helical_layer_change_gcode( - const coordf_t previous_layer_z, - const coordf_t print_z, - const std::string& comment -) { - - if (!this->last_pos_defined()) { - return std::nullopt; - } - - const double circle_radius{2}; - const unsigned n_gon_points_count{16}; - - const Point n_gon_start_point{this->last_pos()}; - - GCode::Impl::LayerChanges::Bed bed{ - this->m_config.bed_shape.values, - circle_radius * 2 - }; - if (!bed.contains_within_padding(this->point_to_gcode(n_gon_start_point))) { - return std::nullopt; - } - - const Vec2crd n_gon_vector{scaled(Vec2d{ - (bed.centroid - this->point_to_gcode(n_gon_start_point)).normalized() * circle_radius - })}; - const Point n_gon_centeroid{n_gon_start_point + n_gon_vector}; - - const Polygon n_gon{GCode::Impl::LayerChanges::generate_regular_polygon( - n_gon_centeroid, - n_gon_start_point, - n_gon_points_count - )}; - - const double n_gon_circumference = unscaled(n_gon.length()); - - const double z_change{print_z - previous_layer_z}; - Points3 helix{GCode::Impl::Travels::generate_elevated_travel( - n_gon.points, - {}, - previous_layer_z, - [&](const double distance){ - return distance / n_gon_circumference * z_change; - } - )}; - - helix.emplace_back(to_3d(this->last_pos(), scaled(print_z))); - - return this->generate_travel_gcode(helix, comment); -} - // called by GCodeGenerator::process_layer() std::string GCodeGenerator::change_layer( coordf_t previous_layer_z, - coordf_t print_z, - const bool spiral_vase_enabled + coordf_t print_z ) { std::string gcode; if (m_layer_count > 0) @@ -2670,31 +2689,16 @@ std::string GCodeGenerator::change_layer( if (EXTRUDER_CONFIG(retract_layer_change)) gcode += this->retract_and_wipe(); - const std::string comment{"move to next layer (" + std::to_string(m_layer_index) + ")"}; + Vec3d new_position = this->writer().get_position(); + new_position.z() = print_z; + this->writer().update_position(new_position); - bool do_helical_layer_change{ - !spiral_vase_enabled - && print_z > previous_layer_z - && EXTRUDER_CONFIG(retract_layer_change) - && EXTRUDER_CONFIG(retract_length) > 0 - && EXTRUDER_CONFIG(travel_ramping_lift) - && EXTRUDER_CONFIG(travel_slope) > 0 && EXTRUDER_CONFIG(travel_slope) < 90 - }; + m_previous_layer_last_position = this->m_last_pos_defined ? + std::optional{to_3d(this->point_to_gcode(this->last_pos()), previous_layer_z)} : + std::nullopt; - const std::optional helix_gcode{ - do_helical_layer_change ? - this->get_helical_layer_change_gcode( - m_config.z_offset.value + previous_layer_z, - m_config.z_offset.value + print_z, - comment - ) : - std::nullopt - }; - gcode += ( - helix_gcode ? - *helix_gcode : - m_writer.travel_to_z(m_config.z_offset.value + print_z, comment) - ); + gcode += GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Layer_Change_Travel); + this->m_layer_change_extruder_id = m_writer.extruder()->id(); // forget last wiping path as wiping after raising Z is pointless m_wipe.reset_path(); @@ -2963,19 +2967,31 @@ std::string GCodeGenerator::_extrude( std::string gcode; const std::string_view description_bridge = path_attr.role.is_bridge() ? " (bridge)"sv : ""sv; - // go to first point of extrusion path - if (!m_last_pos_defined) { - const double z = this->m_last_layer_z + this->m_config.z_offset.value; - const std::string comment{"move to print after unknown position"}; - gcode += this->retract_and_wipe(); - gcode += this->m_writer.travel_to_xy(this->point_to_gcode(path.front().point), comment); - gcode += this->m_writer.get_travel_to_z_gcode(z, comment); - } else if ( m_last_pos != path.front().point) { - std::string comment = "move to first "; - comment += description; - comment += description_bridge; - comment += " point"; - gcode += this->travel_to(path.front().point, path_attr.role, comment); + if (!m_current_layer_first_position) { + // Make the first travel just one G1. + const Vec3crd point = to_3d(path.front().point, scaled(this->m_last_layer_z + this->m_config.z_offset.value)); + const Vec3d gcode_point = to_3d(this->point_to_gcode(point.head<2>()), unscaled(point.z())); + this->set_last_pos(path.front().point); + this->writer().update_position(gcode_point); + gcode += this->writer().get_travel_to_xy_gcode(gcode_point.head<2>(), "move to first layer point"); + gcode += this->writer().get_travel_to_z_gcode(gcode_point.z(), "move to first layer point"); + m_current_layer_first_position = gcode_point; + } else { + // go to first point of extrusion path + if (!m_last_pos_defined) { + const double z = this->m_last_layer_z + this->m_config.z_offset.value; + const std::string comment{"move to print after unknown position"}; + gcode += this->retract_and_wipe(); + gcode += this->m_writer.travel_to_xy(this->point_to_gcode(path.front().point), comment); + gcode += this->m_writer.get_travel_to_z_gcode(z, comment); + } else if ( m_last_pos != path.front().point) { + std::string comment = "move to first "; + comment += description; + comment += description_bridge; + comment += " point"; + const std::string travel_gcode{this->travel_to(path.front().point, path_attr.role, comment)}; + gcode += travel_gcode; + } } // compensate retraction @@ -3217,9 +3233,13 @@ std::string GCodeGenerator::generate_travel_gcode( // use G1 because we rely on paths being straight (G0 may make round paths) gcode += this->m_writer.set_travel_acceleration(acceleration); - for (const Vec3crd& point : travel) { - gcode += this->m_writer.travel_to_xyz(to_3d(this->point_to_gcode(point.head<2>()), unscaled(point.z())), comment); + Vec3d previous_point{this->point_to_gcode(travel.front())}; + for (const Vec3crd& point : tcb::span{travel}.subspan(1)) { + const Vec3d gcode_point{this->point_to_gcode(point)}; + + gcode += this->m_writer.travel_to_xyz(previous_point, gcode_point, comment); this->set_last_pos(point.head<2>()); + previous_point = gcode_point; } if (! GCodeWriter::supports_separate_travel_acceleration(config().gcode_flavor)) { @@ -3351,6 +3371,14 @@ std::string GCodeGenerator::travel_to(const Point &point, ExtrusionRole role, st const double retract_length = this->m_config.retract_length.get_at(extruder_id); bool can_be_flat{!needs_retraction || retract_length == 0}; const double initial_elevation = this->m_last_layer_z + this->m_config.z_offset.value; + + const double upper_limit = this->m_config.retract_lift_below.get_at(extruder_id); + const double lower_limit = this->m_config.retract_lift_above.get_at(extruder_id); + if ((lower_limit > 0 && initial_elevation < lower_limit) || + (upper_limit > 0 && initial_elevation > upper_limit)) { + can_be_flat = true; + } + const Points3 travel = ( can_be_flat ? GCode::Impl::Travels::generate_flat_travel(xy_path.points, initial_elevation) : diff --git a/src/libslic3r/GCode.hpp b/src/libslic3r/GCode.hpp index 8890ec6125..92586e8d16 100644 --- a/src/libslic3r/GCode.hpp +++ b/src/libslic3r/GCode.hpp @@ -127,11 +127,25 @@ public: const Point& last_pos() const { return m_last_pos; } // Convert coordinates of the active object to G-code coordinates, possibly adjusted for extruder offset. template - Vec2d point_to_gcode(const Eigen::MatrixBase &point) const { - static_assert(Derived::IsVectorAtCompileTime && int(Derived::SizeAtCompileTime) == 2, "GCodeGenerator::point_to_gcode(): first parameter is not a 2D vector"); - return Vec2d(unscaled(point.x()), unscaled(point.y())) + m_origin - - m_config.extruder_offset.get_at(m_writer.extruder()->id()); + Eigen::Matrix point_to_gcode(const Eigen::MatrixBase &point) const { + static_assert( + Derived::IsVectorAtCompileTime, + "GCodeGenerator::point_to_gcode(): first parameter is not a vector" + ); + static_assert( + int(Derived::SizeAtCompileTime) == 2 || int(Derived::SizeAtCompileTime) == 3, + "GCodeGenerator::point_to_gcode(): first parameter is not a 2D or 3D vector" + ); + + if constexpr (Derived::SizeAtCompileTime == 2) { + return Vec2d(unscaled(point.x()), unscaled(point.y())) + m_origin + - m_config.extruder_offset.get_at(m_writer.extruder()->id()); + } else { + const Vec2d gcode_point_xy{this->point_to_gcode(point.template head<2>())}; + return to_3d(gcode_point_xy, unscaled(point.z())); + } } + // Convert coordinates of the active object to G-code coordinates, possibly adjusted for extruder offset and quantized to G-code resolution. template Vec2d point_to_gcode_quantized(const Eigen::MatrixBase &point) const { @@ -216,6 +230,9 @@ private: static ObjectsLayerToPrint collect_layers_to_print(const PrintObject &object); static std::vector> collect_layers_to_print(const Print &print); + /** @brief Generates ramping travel gcode for layer change. */ + std::string get_layer_change_gcode(const Vec3d& from, const Vec3d& to, const unsigned extruder_id); + LayerResult process_layer( const Print &print, // Set of object & print layers of the same PrintObject and with the same print_z. @@ -253,15 +270,9 @@ private: bool last_pos_defined() const { return m_last_pos_defined; } void set_extruders(const std::vector &extruder_ids); std::string preamble(); - std::optional get_helical_layer_change_gcode( - const coordf_t previous_layer_z, - const coordf_t print_z, - const std::string& comment - ); std::string change_layer( coordf_t previous_layer_z, - coordf_t print_z, - const bool spiral_vase_enabled + coordf_t print_z ); std::string extrude_entity(const ExtrusionEntityReference &entity, const GCode::SmoothPathCache &smooth_path_cache, const std::string_view description, double speed = -1.); std::string extrude_loop(const ExtrusionLoop &loop, const GCode::SmoothPathCache &smooth_path_cache, const std::string_view description, double speed = -1.); @@ -412,7 +423,10 @@ private: Point m_last_pos; bool m_last_pos_defined; - + std::optional m_previous_layer_last_position; + // This needs to be populated during the layer processing! + std::optional m_current_layer_first_position; + std::optional m_layer_change_extruder_id; std::unique_ptr m_cooling_buffer; std::unique_ptr m_spiral_vase; std::unique_ptr m_find_replace; diff --git a/src/libslic3r/GCode/GCodeProcessor.cpp b/src/libslic3r/GCode/GCodeProcessor.cpp index 87e319b3b9..e3a576e520 100644 --- a/src/libslic3r/GCode/GCodeProcessor.cpp +++ b/src/libslic3r/GCode/GCodeProcessor.cpp @@ -57,6 +57,7 @@ const std::vector GCodeProcessor::Reserved_Tags = { "HEIGHT:", "WIDTH:", "LAYER_CHANGE", + "LAYER_CHANGE_TRAVEL", "COLOR_CHANGE", "PAUSE_PRINT", "CUSTOM_GCODE", diff --git a/src/libslic3r/GCode/GCodeProcessor.hpp b/src/libslic3r/GCode/GCodeProcessor.hpp index a055eaa347..f5658fcec8 100644 --- a/src/libslic3r/GCode/GCodeProcessor.hpp +++ b/src/libslic3r/GCode/GCodeProcessor.hpp @@ -192,6 +192,7 @@ namespace Slic3r { Height, Width, Layer_Change, + Layer_Change_Travel, Color_Change, Pause_Print, Custom_Code, diff --git a/src/libslic3r/GCode/GCodeWriter.cpp b/src/libslic3r/GCode/GCodeWriter.cpp index 5231f97cd8..4983b59374 100644 --- a/src/libslic3r/GCode/GCodeWriter.cpp +++ b/src/libslic3r/GCode/GCodeWriter.cpp @@ -275,10 +275,8 @@ std::string GCodeWriter::set_speed(double F, const std::string_view comment, con return w.string(); } -std::string GCodeWriter::travel_to_xy(const Vec2d &point, const std::string_view comment) +std::string GCodeWriter::get_travel_to_xy_gcode(const Vec2d &point, const std::string_view comment) const { - m_pos.head<2>() = point.head<2>(); - GCodeG1Formatter w; w.emit_xy(point); w.emit_f(this->config.travel_speed.value * 60.0); @@ -286,6 +284,12 @@ std::string GCodeWriter::travel_to_xy(const Vec2d &point, const std::string_view return w.string(); } +std::string GCodeWriter::travel_to_xy(const Vec2d &point, const std::string_view comment) +{ + m_pos.head<2>() = point.head<2>(); + return this->get_travel_to_xy_gcode(point, comment); +} + std::string GCodeWriter::travel_to_xy_G2G3IJ(const Vec2d &point, const Vec2d &ij, const bool ccw, const std::string_view comment) { assert(std::abs(point.x()) < 1200.); @@ -303,35 +307,49 @@ std::string GCodeWriter::travel_to_xy_G2G3IJ(const Vec2d &point, const Vec2d &ij return w.string(); } -std::string GCodeWriter::travel_to_xyz(const Vec3d &point, const std::string_view comment) +std::string GCodeWriter::travel_to_xyz(const Vec3d& from, const Vec3d &to, const std::string_view comment) { - if (std::abs(point.x() - m_pos.x()) < EPSILON && std::abs(point.y() - m_pos.y()) < EPSILON) { - return this->travel_to_z(point.z(), comment); - } else if (std::abs(point.z() - m_pos.z()) < EPSILON) { - return this->travel_to_xy(point.head<2>(), comment); + if (std::abs(to.x() - m_pos.x()) < EPSILON && std::abs(to.y() - m_pos.y()) < EPSILON) { + return this->travel_to_z(to.z(), comment); + } else if (std::abs(to.z() - m_pos.z()) < EPSILON) { + return this->travel_to_xy(to.head<2>(), comment); } else { - m_pos = point; - - GCodeG1Formatter w; - w.emit_xyz(point); - - Vec2f speed {this->config.travel_speed_z.value, this->config.travel_speed.value}; - w.emit_f(speed.norm() * 60.0); - w.emit_comment(this->config.gcode_comments, comment); - return w.string(); + m_pos = to; + return this->get_travel_to_xyz_gcode(from, to, comment); } } +std::string GCodeWriter::get_travel_to_xyz_gcode(const Vec3d &from, const Vec3d &to, const std::string_view comment) const { + GCodeG1Formatter w; + w.emit_xyz(to); + + const double distance_xy{(to.head<2>() - from.head<2>()).norm()}; + const double distnace_z{std::abs(to.z() - from.z())}; + const double time_z = distnace_z / this->config.travel_speed_z.value; + const double time_xy = distance_xy / this->config.travel_speed.value; + const double factor = time_z > 0 ? time_xy / time_z : 1; + if (factor < 1) { + w.emit_f((this->config.travel_speed.value * factor + (1 - factor) * this->config.travel_speed_z.value) * 60.0); + } else { + w.emit_f(this->config.travel_speed.value * 60.0); + } + + w.emit_comment(this->config.gcode_comments, comment); + return w.string(); +} std::string GCodeWriter::travel_to_z(double z, const std::string_view comment) { - return std::abs(m_pos.z() - z) < EPSILON ? "" : this->get_travel_to_z_gcode(z, comment); + if (std::abs(m_pos.z() - z) < EPSILON) { + return ""; + } else { + m_pos.z() = z; + return this->get_travel_to_z_gcode(z, comment); + } } -std::string GCodeWriter::get_travel_to_z_gcode(double z, const std::string_view comment) +std::string GCodeWriter::get_travel_to_z_gcode(double z, const std::string_view comment) const { - m_pos.z() = z; - double speed = this->config.travel_speed_z.value; if (speed == 0.) speed = this->config.travel_speed.value; diff --git a/src/libslic3r/GCode/GCodeWriter.hpp b/src/libslic3r/GCode/GCodeWriter.hpp index d91e67728d..f857d07e4f 100644 --- a/src/libslic3r/GCode/GCodeWriter.hpp +++ b/src/libslic3r/GCode/GCodeWriter.hpp @@ -66,10 +66,23 @@ public: std::string toolchange_prefix() const; std::string toolchange(unsigned int extruder_id); std::string set_speed(double F, const std::string_view comment = {}, const std::string_view cooling_marker = {}) const; + + std::string get_travel_to_xy_gcode(const Vec2d &point, const std::string_view comment) const; std::string travel_to_xy(const Vec2d &point, const std::string_view comment = {}); std::string travel_to_xy_G2G3IJ(const Vec2d &point, const Vec2d &ij, const bool ccw, const std::string_view comment = {}); - std::string travel_to_xyz(const Vec3d &point, const std::string_view comment = {}); - std::string get_travel_to_z_gcode(double z, const std::string_view comment); + + /** + * @brief Return gcode with all three axis defined. Optionally adds feedrate. + * + * Feedrate is added the starting point "from" is specified. + * + * @param from Optional starting point of the travel. + * @param to Where to travel to. + * @param comment Description of the travel purpose. + */ + std::string get_travel_to_xyz_gcode(const Vec3d &from, const Vec3d &to, const std::string_view comment) const; + std::string travel_to_xyz(const Vec3d &from, const Vec3d &to, const std::string_view comment = {}); + std::string get_travel_to_z_gcode(double z, const std::string_view comment) const; std::string travel_to_z(double z, const std::string_view comment = {}); std::string extrude_to_xy(const Vec2d &point, double dE, const std::string_view comment = {}); std::string extrude_to_xy_G2G3IJ(const Vec2d &point, const Vec2d &ij, const bool ccw, double dE, const std::string_view comment); diff --git a/src/libslic3r/GCode/LayerChanges.cpp b/src/libslic3r/GCode/LayerChanges.cpp deleted file mode 100644 index bb6656383a..0000000000 --- a/src/libslic3r/GCode/LayerChanges.cpp +++ /dev/null @@ -1,53 +0,0 @@ -#include "LayerChanges.hpp" -#include "libslic3r/ClipperUtils.hpp" - -namespace Slic3r::GCode::Impl::LayerChanges { - -Polygon generate_regular_polygon( - const Point ¢roid, const Point &start_point, const unsigned points_count -) { - Points points; - points.reserve(points_count); - const double part_angle{2 * M_PI / points_count}; - for (unsigned i = 0; i < points_count; ++i) { - const double current_angle{i * part_angle}; - points.emplace_back(scaled(std::cos(current_angle)), scaled(std::sin(current_angle))); - } - - Polygon regular_polygon{points}; - const Vec2d current_vector{unscaled(regular_polygon.points.front())}; - const Vec2d expected_vector{unscaled(start_point) - unscaled(centroid)}; - - const double current_scale = current_vector.norm(); - const double expected_scale = expected_vector.norm(); - regular_polygon.scale(expected_scale / current_scale); - - regular_polygon.rotate(angle(current_vector, expected_vector)); - - regular_polygon.translate(centroid); - - return regular_polygon; -} - -Bed::Bed(const std::vector &shape, const double padding) - : inner_offset(get_inner_offset(shape, padding)), centroid(unscaled(inner_offset.centroid())) {} - -bool Bed::contains_within_padding(const Vec2d &point) const { - return inner_offset.contains(scaled(point)); -} - -Polygon Bed::get_inner_offset(const std::vector &shape, const double padding) { - Points shape_scaled; - shape_scaled.reserve(shape.size()); - using std::begin, std::end, std::back_inserter, std::transform; - transform(begin(shape), end(shape), back_inserter(shape_scaled), [](const Vec2d &point) { - return scaled(point); - }); - const Polygons inner_offset{shrink({Polygon{shape_scaled}}, scaled(padding))}; - if (inner_offset.empty()) { - return Polygon{}; - } - return inner_offset.front(); -} - -} // namespace Slic3r::GCode::Impl::LayerChanges diff --git a/src/libslic3r/GCode/LayerChanges.hpp b/src/libslic3r/GCode/LayerChanges.hpp deleted file mode 100644 index 5eb178e3f1..0000000000 --- a/src/libslic3r/GCode/LayerChanges.hpp +++ /dev/null @@ -1,52 +0,0 @@ -/** - * @file - * @brief Utility functions for layer change gcode generation. - */ - -#ifndef slic3r_GCode_LayerChanges_hpp_ -#define slic3r_GCode_LayerChanges_hpp_ - -#include "libslic3r/Point.hpp" -#include "libslic3r/Polygon.hpp" - -namespace Slic3r::GCode::Impl::LayerChanges { -/** - * Generates a regular polygon - all angles are the same (e.g. typical hexagon). - * - * @param centroid Central point. - * @param start_point The polygon point are ordered. This is the first point. - * @param points_count Amount of nodes of the polygon (e.g. 6 for haxagon). - * - * Distance between centroid and start point sets the scale of the polygon. - */ -Polygon generate_regular_polygon( - const Point ¢roid, const Point &start_point, const unsigned points_count -); - -/** - * @brief A representation of the bed shape with inner padding. - * - * Its purpose is to facilitate the bed boundary checking. - */ -class Bed -{ -private: - Polygon inner_offset; - static Polygon get_inner_offset(const std::vector &shape, const double padding); - -public: - /** - * Bed shape with inner padding. - */ - Bed(const std::vector &shape, const double padding); - - Vec2d centroid; - - /** - * Returns true if the point is within the bed shape including inner padding. - */ - bool contains_within_padding(const Vec2d &point) const; -}; -} // namespace Slic3r::GCode::Impl::LayerChanges - -#endif // slic3r_GCode_LayerChanges_hpp_ diff --git a/src/libslic3r/GCode/Travels.cpp b/src/libslic3r/GCode/Travels.cpp index c894debbf4..1253b88845 100644 --- a/src/libslic3r/GCode/Travels.cpp +++ b/src/libslic3r/GCode/Travels.cpp @@ -43,8 +43,8 @@ double ElevatedTravelFormula::operator()(const double distance_from_start) const Points3 generate_flat_travel(tcb::span xy_path, const float elevation) { Points3 result; - result.reserve(xy_path.size() - 1); - for (const Point &point : xy_path.subspan(1)) { + result.reserve(xy_path.size()); + for (const Point &point : xy_path) { result.emplace_back(point.x(), point.y(), scaled(elevation)); } return result; @@ -140,21 +140,6 @@ std::optional get_first_crossed_line_distance( return {}; } -std::optional get_obstacle_adjusted_slope_end( - const Lines &xy_path, - const std::optional> &previous_layer_distancer -) { - if (!previous_layer_distancer) { - return std::nullopt; - } - std::optional first_obstacle_distance = - get_first_crossed_line_distance(xy_path, *previous_layer_distancer); - if (!first_obstacle_distance) { - return std::nullopt; - } - return *first_obstacle_distance; -} - struct SmoothingParams { double blend_width{}; @@ -212,7 +197,7 @@ SmoothingParams get_smoothing_params( } ElevatedTravelParams get_elevated_traval_params( - const Polyline &xy_path, + const Polyline& xy_path, const FullPrintConfig &config, const unsigned extruder_id, const std::optional> &previous_layer_distancer @@ -236,7 +221,10 @@ ElevatedTravelParams get_elevated_traval_params( } std::optional obstacle_adjusted_slope_end{ - get_obstacle_adjusted_slope_end(xy_path.lines(), previous_layer_distancer)}; + previous_layer_distancer ? + get_first_crossed_line_distance(xy_path.lines(), *previous_layer_distancer) : + std::nullopt + }; if (obstacle_adjusted_slope_end && obstacle_adjusted_slope_end < elevation_params.slope_end) { elevation_params.slope_end = *obstacle_adjusted_slope_end; @@ -252,11 +240,6 @@ ElevatedTravelParams get_elevated_traval_params( return elevation_params; } -/** - * @brief Generate regulary spaced points on 1 axis. Includes both from and to. - * - * If count is 1, the point is in the middle of the range. - */ std::vector linspace(const double from, const double to, const unsigned count) { if (count == 0) { return {}; diff --git a/src/libslic3r/GCode/Travels.hpp b/src/libslic3r/GCode/Travels.hpp index 84020bb2cc..5ccf30ec2f 100644 --- a/src/libslic3r/GCode/Travels.hpp +++ b/src/libslic3r/GCode/Travels.hpp @@ -89,6 +89,20 @@ std::vector slice_xy_path( tcb::span xy_path, tcb::span sorted_distances ); +/** + * @brief Generate regulary spaced points on 1 axis. Includes both from and to. + * + * If count is 1, the point is in the middle of the range. + */ +std::vector linspace(const double from, const double to, const unsigned count); + +ElevatedTravelParams get_elevated_traval_params( + const Polyline& xy_path, + const FullPrintConfig &config, + const unsigned extruder_id, + const std::optional> &previous_layer_distancer = std::nullopt +); + /** * @brief Simply return the xy_path with z coord set to elevation. */ diff --git a/src/libslic3r/GCode/WipeTowerIntegration.cpp b/src/libslic3r/GCode/WipeTowerIntegration.cpp index 3b2bb4ddd3..04c398e078 100644 --- a/src/libslic3r/GCode/WipeTowerIntegration.cpp +++ b/src/libslic3r/GCode/WipeTowerIntegration.cpp @@ -57,12 +57,24 @@ std::string WipeTowerIntegration::append_tcr(GCodeGenerator &gcodegen, const Wip || is_ramming || will_go_down); // don't dig into the print if (should_travel_to_tower) { + + const Point xy_point = wipe_tower_point_to_object_point(gcodegen, start_pos); gcode += gcodegen.retract_and_wipe(); gcodegen.m_avoid_crossing_perimeters.use_external_mp_once(); - gcode += gcodegen.travel_to( - wipe_tower_point_to_object_point(gcodegen, start_pos), - ExtrusionRole::Mixed, - "Travel to a Wipe Tower"); + if (gcodegen.m_current_layer_first_position) { + gcode += gcodegen.travel_to( + xy_point, + ExtrusionRole::Mixed, + "Travel to a Wipe Tower"); + } else { + const Vec3crd point = to_3d(xy_point, scaled(z)); + const Vec3d gcode_point = to_3d(gcodegen.point_to_gcode(point.head<2>()), z); + gcodegen.set_last_pos(point.head<2>()); + gcodegen.writer().update_position(gcode_point); + gcode += gcodegen.writer().get_travel_to_xy_gcode(gcode_point.head<2>(), "move to first layer point"); + gcode += gcodegen.writer().get_travel_to_z_gcode(gcode_point.z(), "move to first layer point"); + gcodegen.m_current_layer_first_position = gcode_point; + } gcode += gcodegen.unretract(); } else { // When this is multiextruder printer without any ramming, we can just change diff --git a/tests/fff_print/CMakeLists.txt b/tests/fff_print/CMakeLists.txt index 43d314a01c..23be4ddedc 100644 --- a/tests/fff_print/CMakeLists.txt +++ b/tests/fff_print/CMakeLists.txt @@ -14,7 +14,6 @@ add_executable(${_TEST_NAME}_tests test_gaps.cpp test_gcode.cpp test_gcode_travels.cpp - test_gcode_layer_changes.cpp test_gcodefindreplace.cpp test_gcodewriter.cpp test_layers.cpp diff --git a/tests/fff_print/test_gcode_layer_changes.cpp b/tests/fff_print/test_gcode_layer_changes.cpp deleted file mode 100644 index 6621d38cbe..0000000000 --- a/tests/fff_print/test_gcode_layer_changes.cpp +++ /dev/null @@ -1,55 +0,0 @@ -#include -#include - -using namespace Slic3r; -using namespace Slic3r::GCode::Impl::LayerChanges; - -TEST_CASE("Generate regular polygon", "[GCode]") { - const unsigned points_count{32}; - const Point centroid{scaled(Vec2d{5, -2})}; - const Polygon result{generate_regular_polygon(centroid, scaled(Vec2d{0, 0}), points_count)}; - const Point oposite_point{centroid * 2}; - - REQUIRE(result.size() == 32); - CHECK(result[16].x() == Approx(oposite_point.x())); - CHECK(result[16].y() == Approx(oposite_point.y())); - - std::vector angles; - angles.reserve(points_count); - for (unsigned index = 0; index < points_count; index++) { - const unsigned previous_index{index == 0 ? points_count - 1 : index - 1}; - const unsigned next_index{index == points_count - 1 ? 0 : index + 1}; - - const Point previous_point = result.points[previous_index]; - const Point current_point = result.points[index]; - const Point next_point = result.points[next_index]; - - angles.emplace_back(angle(Vec2crd{previous_point - current_point}, Vec2crd{next_point - current_point})); - } - - std::vector expected; - angles.reserve(points_count); - std::generate_n(std::back_inserter(expected), points_count, [&](){ - return angles.front(); - }); - - CHECK_THAT(angles, Catch::Matchers::Approx(expected)); -} - -TEST_CASE("Square bed with padding", "[GCode]") { - const Bed bed{ - { - Vec2d{0, 0}, - Vec2d{100, 0}, - Vec2d{100, 100}, - Vec2d{0, 100} - }, - 10.0 - }; - - CHECK(bed.centroid.x() == 50); - CHECK(bed.centroid.y() == 50); - CHECK(bed.contains_within_padding(Vec2d{10, 10})); - CHECK_FALSE(bed.contains_within_padding(Vec2d{9, 10})); - -} From ff30d7aad3981d5736625571a2f0230c8c78c95c Mon Sep 17 00:00:00 2001 From: SachCZ Date: Fri, 5 Jan 2024 16:36:09 +0100 Subject: [PATCH 60/91] Replace last_pos and helpers with optional in GCode.cpp --- src/libslic3r/GCode.cpp | 55 +++++++++---------- src/libslic3r/GCode.hpp | 15 ++--- .../GCode/AvoidCrossingPerimeters.cpp | 2 +- src/libslic3r/GCode/Wipe.cpp | 4 +- src/libslic3r/GCode/WipeTowerIntegration.cpp | 26 +++++---- 5 files changed, 54 insertions(+), 48 deletions(-) diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 1a8efc7a35..5678ce6f78 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -1213,7 +1213,7 @@ void GCodeGenerator::_do_export(Print& print, GCodeOutputStream &file, Thumbnail m_enable_cooling_markers = false; // we're not filtering these moves through CoolingBuffer m_avoid_crossing_perimeters.use_external_mp_once(); file.write(this->retract_and_wipe()); - file.write(this->travel_to(Point(0, 0), ExtrusionRole::None, "move to origin position for next object")); + file.write(this->travel_to(*this->last_position, Point(0, 0), ExtrusionRole::None, "move to origin position for next object")); m_enable_cooling_markers = true; // Disable motion planner when traveling to first object point. m_avoid_crossing_perimeters.disable_once(); @@ -1636,7 +1636,7 @@ std::string GCodeGenerator::placeholder_parser_process( if (const std::vector &pos = ppi.opt_position->values; ppi.position != pos) { // Update G-code writer. m_writer.update_position({ pos[0], pos[1], pos[2] }); - this->set_last_pos(this->gcode_to_point({ pos[0], pos[1] })); + this->last_position = this->gcode_to_point({ pos[0], pos[1] }); } for (const Extruder &e : m_writer.extruders()) { @@ -2534,9 +2534,10 @@ void GCodeGenerator::process_layer_single_object( init_layer_delayed(); m_config.apply(region.config()); const auto extrusion_name = ironing ? "ironing"sv : "infill"sv; - for (const ExtrusionEntityReference &fill : chain_extrusion_references(temp_fill_extrusions, &m_last_pos)) + const Point* start_near = this->last_position ? &(*(this->last_position)) : nullptr; + for (const ExtrusionEntityReference &fill : chain_extrusion_references(temp_fill_extrusions, start_near)) if (auto *eec = dynamic_cast(&fill.extrusion_entity()); eec) { - for (const ExtrusionEntityReference &ee : chain_extrusion_references(*eec, &m_last_pos, fill.flipped())) + for (const ExtrusionEntityReference &ee : chain_extrusion_references(*eec, start_near, fill.flipped())) gcode += this->extrude_entity(ee, smooth_path_cache, extrusion_name); } else gcode += this->extrude_entity(fill, smooth_path_cache, extrusion_name); @@ -2658,7 +2659,7 @@ void GCodeGenerator::set_origin(const Vec2d &pointf) { // if origin increases (goes towards right), last_pos decreases because it goes towards left const auto offset = Point::new_scale(m_origin - pointf); - m_last_pos += offset; + *(this->last_position) += offset; m_wipe.offset_path(offset); m_origin = pointf; } @@ -2693,8 +2694,8 @@ std::string GCodeGenerator::change_layer( new_position.z() = print_z; this->writer().update_position(new_position); - m_previous_layer_last_position = this->m_last_pos_defined ? - std::optional{to_3d(this->point_to_gcode(this->last_pos()), previous_layer_z)} : + m_previous_layer_last_position = this->last_position ? + std::optional{to_3d(this->point_to_gcode(*this->last_position), previous_layer_z)} : std::nullopt; gcode += GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Layer_Change_Travel); @@ -2724,10 +2725,10 @@ std::string GCodeGenerator::extrude_loop(const ExtrusionLoop &loop_src, const GC { // Extrude all loops CCW. bool is_hole = loop_src.is_clockwise(); - Point seam_point = this->last_pos(); + Point seam_point = *this->last_position; if (! m_config.spiral_vase && comment_is_perimeter(description)) { assert(m_layer != nullptr); - seam_point = m_seam_placer.place_seam(m_layer, loop_src, m_config.external_perimeters_first, this->last_pos()); + seam_point = m_seam_placer.place_seam(m_layer, loop_src, m_config.external_perimeters_first, *this->last_position); } // Because the G-code export has 1um resolution, don't generate segments shorter than 1.5 microns, // thus empty path segments will not be produced by G-code export. @@ -2766,7 +2767,7 @@ std::string GCodeGenerator::extrude_loop(const ExtrusionLoop &loop_src, const GC if (std::optional pt = wipe_hide_seam(smooth_path, is_hole, scale_(EXTRUDER_CONFIG(nozzle_diameter))); pt) { // Generate the seam hiding travel move. gcode += m_writer.travel_to_xy(this->point_to_gcode(*pt), "move inwards before travel"); - this->set_last_pos(*pt); + this->last_position = *pt; } } @@ -2779,7 +2780,7 @@ std::string GCodeGenerator::extrude_skirt( { assert(loop_src.is_counter_clockwise()); GCode::SmoothPath smooth_path = smooth_path_cache.resolve_or_fit_split_with_seam( - loop_src, false, m_scaled_resolution, this->last_pos(), scaled(0.0015)); + loop_src, false, m_scaled_resolution, *this->last_position, scaled(0.0015)); // Clip the path to avoid the extruder to get exactly on the first point of the loop; // if polyline was shorter than the clipping distance we'd get a null polyline, so @@ -2971,25 +2972,25 @@ std::string GCodeGenerator::_extrude( // Make the first travel just one G1. const Vec3crd point = to_3d(path.front().point, scaled(this->m_last_layer_z + this->m_config.z_offset.value)); const Vec3d gcode_point = to_3d(this->point_to_gcode(point.head<2>()), unscaled(point.z())); - this->set_last_pos(path.front().point); + this->last_position = path.front().point; this->writer().update_position(gcode_point); gcode += this->writer().get_travel_to_xy_gcode(gcode_point.head<2>(), "move to first layer point"); gcode += this->writer().get_travel_to_z_gcode(gcode_point.z(), "move to first layer point"); m_current_layer_first_position = gcode_point; } else { // go to first point of extrusion path - if (!m_last_pos_defined) { + if (!this->last_position) { const double z = this->m_last_layer_z + this->m_config.z_offset.value; const std::string comment{"move to print after unknown position"}; gcode += this->retract_and_wipe(); gcode += this->m_writer.travel_to_xy(this->point_to_gcode(path.front().point), comment); gcode += this->m_writer.get_travel_to_z_gcode(z, comment); - } else if ( m_last_pos != path.front().point) { + } else if ( this->last_position != path.front().point) { std::string comment = "move to first "; comment += description; comment += description_bridge; comment += " point"; - const std::string travel_gcode{this->travel_to(path.front().point, path_attr.role, comment)}; + const std::string travel_gcode{this->travel_to(*this->last_position, path.front().point, path_attr.role, comment)}; gcode += travel_gcode; } } @@ -3213,7 +3214,7 @@ std::string GCodeGenerator::_extrude( if (dynamic_speed_and_fan_speed.second >= 0) gcode += ";_RESET_FAN_SPEED\n"; - this->set_last_pos(path.back().point); + this->last_position = path.back().point; return gcode; } @@ -3238,7 +3239,7 @@ std::string GCodeGenerator::generate_travel_gcode( const Vec3d gcode_point{this->point_to_gcode(point)}; gcode += this->m_writer.travel_to_xyz(previous_point, gcode_point, comment); - this->set_last_pos(point.head<2>()); + this->last_position = point.head<2>(); previous_point = gcode_point; } @@ -3331,18 +3332,16 @@ Polyline GCodeGenerator::generate_travel_xy_path( } // This method accepts &point in print coordinates. -std::string GCodeGenerator::travel_to(const Point &point, ExtrusionRole role, std::string comment) -{ - - const Point start_point = this->last_pos(); - +std::string GCodeGenerator::travel_to( + const Point &start_point, const Point &end_point, ExtrusionRole role, const std::string &comment +) { // check whether a straight travel move would need retraction bool could_be_wipe_disabled {false}; - bool needs_retraction = this->needs_retraction(Polyline{start_point, point}, role); + bool needs_retraction = this->needs_retraction(Polyline{start_point, end_point}, role); Polyline xy_path{generate_travel_xy_path( - start_point, point, needs_retraction, could_be_wipe_disabled + start_point, end_point, needs_retraction, could_be_wipe_disabled )}; needs_retraction = this->needs_retraction(xy_path, role); @@ -3353,12 +3352,12 @@ std::string GCodeGenerator::travel_to(const Point &point, ExtrusionRole role, st m_wipe.reset_path(); } - Point position_before_wipe{this->last_pos()}; + Point position_before_wipe{*this->last_position}; wipe_retract_gcode = this->retract_and_wipe(); - if (this->last_pos() != position_before_wipe) { + if (*this->last_position != position_before_wipe) { xy_path = generate_travel_xy_path( - this->last_pos(), point, needs_retraction, could_be_wipe_disabled + *this->last_position, end_point, needs_retraction, could_be_wipe_disabled ); } } else { @@ -3522,7 +3521,7 @@ std::string GCodeGenerator::set_extruder(unsigned int extruder_id, double print_ gcode += m_ooze_prevention.post_toolchange(*this); // The position is now known after the tool change. - this->m_last_pos_defined = false; + this->last_position = std::nullopt; return gcode; } diff --git a/src/libslic3r/GCode.hpp b/src/libslic3r/GCode.hpp index 92586e8d16..42e0e36647 100644 --- a/src/libslic3r/GCode.hpp +++ b/src/libslic3r/GCode.hpp @@ -103,7 +103,6 @@ public: m_layer(nullptr), m_object_layer_over_raft(false), m_volumetric_speed(0), - m_last_pos_defined(false), m_last_extrusion_role(GCodeExtrusionRole::None), m_last_width(0.0f), #if ENABLE_GCODE_VIEWER_DATA_CHECKING @@ -124,7 +123,6 @@ public: const Vec2d& origin() const { return m_origin; } void set_origin(const Vec2d &pointf); void set_origin(const coordf_t x, const coordf_t y) { this->set_origin(Vec2d(x, y)); } - const Point& last_pos() const { return m_last_pos; } // Convert coordinates of the active object to G-code coordinates, possibly adjusted for extruder offset. template Eigen::Matrix point_to_gcode(const Eigen::MatrixBase &point) const { @@ -186,6 +184,8 @@ public: }; using ObjectsLayerToPrint = std::vector; + std::optional last_position; + private: class GCodeOutputStream { public: @@ -266,8 +266,6 @@ private: const GCode::SmoothPathCache &smooth_path_cache_global, GCodeOutputStream &output_stream); - void set_last_pos(const Point &pos) { m_last_pos = pos; m_last_pos_defined = true; } - bool last_pos_defined() const { return m_last_pos_defined; } void set_extruders(const std::vector &extruder_ids); std::string preamble(); std::string change_layer( @@ -332,7 +330,12 @@ private: const bool needs_retraction, bool& could_be_wipe_disabled ); - std::string travel_to(const Point &point, ExtrusionRole role, std::string comment); + std::string travel_to( + const Point &start_point, + const Point &end_point, + ExtrusionRole role, + const std::string &comment + ); bool needs_retraction(const Polyline &travel, ExtrusionRole role = ExtrusionRole::None); std::string retract_and_wipe(bool toolchange = false); @@ -421,8 +424,6 @@ private: double m_last_mm3_per_mm; #endif // ENABLE_GCODE_VIEWER_DATA_CHECKING - Point m_last_pos; - bool m_last_pos_defined; std::optional m_previous_layer_last_position; // This needs to be populated during the layer processing! std::optional m_current_layer_first_position; diff --git a/src/libslic3r/GCode/AvoidCrossingPerimeters.cpp b/src/libslic3r/GCode/AvoidCrossingPerimeters.cpp index 782ebc306f..0b678ae4f7 100644 --- a/src/libslic3r/GCode/AvoidCrossingPerimeters.cpp +++ b/src/libslic3r/GCode/AvoidCrossingPerimeters.cpp @@ -1177,7 +1177,7 @@ Polyline AvoidCrossingPerimeters::travel_to(const GCodeGenerator &gcodegen, cons // Otherwise perform the path planning in the coordinate system of the active object. bool use_external = m_use_external_mp || m_use_external_mp_once; Point scaled_origin = use_external ? Point::new_scale(gcodegen.origin()(0), gcodegen.origin()(1)) : Point(0, 0); - const Point start = gcodegen.last_pos() + scaled_origin; + const Point start = *gcodegen.last_position + scaled_origin; const Point end = point + scaled_origin; const Line travel(start, end); diff --git a/src/libslic3r/GCode/Wipe.cpp b/src/libslic3r/GCode/Wipe.cpp index e75c599297..774512199a 100644 --- a/src/libslic3r/GCode/Wipe.cpp +++ b/src/libslic3r/GCode/Wipe.cpp @@ -164,7 +164,7 @@ std::string Wipe::wipe(GCodeGenerator &gcodegen, bool toolchange) return done; }; // Start with the current position, which may be different from the wipe path start in case of loop clipping. - Vec2d prev = gcodegen.point_to_gcode_quantized(gcodegen.last_pos()); + Vec2d prev = gcodegen.point_to_gcode_quantized(*gcodegen.last_position); auto it = this->path().begin(); Vec2d p = gcodegen.point_to_gcode(it->point + m_offset); ++ it; @@ -192,7 +192,7 @@ std::string Wipe::wipe(GCodeGenerator &gcodegen, bool toolchange) // add tag for processor assert(p == GCodeFormatter::quantize(p)); gcode += ";" + GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Wipe_End) + "\n"; - gcodegen.set_last_pos(gcodegen.gcode_to_point(p)); + gcodegen.last_position = gcodegen.gcode_to_point(p); } } diff --git a/src/libslic3r/GCode/WipeTowerIntegration.cpp b/src/libslic3r/GCode/WipeTowerIntegration.cpp index 04c398e078..3cccbde78d 100644 --- a/src/libslic3r/GCode/WipeTowerIntegration.cpp +++ b/src/libslic3r/GCode/WipeTowerIntegration.cpp @@ -57,22 +57,28 @@ std::string WipeTowerIntegration::append_tcr(GCodeGenerator &gcodegen, const Wip || is_ramming || will_go_down); // don't dig into the print if (should_travel_to_tower) { - const Point xy_point = wipe_tower_point_to_object_point(gcodegen, start_pos); gcode += gcodegen.retract_and_wipe(); gcodegen.m_avoid_crossing_perimeters.use_external_mp_once(); if (gcodegen.m_current_layer_first_position) { - gcode += gcodegen.travel_to( - xy_point, - ExtrusionRole::Mixed, - "Travel to a Wipe Tower"); + const std::string comment{"Travel to a Wipe Tower"}; + if (gcodegen.last_position) { + gcode += gcodegen.travel_to( + *gcodegen.last_position, xy_point, ExtrusionRole::Mixed, comment + ); + } else { + gcode += gcodegen.writer().travel_to_xy(gcodegen.point_to_gcode(xy_point), comment); + gcode += gcodegen.writer().get_travel_to_z_gcode(z, comment); + } } else { const Vec3crd point = to_3d(xy_point, scaled(z)); const Vec3d gcode_point = to_3d(gcodegen.point_to_gcode(point.head<2>()), z); - gcodegen.set_last_pos(point.head<2>()); + gcodegen.last_position = point.head<2>(); gcodegen.writer().update_position(gcode_point); - gcode += gcodegen.writer().get_travel_to_xy_gcode(gcode_point.head<2>(), "move to first layer point"); - gcode += gcodegen.writer().get_travel_to_z_gcode(gcode_point.z(), "move to first layer point"); + gcode += gcodegen.writer() + .get_travel_to_xy_gcode(gcode_point.head<2>(), "move to first layer point"); + gcode += gcodegen.writer() + .get_travel_to_z_gcode(gcode_point.z(), "move to first layer point"); gcodegen.m_current_layer_first_position = gcode_point; } gcode += gcodegen.unretract(); @@ -110,7 +116,7 @@ std::string WipeTowerIntegration::append_tcr(GCodeGenerator &gcodegen, const Wip // A phony move to the end position at the wipe tower. gcodegen.writer().travel_to_xy(end_pos.cast()); - gcodegen.set_last_pos(wipe_tower_point_to_object_point(gcodegen, end_pos)); + gcodegen.last_position = wipe_tower_point_to_object_point(gcodegen, end_pos); if (!is_approx(z, current_z)) { gcode += gcodegen.writer().retract(); gcode += gcodegen.writer().travel_to_z(current_z, "Travel back up to the topmost object layer."); @@ -259,7 +265,7 @@ std::string WipeTowerIntegration::finalize(GCodeGenerator &gcodegen) std::string gcode; if (std::abs(gcodegen.writer().get_position().z() - m_final_purge.print_z) > EPSILON) gcode += gcodegen.generate_travel_gcode( - {{gcodegen.last_pos().x(), gcodegen.last_pos().y(), scaled(m_final_purge.print_z)}}, + {{gcodegen.last_position->x(), gcodegen.last_position->y(), scaled(m_final_purge.print_z)}}, "move to safe place for purging" ); gcode += append_tcr(gcodegen, m_final_purge, -1); From 5858cbf0f71fa6821b3eec33ac378f23a8400e25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hejl?= Date: Fri, 1 Dec 2023 11:22:52 +0100 Subject: [PATCH 61/91] Fix warnings in Travels tests. --- tests/fff_print/test_gcode_travels.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/fff_print/test_gcode_travels.cpp b/tests/fff_print/test_gcode_travels.cpp index a5ec848df5..af947958d2 100644 --- a/tests/fff_print/test_gcode_travels.cpp +++ b/tests/fff_print/test_gcode_travels.cpp @@ -16,8 +16,8 @@ struct ApproxEqualsPoints : public Catch::MatcherBase { const Point& point = points[i]; const Point& expected_point = this->expected[i]; if ( - std::abs(point.x() - expected_point.x()) > this->tolerance - || std::abs(point.y() - expected_point.y()) > this->tolerance + std::abs(point.x() - expected_point.x()) > int(this->tolerance) + || std::abs(point.y() - expected_point.y()) > int(this->tolerance) ) { return false; } @@ -117,10 +117,10 @@ TEST_CASE("Generate elevated travel", "[GCode]") { Points3 result{generate_elevated_travel(xy_path, ensure_points_at_distances, 2.0, [](double x){return 1 + x;})}; CHECK(result == Points3{ - scaled(Vec3f{0, 0, 3.0}), - scaled(Vec3f{0.2, 0, 3.2}), - scaled(Vec3f{0.5, 0, 3.5}), - scaled(Vec3f{1, 0, 4.0}) + scaled(Vec3f{ 0.f, 0.f, 3.f}), + scaled(Vec3f{0.2f, 0.f, 3.2f}), + scaled(Vec3f{0.5f, 0.f, 3.5f}), + scaled(Vec3f{ 1.f, 0.f, 4.f}) }); } From 317db5fab4b62952a477d9bc91e77316d75e0c89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hejl?= Date: Fri, 1 Dec 2023 11:23:30 +0100 Subject: [PATCH 62/91] Move ObjectLayerToPrint from GCodeGenerator to outside to allow using forward declaration. --- src/libslic3r/GCode.hpp | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/src/libslic3r/GCode.hpp b/src/libslic3r/GCode.hpp index 42e0e36647..986cf6d92e 100644 --- a/src/libslic3r/GCode.hpp +++ b/src/libslic3r/GCode.hpp @@ -89,6 +89,21 @@ struct LayerResult { static LayerResult make_nop_layer_result() { return {"", std::numeric_limits::max(), false, false, true}; } }; +namespace GCode { +// Object and support extrusions of the same PrintObject at the same print_z. +// public, so that it could be accessed by free helper functions from GCode.cpp +struct ObjectLayerToPrint +{ + ObjectLayerToPrint() : object_layer(nullptr), support_layer(nullptr) {} + const Layer* object_layer; + const SupportLayer* support_layer; + const Layer* layer() const { return (object_layer != nullptr) ? object_layer : support_layer; } + const PrintObject* object() const { return (this->layer() != nullptr) ? this->layer()->object() : nullptr; } + coordf_t print_z() const { return (object_layer != nullptr && support_layer != nullptr) ? 0.5 * (object_layer->print_z + support_layer->print_z) : this->layer()->print_z; } +}; + +} // namespace GCode + class GCodeGenerator { public: @@ -171,18 +186,8 @@ public: // translate full config into a list of items static void encode_full_config(const Print& print, std::vector>& config); - // Object and support extrusions of the same PrintObject at the same print_z. - // public, so that it could be accessed by free helper functions from GCode.cpp - struct ObjectLayerToPrint - { - ObjectLayerToPrint() : object_layer(nullptr), support_layer(nullptr) {} - const Layer* object_layer; - const SupportLayer* support_layer; - const Layer* layer() const { return (object_layer != nullptr) ? object_layer : support_layer; } - const PrintObject* object() const { return (this->layer() != nullptr) ? this->layer()->object() : nullptr; } - coordf_t print_z() const { return (object_layer != nullptr && support_layer != nullptr) ? 0.5 * (object_layer->print_z + support_layer->print_z) : this->layer()->print_z; } - }; - using ObjectsLayerToPrint = std::vector; + using ObjectLayerToPrint = GCode::ObjectLayerToPrint; + using ObjectsLayerToPrint = std::vector; std::optional last_position; From 1b0ba60280eba992bdb460b98a9699a496e0496d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hejl?= Date: Fri, 1 Dec 2023 11:24:29 +0100 Subject: [PATCH 63/91] Rename m_last_obj_copy to m_current_instance and use struct instead of std::pair. Also, instead of storing the shift of the instance, store the instance index. --- src/libslic3r/GCode.cpp | 6 +++--- src/libslic3r/GCode.hpp | 15 ++++++++++++--- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 5678ce6f78..032f04dfef 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -2422,10 +2422,10 @@ void GCodeGenerator::process_layer_single_object( m_avoid_crossing_perimeters.init_layer(*m_layer); // When starting a new object, use the external motion planner for the first travel move. const Point &offset = print_object.instances()[print_instance.instance_id].shift; - std::pair this_object_copy(&print_object, offset); - if (m_last_obj_copy != this_object_copy) + GCode::PrintObjectInstance next_instance = {&print_object, int(print_instance.instance_id)}; + if (m_current_instance != next_instance) m_avoid_crossing_perimeters.use_external_mp_once(); - m_last_obj_copy = this_object_copy; + m_current_instance = next_instance; this->set_origin(unscale(offset)); gcode += m_label_objects.start_object(print_instance.print_object.instances()[print_instance.instance_id], GCode::LabelObjects::IncludeName::No); } diff --git a/src/libslic3r/GCode.hpp b/src/libslic3r/GCode.hpp index 986cf6d92e..91dc8e75c9 100644 --- a/src/libslic3r/GCode.hpp +++ b/src/libslic3r/GCode.hpp @@ -102,6 +102,15 @@ struct ObjectLayerToPrint coordf_t print_z() const { return (object_layer != nullptr && support_layer != nullptr) ? 0.5 * (object_layer->print_z + support_layer->print_z) : this->layer()->print_z; } }; +struct PrintObjectInstance +{ + const PrintObject *print_object = nullptr; + int instance_idx = -1; + + bool operator==(const PrintObjectInstance &other) const {return print_object == other.print_object && instance_idx == other.instance_idx; } + bool operator!=(const PrintObjectInstance &other) const { return *this == other; } +}; + } // namespace GCode class GCodeGenerator { @@ -126,7 +135,7 @@ public: m_brim_done(false), m_second_layer_things_done(false), m_silent_time_estimator_enabled(false), - m_last_obj_copy(nullptr, Point(std::numeric_limits::max(), std::numeric_limits::max())) + m_current_instance({nullptr, -1}) {} ~GCodeGenerator() = default; @@ -445,8 +454,8 @@ private: bool m_brim_done; // Flag indicating whether the nozzle temperature changes from 1st to 2nd layer were performed. bool m_second_layer_things_done; - // Index of a last object copy extruded. - std::pair m_last_obj_copy; + // Pointer to currently exporting PrintObject and instance index. + GCode::PrintObjectInstance m_current_instance; bool m_silent_time_estimator_enabled; From dbd036976794b8ac2c8ebbe13e0fd9436cd794ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hejl?= Date: Fri, 1 Dec 2023 11:25:17 +0100 Subject: [PATCH 64/91] Use forward declarations in Travel.hpp. --- src/libslic3r/GCode/Travels.cpp | 2 ++ src/libslic3r/GCode/Travels.hpp | 12 +++++++++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/libslic3r/GCode/Travels.cpp b/src/libslic3r/GCode/Travels.cpp index 1253b88845..45b443ce66 100644 --- a/src/libslic3r/GCode/Travels.cpp +++ b/src/libslic3r/GCode/Travels.cpp @@ -1,5 +1,7 @@ #include "Travels.hpp" +#include "libslic3r/PrintConfig.hpp" + namespace Slic3r::GCode::Impl::Travels { ElevatedTravelFormula::ElevatedTravelFormula(const ElevatedTravelParams ¶ms) diff --git a/src/libslic3r/GCode/Travels.hpp b/src/libslic3r/GCode/Travels.hpp index 5ccf30ec2f..bbaccd46ee 100644 --- a/src/libslic3r/GCode/Travels.hpp +++ b/src/libslic3r/GCode/Travels.hpp @@ -13,10 +13,16 @@ #include -#include "libslic3r/Line.hpp" -#include "libslic3r/Point.hpp" #include "libslic3r/AABBTreeLines.hpp" -#include "libslic3r/PrintConfig.hpp" + +// Forward declarations. +namespace Slic3r { +class Point; +class Linef; +class Polyline; +class FullPrintConfig; + +} // namespace Slic3r namespace Slic3r::GCode::Impl::Travels { /** From 2fc9299c65c64d058bb3a7c65b7a263bd1f6f22e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hejl?= Date: Fri, 1 Dec 2023 11:28:45 +0100 Subject: [PATCH 65/91] Use max value of double instead of std::optional in get_first_crossed_line_distance() and get_obstacle_adjusted_slope_end(). --- src/libslic3r/GCode/Travels.cpp | 20 +++++++++----------- src/libslic3r/GCode/Travels.hpp | 2 +- tests/fff_print/test_gcode_travels.cpp | 14 +++++++------- 3 files changed, 17 insertions(+), 19 deletions(-) diff --git a/src/libslic3r/GCode/Travels.cpp b/src/libslic3r/GCode/Travels.cpp index 45b443ce66..1146d096f4 100644 --- a/src/libslic3r/GCode/Travels.cpp +++ b/src/libslic3r/GCode/Travels.cpp @@ -114,13 +114,12 @@ Points3 generate_elevated_travel( return result; } -std::optional get_first_crossed_line_distance( +double get_first_crossed_line_distance( tcb::span xy_path, const AABBTreeLines::LinesDistancer &distancer ) { assert(!xy_path.empty()); - if (xy_path.empty()) { - return {}; - } + if (xy_path.empty()) + return std::numeric_limits::max(); double traversed_distance = 0; for (const Line &line : xy_path) { @@ -139,7 +138,7 @@ std::optional get_first_crossed_line_distance( traversed_distance += (unscaled_line.a - unscaled_line.b).norm(); } - return {}; + return std::numeric_limits::max(); } struct SmoothingParams @@ -222,15 +221,14 @@ ElevatedTravelParams get_elevated_traval_params( elevation_params.slope_end = elevation_params.lift_height / std::tan(slope_rad); } - std::optional obstacle_adjusted_slope_end{ + const double obstacle_adjusted_slope_end{ previous_layer_distancer ? - get_first_crossed_line_distance(xy_path.lines(), *previous_layer_distancer) : - std::nullopt + get_first_crossed_line_distance(xy_path.lines(), *previous_layer_distancer) : + std::numeric_limits::max() }; - if (obstacle_adjusted_slope_end && obstacle_adjusted_slope_end < elevation_params.slope_end) { - elevation_params.slope_end = *obstacle_adjusted_slope_end; - } + if (obstacle_adjusted_slope_end < elevation_params.slope_end) + elevation_params.slope_end = obstacle_adjusted_slope_end; SmoothingParams smoothing_params{get_smoothing_params( elevation_params.lift_height, elevation_params.slope_end, extruder_id, diff --git a/src/libslic3r/GCode/Travels.hpp b/src/libslic3r/GCode/Travels.hpp index bbaccd46ee..c0a9c4442d 100644 --- a/src/libslic3r/GCode/Travels.hpp +++ b/src/libslic3r/GCode/Travels.hpp @@ -141,7 +141,7 @@ Points3 generate_elevated_travel( * * **Ignores intersection with xy_path starting point.** */ -std::optional get_first_crossed_line_distance( +double get_first_crossed_line_distance( tcb::span xy_path, const AABBTreeLines::LinesDistancer &distancer ); diff --git a/tests/fff_print/test_gcode_travels.cpp b/tests/fff_print/test_gcode_travels.cpp index af947958d2..9d43c3f06e 100644 --- a/tests/fff_print/test_gcode_travels.cpp +++ b/tests/fff_print/test_gcode_travels.cpp @@ -171,13 +171,13 @@ TEST_CASE("Get first crossed line distance", "[GCode]") { // Try different cases by skipping lines in the travel. AABBTreeLines::LinesDistancer distancer{std::move(lines)}; - CHECK(*get_first_crossed_line_distance(travel, distancer) == Approx(1)); - CHECK(*get_first_crossed_line_distance(tcb::span{travel}.subspan(1), distancer) == Approx(0.2)); - CHECK(*get_first_crossed_line_distance(tcb::span{travel}.subspan(2), distancer) == Approx(0.5)); - CHECK(*get_first_crossed_line_distance(tcb::span{travel}.subspan(3), distancer) == Approx(1.0)); //Edge case - CHECK(*get_first_crossed_line_distance(tcb::span{travel}.subspan(4), distancer) == Approx(0.7)); - CHECK(*get_first_crossed_line_distance(tcb::span{travel}.subspan(5), distancer) == Approx(1.6)); - CHECK_FALSE(get_first_crossed_line_distance(tcb::span{travel}.subspan(6), distancer)); + CHECK(get_first_crossed_line_distance(travel, distancer) == Approx(1)); + CHECK(get_first_crossed_line_distance(tcb::span{travel}.subspan(1), distancer) == Approx(0.2)); + CHECK(get_first_crossed_line_distance(tcb::span{travel}.subspan(2), distancer) == Approx(0.5)); + CHECK(get_first_crossed_line_distance(tcb::span{travel}.subspan(3), distancer) == Approx(1.0)); //Edge case + CHECK(get_first_crossed_line_distance(tcb::span{travel}.subspan(4), distancer) == Approx(0.7)); + CHECK(get_first_crossed_line_distance(tcb::span{travel}.subspan(5), distancer) == Approx(1.6)); + CHECK(get_first_crossed_line_distance(tcb::span{travel}.subspan(6), distancer) == std::numeric_limits::max()); } From da57489874a3812cbe517f310897c6be8c2b4709 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hejl?= Date: Fri, 1 Dec 2023 11:31:38 +0100 Subject: [PATCH 66/91] Implement lift before obstacles that take into account already extruder extrusions on the current layer. Ignore the first intersection of the travel path with the object from which the travel starts. Created a new class TravelObstacleTracker, for wrapping all data structures related to lift before obstacles. --- src/libslic3r/ExPolygon.hpp | 2 +- src/libslic3r/GCode.cpp | 38 ++--- src/libslic3r/GCode.hpp | 5 +- src/libslic3r/GCode/Travels.cpp | 188 ++++++++++++++++++++++--- src/libslic3r/GCode/Travels.hpp | 86 ++++++++++- src/libslic3r/Line.hpp | 1 + src/slic3r/GUI/Tab.cpp | 6 +- tests/fff_print/test_gcode_travels.cpp | 5 +- 8 files changed, 270 insertions(+), 61 deletions(-) diff --git a/src/libslic3r/ExPolygon.hpp b/src/libslic3r/ExPolygon.hpp index 96c8ac735f..ce6750308a 100644 --- a/src/libslic3r/ExPolygon.hpp +++ b/src/libslic3r/ExPolygon.hpp @@ -446,7 +446,7 @@ inline void expolygons_rotate(ExPolygons &expolys, double angle) expoly.rotate(angle); } -inline bool expolygons_contain(ExPolygons &expolys, const Point &pt, bool border_result = true) +inline bool expolygons_contain(const ExPolygons &expolys, const Point &pt, bool border_result = true) { for (const ExPolygon &expoly : expolys) if (expoly.contains(pt, border_result)) diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 032f04dfef..5f8e5df2b5 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -2060,26 +2060,6 @@ bool GCodeGenerator::line_distancer_is_required(const std::vector& return false; } -namespace GCode::Impl { -AABBTreeLines::LinesDistancer get_previous_layer_distancer( - const GCodeGenerator::ObjectsLayerToPrint& objects_to_print, - const ExPolygons& slices -) { - std::vector lines; - for (const GCodeGenerator::ObjectLayerToPrint &object_to_print : objects_to_print) { - for (const PrintInstance& instance: object_to_print.object()->instances()) { - for (const ExPolygon& polygon : slices) { - for (const Line& line : polygon.lines()) { - lines.emplace_back(unscaled(Point{line.a + instance.shift}), unscaled(Point{line.b + instance.shift})); - } - } - - } - } - return AABBTreeLines::LinesDistancer{std::move(lines)}; -} -} - std::string GCodeGenerator::get_layer_change_gcode(const Vec3d& from, const Vec3d& to, const unsigned extruder_id) { const Polyline xy_path{ this->gcode_to_point(from.head<2>()), @@ -2089,7 +2069,7 @@ std::string GCodeGenerator::get_layer_change_gcode(const Vec3d& from, const Vec3 using namespace GCode::Impl::Travels; ElevatedTravelParams elevation_params{ - get_elevated_traval_params(xy_path, this->m_config, extruder_id)}; + get_elevated_traval_params(xy_path, this->m_config, extruder_id, this->m_travel_obstacle_tracker)}; const double initial_elevation = from.z(); const double z_change = to.z() - from.z(); @@ -2226,9 +2206,9 @@ LayerResult GCodeGenerator::process_layer( } gcode += this->change_layer(previous_layer_z, print_z); // this will increase m_layer_index m_layer = &layer; - if (this->line_distancer_is_required(layer_tools.extruders) && this->m_layer != nullptr && this->m_layer->lower_layer != nullptr) { - this->m_previous_layer_distancer = GCode::Impl::get_previous_layer_distancer(layers, layer.lower_layer->lslices); - } + if (this->line_distancer_is_required(layer_tools.extruders) && this->m_layer != nullptr && this->m_layer->lower_layer != nullptr) + m_travel_obstacle_tracker.init_layer(layer, layers); + m_object_layer_over_raft = false; if (! print.config().layer_gcode.value.empty()) { DynamicConfig config; @@ -2566,9 +2546,11 @@ void GCodeGenerator::process_layer_single_object( init_layer_delayed(); m_config.apply(region.config()); } - for (const ExtrusionEntity *ee : *eec) + for (const ExtrusionEntity *ee : *eec) { // Don't reorder, don't flip. - gcode += this->extrude_entity({ *ee, false }, smooth_path_cache, comment_perimeter, -1.); + gcode += this->extrude_entity({*ee, false}, smooth_path_cache, comment_perimeter, -1.); + m_travel_obstacle_tracker.mark_extruded(ee, print_instance.object_layer_to_print_id, print_instance.instance_id); + } } } }; @@ -3383,10 +3365,10 @@ std::string GCodeGenerator::travel_to( GCode::Impl::Travels::generate_flat_travel(xy_path.points, initial_elevation) : GCode::Impl::Travels::generate_travel_to_extrusion( xy_path, - this->m_config, + m_config, extruder_id, initial_elevation, - this->m_previous_layer_distancer, + m_travel_obstacle_tracker, scaled(m_origin) ) ); diff --git a/src/libslic3r/GCode.hpp b/src/libslic3r/GCode.hpp index 91dc8e75c9..fc63bf2af2 100644 --- a/src/libslic3r/GCode.hpp +++ b/src/libslic3r/GCode.hpp @@ -38,8 +38,9 @@ #include "GCode/WipeTowerIntegration.hpp" #include "GCode/SeamPlacer.hpp" #include "GCode/GCodeProcessor.hpp" -#include "EdgeGrid.hpp" #include "GCode/ThumbnailData.hpp" +#include "GCode/Travels.hpp" +#include "EdgeGrid.hpp" #include "tcbspan/span.hpp" #include @@ -405,6 +406,7 @@ private: AvoidCrossingPerimeters m_avoid_crossing_perimeters; JPSPathFinder m_avoid_crossing_curled_overhangs; RetractWhenCrossingPerimeters m_retract_when_crossing_perimeters; + GCode::TravelObstacleTracker m_travel_obstacle_tracker; bool m_enable_loop_clipping; // If enabled, the G-code generator will put following comments at the ends // of the G-code lines: _EXTRUDE_SET_SPEED, _WIPE, _BRIDGE_FAN_START, _BRIDGE_FAN_END @@ -424,7 +426,6 @@ private: // In non-sequential mode, all its copies will be printed. const Layer* m_layer; // m_layer is an object layer and it is being printed over raft surface. - std::optional> m_previous_layer_distancer; bool m_object_layer_over_raft; double m_volumetric_speed; // Support for the extrusion role markers. Which marker is active? diff --git a/src/libslic3r/GCode/Travels.cpp b/src/libslic3r/GCode/Travels.cpp index 1146d096f4..e1f9ddcd37 100644 --- a/src/libslic3r/GCode/Travels.cpp +++ b/src/libslic3r/GCode/Travels.cpp @@ -1,6 +1,104 @@ #include "Travels.hpp" #include "libslic3r/PrintConfig.hpp" +#include "libslic3r/Layer.hpp" +#include "libslic3r/Print.hpp" + +#include "../GCode.hpp" + +namespace Slic3r::GCode { + +static Lines extrusion_entity_to_lines(const ExtrusionEntity &e_entity) +{ + if (const auto *path = dynamic_cast(&e_entity)) { + return to_lines(path->as_polyline()); + } else if (const auto *multipath = dynamic_cast(&e_entity)) { + return to_lines(multipath->as_polyline()); + } else if (const auto *loop = dynamic_cast(&e_entity)) { + return to_lines(loop->polygon()); + } else { + throw Slic3r::InvalidArgument("Invalid argument supplied to TODO()"); + } + + return {}; +} + +AABBTreeLines::LinesDistancer get_previous_layer_distancer( + const GCodeGenerator::ObjectsLayerToPrint &objects_to_print, const ExPolygons &slices +) { + std::vector lines; + for (const GCodeGenerator::ObjectLayerToPrint &object_to_print : objects_to_print) { + if (const PrintObject *object = object_to_print.object(); object) { + const size_t object_layer_idx = &object_to_print - &objects_to_print.front(); + for (const PrintInstance &instance : object->instances()) { + const size_t instance_idx = &instance - &object->instances().front(); + for (const ExPolygon &polygon : slices) + for (const Line &line : polygon.lines()) + lines.emplace_back(unscaled(Point{line.a + instance.shift}), unscaled(Point{line.b + instance.shift}), object_layer_idx, instance_idx); + } + } + } + + return AABBTreeLines::LinesDistancer{std::move(lines)}; +} + +std::pair, size_t> get_current_layer_distancer(const ObjectsLayerToPrint &objects_to_print) +{ + std::vector lines; + size_t extrusion_entity_cnt = 0; + for (const ObjectLayerToPrint &object_to_print : objects_to_print) { + const size_t object_layer_idx = &object_to_print - &objects_to_print.front(); + if (const Layer *layer = object_to_print.object_layer; layer) { + for (const PrintInstance &instance : layer->object()->instances()) { + const size_t instance_idx = &instance - &layer->object()->instances().front(); + for (const LayerSlice &lslice : layer->lslices_ex) { + for (const LayerIsland &island : lslice.islands) { + const LayerRegion &layerm = *layer->get_region(island.perimeters.region()); + for (uint32_t perimeter_id : island.perimeters) { + assert(dynamic_cast(layerm.perimeters().entities[perimeter_id])); + const auto *eec = static_cast(layerm.perimeters().entities[perimeter_id]); + for (const ExtrusionEntity *ee : *eec) { + if (ee->role().is_external_perimeter()) { + for (const Line &line : extrusion_entity_to_lines(*ee)) + lines.emplace_back(unscaled(Point{line.a + instance.shift}), unscaled(Point{line.b + instance.shift}), object_layer_idx, instance_idx, ee); + } + + ++extrusion_entity_cnt; + } + } + } + } + } + } + } + + return {AABBTreeLines::LinesDistancer{std::move(lines)}, extrusion_entity_cnt}; +} + +void TravelObstacleTracker::init_layer(const Layer &layer, const ObjectsLayerToPrint &objects_to_print) +{ + size_t extrusion_entity_cnt = 0; + m_extruded_extrusion.clear(); + + m_objects_to_print = objects_to_print; + m_previous_layer_distancer = get_previous_layer_distancer(m_objects_to_print, layer.lower_layer->lslices); + + std::tie(m_current_layer_distancer, extrusion_entity_cnt) = get_current_layer_distancer(m_objects_to_print); + m_extruded_extrusion.reserve(extrusion_entity_cnt); +} + +void TravelObstacleTracker::mark_extruded(const ExtrusionEntity *extrusion_entity, size_t object_layer_idx, size_t instance_idx) +{ + if (extrusion_entity->role().is_external_perimeter()) + this->m_extruded_extrusion.insert({int(object_layer_idx), int(instance_idx), extrusion_entity}); +} + +bool TravelObstacleTracker::is_extruded(const ObjectOrExtrusionLinef &line) const +{ + return m_extruded_extrusion.find({line.object_layer_idx, line.instance_idx, line.extrusion_entity}) != m_extruded_extrusion.end(); +} + +} // namespace Slic3r::GCode namespace Slic3r::GCode::Impl::Travels { @@ -114,33 +212,86 @@ Points3 generate_elevated_travel( return result; } +struct Intersection +{ + int object_layer_idx = -1; + int instance_idx = -1; + bool is_inside = false; + + bool is_print_instance_equal(const ObjectOrExtrusionLinef &print_istance) { + return this->object_layer_idx == print_istance.object_layer_idx && this->instance_idx == print_istance.instance_idx; + } +}; + double get_first_crossed_line_distance( - tcb::span xy_path, const AABBTreeLines::LinesDistancer &distancer + tcb::span xy_path, + const AABBTreeLines::LinesDistancer &distancer, + const ObjectsLayerToPrint &objects_to_print, + const std::function &predicate, + const bool ignore_starting_object_intersection ) { assert(!xy_path.empty()); if (xy_path.empty()) return std::numeric_limits::max(); + const Point path_first_point = xy_path.front().a; double traversed_distance = 0; + bool skip_intersection = ignore_starting_object_intersection; + Intersection first_intersection; + for (const Line &line : xy_path) { - const Linef unscaled_line = {unscaled(line.a), unscaled(line.b)}; - auto intersections = distancer.intersections_with_line(unscaled_line); - if (!intersections.empty()) { - const Vec2d intersection = intersections.front().first; - const double distance = traversed_distance + (unscaled_line.a - intersection).norm(); - if (distance > EPSILON) { - return distance; - } else if (intersections.size() >= 2) { // Edge case - const Vec2d second_intersection = intersections[1].first; - return traversed_distance + (unscaled_line.a - second_intersection).norm(); - } + const ObjectOrExtrusionLinef unscaled_line = {unscaled(line.a), unscaled(line.b)}; + const std::vector> intersections = distancer.intersections_with_line(unscaled_line); + + if (intersections.empty()) + continue; + + if (!objects_to_print.empty() && ignore_starting_object_intersection && first_intersection.object_layer_idx == -1) { + const ObjectOrExtrusionLinef &intersection_line = distancer.get_line(intersections.front().second); + const Point shift = objects_to_print[intersection_line.object_layer_idx].layer()->object()->instances()[intersection_line.instance_idx].shift; + const Point shifted_first_point = path_first_point - shift; + const bool contain_first_point = expolygons_contain(objects_to_print[intersection_line.object_layer_idx].layer()->lslices, shifted_first_point); + + first_intersection = {intersection_line.object_layer_idx, intersection_line.instance_idx, contain_first_point}; } + + for (const auto &intersection : intersections) { + const ObjectOrExtrusionLinef &intersection_line = distancer.get_line(intersection.second); + const double distance = traversed_distance + (unscaled_line.a - intersection.first).norm(); + if (distance <= EPSILON) + continue; + + // There is only one external border for each object, so when we cross this border, + // we definitely know that we are outside the object. + if (skip_intersection && first_intersection.is_print_instance_equal(intersection_line) && first_intersection.is_inside) { + skip_intersection = false; + continue; + } + + if (!predicate(intersection_line)) + continue; + + return distance; + } + traversed_distance += (unscaled_line.a - unscaled_line.b).norm(); } return std::numeric_limits::max(); } +double get_obstacle_adjusted_slope_end(const Lines &xy_path, const GCode::TravelObstacleTracker &obstacle_tracker) { + const double previous_layer_crossed_line = get_first_crossed_line_distance( + xy_path, obstacle_tracker.previous_layer_distancer(), obstacle_tracker.objects_to_print() + ); + const double current_layer_crossed_line = get_first_crossed_line_distance( + xy_path, obstacle_tracker.current_layer_distancer(), obstacle_tracker.objects_to_print(), + [&obstacle_tracker](const ObjectOrExtrusionLinef &line) { return obstacle_tracker.is_extruded(line); } + ); + + return std::min(previous_layer_crossed_line, current_layer_crossed_line); +} + struct SmoothingParams { double blend_width{}; @@ -201,7 +352,7 @@ ElevatedTravelParams get_elevated_traval_params( const Polyline& xy_path, const FullPrintConfig &config, const unsigned extruder_id, - const std::optional> &previous_layer_distancer + const GCode::TravelObstacleTracker &obstacle_tracker ) { ElevatedTravelParams elevation_params{}; if (!config.travel_ramping_lift.get_at(extruder_id)) { @@ -221,12 +372,7 @@ ElevatedTravelParams get_elevated_traval_params( elevation_params.slope_end = elevation_params.lift_height / std::tan(slope_rad); } - const double obstacle_adjusted_slope_end{ - previous_layer_distancer ? - get_first_crossed_line_distance(xy_path.lines(), *previous_layer_distancer) : - std::numeric_limits::max() - }; - + const double obstacle_adjusted_slope_end = get_obstacle_adjusted_slope_end(xy_path.lines(), obstacle_tracker); if (obstacle_adjusted_slope_end < elevation_params.slope_end) elevation_params.slope_end = obstacle_adjusted_slope_end; @@ -263,7 +409,7 @@ Points3 generate_travel_to_extrusion( const FullPrintConfig &config, const unsigned extruder_id, const double initial_elevation, - const std::optional> &previous_layer_distancer, + const GCode::TravelObstacleTracker &obstacle_tracker, const Point &xy_path_coord_origin ) { const double upper_limit = config.retract_lift_below.get_at(extruder_id); @@ -279,7 +425,7 @@ Points3 generate_travel_to_extrusion( } ElevatedTravelParams elevation_params{get_elevated_traval_params( - Polyline{std::move(global_xy_path)}, config, extruder_id, previous_layer_distancer + Polyline{std::move(global_xy_path)}, config, extruder_id, obstacle_tracker )}; const std::vector ensure_points_at_distances = linspace( diff --git a/src/libslic3r/GCode/Travels.hpp b/src/libslic3r/GCode/Travels.hpp index c0a9c4442d..7f7c017840 100644 --- a/src/libslic3r/GCode/Travels.hpp +++ b/src/libslic3r/GCode/Travels.hpp @@ -11,19 +11,91 @@ #include #include +#include #include #include "libslic3r/AABBTreeLines.hpp" // Forward declarations. namespace Slic3r { +class Layer; class Point; class Linef; class Polyline; class FullPrintConfig; +class ExtrusionEntity; } // namespace Slic3r +namespace Slic3r::GCode { +struct ObjectLayerToPrint; +using ObjectsLayerToPrint = std::vector; + +class ObjectOrExtrusionLinef : public Linef +{ +public: + ObjectOrExtrusionLinef() = delete; + ObjectOrExtrusionLinef(const Vec2d &a, const Vec2d &b) : Linef(a, b) {} + explicit ObjectOrExtrusionLinef(const Vec2d &a, const Vec2d &b, size_t object_layer_idx, size_t instance_idx) + : Linef(a, b), object_layer_idx(int(object_layer_idx)), instance_idx(int(instance_idx)) {} + ObjectOrExtrusionLinef(const Vec2d &a, const Vec2d &b, size_t object_layer_idx, size_t instance_idx, const ExtrusionEntity *extrusion_entity) + : Linef(a, b), object_layer_idx(int(object_layer_idx)), instance_idx(int(instance_idx)), extrusion_entity(extrusion_entity) {} + + virtual ~ObjectOrExtrusionLinef() = default; + + const int object_layer_idx = -1; + const int instance_idx = -1; + const ExtrusionEntity *extrusion_entity = nullptr; +}; + +struct ExtrudedExtrusionEntity +{ + const int object_layer_idx = -1; + const int instance_idx = -1; + const ExtrusionEntity *extrusion_entity = nullptr; + + bool operator==(const ExtrudedExtrusionEntity &other) const + { + return extrusion_entity == other.extrusion_entity && object_layer_idx == other.object_layer_idx && + instance_idx == other.instance_idx; + } +}; + +struct ExtrudedExtrusionEntityHash +{ + size_t operator()(const ExtrudedExtrusionEntity &eee) const noexcept + { + std::size_t seed = std::hash{}(eee.extrusion_entity); + boost::hash_combine(seed, std::hash{}(eee.object_layer_idx)); + boost::hash_combine(seed, std::hash{}(eee.instance_idx)); + return seed; + } +}; + +class TravelObstacleTracker +{ +public: + void init_layer(const Layer &layer, const ObjectsLayerToPrint &objects_to_print); + + void mark_extruded(const ExtrusionEntity *extrusion_entity, size_t object_layer_idx, size_t instance_idx); + + bool is_extruded(const ObjectOrExtrusionLinef &line) const; + + const AABBTreeLines::LinesDistancer &previous_layer_distancer() const { return m_previous_layer_distancer; } + + const AABBTreeLines::LinesDistancer ¤t_layer_distancer() const { return m_current_layer_distancer; } + + const ObjectsLayerToPrint &objects_to_print() const { return m_objects_to_print; } + +private: + ObjectsLayerToPrint m_objects_to_print; + AABBTreeLines::LinesDistancer m_previous_layer_distancer; + + AABBTreeLines::LinesDistancer m_current_layer_distancer; + std::unordered_set m_extruded_extrusion; +}; +} // namespace Slic3r::GCode + namespace Slic3r::GCode::Impl::Travels { /** * @brief A point on a curve with a distance from start. @@ -106,7 +178,7 @@ ElevatedTravelParams get_elevated_traval_params( const Polyline& xy_path, const FullPrintConfig &config, const unsigned extruder_id, - const std::optional> &previous_layer_distancer = std::nullopt + const GCode::TravelObstacleTracker &obstacle_tracker ); /** @@ -137,13 +209,19 @@ Points3 generate_elevated_travel( * * @param xy_path A path in 2D. * @param distancer AABB Tree over lines. + * @param objects_to_print Objects to print are used to determine in which object xy_path starts. + + * @param ignore_starting_object_intersection When it is true, then the first intersection during traveling from the object out is ignored. * @return Distance to the first intersection if there is one. * * **Ignores intersection with xy_path starting point.** */ double get_first_crossed_line_distance( - tcb::span xy_path, const AABBTreeLines::LinesDistancer &distancer -); + tcb::span xy_path, + const AABBTreeLines::LinesDistancer &distancer, + const ObjectsLayerToPrint &objects_to_print = {}, + const std::function &predicate = [](const ObjectOrExtrusionLinef &) { return true; }, + bool ignore_starting_object_intersection = true); /** * @brief Extract parameters and decide wheather the travel can be elevated. @@ -154,7 +232,7 @@ Points3 generate_travel_to_extrusion( const FullPrintConfig &config, const unsigned extruder_id, const double initial_elevation, - const std::optional> &previous_layer_distancer, + const GCode::TravelObstacleTracker &obstacle_tracker, const Point &xy_path_coord_origin ); } // namespace Slic3r::GCode::Impl::Travels diff --git a/src/libslic3r/Line.hpp b/src/libslic3r/Line.hpp index e3b1c81183..fdbac86a33 100644 --- a/src/libslic3r/Line.hpp +++ b/src/libslic3r/Line.hpp @@ -280,6 +280,7 @@ class Linef public: Linef() : a(Vec2d::Zero()), b(Vec2d::Zero()) {} Linef(const Vec2d& _a, const Vec2d& _b) : a(_a), b(_b) {} + virtual ~Linef() = default; Vec2d a; Vec2d b; diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index fe15f36aea..47aeeff75f 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -1966,7 +1966,7 @@ std::vector>> option_keys { "filament_travel_ramping_lift", "filament_travel_max_lift", "filament_travel_slope", - //"filament_travel_lift_before_obstacle", + "filament_travel_lift_before_obstacle", "filament_retract_lift_above", "filament_retract_lift_below" }}, @@ -3283,7 +3283,7 @@ void TabPrinter::build_extruder_pages(size_t n_before_extruders) optgroup->append_single_option_line("travel_ramping_lift", "", extruder_idx); optgroup->append_single_option_line("travel_max_lift", "", extruder_idx); optgroup->append_single_option_line("travel_slope", "", extruder_idx); - //optgroup->append_single_option_line("travel_lift_before_obstacle", "", extruder_idx); + optgroup->append_single_option_line("travel_lift_before_obstacle", "", extruder_idx); line = { L("Only lift"), "" }; line.append_option(optgroup->get_option("retract_lift_above", extruder_idx)); @@ -3557,7 +3557,7 @@ void TabPrinter::toggle_options() load_config(new_conf); } - //toggle_option("travel_lift_before_obstacle", ramping_lift, i); + toggle_option("travel_lift_before_obstacle", ramping_lift, i); toggle_option("retract_length_toolchange", have_multiple_extruders, i); diff --git a/tests/fff_print/test_gcode_travels.cpp b/tests/fff_print/test_gcode_travels.cpp index 9d43c3f06e..895c415c86 100644 --- a/tests/fff_print/test_gcode_travels.cpp +++ b/tests/fff_print/test_gcode_travels.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include using namespace Slic3r; @@ -162,14 +163,14 @@ TEST_CASE("Get first crossed line distance", "[GCode]") { scaled(Vec2f{0, 5}), }.lines()}; - std::vector lines; + std::vector lines; for (const ExPolygon& polygon : {square_with_hole, square_above}) { for (const Line& line : polygon.lines()) { lines.emplace_back(unscale(line.a), unscale(line.b)); } } // Try different cases by skipping lines in the travel. - AABBTreeLines::LinesDistancer distancer{std::move(lines)}; + AABBTreeLines::LinesDistancer distancer{std::move(lines)}; CHECK(get_first_crossed_line_distance(travel, distancer) == Approx(1)); CHECK(get_first_crossed_line_distance(tcb::span{travel}.subspan(1), distancer) == Approx(0.2)); From 5ddcea806b6761c2ec153705d19294a1e682300c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hejl?= Date: Tue, 9 Jan 2024 10:53:43 +0100 Subject: [PATCH 67/91] Add to GCodeGenerator::last_position only when it has an assigned value. This behavior was there for a long time, but it was uncovered when std::optional was used. --- src/libslic3r/GCode.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 5f8e5df2b5..ff7b341807 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -2641,7 +2641,9 @@ void GCodeGenerator::set_origin(const Vec2d &pointf) { // if origin increases (goes towards right), last_pos decreases because it goes towards left const auto offset = Point::new_scale(m_origin - pointf); - *(this->last_position) += offset; + if (last_position.has_value()) + *(this->last_position) += offset; + m_wipe.offset_path(offset); m_origin = pointf; } From f9283728d693840abe19335601ab2e4f5fb79b10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20=C5=A0ach?= Date: Mon, 8 Jan 2024 14:45:37 +0100 Subject: [PATCH 68/91] During first layer change, do not actually move z. This enables the user to set his own z in start gcode. Fixes #11843. --- src/libslic3r/GCode.cpp | 22 ++++++++++++-------- src/libslic3r/GCode/WipeTowerIntegration.cpp | 8 +++---- src/libslic3r/GCode/WipeTowerIntegration.hpp | 5 +++-- tests/fff_print/test_cooling.cpp | 6 +++--- tests/fff_print/test_custom_gcode.cpp | 14 ++++++++++--- 5 files changed, 34 insertions(+), 21 deletions(-) diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index ff7b341807..9061d8bc27 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -1249,7 +1249,12 @@ void GCodeGenerator::_do_export(Print& print, GCodeOutputStream &file, Thumbnail // Prusa Multi-Material wipe tower. if (has_wipe_tower && ! layers_to_print.empty()) { m_wipe_tower = std::make_unique(print.config(), *print.wipe_tower_data().priming.get(), print.wipe_tower_data().tool_changes, *print.wipe_tower_data().final_purge.get()); - file.write(m_writer.travel_to_z(first_layer_height + m_config.z_offset.value, "Move to the first layer height")); + + // Set position for wipe tower generation. + Vec3d new_position = this->writer().get_position(); + new_position.z() = first_layer_height + m_config.z_offset.value; + this->writer().update_position(new_position); + if (print.config().single_extruder_multi_material_priming) { file.write(m_wipe_tower->prime(*this)); // Verify, whether the print overaps the priming extrusions. @@ -2195,7 +2200,7 @@ LayerResult GCodeGenerator::process_layer( m_current_layer_first_position = std::nullopt; // Set new layer - this will change Z and force a retraction if retract_layer_change is enabled. - if (! print.config().before_layer_gcode.value.empty()) { + if (!first_layer && ! print.config().before_layer_gcode.value.empty()) { DynamicConfig config; config.set_key_value("layer_num", new ConfigOptionInt(m_layer_index + 1)); config.set_key_value("layer_z", new ConfigOptionFloat(print_z)); @@ -2210,7 +2215,7 @@ LayerResult GCodeGenerator::process_layer( m_travel_obstacle_tracker.init_layer(layer, layers); m_object_layer_over_raft = false; - if (! print.config().layer_gcode.value.empty()) { + if (!first_layer && ! print.config().layer_gcode.value.empty()) { DynamicConfig config; config.set_key_value("layer_num", new ConfigOptionInt(m_layer_index)); config.set_key_value("layer_z", new ConfigOptionFloat(print_z)); @@ -2346,13 +2351,12 @@ LayerResult GCodeGenerator::process_layer( && EXTRUDER_CONFIG(travel_ramping_lift) && EXTRUDER_CONFIG(travel_slope) > 0 && EXTRUDER_CONFIG(travel_slope) < 90 ); - if (do_ramping_layer_change) { + if (first_layer) { + layer_change_gcode = ""; // Explicit for readability. + } else if (do_ramping_layer_change) { layer_change_gcode = this->get_layer_change_gcode(*m_previous_layer_last_position, *m_current_layer_first_position, *m_layer_change_extruder_id); } else { - if (!m_current_layer_first_position) { - throw std::runtime_error("Destination is required for layer change!"); - } - layer_change_gcode = this->writer().get_travel_to_z_gcode(m_current_layer_first_position->z(), "simple layer change"); + layer_change_gcode = this->writer().get_travel_to_z_gcode(m_config.z_offset.value + print_z, "simple layer change"); } boost::algorithm::replace_first(gcode, tag, layer_change_gcode); @@ -2675,7 +2679,7 @@ std::string GCodeGenerator::change_layer( gcode += this->retract_and_wipe(); Vec3d new_position = this->writer().get_position(); - new_position.z() = print_z; + new_position.z() = print_z + m_config.z_offset.value; this->writer().update_position(new_position); m_previous_layer_last_position = this->last_position ? diff --git a/src/libslic3r/GCode/WipeTowerIntegration.cpp b/src/libslic3r/GCode/WipeTowerIntegration.cpp index 3cccbde78d..56c2f4af93 100644 --- a/src/libslic3r/GCode/WipeTowerIntegration.cpp +++ b/src/libslic3r/GCode/WipeTowerIntegration.cpp @@ -60,8 +60,8 @@ std::string WipeTowerIntegration::append_tcr(GCodeGenerator &gcodegen, const Wip const Point xy_point = wipe_tower_point_to_object_point(gcodegen, start_pos); gcode += gcodegen.retract_and_wipe(); gcodegen.m_avoid_crossing_perimeters.use_external_mp_once(); + const std::string comment{"Travel to a Wipe Tower"}; if (gcodegen.m_current_layer_first_position) { - const std::string comment{"Travel to a Wipe Tower"}; if (gcodegen.last_position) { gcode += gcodegen.travel_to( *gcodegen.last_position, xy_point, ExtrusionRole::Mixed, comment @@ -72,13 +72,13 @@ std::string WipeTowerIntegration::append_tcr(GCodeGenerator &gcodegen, const Wip } } else { const Vec3crd point = to_3d(xy_point, scaled(z)); - const Vec3d gcode_point = to_3d(gcodegen.point_to_gcode(point.head<2>()), z); + const Vec3d gcode_point = gcodegen.point_to_gcode(point); gcodegen.last_position = point.head<2>(); gcodegen.writer().update_position(gcode_point); gcode += gcodegen.writer() - .get_travel_to_xy_gcode(gcode_point.head<2>(), "move to first layer point"); + .get_travel_to_xy_gcode(gcode_point.head<2>(), comment); gcode += gcodegen.writer() - .get_travel_to_z_gcode(gcode_point.z(), "move to first layer point"); + .get_travel_to_z_gcode(gcode_point.z(), comment); gcodegen.m_current_layer_first_position = gcode_point; } gcode += gcodegen.unretract(); diff --git a/src/libslic3r/GCode/WipeTowerIntegration.hpp b/src/libslic3r/GCode/WipeTowerIntegration.hpp index 52b27625bb..231e6659c6 100644 --- a/src/libslic3r/GCode/WipeTowerIntegration.hpp +++ b/src/libslic3r/GCode/WipeTowerIntegration.hpp @@ -26,7 +26,8 @@ public: m_tool_changes(tool_changes), m_final_purge(final_purge), m_layer_idx(-1), - m_tool_change_idx(0) + m_tool_change_idx(0), + m_last_wipe_tower_print_z(print_config.z_offset.value) {} std::string prime(GCodeGenerator &gcodegen); @@ -56,7 +57,7 @@ private: // Current layer index. int m_layer_idx; int m_tool_change_idx; - double m_last_wipe_tower_print_z = 0.f; + double m_last_wipe_tower_print_z; }; } // namespace GCode diff --git a/tests/fff_print/test_cooling.cpp b/tests/fff_print/test_cooling.cpp index 1f560d53f0..187d7f4394 100644 --- a/tests/fff_print/test_cooling.cpp +++ b/tests/fff_print/test_cooling.cpp @@ -250,9 +250,9 @@ SCENARIO("Cooling integration tests", "[Cooling]") { if (l == 0) l = line.dist_Z(self); if (l > 0.) { - if (layer_times.empty()) - layer_times.emplace_back(0.); - layer_times.back() += 60. * std::abs(l) / line.new_F(self); + if (!layer_times.empty()) { // Ignore anything before first z move. + layer_times.back() += 60. * std::abs(l) / line.new_F(self); + } } if (line.has('F') && line.f() == external_perimeter_speed) ++ layer_external[scaled(self.z())]; diff --git a/tests/fff_print/test_custom_gcode.cpp b/tests/fff_print/test_custom_gcode.cpp index 0d109070bf..2dd97e9c35 100644 --- a/tests/fff_print/test_custom_gcode.cpp +++ b/tests/fff_print/test_custom_gcode.cpp @@ -45,13 +45,21 @@ SCENARIO("Custom G-code", "[CustomGCode]") }); GCodeReader parser; bool last_move_was_z_change = false; + bool first_z_move = true; // First z move is not a layer change. int num_layer_changes_not_applied = 0; parser.parse_buffer(Slic3r::Test::slice({ Test::TestMesh::cube_2x20x10 }, config), - [&last_move_was_z_change, &num_layer_changes_not_applied](Slic3r::GCodeReader &self, const Slic3r::GCodeReader::GCodeLine &line) + [&](Slic3r::GCodeReader &self, const Slic3r::GCodeReader::GCodeLine &line) { - if (last_move_was_z_change != line.cmd_is("_MY_CUSTOM_LAYER_GCODE_")) + if (last_move_was_z_change != line.cmd_is("_MY_CUSTOM_LAYER_GCODE_")) { ++ num_layer_changes_not_applied; - last_move_was_z_change = line.dist_Z(self) > 0; + } + if (line.dist_Z(self) > 0 && first_z_move) { + first_z_move = false; + } else if (line.dist_Z(self) > 0){ + last_move_was_z_change = true; + } else { + last_move_was_z_change = false; + } }); THEN("custom layer G-code is applied after Z move and before other moves") { REQUIRE(num_layer_changes_not_applied == 0); From 97ba0fb478ef80c1a9920dd30854d16b3b32c254 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20=C5=A0ach?= Date: Wed, 17 Jan 2024 13:09:26 +0100 Subject: [PATCH 69/91] Fix retraction test --- tests/fff_print/test_retraction.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/fff_print/test_retraction.cpp b/tests/fff_print/test_retraction.cpp index 0c7d42a766..a9951925c9 100644 --- a/tests/fff_print/test_retraction.cpp +++ b/tests/fff_print/test_retraction.cpp @@ -147,6 +147,7 @@ TEST_CASE("Slicing with retraction and lifing", "[retraction]") { { "start_gcode", "" }, // To avoid dealing with the nozzle lift in start G-code { "retract_length", "1.5" }, { "retract_before_travel", "3" }, + { "retract_layer_change", "1" }, { "only_retract_when_crossing_perimeters", 0 }, }); From d110541e12040ab11f6a2d300c331135dd945ff5 Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Mon, 4 Dec 2023 11:16:35 +0100 Subject: [PATCH 70/91] Fixing issue with aligning to unprintable objects when doing shift+a --- src/libslic3r/Arrange/Tasks/ArrangeTaskImpl.hpp | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/src/libslic3r/Arrange/Tasks/ArrangeTaskImpl.hpp b/src/libslic3r/Arrange/Tasks/ArrangeTaskImpl.hpp index 4344bdc8d4..aedc8fb71b 100644 --- a/src/libslic3r/Arrange/Tasks/ArrangeTaskImpl.hpp +++ b/src/libslic3r/Arrange/Tasks/ArrangeTaskImpl.hpp @@ -118,21 +118,13 @@ ArrangeTask::process_native(Ctl &ctl) } subctl{ctl, *this}; - auto fixed_items = printable.unselected; - - // static (unselected) unprintable objects should not be overlapped by - // movable and printable objects - std::copy(unprintable.unselected.begin(), - unprintable.unselected.end(), - std::back_inserter(fixed_items)); - - arranger->arrange(printable.selected, fixed_items, bed, subctl); + arranger->arrange(printable.selected, printable.unselected, bed, subctl); std::vector printable_bed_indices = get_bed_indices(crange(printable.selected), crange(printable.unselected)); // If there are no printables, leave the physical bed empty - constexpr int SearchFrom = 1; + static constexpr int SearchFrom = 1; // Unprintable items should go to the first logical (!) bed not containing // any printable items From e24be7891e55b4e509720815fdb3afcfa8e0cf0b Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Wed, 17 Jan 2024 14:41:42 +0100 Subject: [PATCH 71/91] FIxed the issue but TMArrangeKernel needed changes fixing object function not favoring existing pile to stick to Trying to fix problem with shit+arrange not sticking to existing objects --- src/libslic3r/Arrange/Arrange.hpp | 2 +- src/libslic3r/Arrange/ArrangeImpl.hpp | 4 +- src/libslic3r/Arrange/Core/Beds.hpp | 6 ++ .../Core/NFP/Kernels/TMArrangeKernel.hpp | 59 ++++++------------- .../Arrange/SegmentedRectangleBed.hpp | 4 ++ tests/arrange/test_arrange.cpp | 2 +- 6 files changed, 31 insertions(+), 46 deletions(-) diff --git a/src/libslic3r/Arrange/Arrange.hpp b/src/libslic3r/Arrange/Arrange.hpp index 466de153ce..6bf1321e44 100644 --- a/src/libslic3r/Arrange/Arrange.hpp +++ b/src/libslic3r/Arrange/Arrange.hpp @@ -61,7 +61,7 @@ class DefaultArrangerCtl : public Arranger::Ctl { public: DefaultArrangerCtl() = default; - explicit DefaultArrangerCtl(ArrangeTaskBase::Ctl &ctl) : taskctl{&ctl} {} + explicit DefaultArrangerCtl(ArrangeTaskCtl &ctl) : taskctl{&ctl} {} void update_status(int st) override { diff --git a/src/libslic3r/Arrange/ArrangeImpl.hpp b/src/libslic3r/Arrange/ArrangeImpl.hpp index d3cda35e3e..c0e6be35f8 100644 --- a/src/libslic3r/Arrange/ArrangeImpl.hpp +++ b/src/libslic3r/Arrange/ArrangeImpl.hpp @@ -292,7 +292,7 @@ class DefaultArranger: public Arranger { firstfit::SelectionStrategy sel{cmpfn, on_arranged, stop_cond}; - constexpr auto ep = ex_tbb; + constexpr auto ep = ex_seq; VariantKernel basekernel; switch (m_settings.get_arrange_strategy()) { @@ -328,7 +328,7 @@ class DefaultArranger: public Arranger { // a pure RectangleBed with inner-fit polygon calculation. if (!with_wipe_tower && m_settings.get_arrange_strategy() == ArrangeSettingsView::asAuto && - std::is_convertible_v) { + IsRectangular) { PackStrategyNFP base_strategy{std::move(kernel), ep, Accuracy, stop_cond}; RectangleOverfitPackingStrategy final_strategy{std::move(base_strategy)}; diff --git a/src/libslic3r/Arrange/Core/Beds.hpp b/src/libslic3r/Arrange/Core/Beds.hpp index 4f4a41251c..56566a0b40 100644 --- a/src/libslic3r/Arrange/Core/Beds.hpp +++ b/src/libslic3r/Arrange/Core/Beds.hpp @@ -184,6 +184,12 @@ inline ExPolygons to_expolygons(const ArrangeBed &bed) ArrangeBed to_arrange_bed(const Points &bedpts); +template struct IsRectangular_ : public std::false_type {}; +template<> struct IsRectangular_: public std::true_type {}; +template<> struct IsRectangular_: public std::true_type {}; + +template static constexpr bool IsRectangular = IsRectangular_::value; + } // namespace arr2 inline BoundingBox &bounding_box(BoundingBox &bb) { return bb; } diff --git a/src/libslic3r/Arrange/Core/NFP/Kernels/TMArrangeKernel.hpp b/src/libslic3r/Arrange/Core/NFP/Kernels/TMArrangeKernel.hpp index b73327c522..9cab9d5936 100644 --- a/src/libslic3r/Arrange/Core/NFP/Kernels/TMArrangeKernel.hpp +++ b/src/libslic3r/Arrange/Core/NFP/Kernels/TMArrangeKernel.hpp @@ -54,9 +54,9 @@ protected: public: TMArrangeKernel() = default; TMArrangeKernel(Vec2crd gravity_center, size_t itm_cnt, double bedarea = NaNd) - : sink{gravity_center} - , m_bin_area(bedarea) + : m_bin_area(bedarea) , m_item_cnt{itm_cnt} + , sink{gravity_center} {} TMArrangeKernel(size_t itm_cnt, double bedarea = NaNd) @@ -90,18 +90,12 @@ public: // Will hold the resulting score double score = 0; - // Density is the pack density: how big is the arranged pile - double density = 0; - // Distinction of cases for the arrangement scene enum e_cases { // This branch is for big items in a mixed (big and small) scene // OR for all items in a small-only scene. BIG_ITEM, - // This branch is for the last big item in a mixed scene - LAST_BIG_ITEM, - // For small items in a mixed scene. SMALL_ITEM, @@ -112,10 +106,8 @@ public: bool bigitems = is_big(envelope_area(item)) || m_rtree.empty(); if (is_wt) compute_case = WIPE_TOWER; - else if (bigitems && m_rem_cnt > 0) + else if (bigitems) compute_case = BIG_ITEM; - else if (bigitems && m_rem_cnt == 0) - compute_case = LAST_BIG_ITEM; else compute_case = SMALL_ITEM; @@ -132,20 +124,8 @@ public: Point top_left{minc.x(), maxc.y()}; Point bottom_right{maxc.x(), minc.y()}; - // Now the distance of the gravity center will be calculated to the - // five anchor points and the smallest will be chosen. - std::array dists; - auto cc = fullbb.center(); // The gravity center - dists[0] = (minc - cc).cast().norm(); - dists[1] = (maxc - cc).cast().norm(); - dists[2] = (itmcntr - cc).template cast().norm(); - dists[3] = (top_left - cc).cast().norm(); - dists[4] = (bottom_right - cc).cast().norm(); - - // The smalles distance from the arranged pile center: - double dist = norm(*(std::min_element(dists.begin(), dists.end()))); - double bindist = norm((ibb.center() - active_sink).template cast().norm()); - dist = 0.8 * dist + 0.2 * bindist; + // The smallest distance from the arranged pile center: + double dist = norm((itmcntr - m_pilebb.center()).template cast().norm()); // Prepare a variable for the alignment score. // This will indicate: how well is the candidate item @@ -153,7 +133,7 @@ public: // with all neighbors and return the score for the best // alignment. So it is enough for the candidate to be // aligned with only one item. - auto alignment_score = 1.0; + auto alignment_score = 1.; auto query = bgi::intersects(ibb); auto& index = is_big(envelope_area(item)) ? m_rtree : m_smallsrtree; @@ -173,31 +153,23 @@ public: auto bb = p.bb; bb.merge(ibb); auto bbarea = area(bb); - auto ascore = 1.0 - (fixed_area(item) + parea) / bbarea; + auto ascore = 1.0 - (area(fixed_bounding_box(item)) + area(p.bb)) / bbarea; if(ascore < alignment_score) alignment_score = ascore; } } - auto fullbbsz = fullbb.size(); - density = std::sqrt(norm(fullbbsz.x()) * norm(fullbbsz.y())); double R = double(m_rem_cnt) / (m_item_cnt); + R = std::pow(R, 1./3.); // The final mix of the score is the balance between the // distance from the full pile center, the pack density and // the alignment with the neighbors - if (result.empty()) - score = 0.50 * dist + 0.50 * density; - else - // Let the density matter more when fewer objects remain - score = 0.50 * dist + (1.0 - R) * 0.20 * density + - 0.30 * alignment_score; - break; - } - case LAST_BIG_ITEM: { - score = norm((itmcntr - m_pilebb.center()).template cast().norm()); + // Let the density matter more when fewer objects remain + score = 0.6 * dist + 0.1 * alignment_score + (1.0 - R) * (0.3 * dist) + R * 0.3 * alignment_score; + break; } case SMALL_ITEM: { @@ -239,8 +211,11 @@ public: if (m_item_cnt == 0) m_item_cnt = m_rem_cnt + fixed.size() + 1; - if (std::isnan(m_bin_area)) - m_bin_area = area(bed); + if (std::isnan(m_bin_area)) { + auto sz = bounding_box(bed).size(); + + m_bin_area = scaled(unscaled(sz.x()) * unscaled(sz.y())); + } m_norm = std::sqrt(m_bin_area); @@ -248,7 +223,7 @@ public: m_itemstats.reserve(fixed.size()); m_rtree.clear(); m_smallsrtree.clear(); - m_pilebb = {}; + m_pilebb = {active_sink, active_sink}; unsigned idx = 0; for (auto &fixitem : fixed) { auto fixitmbb = fixed_bounding_box(fixitem); diff --git a/src/libslic3r/Arrange/SegmentedRectangleBed.hpp b/src/libslic3r/Arrange/SegmentedRectangleBed.hpp index cc8594ddc7..08778911af 100644 --- a/src/libslic3r/Arrange/SegmentedRectangleBed.hpp +++ b/src/libslic3r/Arrange/SegmentedRectangleBed.hpp @@ -104,6 +104,10 @@ ExPolygons to_expolygons(const SegmentedRectangleBed &bed) return to_expolygons(RectangleBed{bed.bb}); } +template +struct IsRectangular_, void>> : public std::true_type +{}; + }} // namespace Slic3r::arr2 #endif // SEGMENTEDRECTANGLEBED_HPP diff --git a/tests/arrange/test_arrange.cpp b/tests/arrange/test_arrange.cpp index a2eda8c480..b36eac7065 100644 --- a/tests/arrange/test_arrange.cpp +++ b/tests/arrange/test_arrange.cpp @@ -207,7 +207,7 @@ static void check_nfp(const std::string & outfile_prefix, auto orb_ex_offs_pos_r_ch = offset_ex(orb_ex_r_ch, scaled(EPSILON)); auto orb_ex_offs_neg_r_ch = offset_ex(orb_ex_r_ch, -scaled(EPSILON)); - auto bedpoly_offs = offset_ex(bedpoly, SCALED_EPSILON); + auto bedpoly_offs = offset_ex(bedpoly, static_cast(SCALED_EPSILON)); auto check_at_nfppos = [&](const Point &pos) { ExPolygons orb_ex = orb_ex_r; From 906f6053334c487260a311b3e928853afe284d66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20=C5=A0ach?= Date: Wed, 17 Jan 2024 14:43:42 +0100 Subject: [PATCH 72/91] Fix: disable debug and trace logs in builds --- src/libslic3r/utils.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/libslic3r/utils.cpp b/src/libslic3r/utils.cpp index 08f9d430d8..29c9bad1c0 100644 --- a/src/libslic3r/utils.cpp +++ b/src/libslic3r/utils.cpp @@ -123,6 +123,14 @@ unsigned get_logging_level() } } +// Force set_logging_level(<=error) after loading of the DLL. +// This is used ot disable logging for unit and integration tests. +static struct RunOnInit { + RunOnInit() { + set_logging_level(1); + } +} g_RunOnInit; + void enforce_thread_count(const std::size_t count) { // Disable parallelization to simplify debugging. From e46c711fce68fb292b44e3cf8e40251194b8c522 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Thu, 23 Nov 2023 15:54:18 +0100 Subject: [PATCH 73/91] Fix for SPE-2056 : Wrong printer selection when add new logical printer but some physical printer is selected --- src/slic3r/GUI/PresetComboBoxes.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slic3r/GUI/PresetComboBoxes.cpp b/src/slic3r/GUI/PresetComboBoxes.cpp index 224752bdff..c40978b03d 100644 --- a/src/slic3r/GUI/PresetComboBoxes.cpp +++ b/src/slic3r/GUI/PresetComboBoxes.cpp @@ -1169,7 +1169,7 @@ void TabPresetComboBox::update() if (m_type == Preset::TYPE_PRINTER && m_preset_bundle->physical_printers.has_selection()) { std::string sel_preset_name = m_preset_bundle->physical_printers.get_selected_printer_preset_name(); Preset* preset = m_collection->find_preset(sel_preset_name); - if (!preset) + if (!preset || m_collection->get_selected_preset_name() != sel_preset_name) m_preset_bundle->physical_printers.unselect_printer(); } From b0673265ebe4d644a76f1a8d4c8d16362aeb5330 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Tue, 5 Dec 2023 09:51:13 +0100 Subject: [PATCH 74/91] ConfigWizard : Fixed get_preferred_printer_technology() function. This bug was caused a wrong selection of the new added printer, when some new vendor other then PrusaSlicer is added, but PrusaSlicer has installed SLA printers. (see SPE-2056) --- src/slic3r/GUI/ConfigWizard.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slic3r/GUI/ConfigWizard.cpp b/src/slic3r/GUI/ConfigWizard.cpp index 7ab9242aac..41830f8095 100644 --- a/src/slic3r/GUI/ConfigWizard.cpp +++ b/src/slic3r/GUI/ConfigWizard.cpp @@ -3000,7 +3000,7 @@ bool ConfigWizard::priv::apply_config(AppConfig *app_config, PresetBundle *prese } } } - return pt; + return ptAny; }; // Prusa printers are considered first, then 3rd party. if (preferred_pt = get_preferred_printer_technology("PrusaResearch", bundles.prusa_bundle()); From 00a08831a7a50448235d3495d778233716517093 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Wed, 10 Jan 2024 12:28:07 +0100 Subject: [PATCH 75/91] ComboBox: Fix for scrolling over a dropdown. It doesn't need to propagate the MouseWhile event to the parent. --- src/slic3r/GUI/Widgets/ComboBox.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/slic3r/GUI/Widgets/ComboBox.cpp b/src/slic3r/GUI/Widgets/ComboBox.cpp index 055971571a..52f0f6afdf 100644 --- a/src/slic3r/GUI/Widgets/ComboBox.cpp +++ b/src/slic3r/GUI/Widgets/ComboBox.cpp @@ -294,7 +294,6 @@ void ComboBox::mouseDown(wxMouseEvent &event) void ComboBox::mouseWheelMoved(wxMouseEvent &event) { - event.Skip(); if (drop_down) return; auto delta = ((event.GetWheelRotation() < 0) == event.IsWheelInverted()) ? -1 : 1; unsigned int n = GetSelection() + delta; From 6ff8537ff4fbd14ca09934cdb2bb987131a7b559 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Thu, 11 Jan 2024 15:04:07 +0100 Subject: [PATCH 76/91] Fix for #11988 : Drop down menus appear outside of PS and cannot be opened again Note: Win specific --- src/slic3r/GUI/Plater.cpp | 28 ++++++++++++++++++++++++++++ src/slic3r/GUI/Widgets/DropDown.hpp | 2 ++ 2 files changed, 30 insertions(+) diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 71aacc326d..6cf4caa724 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -753,10 +753,38 @@ static wxRichToolTipPopup* get_rtt_popup(wxButton* btn) return nullptr; } +// Help function to find and check if some combobox is dropped down and then dismiss it +static bool found_and_dismiss_shown_dropdown(wxWindow* win) +{ + auto children = win->GetChildren(); + if (children.IsEmpty()) { + if (auto dd = dynamic_cast(win); dd && dd->IsShown()) { + dd->CallDismissAndNotify(); + return true; + } + } + + for (auto child : children) { + if (found_and_dismiss_shown_dropdown(child)) + return true; + } + return false; +} + void Sidebar::priv::show_rich_tip(const wxString& tooltip, wxButton* btn) { if (tooltip.IsEmpty()) return; + + // Currently state (propably wxWidgets issue) : + // When second wxPopupTransientWindow is popped up, then first wxPopupTransientWindow doesn't receive EVT_DISMISS and stay on the top. + // New comboboxes use wxPopupTransientWindow as DropDown now + // That is why DropDown stay on top, when we show rich tooltip for btn. + // (see https://github.com/prusa3d/PrusaSlicer/issues/11988) + + // So, check the combo boxes and close them if necessary before showing the rich tip. + found_and_dismiss_shown_dropdown(scrolled); + wxRichToolTip tip(tooltip, ""); tip.SetIcon(wxICON_NONE); tip.SetTipKind(wxTipKind_BottomRight); diff --git a/src/slic3r/GUI/Widgets/DropDown.hpp b/src/slic3r/GUI/Widgets/DropDown.hpp index 8a4757f5f7..8d17ea658d 100644 --- a/src/slic3r/GUI/Widgets/DropDown.hpp +++ b/src/slic3r/GUI/Widgets/DropDown.hpp @@ -86,6 +86,8 @@ public: bool HasDismissLongTime(); static void SetTransparentBG(wxDC& dc, wxWindow* win); + + void CallDismissAndNotify() { DismissAndNotify(); } protected: void OnDismiss() override; From cda2446649cb29ea8f9f16cdc8354f3a2c40e484 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hejl?= Date: Mon, 22 Jan 2024 10:28:08 +0100 Subject: [PATCH 77/91] SPE-2120: Fix crash caused by using GCodeGenerator::last_position when it doesn't have an assigned value. This behavior was there for a long time, but it was uncovered when std::optional was used. --- src/libslic3r/GCode.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 9061d8bc27..62856612cc 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -2712,11 +2712,11 @@ static constexpr const double min_gcode_segment_length = 0.002; std::string GCodeGenerator::extrude_loop(const ExtrusionLoop &loop_src, const GCode::SmoothPathCache &smooth_path_cache, const std::string_view description, double speed) { // Extrude all loops CCW. - bool is_hole = loop_src.is_clockwise(); - Point seam_point = *this->last_position; - if (! m_config.spiral_vase && comment_is_perimeter(description)) { + bool is_hole = loop_src.is_clockwise(); + Point seam_point = this->last_position.has_value() ? *this->last_position : Point::Zero(); + if (!m_config.spiral_vase && comment_is_perimeter(description)) { assert(m_layer != nullptr); - seam_point = m_seam_placer.place_seam(m_layer, loop_src, m_config.external_perimeters_first, *this->last_position); + seam_point = m_seam_placer.place_seam(m_layer, loop_src, m_config.external_perimeters_first, seam_point); } // Because the G-code export has 1um resolution, don't generate segments shorter than 1.5 microns, // thus empty path segments will not be produced by G-code export. From 85fa892c12aa228f450ba14e46fe4c9f6f1c3abe Mon Sep 17 00:00:00 2001 From: YuSanka Date: Mon, 22 Jan 2024 11:32:10 +0100 Subject: [PATCH 78/91] SPE-2112 : Don't check an object units, when it was loaded from file with known units (3mf) --- src/slic3r/GUI/Plater.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 6cf4caa724..e3a184639f 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -2721,7 +2721,7 @@ std::vector Plater::priv::load_files(const std::vector& input_ if (imperial_units) // Convert even if the object is big. convert_from_imperial_units(model, false); - else if (model.looks_like_saved_in_meters()) { + else if (!type_3mf && model.looks_like_saved_in_meters()) { auto convert_model_if = [](Model& model, bool condition) { if (condition) //FIXME up-scale only the small parts? @@ -2743,7 +2743,7 @@ std::vector Plater::priv::load_files(const std::vector& input_ } convert_model_if(model, answer_convert_from_meters == wxID_YES); } - else if (model.looks_like_imperial_units()) { + else if (!type_3mf && model.looks_like_imperial_units()) { auto convert_model_if = [convert_from_imperial_units](Model& model, bool condition) { if (condition) //FIXME up-scale only the small parts? From 1832c833a1747e5ff6ba5025d634182313737db7 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Wed, 3 Jan 2024 12:53:43 +0100 Subject: [PATCH 79/91] #12000: Fixes incorrect detection of supported OpenGL version (SPE-2092) 1) Force OpenGL 3.2 as minimum required. If the graphic card does not support it, automatically switch to software renderer. 2) command line option: --opengl-version=X.Y -> allows to select core profile of version X.Y. 3) command line option: --opengl-compatibility -> allows to select compatibility profile of the highest OpenGL version supported by the graphic card. 4) command line option: --opengl-debug -> enable OpenGL debug output on card supporting OpenGL 4.3 or higher (output on console). --- src/PrusaSlicer.cpp | 30 ++++++----- src/PrusaSlicer_app_msvc.cpp | 2 +- src/libslic3r/PrintConfig.cpp | 8 ++- src/libslic3r/Technologies.hpp | 2 - src/slic3r/GUI/GUI_App.cpp | 6 +-- src/slic3r/GUI/GUI_Init.hpp | 13 +++-- src/slic3r/GUI/OpenGLManager.cpp | 92 ++++++++++++++------------------ src/slic3r/GUI/OpenGLManager.hpp | 14 ++--- 8 files changed, 76 insertions(+), 91 deletions(-) diff --git a/src/PrusaSlicer.cpp b/src/PrusaSlicer.cpp index 04b481bc42..80a990fb8c 100644 --- a/src/PrusaSlicer.cpp +++ b/src/PrusaSlicer.cpp @@ -170,10 +170,9 @@ int CLI::run(int argc, char **argv) #ifdef SLIC3R_GUI #if ENABLE_GL_CORE_PROFILE - std::pair opengl_version = { 0, 0 }; -#if ENABLE_OPENGL_DEBUG_OPTION - bool opengl_debug = false; -#endif // ENABLE_OPENGL_DEBUG_OPTION + std::pair opengl_version = { 0, 0 }; + bool opengl_debug = false; + bool opengl_compatibility_profile = false; // search for special keys into command line parameters auto it = std::find(m_actions.begin(), m_actions.end(), "gcodeviewer"); @@ -187,10 +186,8 @@ int CLI::run(int argc, char **argv) if (it != m_actions.end()) { std::string opengl_version_str = m_config.opt_string("opengl-version"); if (std::find(Slic3r::GUI::OpenGLVersions::core_str.begin(), Slic3r::GUI::OpenGLVersions::core_str.end(), opengl_version_str) == Slic3r::GUI::OpenGLVersions::core_str.end()) { - if (std::find(Slic3r::GUI::OpenGLVersions::precore_str.begin(), Slic3r::GUI::OpenGLVersions::precore_str.end(), opengl_version_str) == Slic3r::GUI::OpenGLVersions::precore_str.end()) { - boost::nowide::cerr << "Found invalid OpenGL version: " << opengl_version_str << std::endl; - opengl_version_str.clear(); - } + boost::nowide::cerr << "Required OpenGL version " << opengl_version_str << " is invalid. Must be greater than or equal to 3.2" << std::endl; + opengl_version_str.clear(); } if (!opengl_version_str.empty()) { @@ -203,12 +200,20 @@ int CLI::run(int argc, char **argv) m_actions.erase(it); } + it = std::find(m_actions.begin(), m_actions.end(), "opengl-compatibility"); + if (it != m_actions.end()) { + start_gui = true; + opengl_compatibility_profile = true; + // reset version as compatibility profile always take the highest version + // supported by the graphic card + opengl_version = std::make_pair(0, 0); + m_actions.erase(it); + } + it = std::find(m_actions.begin(), m_actions.end(), "opengl-debug"); if (it != m_actions.end()) { start_gui = true; -#if ENABLE_OPENGL_DEBUG_OPTION opengl_debug = true; -#endif // ENABLE_OPENGL_DEBUG_OPTION m_actions.erase(it); } #else @@ -224,7 +229,7 @@ int CLI::run(int argc, char **argv) #endif // ENABLE_GL_CORE_PROFILE #else // SLIC3R_GUI // If there is no GUI, we shall ignore the parameters. Remove them from the list. - for (const std::string& s : { "opengl-version", "opengl-debug", "gcodeviewer" }) { + for (const std::string& s : { "opengl-version", "opengl-compatibility", "opengl-debug", "gcodeviewer" }) { auto it = std::find(m_actions.cbegin(), m_actions.cend(), s); if (it != m_actions.end()) { boost::nowide::cerr << "Parameter '" << s << "' is ignored, this PrusaSlicer build is CLI only." << std::endl; @@ -714,10 +719,9 @@ int CLI::run(int argc, char **argv) params.download_url = download_url; params.delete_after_load = delete_after_load; #if ENABLE_GL_CORE_PROFILE -#if ENABLE_OPENGL_DEBUG_OPTION params.opengl_version = opengl_version; params.opengl_debug = opengl_debug; -#endif // ENABLE_OPENGL_DEBUG_OPTION + params.opengl_compatibiity_profile = opengl_compatibility_profile; #endif // ENABLE_GL_CORE_PROFILE return Slic3r::GUI::GUI_Run(params); #else // SLIC3R_GUI diff --git a/src/PrusaSlicer_app_msvc.cpp b/src/PrusaSlicer_app_msvc.cpp index 06f15aa5ad..c6ba41e4ea 100644 --- a/src/PrusaSlicer_app_msvc.cpp +++ b/src/PrusaSlicer_app_msvc.cpp @@ -266,7 +266,7 @@ int wmain(int argc, wchar_t **argv) // In that case, use Mesa. (::GetSystemMetrics(SM_REMOTESESSION) && !force_hw) || // Try to load the default OpenGL driver and test its context version. - ! opengl_version_check.load_opengl_dll() || ! opengl_version_check.is_version_greater_or_equal_to(2, 0); + ! opengl_version_check.load_opengl_dll() || ! opengl_version_check.is_version_greater_or_equal_to(3, 2); #endif /* SLIC3R_GUI */ wchar_t path_to_exe[MAX_PATH + 1] = { 0 }; diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 02e824efe6..34e513f571 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -4889,9 +4889,15 @@ CLIActionsConfigDef::CLIActionsConfigDef() def->cli = "opengl-version"; def->set_default_value(new ConfigOptionString()); + def = this->add("opengl-compatibility", coBool); + def->label = L("OpenGL compatibility profile"); + def->tooltip = L("Enable OpenGL compatibility profile"); + def->cli = "opengl-compatibility"; + def->set_default_value(new ConfigOptionBool(false)); + def = this->add("opengl-debug", coBool); def->label = L("OpenGL debug output"); - def->tooltip = L("Activate OpenGL debug output on graphic cards which support it"); + def->tooltip = L("Activate OpenGL debug output on graphic cards which support it (OpenGL 4.3 or higher)"); def->cli = "opengl-debug"; def->set_default_value(new ConfigOptionBool(false)); #endif // ENABLE_GL_CORE_PROFILE diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp index 3989eab3d2..b95b7a37fd 100644 --- a/src/libslic3r/Technologies.hpp +++ b/src/libslic3r/Technologies.hpp @@ -55,8 +55,6 @@ #define ENABLE_OPENGL_ES 0 // Enable OpenGL core profile context (tested against Mesa 20.1.8 on Windows) #define ENABLE_GL_CORE_PROFILE (1 && !ENABLE_OPENGL_ES) -// Enable OpenGL debug messages using debug context -#define ENABLE_OPENGL_DEBUG_OPTION (1 && ENABLE_GL_CORE_PROFILE) // Enable imgui dialog which allows to set the parameters used to export binarized gcode #define ENABLE_BINARIZED_GCODE_DEBUG_WINDOW 0 diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 75f52eaf36..fd88b61573 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -889,12 +889,8 @@ std::string GUI_App::get_gl_info(bool for_github) wxGLContext* GUI_App::init_glcontext(wxGLCanvas& canvas) { #if ENABLE_GL_CORE_PROFILE -#if ENABLE_OPENGL_DEBUG_OPTION return m_opengl_mgr.init_glcontext(canvas, init_params != nullptr ? init_params->opengl_version : std::make_pair(0, 0), - init_params != nullptr ? init_params->opengl_debug : false); -#else - return m_opengl_mgr.init_glcontext(canvas, init_params != nullptr ? init_params->opengl_version : std::make_pair(0, 0)); -#endif // ENABLE_OPENGL_DEBUG_OPTION + init_params != nullptr ? init_params->opengl_compatibiity_profile : false, init_params != nullptr ? init_params->opengl_debug : false); #else return m_opengl_mgr.init_glcontext(canvas); #endif // ENABLE_GL_CORE_PROFILE diff --git a/src/slic3r/GUI/GUI_Init.hpp b/src/slic3r/GUI/GUI_Init.hpp index e2d43ae6da..30c24d2bee 100644 --- a/src/slic3r/GUI/GUI_Init.hpp +++ b/src/slic3r/GUI/GUI_Init.hpp @@ -33,15 +33,14 @@ struct GUI_InitParams DynamicPrintConfig extra_config; std::vector input_files; - bool start_as_gcodeviewer; - bool start_downloader; - bool delete_after_load; + bool start_as_gcodeviewer; + bool start_downloader; + bool delete_after_load; std::string download_url; #if ENABLE_GL_CORE_PROFILE - std::pair opengl_version; -#if ENABLE_OPENGL_DEBUG_OPTION - bool opengl_debug; -#endif // ENABLE_OPENGL_DEBUG_OPTION + std::pair opengl_version; + bool opengl_debug; + bool opengl_compatibiity_profile; #endif // ENABLE_GL_CORE_PROFILE }; diff --git a/src/slic3r/GUI/OpenGLManager.cpp b/src/slic3r/GUI/OpenGLManager.cpp index c64cf9b5a6..c9df0caaa6 100644 --- a/src/slic3r/GUI/OpenGLManager.cpp +++ b/src/slic3r/GUI/OpenGLManager.cpp @@ -127,6 +127,10 @@ void OpenGLManager::GLInfo::detect() const float* max_anisotropy = const_cast(&m_max_anisotropy); glsafe(::glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, max_anisotropy)); } + + if (!GLEW_ARB_compatibility) + *const_cast(&m_core_profile) = true; + *const_cast(&m_detected) = true; } @@ -197,7 +201,7 @@ std::string OpenGLManager::GLInfo::to_string(bool for_github) const std::string line_end = format_as_html ? "
" : "\n"; out << h2_start << "OpenGL installation" << h2_end << line_end; - out << b_start << "GL version: " << b_end << m_version << line_end; + out << b_start << "GL version: " << b_end << m_version << " (" << m_version_string << ")" << line_end; #if ENABLE_GL_CORE_PROFILE out << b_start << "Profile: " << b_end << (is_core_profile() ? "Core" : "Compatibility") << line_end; #endif // ENABLE_GL_CORE_PROFILE @@ -287,14 +291,14 @@ OpenGLManager::~OpenGLManager() #endif //__APPLE__ } -#if ENABLE_OPENGL_DEBUG_OPTION +#if ENABLE_GL_CORE_PROFILE #ifdef _WIN32 static void APIENTRY CustomGLDebugOutput(GLenum source, GLenum type, unsigned int id, GLenum severity, GLsizei length, const char* message, const void* userParam) #else static void CustomGLDebugOutput(GLenum source, GLenum type, unsigned int id, GLenum severity, GLsizei length, const char* message, const void* userParam) #endif // _WIN32 { - if (severity == GL_DEBUG_SEVERITY_NOTIFICATION) + if (severity != GL_DEBUG_SEVERITY_HIGH) return; std::string out = "OpenGL DEBUG message ["; @@ -331,7 +335,7 @@ static void CustomGLDebugOutput(GLenum source, GLenum type, unsigned int id, GLe out += "]:\n"; std::cout << out << "(" << id << "): " << message << "\n\n"; } -#endif // ENABLE_OPENGL_DEBUG_OPTION +#endif // ENABLE_GL_CORE_PROFILE bool OpenGLManager::init_gl() { @@ -369,7 +373,7 @@ bool OpenGLManager::init_gl() #if ENABLE_OPENGL_ES bool valid_version = s_gl_info.is_version_greater_or_equal_to(2, 0); #elif ENABLE_GL_CORE_PROFILE - bool valid_version = s_gl_info.is_core_profile() ? s_gl_info.is_version_greater_or_equal_to(3, 2) : s_gl_info.is_version_greater_or_equal_to(2, 0); + const bool valid_version = s_gl_info.is_version_greater_or_equal_to(3, 2); #else bool valid_version = s_gl_info.is_version_greater_or_equal_to(2, 0); #endif // ENABLE_OPENGL_ES @@ -379,16 +383,16 @@ bool OpenGLManager::init_gl() wxString message = format_wxstr( #if ENABLE_OPENGL_ES _L("PrusaSlicer requires OpenGL ES 2.0 capable graphics driver to run correctly, \n" - "while OpenGL version %s, render %s, vendor %s was detected."), s_gl_info.get_version_string(), s_gl_info.get_renderer(), s_gl_info.get_vendor()); + "while OpenGL version %s, render %s, vendor %s was detected."), s_gl_info.get_version_string(), s_gl_info.get_renderer(), s_gl_info.get_vendor()); #elif ENABLE_GL_CORE_PROFILE - _L("PrusaSlicer requires OpenGL %s capable graphics driver to run correctly, \n" - "while OpenGL version %s, render %s, vendor %s was detected."), (s_gl_info.is_core_profile() ? "3.3" : "2.0"), s_gl_info.get_version_string(), s_gl_info.get_renderer(), s_gl_info.get_vendor()); + _L("PrusaSlicer requires OpenGL 3.2 capable graphics driver to run correctly,\n" + "while OpenGL version %s, render %s, vendor %s was detected."), s_gl_info.get_version_string(), s_gl_info.get_renderer(), s_gl_info.get_vendor()); #else _L("PrusaSlicer requires OpenGL 2.0 capable graphics driver to run correctly, \n" - "while OpenGL version %s, render %s, vendor %s was detected."), s_gl_info.get_version_string(), s_gl_info.get_renderer(), s_gl_info.get_vendor()); + "while OpenGL version %s, render %s, vendor %s was detected."), s_gl_info.get_version_string(), s_gl_info.get_renderer(), s_gl_info.get_vendor()); #endif // ENABLE_OPENGL_ES message += "\n"; - message += _L("You may need to update your graphics card driver."); + message += _L("You may need to update your graphics card driver."); #ifdef _WIN32 message += "\n"; message += _L("As a workaround, you may run PrusaSlicer with a software rendered 3D graphics by running prusa-slicer.exe with the --sw-renderer parameter."); @@ -403,14 +407,15 @@ bool OpenGLManager::init_gl() wxString message = format_wxstr(_L("Unable to load the following shaders:\n%s"), error); wxMessageBox(message, wxString("PrusaSlicer - ") + _L("Error loading shaders"), wxOK | wxICON_ERROR); } -#if ENABLE_OPENGL_DEBUG_OPTION - if (m_debug_enabled && GLEW_KHR_debug) { +#if ENABLE_GL_CORE_PROFILE + if (m_debug_enabled && s_gl_info.is_version_greater_or_equal_to(4, 3) && GLEW_KHR_debug) { ::glEnable(GL_DEBUG_OUTPUT); ::glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); ::glDebugMessageCallback(CustomGLDebugOutput, nullptr); ::glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, nullptr, GL_TRUE); + std::cout << "Enabled OpenGL debug output\n"; } -#endif // ENABLE_OPENGL_DEBUG_OPTION +#endif // ENABLE_GL_CORE_PROFILE } #ifdef _WIN32 @@ -437,11 +442,8 @@ bool OpenGLManager::init_gl() } #if ENABLE_GL_CORE_PROFILE -#if ENABLE_OPENGL_DEBUG_OPTION -wxGLContext* OpenGLManager::init_glcontext(wxGLCanvas& canvas, const std::pair& required_opengl_version, bool enable_debug) -#else -wxGLContext* OpenGLManager::init_glcontext(wxGLCanvas& canvas, const std::pair& required_opengl_version) -#endif // ENABLE_OPENGL_DEBUG_OPTION +wxGLContext* OpenGLManager::init_glcontext(wxGLCanvas& canvas, const std::pair& required_opengl_version, bool enable_compatibility_profile, + bool enable_debug) #else wxGLContext* OpenGLManager::init_glcontext(wxGLCanvas& canvas) #endif // ENABLE_GL_CORE_PROFILE @@ -452,33 +454,25 @@ wxGLContext* OpenGLManager::init_glcontext(wxGLCanvas& canvas) attrs.PlatformDefaults().ES2().MajorVersion(2).EndList(); m_context = new wxGLContext(&canvas, nullptr, &attrs); #elif ENABLE_GL_CORE_PROFILE -#if ENABLE_OPENGL_DEBUG_OPTION m_debug_enabled = enable_debug; -#endif // ENABLE_OPENGL_DEBUG_OPTION const int gl_major = required_opengl_version.first; const int gl_minor = required_opengl_version.second; const bool supports_core_profile = (gl_major < 3) ? false : (gl_major > 3) ? true : gl_minor >= 2; - if (gl_major == 0) { + if (gl_major == 0 && !enable_compatibility_profile) { // search for highest supported core profile version // disable wxWidgets logging to avoid showing the log dialog in case the following code fails generating a valid gl context wxLogNull logNo; for (auto v = OpenGLVersions::core.rbegin(); v != OpenGLVersions::core.rend(); ++v) { wxGLContextAttrs attrs; -#if ENABLE_OPENGL_DEBUG_OPTION attrs.PlatformDefaults().MajorVersion(v->first).MinorVersion(v->second).CoreProfile().ForwardCompatible(); if (m_debug_enabled) attrs.DebugCtx(); attrs.EndList(); -#else - attrs.PlatformDefaults().MajorVersion(gl_major).MinorVersion(gl_minor).CoreProfile().ForwardCompatible().EndList(); -#endif // ENABLE_OPENGL_DEBUG_OPTION m_context = new wxGLContext(&canvas, nullptr, &attrs); - if (m_context->IsOK()) { - s_gl_info.set_core_profile(true); + if (m_context->IsOK()) break; - } else { delete m_context; m_context = nullptr; @@ -487,45 +481,41 @@ wxGLContext* OpenGLManager::init_glcontext(wxGLCanvas& canvas) } if (m_context == nullptr) { - // search for requested core profile version - if (supports_core_profile) { + // search for requested compatibility profile version + if (enable_compatibility_profile) { + // disable wxWidgets logging to avoid showing the log dialog in case the following code fails generating a valid gl context + wxLogNull logNo; + wxGLContextAttrs attrs; + attrs.PlatformDefaults().CompatibilityProfile(); + if (m_debug_enabled) + attrs.DebugCtx(); + attrs.EndList(); + m_context = new wxGLContext(&canvas, nullptr, &attrs); + if (!m_context->IsOK()) { + delete m_context; + m_context = nullptr; + } + } + // search for requested core profile version + else if (supports_core_profile) { // disable wxWidgets logging to avoid showing the log dialog in case the following code fails generating a valid gl context wxLogNull logNo; wxGLContextAttrs attrs; -#if ENABLE_OPENGL_DEBUG_OPTION attrs.PlatformDefaults().MajorVersion(gl_major).MinorVersion(gl_minor).CoreProfile().ForwardCompatible(); if (m_debug_enabled) attrs.DebugCtx(); attrs.EndList(); -#else - attrs.PlatformDefaults().MajorVersion(gl_major).MinorVersion(gl_minor).CoreProfile().ForwardCompatible().EndList(); -#endif // ENABLE_OPENGL_DEBUG_OPTION m_context = new wxGLContext(&canvas, nullptr, &attrs); if (!m_context->IsOK()) { - BOOST_LOG_TRIVIAL(error) << "Unable to create context for required OpenGL " << gl_major << "." << gl_minor; delete m_context; m_context = nullptr; } - else - s_gl_info.set_core_profile(true); } } -#if ENABLE_OPENGL_DEBUG_OPTION - if (m_context == nullptr) { - wxGLContextAttrs attrs; - attrs.PlatformDefaults(); - if (m_debug_enabled) - attrs.DebugCtx(); - attrs.EndList(); - // if no valid context was created use the default one - m_context = new wxGLContext(&canvas, nullptr, &attrs); - } -#else if (m_context == nullptr) - // if no valid context was created use the default one - m_context = new wxGLContext(&canvas); -#endif // ENABLE_OPENGL_DEBUG_OPTION + // no valid context was created + throw Slic3r::RuntimeError("Unable to create context for OpenGL."); #else m_context = new wxGLContext(&canvas); #endif // ENABLE_OPENGL_ES diff --git a/src/slic3r/GUI/OpenGLManager.hpp b/src/slic3r/GUI/OpenGLManager.hpp index 265ceb5160..9b45a08c0a 100644 --- a/src/slic3r/GUI/OpenGLManager.hpp +++ b/src/slic3r/GUI/OpenGLManager.hpp @@ -54,15 +54,13 @@ public: const std::string& get_renderer() const; bool is_core_profile() const { return m_core_profile; } - void set_core_profile(bool value) { m_core_profile = value; } bool is_mesa() const; bool is_es() const { - return #if ENABLE_OPENGL_ES - true; + return true; #else - false; + return false; #endif // ENABLE_OPENGL_ES } @@ -104,9 +102,7 @@ private: bool m_gl_initialized{ false }; wxGLContext* m_context{ nullptr }; -#if ENABLE_OPENGL_DEBUG_OPTION bool m_debug_enabled{ false }; -#endif // ENABLE_OPENGL_DEBUG_OPTION GLShadersManager m_shaders_manager; static GLInfo s_gl_info; #ifdef __APPLE__ @@ -125,11 +121,7 @@ public: bool init_gl(); #if ENABLE_GL_CORE_PROFILE -#if ENABLE_OPENGL_DEBUG_OPTION - wxGLContext* init_glcontext(wxGLCanvas& canvas, const std::pair& required_opengl_version, bool enable_debug); -#else - wxGLContext* init_glcontext(wxGLCanvas& canvas, const std::pair& required_opengl_version); -#endif // ENABLE_OPENGL_DEBUG_OPTION + wxGLContext* init_glcontext(wxGLCanvas& canvas, const std::pair& required_opengl_version, bool enable_compatibility_profile, bool enable_debug); #else wxGLContext* init_glcontext(wxGLCanvas& canvas); #endif // ENABLE_GL_CORE_PROFILE From 3cab0cbecb887c5a39030b40e42fa51659ddec7e Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Fri, 19 Jan 2024 16:12:27 +0100 Subject: [PATCH 80/91] Using Semver to check minimum required OpenGL version --- src/PrusaSlicer.cpp | 20 ++++++++------------ src/slic3r/GUI/GUI_Init.cpp | 4 ---- src/slic3r/GUI/GUI_Init.hpp | 4 ---- 3 files changed, 8 insertions(+), 20 deletions(-) diff --git a/src/PrusaSlicer.cpp b/src/PrusaSlicer.cpp index 80a990fb8c..44f1c28d34 100644 --- a/src/PrusaSlicer.cpp +++ b/src/PrusaSlicer.cpp @@ -184,18 +184,14 @@ int CLI::run(int argc, char **argv) it = std::find(m_actions.begin(), m_actions.end(), "opengl-version"); if (it != m_actions.end()) { - std::string opengl_version_str = m_config.opt_string("opengl-version"); - if (std::find(Slic3r::GUI::OpenGLVersions::core_str.begin(), Slic3r::GUI::OpenGLVersions::core_str.end(), opengl_version_str) == Slic3r::GUI::OpenGLVersions::core_str.end()) { - boost::nowide::cerr << "Required OpenGL version " << opengl_version_str << " is invalid. Must be greater than or equal to 3.2" << std::endl; - opengl_version_str.clear(); - } - - if (!opengl_version_str.empty()) { - std::vector tokens; - boost::split(tokens, opengl_version_str, boost::is_any_of("."), boost::token_compress_on); - opengl_version.first = std::stoi(tokens[0].c_str()); - opengl_version.second = std::stoi(tokens[1].c_str()); - } + const Semver opengl_minimum = Semver(3,2,0); + const std::string opengl_version_str = m_config.opt_string("opengl-version"); + boost::optional semver = Semver::parse(opengl_version_str); + if (semver.has_value() && (*semver) >= opengl_minimum ) { + opengl_version.first = semver->maj(); + opengl_version.second = semver->min(); + } else + boost::nowide::cerr << "Required OpenGL version " << opengl_version_str << " is invalid. Must be greater than or equal to " << opengl_minimum.to_string() << std::endl; start_gui = true; m_actions.erase(it); } diff --git a/src/slic3r/GUI/GUI_Init.cpp b/src/slic3r/GUI/GUI_Init.cpp index 6f734388e4..504a42a932 100644 --- a/src/slic3r/GUI/GUI_Init.cpp +++ b/src/slic3r/GUI/GUI_Init.cpp @@ -30,11 +30,7 @@ namespace Slic3r { namespace GUI { -const std::vector OpenGLVersions::core_str = { "3.2", "3.3", "4.0", "4.1", "4.2", "4.3", "4.4", "4.5", "4.6" }; -const std::vector OpenGLVersions::precore_str = { "2.0", "2.1", "3.0", "3.1" }; - const std::vector> OpenGLVersions::core = { {3,2}, {3,3}, {4,0}, {4,1}, {4,2}, {4,3}, {4,4}, {4,5}, {4,6} }; -const std::vector> OpenGLVersions::precore = { {2,0}, {2,1}, {3,0}, {3,1} }; int GUI_Run(GUI_InitParams ¶ms) { diff --git a/src/slic3r/GUI/GUI_Init.hpp b/src/slic3r/GUI/GUI_Init.hpp index 30c24d2bee..b21da42a5e 100644 --- a/src/slic3r/GUI/GUI_Init.hpp +++ b/src/slic3r/GUI/GUI_Init.hpp @@ -14,11 +14,7 @@ namespace GUI { struct OpenGLVersions { - static const std::vector core_str; - static const std::vector precore_str; - static const std::vector> core; - static const std::vector> precore; }; struct GUI_InitParams From 8cbea4982a9ccd879a5e970aecd844ec0d65757a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20=C5=A0ach?= Date: Wed, 17 Jan 2024 13:42:17 +0100 Subject: [PATCH 81/91] Add lift before the first travel move in GCode.cpp --- src/libslic3r/GCode.cpp | 16 +++++++++++++++- tests/fff_print/test_retraction.cpp | 13 +++++++++++-- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 62856612cc..07a7a211b9 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -2957,11 +2957,25 @@ std::string GCodeGenerator::_extrude( const std::string_view description_bridge = path_attr.role.is_bridge() ? " (bridge)"sv : ""sv; if (!m_current_layer_first_position) { - // Make the first travel just one G1. const Vec3crd point = to_3d(path.front().point, scaled(this->m_last_layer_z + this->m_config.z_offset.value)); const Vec3d gcode_point = to_3d(this->point_to_gcode(point.head<2>()), unscaled(point.z())); + + if (!this->last_position) { + double lift{ + EXTRUDER_CONFIG(travel_ramping_lift) ? EXTRUDER_CONFIG(travel_max_lift) : + EXTRUDER_CONFIG(retract_lift)}; + const double upper_limit = EXTRUDER_CONFIG(retract_lift_below); + const double lower_limit = EXTRUDER_CONFIG(retract_lift_above); + if ((lower_limit > 0 && gcode_point.z() < lower_limit) || + (upper_limit > 0 && gcode_point.z() > upper_limit)) { + lift = 0.0; + } + gcode += this->writer().get_travel_to_z_gcode(gcode_point.z() + lift, "lift"); + } + this->last_position = path.front().point; this->writer().update_position(gcode_point); + gcode += this->writer().get_travel_to_xy_gcode(gcode_point.head<2>(), "move to first layer point"); gcode += this->writer().get_travel_to_z_gcode(gcode_point.z(), "move to first layer point"); m_current_layer_first_position = gcode_point; diff --git a/tests/fff_print/test_retraction.cpp b/tests/fff_print/test_retraction.cpp index a9951925c9..f75df4d42c 100644 --- a/tests/fff_print/test_retraction.cpp +++ b/tests/fff_print/test_retraction.cpp @@ -9,10 +9,13 @@ #include "test_data.hpp" #include +#include using namespace Slic3r; using namespace Test; +constexpr bool debug_files {false}; + void check_gcode(std::initializer_list meshes, const DynamicPrintConfig& config, const unsigned duplicate) { constexpr std::size_t tools_count = 4; std::size_t tool = 0; @@ -183,6 +186,12 @@ TEST_CASE("Z moves", "[retraction]") { unsigned z_restores = 0; std::string gcode = Slic3r::Test::slice({TestMesh::cube_20x20x20}, config); + + if constexpr(debug_files) { + std::ofstream file{"zmoves.gcode"}; + file << gcode; + } + GCodeReader parser; parser.parse_buffer(gcode, [&] (Slic3r::GCodeReader &self, const Slic3r::GCodeReader::GCodeLine &line) { if (line.retracting(self)) { @@ -205,8 +214,8 @@ TEST_CASE("Z moves", "[retraction]") { CHECK(layer_changes_with_retraction == 0); INFO("no retractions"); CHECK(retractions == 0); - INFO("no lift"); - CHECK(z_restores == 0); + INFO("no lift other than for the first move"); + CHECK(z_restores == 1); } TEST_CASE("Firmware retraction handling", "[retraction]") { From 812c40e88734c43985291f58dc88771ff8a9d68a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20=C5=A0ach?= Date: Mon, 22 Jan 2024 11:11:59 +0100 Subject: [PATCH 82/91] Unify GCodeGenerator travel to first layer position. * Fixes SPE-2116. The reason for this bug was forgotten change in WipeTowerIntegration after change in gcode.cpp. * Prevents future similar bugs by unifing the functionality to a method. --- src/libslic3r/GCode.cpp | 55 ++++++++++++-------- src/libslic3r/GCode.hpp | 3 ++ src/libslic3r/GCode/WipeTowerIntegration.cpp | 9 +--- 3 files changed, 36 insertions(+), 31 deletions(-) diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 07a7a211b9..671819c2d9 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -2947,9 +2947,38 @@ void GCodeGenerator::GCodeOutputStream::write_format(const char* format, ...) va_end(args); } +std::string GCodeGenerator::travel_to_first_position(const Vec3crd& point) { + std::string gcode; + + const Vec3d gcode_point = to_3d(this->point_to_gcode(point.head<2>()), unscaled(point.z())); + + if (!this->last_position) { + double lift{ + EXTRUDER_CONFIG(travel_ramping_lift) ? EXTRUDER_CONFIG(travel_max_lift) : + EXTRUDER_CONFIG(retract_lift)}; + const double upper_limit = EXTRUDER_CONFIG(retract_lift_below); + const double lower_limit = EXTRUDER_CONFIG(retract_lift_above); + if ((lower_limit > 0 && gcode_point.z() < lower_limit) || + (upper_limit > 0 && gcode_point.z() > upper_limit)) { + lift = 0.0; + } + gcode += this->writer().get_travel_to_z_gcode(gcode_point.z() + lift, "lift"); + } + + this->last_position = point.head<2>(); + this->writer().update_position(gcode_point); + + std::string comment{"move to first layer point"}; + gcode += this->writer().get_travel_to_xy_gcode(gcode_point.head<2>(), comment); + gcode += this->writer().get_travel_to_z_gcode(gcode_point.z(), comment); + + m_current_layer_first_position = gcode_point; + return gcode; +} + std::string GCodeGenerator::_extrude( - const ExtrusionAttributes &path_attr, - const Geometry::ArcWelder::Path &path, + const ExtrusionAttributes &path_attr, + const Geometry::ArcWelder::Path &path, const std::string_view description, double speed) { @@ -2958,27 +2987,7 @@ std::string GCodeGenerator::_extrude( if (!m_current_layer_first_position) { const Vec3crd point = to_3d(path.front().point, scaled(this->m_last_layer_z + this->m_config.z_offset.value)); - const Vec3d gcode_point = to_3d(this->point_to_gcode(point.head<2>()), unscaled(point.z())); - - if (!this->last_position) { - double lift{ - EXTRUDER_CONFIG(travel_ramping_lift) ? EXTRUDER_CONFIG(travel_max_lift) : - EXTRUDER_CONFIG(retract_lift)}; - const double upper_limit = EXTRUDER_CONFIG(retract_lift_below); - const double lower_limit = EXTRUDER_CONFIG(retract_lift_above); - if ((lower_limit > 0 && gcode_point.z() < lower_limit) || - (upper_limit > 0 && gcode_point.z() > upper_limit)) { - lift = 0.0; - } - gcode += this->writer().get_travel_to_z_gcode(gcode_point.z() + lift, "lift"); - } - - this->last_position = path.front().point; - this->writer().update_position(gcode_point); - - gcode += this->writer().get_travel_to_xy_gcode(gcode_point.head<2>(), "move to first layer point"); - gcode += this->writer().get_travel_to_z_gcode(gcode_point.z(), "move to first layer point"); - m_current_layer_first_position = gcode_point; + gcode += this->travel_to_first_position(point); } else { // go to first point of extrusion path if (!this->last_position) { diff --git a/src/libslic3r/GCode.hpp b/src/libslic3r/GCode.hpp index fc63bf2af2..1548af4513 100644 --- a/src/libslic3r/GCode.hpp +++ b/src/libslic3r/GCode.hpp @@ -351,6 +351,9 @@ private: ExtrusionRole role, const std::string &comment ); + + std::string travel_to_first_position(const Vec3crd& point); + bool needs_retraction(const Polyline &travel, ExtrusionRole role = ExtrusionRole::None); std::string retract_and_wipe(bool toolchange = false); diff --git a/src/libslic3r/GCode/WipeTowerIntegration.cpp b/src/libslic3r/GCode/WipeTowerIntegration.cpp index 56c2f4af93..9e86dfd967 100644 --- a/src/libslic3r/GCode/WipeTowerIntegration.cpp +++ b/src/libslic3r/GCode/WipeTowerIntegration.cpp @@ -72,14 +72,7 @@ std::string WipeTowerIntegration::append_tcr(GCodeGenerator &gcodegen, const Wip } } else { const Vec3crd point = to_3d(xy_point, scaled(z)); - const Vec3d gcode_point = gcodegen.point_to_gcode(point); - gcodegen.last_position = point.head<2>(); - gcodegen.writer().update_position(gcode_point); - gcode += gcodegen.writer() - .get_travel_to_xy_gcode(gcode_point.head<2>(), comment); - gcode += gcodegen.writer() - .get_travel_to_z_gcode(gcode_point.z(), comment); - gcodegen.m_current_layer_first_position = gcode_point; + gcode += gcodegen.travel_to_first_position(point); } gcode += gcodegen.unretract(); } else { From 194d53ea255dfe5544d3289be66659b1a9486856 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20=C5=A0ach?= Date: Wed, 17 Jan 2024 12:19:02 +0100 Subject: [PATCH 83/91] Fix z_offset handling in gcode.cpp. Fixes #11843. --- src/libslic3r/GCode.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 671819c2d9..65fb8683e4 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -1252,7 +1252,7 @@ void GCodeGenerator::_do_export(Print& print, GCodeOutputStream &file, Thumbnail // Set position for wipe tower generation. Vec3d new_position = this->writer().get_position(); - new_position.z() = first_layer_height + m_config.z_offset.value; + new_position.z() = first_layer_height; this->writer().update_position(new_position); if (print.config().single_extruder_multi_material_priming) { @@ -2152,7 +2152,7 @@ LayerResult GCodeGenerator::process_layer( return result; // Extract 1st object_layer and support_layer of this set of layers with an equal print_z. - coordf_t print_z = layer.print_z; + coordf_t print_z = layer.print_z + m_config.z_offset.value; bool first_layer = layer.id() == 0; unsigned int first_extruder_id = layer_tools.extruders.front(); @@ -2356,7 +2356,7 @@ LayerResult GCodeGenerator::process_layer( } else if (do_ramping_layer_change) { layer_change_gcode = this->get_layer_change_gcode(*m_previous_layer_last_position, *m_current_layer_first_position, *m_layer_change_extruder_id); } else { - layer_change_gcode = this->writer().get_travel_to_z_gcode(m_config.z_offset.value + print_z, "simple layer change"); + layer_change_gcode = this->writer().get_travel_to_z_gcode(print_z, "simple layer change"); } boost::algorithm::replace_first(gcode, tag, layer_change_gcode); @@ -2679,7 +2679,7 @@ std::string GCodeGenerator::change_layer( gcode += this->retract_and_wipe(); Vec3d new_position = this->writer().get_position(); - new_position.z() = print_z + m_config.z_offset.value; + new_position.z() = print_z; this->writer().update_position(new_position); m_previous_layer_last_position = this->last_position ? @@ -2986,12 +2986,12 @@ std::string GCodeGenerator::_extrude( const std::string_view description_bridge = path_attr.role.is_bridge() ? " (bridge)"sv : ""sv; if (!m_current_layer_first_position) { - const Vec3crd point = to_3d(path.front().point, scaled(this->m_last_layer_z + this->m_config.z_offset.value)); + const Vec3crd point = to_3d(path.front().point, scaled(this->m_last_layer_z)); gcode += this->travel_to_first_position(point); } else { // go to first point of extrusion path if (!this->last_position) { - const double z = this->m_last_layer_z + this->m_config.z_offset.value; + const double z = this->m_last_layer_z; const std::string comment{"move to print after unknown position"}; gcode += this->retract_and_wipe(); gcode += this->m_writer.travel_to_xy(this->point_to_gcode(path.front().point), comment); @@ -3380,7 +3380,7 @@ std::string GCodeGenerator::travel_to( const unsigned extruder_id = this->m_writer.extruder()->id(); const double retract_length = this->m_config.retract_length.get_at(extruder_id); bool can_be_flat{!needs_retraction || retract_length == 0}; - const double initial_elevation = this->m_last_layer_z + this->m_config.z_offset.value; + const double initial_elevation = this->m_last_layer_z; const double upper_limit = this->m_config.retract_lift_below.get_at(extruder_id); const double lower_limit = this->m_config.retract_lift_above.get_at(extruder_id); From 7f423083b48b7bc7eae0d98fa4f359c629645e43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20=C5=A0ach?= Date: Mon, 22 Jan 2024 10:49:57 +0100 Subject: [PATCH 84/91] Fix: Use toolchange z instead of writer z to restore z on wipe tower. Writer z can be set in custom toolchange gcode and than the restoration is invalid. --- src/libslic3r/GCode/WipeTowerIntegration.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libslic3r/GCode/WipeTowerIntegration.cpp b/src/libslic3r/GCode/WipeTowerIntegration.cpp index 9e86dfd967..8493a4e8ef 100644 --- a/src/libslic3r/GCode/WipeTowerIntegration.cpp +++ b/src/libslic3r/GCode/WipeTowerIntegration.cpp @@ -93,7 +93,7 @@ std::string WipeTowerIntegration::append_tcr(GCodeGenerator &gcodegen, const Wip gcodegen.m_wipe.reset_path(); // We don't want wiping on the ramming lines. toolchange_gcode_str = gcodegen.set_extruder(new_extruder_id, tcr.print_z); // TODO: toolchange_z vs print_z if (gcodegen.config().wipe_tower) { - deretraction_str += gcodegen.writer().get_travel_to_z_gcode(z, "restore layer Z"); + deretraction_str += gcodegen.writer().get_travel_to_z_gcode(tcr.print_z, "restore layer Z"); deretraction_str += gcodegen.unretract(); } } From 7d31f8c0bae3ef8b0d572f4391839045730ebdfc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hejl?= Date: Tue, 23 Jan 2024 12:33:19 +0100 Subject: [PATCH 85/91] SPE-2120: Fix another crash caused by using GCodeGenerator::last_position when it doesn't have an assigned value. This behavior was there for a long time, but it was uncovered when std::optional was used. --- src/libslic3r/GCode.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 65fb8683e4..5a9253a8e4 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -2767,8 +2767,9 @@ std::string GCodeGenerator::extrude_skirt( const GCode::SmoothPathCache &smooth_path_cache, const std::string_view description, double speed) { assert(loop_src.is_counter_clockwise()); + Point seam_point = this->last_position.has_value() ? *this->last_position : Point::Zero(); GCode::SmoothPath smooth_path = smooth_path_cache.resolve_or_fit_split_with_seam( - loop_src, false, m_scaled_resolution, *this->last_position, scaled(0.0015)); + loop_src, false, m_scaled_resolution, seam_point, scaled(0.0015)); // Clip the path to avoid the extruder to get exactly on the first point of the loop; // if polyline was shorter than the clipping distance we'd get a null polyline, so From 65525b061684c32bf67daac2af889c6017926088 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Thu, 11 Jan 2024 11:02:53 +0100 Subject: [PATCH 86/91] Model: Improved function looks_like_multipart_object(). Check transformed bounding boxes of loaded objects instead of z_min of bounding boxes. + BoundingBox: added function shares_boundary() to detect if bounding boxes shares some boundary. Fix for #11547 - .3mf files with similar sized components aren't being defined as multi-part objects --- src/libslic3r/BoundingBox.hpp | 10 ++++++++++ src/libslic3r/Model.cpp | 21 ++++++++++++--------- 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/src/libslic3r/BoundingBox.hpp b/src/libslic3r/BoundingBox.hpp index 5e9575b015..9f1d16b27a 100644 --- a/src/libslic3r/BoundingBox.hpp +++ b/src/libslic3r/BoundingBox.hpp @@ -147,6 +147,16 @@ public: return this->min.x() < other.max.x() && this->max.x() > other.min.x() && this->min.y() < other.max.y() && this->max.y() > other.min.y() && this->min.z() < other.max.z() && this->max.z() > other.min.z(); } + + // Shares some boundary. + bool shares_boundary(const BoundingBox3Base& other) const { + return is_approx(this->min.x(), other.max.x()) || + is_approx(this->max.x(), other.min.x()) || + is_approx(this->min.y(), other.max.y()) || + is_approx(this->max.y(), other.min.y()) || + is_approx(this->min.z(), other.max.z()) || + is_approx(this->max.z(), other.min.z()); + } }; // Will prevent warnings caused by non existing definition of template in hpp diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index 6878c0c6b1..9d061dfef1 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -425,18 +425,21 @@ bool Model::looks_like_multipart_object() const { if (this->objects.size() <= 1) return false; - double zmin = std::numeric_limits::max(); + + BoundingBoxf3 tbb; + for (const ModelObject *obj : this->objects) { if (obj->volumes.size() > 1 || obj->config.keys().size() > 1) return false; - for (const ModelVolume *vol : obj->volumes) { - double zmin_this = vol->mesh().bounding_box().min(2); - if (zmin == std::numeric_limits::max()) - zmin = zmin_this; - else if (std::abs(zmin - zmin_this) > EPSILON) - // The volumes don't share zmin. - return true; - } + + BoundingBoxf3 bb_this = obj->volumes[0]->mesh().bounding_box(); + BoundingBoxf3 tbb_this = obj->instances[0]->transform_bounding_box(bb_this); + + if (!tbb.defined) + tbb = tbb_this; + else if (tbb.intersects(tbb_this) || tbb.shares_boundary(tbb_this)) + // The volumes has intersects bounding boxes or share some boundary + return true; } return false; } From ee3546b1860c5ca87e7dc8b5408452d93aea2949 Mon Sep 17 00:00:00 2001 From: Filip Sykala - NTB T15p Date: Thu, 18 Jan 2024 13:07:35 +0100 Subject: [PATCH 87/91] SPE-2103 Make snap-shot to undo/redo stack only on release slider Connected with attributes: Text/advanced(char gap, line gap, boldness, skew ratio) SVG(size) Also change range for Boldness. VRT font-Ascent. (different font may have different slider value range) Fix line gap (it was denied when per glyph was false) --- src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp | 55 +++++++++++++++++-------- src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp | 2 +- src/slic3r/GUI/Gizmos/GLGizmoSVG.cpp | 23 ++++++++--- src/slic3r/GUI/Gizmos/GLGizmoSVG.hpp | 2 +- src/slic3r/GUI/Jobs/EmbossJob.cpp | 11 +++-- src/slic3r/GUI/Jobs/EmbossJob.hpp | 3 ++ 6 files changed, 67 insertions(+), 29 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp index 98cf7a9a88..1486c863a1 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp @@ -96,7 +96,7 @@ static const struct Limits { MinMax emboss{0.01, 1e4}; // in mm MinMax size_in_mm{0.1f, 1000.f}; // in mm - Limit boldness{{-200.f, 200.f}, {-2e4f, 2e4f}}; // in font points + Limit boldness{{-.5f, .5f}, {-5e5f, 5e5f}}; // in font points Limit skew{{-1.f, 1.f}, {-100.f, 100.f}}; // ration without unit MinMax char_gap{-20000, 20000}; // in font points MinMax line_gap{-20000, 20000}; // in font points @@ -380,7 +380,7 @@ bool GLGizmoEmboss::re_emboss(const ModelVolume &text_volume, std::shared_ptrcanvas3D()->get_selection(); DataBasePtr base = create_emboss_data_base(tc.text, style_manager, text_lines, selection, text_volume.type(), job_cancel); - DataUpdate data{std::move(base), text_volume.id()}; + DataUpdate data{std::move(base), text_volume.id(), false}; RaycastManager raycast_manager; // Nothing is cached now, so It need to create raycasters return start_update_volume(std::move(data), text_volume, selection, raycast_manager); @@ -1316,7 +1316,7 @@ namespace { bool is_text_empty(std::string_view text) { return text.empty() || text.find_first_not_of(" \n\t\r") == std::string::npos; } } // namespace -bool GLGizmoEmboss::process() +bool GLGizmoEmboss::process(bool make_snapshot) { // no volume is selected -> selection from right panel assert(m_volume != nullptr); @@ -1330,7 +1330,7 @@ bool GLGizmoEmboss::process() const Selection& selection = m_parent.get_selection(); DataBasePtr base = create_emboss_data_base(m_text, m_style_manager, m_text_lines, selection, m_volume->type(), m_job_cancel); - DataUpdate data{std::move(base), m_volume->id()}; + DataUpdate data{std::move(base), m_volume->id(), make_snapshot}; // check valid count of text lines assert(data.base->text_lines.empty() || data.base->text_lines.size() == get_count_lines(m_text)); @@ -2665,7 +2665,6 @@ void GLGizmoEmboss::draw_advanced() m_imgui->text_colored(ImGuiWrapper::COL_GREY_DARK, ff_property); #endif // SHOW_FONT_FILE_PROPERTY - bool exist_change = false; auto &tr = m_gui_cfg->translations; const StyleManager::Style *stored_style = nullptr; @@ -2757,6 +2756,7 @@ void GLGizmoEmboss::draw_advanced() auto def_char_gap = stored_style ? &stored_style->prop.char_gap : nullptr; + bool exist_change = false; int half_ascent = font_info.ascent / 2; int min_char_gap = -half_ascent; int max_char_gap = half_ascent; @@ -2772,13 +2772,16 @@ void GLGizmoEmboss::draw_advanced() exist_change = true; } } + bool last_change = false; + if (m_imgui->get_last_slider_status().deactivated_after_edit) + last_change = true; // input gap between lines - bool is_multiline = m_text_lines.get_lines().size() > 1; + bool is_multiline = get_count_lines(m_volume->text_configuration->text) > 1; // TODO: cache count lines m_imgui->disabled_begin(!is_multiline); auto def_line_gap = stored_style ? &stored_style->prop.line_gap : nullptr; - int min_line_gap = -half_ascent; + int min_line_gap = -half_ascent; int max_line_gap = half_ascent; if (rev_slider(tr.line_gap, current_prop.line_gap, def_line_gap, _u8L("Revert gap between lines"), min_line_gap, max_line_gap, units_fmt, _L("Distance between lines"))){ @@ -2793,18 +2796,24 @@ void GLGizmoEmboss::draw_advanced() exist_change = true; } } + if (m_imgui->get_last_slider_status().deactivated_after_edit) + last_change = true; m_imgui->disabled_end(); // !is_multiline // input boldness auto def_boldness = stored_style ? &stored_style->prop.boldness : nullptr; + int min_boldness = static_cast(font_info.ascent * limits.boldness.gui.min); + int max_boldness = static_cast(font_info.ascent * limits.boldness.gui.max); if (rev_slider(tr.boldness, current_prop.boldness, def_boldness, _u8L("Undo boldness"), - limits.boldness.gui.min, limits.boldness.gui.max, units_fmt, _L("Tiny / Wide glyphs"))){ + min_boldness, max_boldness, units_fmt, _L("Tiny / Wide glyphs"))){ const std::optional &volume_boldness = m_volume->text_configuration->style.prop.boldness; if (!apply(current_prop.boldness, limits.boldness.values) || !volume_boldness.has_value() || volume_boldness != current_prop.boldness) exist_change = true; } + if (m_imgui->get_last_slider_status().deactivated_after_edit) + last_change = true; // input italic auto def_skew = stored_style ? @@ -2816,6 +2825,8 @@ void GLGizmoEmboss::draw_advanced() !volume_skew.has_value() ||volume_skew != current_prop.skew) exist_change = true; } + if (m_imgui->get_last_slider_status().deactivated_after_edit) + last_change = true; // input surface distance bool allowe_surface_distance = !use_surface && !m_volume->is_the_only_one_part(); @@ -2855,15 +2866,18 @@ void GLGizmoEmboss::draw_advanced() if (is_moved){ if (font_prop.per_glyph){ - process(); + process(false); } else { do_local_z_move(m_parent.get_selection(), distance.value_or(.0f) - prev_distance); } } // Apply move to model(backend) - if (m_imgui->get_last_slider_status().deactivated_after_edit) - m_parent.do_rotate(move_snapshot_name); + if (m_imgui->get_last_slider_status().deactivated_after_edit) { + m_parent.do_move(move_snapshot_name); + if (font_prop.per_glyph) + process(); + } m_imgui->disabled_end(); // allowe_surface_distance @@ -2901,11 +2915,17 @@ void GLGizmoEmboss::draw_advanced() // recalculate for surface cut if (use_surface || font_prop.per_glyph) + process(false); + } + + // Apply rotation on model (backend) + if (m_imgui->get_last_slider_status().deactivated_after_edit) { + m_parent.do_rotate(rotation_snapshot_name); + + // recalculate for surface cut + if (use_surface || font_prop.per_glyph) process(); } - // Apply rotation on model (backend) - if (m_imgui->get_last_slider_status().deactivated_after_edit) - m_parent.do_rotate(rotation_snapshot_name); // Keep up - lock button icon if (!m_volume->is_the_only_one_part()) { @@ -2937,6 +2957,7 @@ void GLGizmoEmboss::draw_advanced() if (i == 0) current_prop.collection_number.reset(); else current_prop.collection_number = i; exist_change = true; + last_change = true; } ImGui::PopID(); } @@ -2946,13 +2967,13 @@ void GLGizmoEmboss::draw_advanced() } } - if (exist_change) { + if (exist_change || last_change) { m_style_manager.clear_glyphs_cache(); - if (m_style_manager.get_font_prop().per_glyph) + if (font_prop.per_glyph) reinit_text_lines(); else m_text_lines.reset(); - process(); + process(last_change); } if (ImGui::Button(_u8L("Set text to face camera").c_str())) { diff --git a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp index aac28f1b89..f2187e46b1 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp @@ -114,7 +114,7 @@ private: void reset_volume(); // create volume from text - main functionality - bool process(); + bool process(bool make_snapshot = true); void close(); void draw_window(); void draw_text_input(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSVG.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSVG.cpp index 3f02201955..eedbfd4295 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSVG.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSVG.cpp @@ -1274,8 +1274,7 @@ void GLGizmoSVG::calculate_scale() { float GLGizmoSVG::get_scale_for_tolerance(){ return std::max(m_scale_width.value_or(1.f), m_scale_height.value_or(1.f)); } -bool GLGizmoSVG::process() -{ +bool GLGizmoSVG::process(bool make_snapshot) { // no volume is selected -> selection from right panel assert(m_volume != nullptr); if (m_volume == nullptr) @@ -1296,7 +1295,7 @@ bool GLGizmoSVG::process() EmbossShape shape = m_volume_shape; // copy auto base = std::make_unique(m_volume->name, m_job_cancel, std::move(shape)); base->is_outside = m_volume->type() == ModelVolumeType::MODEL_PART; - DataUpdate data{std::move(base), m_volume_id}; + DataUpdate data{std::move(base), m_volume_id, make_snapshot}; return start_update_volume(std::move(data), *m_volume, m_parent.get_selection(), m_raycast_manager); } @@ -1690,6 +1689,8 @@ void GLGizmoSVG::draw_size() }; std::optional new_relative_scale; + bool make_snap = false; + if (m_keep_ratio) { std::stringstream ss; ss << std::setprecision(2) << std::fixed << width << " x " << height << " " << (use_inch ? "in" : "mm"); @@ -1708,6 +1709,8 @@ void GLGizmoSVG::draw_size() new_relative_scale = Vec3d(width_ratio, width_ratio, 1.); } } + if (m_imgui->get_last_slider_status().deactivated_after_edit) + make_snap = true; // only last change of slider make snap } else { ImGuiInputTextFlags flags = 0; @@ -1727,6 +1730,7 @@ void GLGizmoSVG::draw_size() if (is_valid_scale_ratio(width_ratio)) { m_scale_width = m_scale_width.value_or(1.f) * width_ratio; new_relative_scale = Vec3d(width_ratio, 1., 1.); + make_snap = true; } } if (ImGui::IsItemHovered()) @@ -1740,6 +1744,7 @@ void GLGizmoSVG::draw_size() if (is_valid_scale_ratio(height_ratio)) { m_scale_height = m_scale_height.value_or(1.f) * height_ratio; new_relative_scale = Vec3d(1., height_ratio, 1.); + make_snap = true; } } if (ImGui::IsItemHovered()) @@ -1761,6 +1766,7 @@ void GLGizmoSVG::draw_size() if (can_reset) { if (reset_button(m_icons)) { new_relative_scale = Vec3d(1./m_scale_width.value_or(1.f), 1./m_scale_height.value_or(1.f), 1.); + make_snap = true; } else if (ImGui::IsItemHovered()) ImGui::SetTooltip("%s", _u8L("Reset scale").c_str()); } @@ -1774,20 +1780,25 @@ void GLGizmoSVG::draw_size() }; selection_transform(selection, selection_scale_fnc); - m_parent.do_scale(L("Resize")); + std::string snap_name; // Empty mean do not store on undo/redo stack + m_parent.do_scale(snap_name); wxGetApp().obj_manipul()->set_dirty(); // should be the almost same calculate_scale(); - NSVGimage *img = m_volume_shape.svg_file->image.get(); + const NSVGimage *img = m_volume_shape.svg_file->image.get(); assert(img != NULL); if (img != NULL){ NSVGLineParams params{get_tesselation_tolerance(get_scale_for_tolerance())}; m_volume_shape.shapes_with_ids = create_shape_with_ids(*img, params); m_volume_shape.final_shape = {}; // reset cache for final shape - process(); + if (!make_snap) // Be carefull: Last change may be without change of scale + process(false); } } + + if (make_snap) + process(); // make undo/redo snap-shot } void GLGizmoSVG::draw_use_surface() diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSVG.hpp b/src/slic3r/GUI/Gizmos/GLGizmoSVG.hpp index 36b1258340..103051c0fa 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSVG.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSVG.hpp @@ -112,7 +112,7 @@ private: void reset_volume(); // create volume from text - main functionality - bool process(); + bool process(bool make_snapshot = true); void close(); void draw_window(); void draw_preview(); diff --git a/src/slic3r/GUI/Jobs/EmbossJob.cpp b/src/slic3r/GUI/Jobs/EmbossJob.cpp index 32b0effbd7..1a72cd7dfc 100644 --- a/src/slic3r/GUI/Jobs/EmbossJob.cpp +++ b/src/slic3r/GUI/Jobs/EmbossJob.cpp @@ -1031,10 +1031,13 @@ void update_volume(TriangleMesh &&mesh, const DataUpdate &data, const Transform3 assert(plater->canvas3D()->get_gizmos_manager().get_current_type() == GLGizmosManager::Emboss || plater->canvas3D()->get_gizmos_manager().get_current_type() == GLGizmosManager::Svg); - // TRN: This is the name of the action appearing in undo/redo stack. - std::string snap_name = _u8L("Text/SVG attribute change"); - Plater::TakeSnapshot snapshot(plater, snap_name, UndoRedo::SnapshotType::GizmoAction); - + if (data.make_snapshot) { + // TRN: This is the title of the action appearing in undo/redo stack. + // It is same for Text and SVG. + std::string snap_name = _u8L("Emboss attribute change"); + Plater::TakeSnapshot snapshot(plater, snap_name, UndoRedo::SnapshotType::GizmoAction); + } + ModelVolume *volume = get_model_volume(data.volume_id, plater->model().objects); // could appear when user delete edited volume diff --git a/src/slic3r/GUI/Jobs/EmbossJob.hpp b/src/slic3r/GUI/Jobs/EmbossJob.hpp index 8dec29572c..46061f3bce 100644 --- a/src/slic3r/GUI/Jobs/EmbossJob.hpp +++ b/src/slic3r/GUI/Jobs/EmbossJob.hpp @@ -113,6 +113,9 @@ struct DataUpdate // unique identifier of volume to change ObjectID volume_id; + + // Used for prevent flooding Undo/Redo stack on slider. + bool make_snapshot; }; /// From 05312cacf7e2f76ea34c8359abeb68ef0d64b9b0 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Thu, 18 Jan 2024 22:20:40 +0100 Subject: [PATCH 88/91] Fix of #11790: missing wlanapi.dll on Win Server 2019 --- src/slic3r/Utils/WifiScanner.cpp | 61 ++++++++++++++++++++++++-------- 1 file changed, 46 insertions(+), 15 deletions(-) diff --git a/src/slic3r/Utils/WifiScanner.cpp b/src/slic3r/Utils/WifiScanner.cpp index aa4c8f4e9f..40b4c98038 100644 --- a/src/slic3r/Utils/WifiScanner.cpp +++ b/src/slic3r/Utils/WifiScanner.cpp @@ -12,9 +12,8 @@ #include #include -// Need to link with Wlanapi.lib and Ole32.lib -#pragma comment(lib, "wlanapi.lib") -#pragma comment(lib, "ole32.lib") +#include "libslic3r//Utils.hpp" + #elif __APPLE_ #include "WifiScannerMac.h" #endif @@ -49,17 +48,49 @@ bool ptree_get_value(const boost::property_tree::ptree& pt, const std::string& t // https://learn.microsoft.com/en-us/windows/win32/api/wlanapi/nf-wlanapi-wlangetavailablenetworklist void fill_wifi_map(Slic3r::WifiSsidPskMap& wifi_map, std::string& connected_ssid) { + HINSTANCE hWlanApi = LoadLibrary(L"wlanapi.dll"); + if (hWlanApi == NULL) + return; + Slic3r::ScopeGuard guard([&hWlanApi] { FreeLibrary(hWlanApi); }); + + using WlanOpenHandleFunc = DWORD(WINAPI*)(DWORD, PVOID, PDWORD, PHANDLE); + using WlanEnumInterfacesFunc = DWORD(WINAPI*)(HANDLE, PVOID, PWLAN_INTERFACE_INFO_LIST*); + using WlanQueryInterfaceFunc = DWORD(WINAPI*)(HANDLE, const GUID*, WLAN_INTF_OPCODE, PVOID, PDWORD, PVOID*, PWLAN_OPCODE_VALUE_TYPE); + using WlanFreeMemoryFunc = VOID(WINAPI* )(PVOID); + using WlanGetProfileFunc = DWORD(WINAPI*)(HANDLE, const GUID*, LPCWSTR, PVOID, LPWSTR*, DWORD*, DWORD*); + using WlanGetProfileListFunc = DWORD(WINAPI*)(HANDLE, const GUID*, PVOID, PWLAN_PROFILE_INFO_LIST*); + using WlanGetAvailableNetworkListFunc = DWORD(WINAPI*)(HANDLE, const GUID*, DWORD, PVOID, PWLAN_AVAILABLE_NETWORK_LIST*); + using WlanCloseHandleFunc = DWORD(WINAPI*)(HANDLE, PVOID); + + WlanOpenHandleFunc wlanOpenHandleFunc = reinterpret_cast(GetProcAddress(hWlanApi, "WlanOpenHandle")); + WlanEnumInterfacesFunc wlanEnumInterfacesFunc = reinterpret_cast(GetProcAddress(hWlanApi, "WlanEnumInterfaces")); + WlanQueryInterfaceFunc wlanQueryInterfaceFunc = reinterpret_cast(GetProcAddress(hWlanApi, "WlanQueryInterface")); + WlanFreeMemoryFunc wlanFreeMemoryFunc = reinterpret_cast(GetProcAddress(hWlanApi, "WlanFreeMemory")); + WlanGetProfileFunc wlanGetProfileFunc = reinterpret_cast(GetProcAddress(hWlanApi, "WlanGetProfile")); + WlanGetProfileListFunc wlanGetProfileListFunc = reinterpret_cast(GetProcAddress(hWlanApi, "WlanGetProfileList")); + WlanGetAvailableNetworkListFunc wlanGetAvailableNetworkListFunc = reinterpret_cast(GetProcAddress(hWlanApi, "WlanGetAvailableNetworkList")); + WlanCloseHandleFunc wlanCloseHandleFunc = reinterpret_cast(GetProcAddress(hWlanApi, "WlanCloseHandle")); + + if (! wlanOpenHandleFunc || ! wlanEnumInterfacesFunc || ! wlanQueryInterfaceFunc || ! wlanFreeMemoryFunc + || ! wlanGetProfileFunc || ! wlanGetProfileListFunc || ! wlanGetAvailableNetworkListFunc || ! wlanCloseHandleFunc) + return; + + HANDLE handle; DWORD supported_version = 0; DWORD client_version = 2; PWLAN_INTERFACE_INFO_LIST interface_list = NULL; - - if (WlanOpenHandle(client_version, NULL, &supported_version, &handle) != ERROR_SUCCESS) + + if (wlanOpenHandleFunc(client_version, NULL, &supported_version, &handle) != ERROR_SUCCESS) return; - if (WlanEnumInterfaces(handle, NULL, &interface_list) != ERROR_SUCCESS) + if (wlanEnumInterfacesFunc(handle, NULL, &interface_list) != ERROR_SUCCESS) { + // Touhle cestou funkce vrati bez toho, aby zavolala WlanCloseHandleFunc. + // I tady by stalo za uvahu pouziti ScopeGuard, ktery podobnou chybu vylouci + // a kod bude exception-safe (coz je tady asi jedno, ale obecne to jedno neni). return; + } for (DWORD i = 0; i < interface_list->dwNumberOfItems; i++) { @@ -69,7 +100,7 @@ void fill_wifi_map(Slic3r::WifiSsidPskMap& wifi_map, std::string& connected_ssid DWORD connectInfoSize = sizeof(WLAN_CONNECTION_ATTRIBUTES); WLAN_OPCODE_VALUE_TYPE opCode = wlan_opcode_value_type_invalid; - if (WlanQueryInterface(handle, &interface_list->InterfaceInfo[i].InterfaceGuid, + if (wlanQueryInterfaceFunc(handle, &interface_list->InterfaceInfo[i].InterfaceGuid, wlan_intf_opcode_current_connection, NULL, &connectInfoSize, (PVOID*)&pConnectInfo, &opCode) == ERROR_SUCCESS && pConnectInfo && pConnectInfo->wlanAssociationAttributes.dot11Ssid.uSSIDLength) { @@ -77,7 +108,7 @@ void fill_wifi_map(Slic3r::WifiSsidPskMap& wifi_map, std::string& connected_ssid pConnectInfo->wlanAssociationAttributes.dot11Ssid.uSSIDLength); } - WlanFreeMemory(pConnectInfo); + wlanFreeMemoryFunc(pConnectInfo); } PWLAN_PROFILE_INFO_LIST profile_list = NULL; @@ -90,7 +121,7 @@ void fill_wifi_map(Slic3r::WifiSsidPskMap& wifi_map, std::string& connected_ssid int iRet = StringFromGUID2(interface_info_entry->InterfaceGuid, (LPOLESTR)&guid, sizeof(guid) / sizeof(*guid)); - if (WlanGetAvailableNetworkList(handle, + if (wlanGetAvailableNetworkListFunc(handle, &interface_info_entry->InterfaceGuid, 0, NULL, @@ -121,7 +152,7 @@ void fill_wifi_map(Slic3r::WifiSsidPskMap& wifi_map, std::string& connected_ssid wifi_map[ssid] = std::string(); - if (WlanGetProfileList(handle, &interface_list->InterfaceInfo[i].InterfaceGuid, + if (wlanGetProfileListFunc(handle, &interface_list->InterfaceInfo[i].InterfaceGuid, NULL, &profile_list) != ERROR_SUCCESS) { continue; @@ -140,7 +171,7 @@ void fill_wifi_map(Slic3r::WifiSsidPskMap& wifi_map, std::string& connected_ssid if (s != ssid) continue; - if ((ret = WlanGetProfile(handle, &interface_list->InterfaceInfo[i].InterfaceGuid, profile_list->ProfileInfo[k].strProfileName, + if ((ret = wlanGetProfileFunc(handle, &interface_list->InterfaceInfo[i].InterfaceGuid, profile_list->ProfileInfo[k].strProfileName, NULL, &xmlstr, &flags, &access)) == ERROR_SUCCESS && xmlstr) { wxString xml(xmlstr); @@ -160,20 +191,20 @@ void fill_wifi_map(Slic3r::WifiSsidPskMap& wifi_map, std::string& connected_ssid if (ptree_get_value(pt, "keyMaterial", password)) wifi_map[ssid] = password; - WlanFreeMemory(xmlstr); + wlanFreeMemoryFunc(xmlstr); break; } } if (profile_list) { - WlanFreeMemory(profile_list); + wlanFreeMemoryFunc(profile_list); } } } if (interface_list) - WlanFreeMemory(interface_list); - WlanCloseHandle(handle, NULL); + wlanFreeMemoryFunc(interface_list); + wlanCloseHandleFunc(handle, NULL); } #elif __APPLE__ void get_connected_ssid(std::string& connected_ssid) From e0e1afd6400bf2c23df5baa3d4e948f50ac2c880 Mon Sep 17 00:00:00 2001 From: David Kocik Date: Fri, 19 Jan 2024 15:19:41 +0100 Subject: [PATCH 89/91] Error message when wlanapi.dll is missing Code improvements due to @lukasmatena code review. --- src/slic3r/GUI/WifiConfigDialog.cpp | 16 ++ src/slic3r/Utils/WifiScanner.cpp | 333 ++++++++++++++-------------- src/slic3r/Utils/WifiScanner.hpp | 34 ++- 3 files changed, 214 insertions(+), 169 deletions(-) diff --git a/src/slic3r/GUI/WifiConfigDialog.cpp b/src/slic3r/GUI/WifiConfigDialog.cpp index e5be758be5..9e535337fc 100644 --- a/src/slic3r/GUI/WifiConfigDialog.cpp +++ b/src/slic3r/GUI/WifiConfigDialog.cpp @@ -29,6 +29,19 @@ WifiConfigDialog::WifiConfigDialog(wxWindow* parent, std::string& file_path, Rem , out_file_path(file_path) , m_removable_manager(removable_manager) { + // Propagation of error in wifi scanner construtor + if (!m_wifi_scanner->is_init()) { + // TRN Error dialog of configuration -> wifi configuration file + wxString msg = format_wxstr(L"%1%\n\n%2%", _L("Failed to scan wireless networks. Please fill SSID manually."), +#ifdef _WIN32 + // TRN Windows specific second line of error dialog of configuration -> wifi configuration file + _L("Library wlanapi.dll was not loaded.") +#else + "" +#endif // _WIN32 + ); + show_error(this, msg); + } wxPanel* panel = new wxPanel(this); wxBoxSizer* vsizer = new wxBoxSizer(wxVERTICAL); panel->SetSizer(vsizer); @@ -188,6 +201,9 @@ void WifiConfigDialog::on_rescan_networks(wxCommandEvent& e) void WifiConfigDialog::rescan_networks(bool select) { assert(m_ssid_combo && m_wifi_scanner); + // Do not do anything if scanner is in faulty state (which should has been propageted in constructor call) + if (!m_wifi_scanner->is_init()) + return; m_wifi_scanner->scan(); std::string current = m_wifi_scanner->get_current_ssid(); const auto& map = m_wifi_scanner->get_map(); diff --git a/src/slic3r/Utils/WifiScanner.cpp b/src/slic3r/Utils/WifiScanner.cpp index 40b4c98038..390a6b2e04 100644 --- a/src/slic3r/Utils/WifiScanner.cpp +++ b/src/slic3r/Utils/WifiScanner.cpp @@ -8,7 +8,6 @@ #ifdef _WIN32 #include -#include #include #include @@ -42,170 +41,6 @@ bool ptree_get_value(const boost::property_tree::ptree& pt, const std::string& t return false; // Element not found in this subtree } - -// Fill SSID map. Implementation from Raspberry Pi imager and Win32 Api examples. -// https://github.com/raspberrypi/rpi-imager/blob/qml/src/windows/winwlancredentials.cpp -// https://learn.microsoft.com/en-us/windows/win32/api/wlanapi/nf-wlanapi-wlangetavailablenetworklist -void fill_wifi_map(Slic3r::WifiSsidPskMap& wifi_map, std::string& connected_ssid) -{ - HINSTANCE hWlanApi = LoadLibrary(L"wlanapi.dll"); - if (hWlanApi == NULL) - return; - Slic3r::ScopeGuard guard([&hWlanApi] { FreeLibrary(hWlanApi); }); - - using WlanOpenHandleFunc = DWORD(WINAPI*)(DWORD, PVOID, PDWORD, PHANDLE); - using WlanEnumInterfacesFunc = DWORD(WINAPI*)(HANDLE, PVOID, PWLAN_INTERFACE_INFO_LIST*); - using WlanQueryInterfaceFunc = DWORD(WINAPI*)(HANDLE, const GUID*, WLAN_INTF_OPCODE, PVOID, PDWORD, PVOID*, PWLAN_OPCODE_VALUE_TYPE); - using WlanFreeMemoryFunc = VOID(WINAPI* )(PVOID); - using WlanGetProfileFunc = DWORD(WINAPI*)(HANDLE, const GUID*, LPCWSTR, PVOID, LPWSTR*, DWORD*, DWORD*); - using WlanGetProfileListFunc = DWORD(WINAPI*)(HANDLE, const GUID*, PVOID, PWLAN_PROFILE_INFO_LIST*); - using WlanGetAvailableNetworkListFunc = DWORD(WINAPI*)(HANDLE, const GUID*, DWORD, PVOID, PWLAN_AVAILABLE_NETWORK_LIST*); - using WlanCloseHandleFunc = DWORD(WINAPI*)(HANDLE, PVOID); - - WlanOpenHandleFunc wlanOpenHandleFunc = reinterpret_cast(GetProcAddress(hWlanApi, "WlanOpenHandle")); - WlanEnumInterfacesFunc wlanEnumInterfacesFunc = reinterpret_cast(GetProcAddress(hWlanApi, "WlanEnumInterfaces")); - WlanQueryInterfaceFunc wlanQueryInterfaceFunc = reinterpret_cast(GetProcAddress(hWlanApi, "WlanQueryInterface")); - WlanFreeMemoryFunc wlanFreeMemoryFunc = reinterpret_cast(GetProcAddress(hWlanApi, "WlanFreeMemory")); - WlanGetProfileFunc wlanGetProfileFunc = reinterpret_cast(GetProcAddress(hWlanApi, "WlanGetProfile")); - WlanGetProfileListFunc wlanGetProfileListFunc = reinterpret_cast(GetProcAddress(hWlanApi, "WlanGetProfileList")); - WlanGetAvailableNetworkListFunc wlanGetAvailableNetworkListFunc = reinterpret_cast(GetProcAddress(hWlanApi, "WlanGetAvailableNetworkList")); - WlanCloseHandleFunc wlanCloseHandleFunc = reinterpret_cast(GetProcAddress(hWlanApi, "WlanCloseHandle")); - - if (! wlanOpenHandleFunc || ! wlanEnumInterfacesFunc || ! wlanQueryInterfaceFunc || ! wlanFreeMemoryFunc - || ! wlanGetProfileFunc || ! wlanGetProfileListFunc || ! wlanGetAvailableNetworkListFunc || ! wlanCloseHandleFunc) - return; - - - HANDLE handle; - DWORD supported_version = 0; - DWORD client_version = 2; - PWLAN_INTERFACE_INFO_LIST interface_list = NULL; - - - if (wlanOpenHandleFunc(client_version, NULL, &supported_version, &handle) != ERROR_SUCCESS) - return; - - if (wlanEnumInterfacesFunc(handle, NULL, &interface_list) != ERROR_SUCCESS) { - // Touhle cestou funkce vrati bez toho, aby zavolala WlanCloseHandleFunc. - // I tady by stalo za uvahu pouziti ScopeGuard, ktery podobnou chybu vylouci - // a kod bude exception-safe (coz je tady asi jedno, ale obecne to jedno neni). - return; - } - - for (DWORD i = 0; i < interface_list->dwNumberOfItems; i++) - { - if (interface_list->InterfaceInfo[i].isState == wlan_interface_state_connected) - { - PWLAN_CONNECTION_ATTRIBUTES pConnectInfo = NULL; - DWORD connectInfoSize = sizeof(WLAN_CONNECTION_ATTRIBUTES); - WLAN_OPCODE_VALUE_TYPE opCode = wlan_opcode_value_type_invalid; - - if (wlanQueryInterfaceFunc(handle, &interface_list->InterfaceInfo[i].InterfaceGuid, - wlan_intf_opcode_current_connection, NULL, - &connectInfoSize, (PVOID*)&pConnectInfo, &opCode) == ERROR_SUCCESS && pConnectInfo && pConnectInfo->wlanAssociationAttributes.dot11Ssid.uSSIDLength) - { - connected_ssid = std::string((const char*)pConnectInfo->wlanAssociationAttributes.dot11Ssid.ucSSID, - pConnectInfo->wlanAssociationAttributes.dot11Ssid.uSSIDLength); - } - - wlanFreeMemoryFunc(pConnectInfo); - } - - PWLAN_PROFILE_INFO_LIST profile_list = NULL; - PWLAN_INTERFACE_INFO interface_info_entry = NULL; - PWLAN_AVAILABLE_NETWORK_LIST available_network_list = NULL; - WCHAR guid[39] = { 0 }; - - // Get all available networks. - interface_info_entry = (WLAN_INTERFACE_INFO*)&interface_list->InterfaceInfo[i]; - int iRet = StringFromGUID2(interface_info_entry->InterfaceGuid, (LPOLESTR)&guid, - sizeof(guid) / sizeof(*guid)); - - if (wlanGetAvailableNetworkListFunc(handle, - &interface_info_entry->InterfaceGuid, - 0, - NULL, - &available_network_list) - != ERROR_SUCCESS) - { - continue; - } - - for (unsigned int j = 0; j < available_network_list->dwNumberOfItems; j++) - { - PWLAN_AVAILABLE_NETWORK available_network_entry = NULL; - wxString ssid; - - // Store SSID into the map. - available_network_entry = - (WLAN_AVAILABLE_NETWORK*)&available_network_list->Network[j]; - - if (available_network_entry->dot11Ssid.uSSIDLength != 0) - ssid = wxString(available_network_entry->dot11Ssid.ucSSID, - available_network_entry->dot11Ssid.uSSIDLength); - - if (ssid.empty()) - continue; - - if (wifi_map.find(ssid) != wifi_map.end()) - continue; - - wifi_map[ssid] = std::string(); - - if (wlanGetProfileListFunc(handle, &interface_list->InterfaceInfo[i].InterfaceGuid, - NULL, &profile_list) != ERROR_SUCCESS) - { - continue; - } - // enmurate all stored profiles, take password from matching one. - for (DWORD k = 0; k < profile_list->dwNumberOfItems; k++) - { - DWORD flags = WLAN_PROFILE_GET_PLAINTEXT_KEY; - DWORD access = 0; - DWORD ret = 0; - LPWSTR xmlstr = NULL; - wxString s(profile_list->ProfileInfo[k].strProfileName); - - BOOST_LOG_TRIVIAL(debug) << "Enumerating wlan profiles, SSID found:" << s << " looking for:" << ssid; - - if (s != ssid) - continue; - - if ((ret = wlanGetProfileFunc(handle, &interface_list->InterfaceInfo[i].InterfaceGuid, profile_list->ProfileInfo[k].strProfileName, - NULL, &xmlstr, &flags, &access)) == ERROR_SUCCESS && xmlstr) - { - wxString xml(xmlstr); - boost::property_tree::ptree pt; - std::stringstream ss(boost::nowide::narrow(xml)); - boost::property_tree::read_xml(ss, pt); - std::string password; - std::string psk_protected; - - BOOST_LOG_TRIVIAL(debug) << "XML wlan profile:" << xml; - - // break if password is not readable - // TODO: what if there is other line "protected" in the XML? - if (ptree_get_value(pt, "protected", psk_protected) && psk_protected != "false") - break; - - if (ptree_get_value(pt, "keyMaterial", password)) - wifi_map[ssid] = password; - - wlanFreeMemoryFunc(xmlstr); - break; - } - } - - if (profile_list) { - wlanFreeMemoryFunc(profile_list); - } - } - } - - if (interface_list) - wlanFreeMemoryFunc(interface_list); - wlanCloseHandleFunc(handle, NULL); -} #elif __APPLE__ void get_connected_ssid(std::string& connected_ssid) { @@ -426,11 +261,39 @@ void fill_wifi_map(Slic3r::WifiSsidPskMap& wifi_map) namespace Slic3r { WifiScanner::WifiScanner() -{} +{ +#ifdef _WIN32 + m_wlanapi_handle = LoadLibrary(L"wlanapi.dll"); + if (m_wlanapi_handle == NULL) + return; + + wlanOpenHandleFunc = reinterpret_cast(GetProcAddress(m_wlanapi_handle, "WlanOpenHandle")); + wlanEnumInterfacesFunc = reinterpret_cast(GetProcAddress(m_wlanapi_handle, "WlanEnumInterfaces")); + wlanQueryInterfaceFunc = reinterpret_cast(GetProcAddress(m_wlanapi_handle, "WlanQueryInterface")); + wlanFreeMemoryFunc = reinterpret_cast(GetProcAddress(m_wlanapi_handle, "WlanFreeMemory")); + wlanGetProfileFunc = reinterpret_cast(GetProcAddress(m_wlanapi_handle, "WlanGetProfile")); + wlanGetProfileListFunc = reinterpret_cast(GetProcAddress(m_wlanapi_handle, "WlanGetProfileList")); + wlanGetAvailableNetworkListFunc = reinterpret_cast(GetProcAddress(m_wlanapi_handle, "WlanGetAvailableNetworkList")); + wlanCloseHandleFunc = reinterpret_cast(GetProcAddress(m_wlanapi_handle, "WlanCloseHandle")); + + if (!wlanOpenHandleFunc || !wlanEnumInterfacesFunc || !wlanQueryInterfaceFunc || !wlanFreeMemoryFunc + || !wlanGetProfileFunc || !wlanGetProfileListFunc || !wlanGetAvailableNetworkListFunc || !wlanCloseHandleFunc) + return; +#endif // _WIN32 + m_init = true; +} WifiScanner::~WifiScanner() -{} +{ +#ifdef _WIN32 + if (m_wlanapi_handle) + FreeLibrary(m_wlanapi_handle); +#endif // _WIN32 + +} void WifiScanner::scan() { + if (!m_init) + return; m_map.clear(); #ifdef _WIN32 fill_wifi_map(m_map, m_current_ssid); @@ -490,4 +353,140 @@ std::string WifiScanner::get_psk(const std::string& ssid) } return {}; } + +#ifdef _WIN32 +// Fill SSID map. Implementation from Raspberry Pi imager and Win32 Api examples. +// https://github.com/raspberrypi/rpi-imager/blob/qml/src/windows/winwlancredentials.cpp +// https://learn.microsoft.com/en-us/windows/win32/api/wlanapi/nf-wlanapi-wlangetavailablenetworklist +void WifiScanner::fill_wifi_map(Slic3r::WifiSsidPskMap& wifi_map, std::string& connected_ssid) +{ + HANDLE handle; + DWORD supported_version = 0; + DWORD client_version = 2; + PWLAN_INTERFACE_INFO_LIST interface_list = NULL; + + if (!m_init) + return; + + if (wlanOpenHandleFunc(client_version, NULL, &supported_version, &handle) != ERROR_SUCCESS) + return; + + Slic3r::ScopeGuard guard([this, &handle] { wlanCloseHandleFunc(handle, NULL); }); + + if (wlanEnumInterfacesFunc(handle, NULL, &interface_list) != ERROR_SUCCESS) + return; + + for (DWORD i = 0; i < interface_list->dwNumberOfItems; i++) + { + if (interface_list->InterfaceInfo[i].isState == wlan_interface_state_connected) + { + PWLAN_CONNECTION_ATTRIBUTES pConnectInfo = NULL; + DWORD connectInfoSize = sizeof(WLAN_CONNECTION_ATTRIBUTES); + WLAN_OPCODE_VALUE_TYPE opCode = wlan_opcode_value_type_invalid; + + if (wlanQueryInterfaceFunc(handle, &interface_list->InterfaceInfo[i].InterfaceGuid, + wlan_intf_opcode_current_connection, NULL, + &connectInfoSize, (PVOID*)&pConnectInfo, &opCode) == ERROR_SUCCESS && pConnectInfo && pConnectInfo->wlanAssociationAttributes.dot11Ssid.uSSIDLength) + { + connected_ssid = std::string((const char*)pConnectInfo->wlanAssociationAttributes.dot11Ssid.ucSSID, + pConnectInfo->wlanAssociationAttributes.dot11Ssid.uSSIDLength); + wlanFreeMemoryFunc(pConnectInfo); + } + } + + PWLAN_PROFILE_INFO_LIST profile_list = NULL; + PWLAN_INTERFACE_INFO interface_info_entry = NULL; + PWLAN_AVAILABLE_NETWORK_LIST available_network_list = NULL; + WCHAR guid[39] = { 0 }; + + // Get all available networks. + interface_info_entry = (WLAN_INTERFACE_INFO*)&interface_list->InterfaceInfo[i]; + int iRet = StringFromGUID2(interface_info_entry->InterfaceGuid, (LPOLESTR)&guid, + sizeof(guid) / sizeof(*guid)); + + if (wlanGetAvailableNetworkListFunc(handle, + &interface_info_entry->InterfaceGuid, + 0, + NULL, + &available_network_list) + != ERROR_SUCCESS) + { + continue; + } + + for (unsigned int j = 0; j < available_network_list->dwNumberOfItems; j++) + { + PWLAN_AVAILABLE_NETWORK available_network_entry = NULL; + wxString ssid; + + // Store SSID into the map. + available_network_entry = + (WLAN_AVAILABLE_NETWORK*)&available_network_list->Network[j]; + + if (available_network_entry->dot11Ssid.uSSIDLength != 0) + ssid = wxString(available_network_entry->dot11Ssid.ucSSID, + available_network_entry->dot11Ssid.uSSIDLength); + + if (ssid.empty()) + continue; + + if (wifi_map.find(ssid) != wifi_map.end()) + continue; + + wifi_map[ssid] = std::string(); + + if (wlanGetProfileListFunc(handle, &interface_list->InterfaceInfo[i].InterfaceGuid, + NULL, &profile_list) != ERROR_SUCCESS) + { + continue; + } + // enmurate all stored profiles, take password from matching one. + for (DWORD k = 0; k < profile_list->dwNumberOfItems; k++) + { + DWORD flags = WLAN_PROFILE_GET_PLAINTEXT_KEY; + DWORD access = 0; + DWORD ret = 0; + LPWSTR xmlstr = NULL; + wxString s(profile_list->ProfileInfo[k].strProfileName); + + BOOST_LOG_TRIVIAL(debug) << "Enumerating wlan profiles, SSID found:" << s << " looking for:" << ssid; + + if (s != ssid) + continue; + + if ((ret = wlanGetProfileFunc(handle, &interface_list->InterfaceInfo[i].InterfaceGuid, profile_list->ProfileInfo[k].strProfileName, + NULL, &xmlstr, &flags, &access)) == ERROR_SUCCESS && xmlstr) + { + wxString xml(xmlstr); + boost::property_tree::ptree pt; + std::stringstream ss(boost::nowide::narrow(xml)); + boost::property_tree::read_xml(ss, pt); + std::string password; + std::string psk_protected; + + BOOST_LOG_TRIVIAL(debug) << "XML wlan profile:" << xml; + + // break if password is not readable + // TODO: what if there is other line "protected" in the XML? + if (ptree_get_value(pt, "protected", psk_protected) && psk_protected != "false") + break; + + if (ptree_get_value(pt, "keyMaterial", password)) + wifi_map[ssid] = password; + + wlanFreeMemoryFunc(xmlstr); + break; + } + } + + if (profile_list) { + wlanFreeMemoryFunc(profile_list); + } + } + } + + if (interface_list) + wlanFreeMemoryFunc(interface_list); +} +#endif // _WIN32 } // Slic3r \ No newline at end of file diff --git a/src/slic3r/Utils/WifiScanner.hpp b/src/slic3r/Utils/WifiScanner.hpp index 96befa5e65..0223e2d8dc 100644 --- a/src/slic3r/Utils/WifiScanner.hpp +++ b/src/slic3r/Utils/WifiScanner.hpp @@ -6,9 +6,13 @@ #include #include +#ifdef _WIN32 +#include +#endif //_WIN32 + namespace Slic3r { -typedef std::map WifiSsidPskMap; +using WifiSsidPskMap = std::map; class WifiScanner { @@ -16,6 +20,8 @@ public: WifiScanner(); ~WifiScanner(); + bool is_init() const { return m_init; } + const WifiSsidPskMap& get_map() const { return m_map; } // returns psk for given ssid // used on APPLE where each psk query requires user to give their password @@ -27,7 +33,31 @@ public: private: WifiSsidPskMap m_map; std::string m_current_ssid; -#if __APPLE__ + + bool m_init { false }; + +#ifdef _WIN32 + void fill_wifi_map(Slic3r::WifiSsidPskMap& wifi_map, std::string& connected_ssid); + HINSTANCE m_wlanapi_handle; + // Functions of wlanapi used by fill_wifi_map + using WlanOpenHandleFunc = DWORD(WINAPI*)(DWORD, PVOID, PDWORD, PHANDLE); + using WlanEnumInterfacesFunc = DWORD(WINAPI*)(HANDLE, PVOID, PWLAN_INTERFACE_INFO_LIST*); + using WlanQueryInterfaceFunc = DWORD(WINAPI*)(HANDLE, const GUID*, WLAN_INTF_OPCODE, PVOID, PDWORD, PVOID*, PWLAN_OPCODE_VALUE_TYPE); + using WlanFreeMemoryFunc = VOID(WINAPI*)(PVOID); + using WlanGetProfileFunc = DWORD(WINAPI*)(HANDLE, const GUID*, LPCWSTR, PVOID, LPWSTR*, DWORD*, DWORD*); + using WlanGetProfileListFunc = DWORD(WINAPI*)(HANDLE, const GUID*, PVOID, PWLAN_PROFILE_INFO_LIST*); + using WlanGetAvailableNetworkListFunc = DWORD(WINAPI*)(HANDLE, const GUID*, DWORD, PVOID, PWLAN_AVAILABLE_NETWORK_LIST*); + using WlanCloseHandleFunc = DWORD(WINAPI*)(HANDLE, PVOID); + + WlanOpenHandleFunc wlanOpenHandleFunc; + WlanEnumInterfacesFunc wlanEnumInterfacesFunc; + WlanQueryInterfaceFunc wlanQueryInterfaceFunc; + WlanFreeMemoryFunc wlanFreeMemoryFunc; + WlanGetProfileFunc wlanGetProfileFunc; + WlanGetProfileListFunc wlanGetProfileListFunc; + WlanGetAvailableNetworkListFunc wlanGetAvailableNetworkListFunc; + WlanCloseHandleFunc wlanCloseHandleFunc; +#elif __APPLE__ void get_ssids_mac(std::vector& ssids); std::string get_psk_mac(const std::string& ssid); std::string get_current_ssid_mac(); From df14f7518dfbb98154d5efe5ba9bcd6e4e6a234d Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Thu, 25 Jan 2024 09:33:16 +0100 Subject: [PATCH 90/91] SPE-2092: Fixed OpenGL initialization when user specifies invalid value for command line option 'opengl-version' --- src/PrusaSlicer.cpp | 7 ++++++- src/slic3r/GUI/OpenGLManager.cpp | 15 +++++++++++---- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/PrusaSlicer.cpp b/src/PrusaSlicer.cpp index 44f1c28d34..79bb8b6f95 100644 --- a/src/PrusaSlicer.cpp +++ b/src/PrusaSlicer.cpp @@ -190,8 +190,13 @@ int CLI::run(int argc, char **argv) if (semver.has_value() && (*semver) >= opengl_minimum ) { opengl_version.first = semver->maj(); opengl_version.second = semver->min(); + if (std::find(Slic3r::GUI::OpenGLVersions::core.begin(), Slic3r::GUI::OpenGLVersions::core.end(), std::make_pair(opengl_version.first, opengl_version.second)) == Slic3r::GUI::OpenGLVersions::core.end()) { + opengl_version = { 0, 0 }; + boost::nowide::cerr << "Required OpenGL version " << opengl_version_str << " not recognized.\n Option 'opengl-version' ignored." << std::endl; + } } else - boost::nowide::cerr << "Required OpenGL version " << opengl_version_str << " is invalid. Must be greater than or equal to " << opengl_minimum.to_string() << std::endl; + boost::nowide::cerr << "Required OpenGL version " << opengl_version_str << " is invalid. Must be greater than or equal to " << + opengl_minimum.to_string() << "\n Option 'opengl-version' ignored." << std::endl; start_gui = true; m_actions.erase(it); } diff --git a/src/slic3r/GUI/OpenGLManager.cpp b/src/slic3r/GUI/OpenGLManager.cpp index c9df0caaa6..003538266c 100644 --- a/src/slic3r/GUI/OpenGLManager.cpp +++ b/src/slic3r/GUI/OpenGLManager.cpp @@ -458,7 +458,8 @@ wxGLContext* OpenGLManager::init_glcontext(wxGLCanvas& canvas) const int gl_major = required_opengl_version.first; const int gl_minor = required_opengl_version.second; - const bool supports_core_profile = (gl_major < 3) ? false : (gl_major > 3) ? true : gl_minor >= 2; + const bool supports_core_profile = + std::find(OpenGLVersions::core.begin(), OpenGLVersions::core.end(), std::make_pair(gl_major, gl_minor)) != OpenGLVersions::core.end(); if (gl_major == 0 && !enable_compatibility_profile) { // search for highest supported core profile version @@ -513,9 +514,15 @@ wxGLContext* OpenGLManager::init_glcontext(wxGLCanvas& canvas) } } - if (m_context == nullptr) - // no valid context was created - throw Slic3r::RuntimeError("Unable to create context for OpenGL."); + if (m_context == nullptr) { + wxGLContextAttrs attrs; + attrs.PlatformDefaults(); + if (m_debug_enabled) + attrs.DebugCtx(); + attrs.EndList(); + // if no valid context was created use the default one + m_context = new wxGLContext(&canvas, nullptr, &attrs); + } #else m_context = new wxGLContext(&canvas); #endif // ENABLE_OPENGL_ES From 69e0bc3064298fc58dd2a870801161821fa16da5 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Fri, 26 Jan 2024 12:54:10 +0100 Subject: [PATCH 91/91] Revert "Fix for #11988 : Drop down menus appear outside of PS and cannot be opened again" This reverts commit 6ff8537ff4fbd14ca09934cdb2bb987131a7b559. There is a non-trivial conflict when merging to master, let's redo the commit after the merge so it is clear in history. --- src/slic3r/GUI/Plater.cpp | 28 ---------------------------- src/slic3r/GUI/Widgets/DropDown.hpp | 2 -- 2 files changed, 30 deletions(-) diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index e3a184639f..5da84a6fbb 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -753,38 +753,10 @@ static wxRichToolTipPopup* get_rtt_popup(wxButton* btn) return nullptr; } -// Help function to find and check if some combobox is dropped down and then dismiss it -static bool found_and_dismiss_shown_dropdown(wxWindow* win) -{ - auto children = win->GetChildren(); - if (children.IsEmpty()) { - if (auto dd = dynamic_cast(win); dd && dd->IsShown()) { - dd->CallDismissAndNotify(); - return true; - } - } - - for (auto child : children) { - if (found_and_dismiss_shown_dropdown(child)) - return true; - } - return false; -} - void Sidebar::priv::show_rich_tip(const wxString& tooltip, wxButton* btn) { if (tooltip.IsEmpty()) return; - - // Currently state (propably wxWidgets issue) : - // When second wxPopupTransientWindow is popped up, then first wxPopupTransientWindow doesn't receive EVT_DISMISS and stay on the top. - // New comboboxes use wxPopupTransientWindow as DropDown now - // That is why DropDown stay on top, when we show rich tooltip for btn. - // (see https://github.com/prusa3d/PrusaSlicer/issues/11988) - - // So, check the combo boxes and close them if necessary before showing the rich tip. - found_and_dismiss_shown_dropdown(scrolled); - wxRichToolTip tip(tooltip, ""); tip.SetIcon(wxICON_NONE); tip.SetTipKind(wxTipKind_BottomRight); diff --git a/src/slic3r/GUI/Widgets/DropDown.hpp b/src/slic3r/GUI/Widgets/DropDown.hpp index 8d17ea658d..8a4757f5f7 100644 --- a/src/slic3r/GUI/Widgets/DropDown.hpp +++ b/src/slic3r/GUI/Widgets/DropDown.hpp @@ -86,8 +86,6 @@ public: bool HasDismissLongTime(); static void SetTransparentBG(wxDC& dc, wxWindow* win); - - void CallDismissAndNotify() { DismissAndNotify(); } protected: void OnDismiss() override;