From 85894dbdcb6da73142513cfab51f63e17150284b Mon Sep 17 00:00:00 2001 From: Samuele Locatelli Date: Tue, 12 Apr 2022 10:27:33 +0200 Subject: [PATCH] Aggiunta progetto iniziale --- 3dPrinting.ini | 15 +++ Esempi/ExSetti.nge | Bin 0 -> 966 bytes Esempi/Params_setti.ini | 41 ++++++ GcodeGenerate.lua | 63 +++++++++ Images/GcodeGenerate.png | Bin 0 -> 1057 bytes Images/MachiningParamCalc.png | Bin 0 -> 497 bytes Images/MachiningParamEdit.png | Bin 0 -> 1158 bytes Images/MaterialParamEdit.png | Bin 0 -> 1158 bytes Images/PartPositioning.png | Bin 0 -> 913 bytes Images/ShowManager.png | Bin 0 -> 919 bytes Images/SliceAdvancement.png | Bin 0 -> 443 bytes Images/Slicing.png | Bin 0 -> 485 bytes Images/ViewManager.png | Bin 0 -> 467 bytes LuaLibs/AddManData.lua | 94 +++++++++++++ LuaLibs/CSVManager.lua | 70 ++++++++++ LuaLibs/CalcPaths.lua | 164 +++++++++++++++++++++++ LuaLibs/CalcSlices.lua | 141 ++++++++++++++++++++ LuaLibs/CalcSolids.lua | 242 ++++++++++++++++++++++++++++++++++ LuaLibs/CalcToolPath.lua | 105 +++++++++++++++ MachiningParamCalc.lua | 177 +++++++++++++++++++++++++ MachiningParamEdit.lua | 53 ++++++++ Machinings/Params.ini | 17 +++ Machinings/Params3.ini | 37 ++++++ MaterialParamEdit.lua | 52 ++++++++ Materials/B461.csv | 26 ++++ PartPositioning.lua | 105 +++++++++++++++ README.md | 91 +------------ README.pdf | Bin 0 -> 29920 bytes ShowManager.lua | 107 +++++++++++++++ SliceAdvancement.lua | 93 +++++++++++++ Slicing.lua | 136 +++++++++++++++++++ ViewManager.lua | 114 ++++++++++++++++ 32 files changed, 1855 insertions(+), 88 deletions(-) create mode 100644 3dPrinting.ini create mode 100644 Esempi/ExSetti.nge create mode 100644 Esempi/Params_setti.ini create mode 100644 GcodeGenerate.lua create mode 100644 Images/GcodeGenerate.png create mode 100644 Images/MachiningParamCalc.png create mode 100644 Images/MachiningParamEdit.png create mode 100644 Images/MaterialParamEdit.png create mode 100644 Images/PartPositioning.png create mode 100644 Images/ShowManager.png create mode 100644 Images/SliceAdvancement.png create mode 100644 Images/Slicing.png create mode 100644 Images/ViewManager.png create mode 100644 LuaLibs/AddManData.lua create mode 100644 LuaLibs/CSVManager.lua create mode 100644 LuaLibs/CalcPaths.lua create mode 100644 LuaLibs/CalcSlices.lua create mode 100644 LuaLibs/CalcSolids.lua create mode 100644 LuaLibs/CalcToolPath.lua create mode 100644 MachiningParamCalc.lua create mode 100644 MachiningParamEdit.lua create mode 100644 Machinings/Params.ini create mode 100644 Machinings/Params3.ini create mode 100644 MaterialParamEdit.lua create mode 100644 Materials/B461.csv create mode 100644 PartPositioning.lua create mode 100644 README.pdf create mode 100644 ShowManager.lua create mode 100644 SliceAdvancement.lua create mode 100644 Slicing.lua create mode 100644 ViewManager.lua diff --git a/3dPrinting.ini b/3dPrinting.ini new file mode 100644 index 0000000..b84435a --- /dev/null +++ b/3dPrinting.ini @@ -0,0 +1,15 @@ +[3dPrinting] +Enable=1 +BaseDir=C:\EgtData\3dPrinting +Button1=PartPositioning.lua,Images\PartPositioning.png,Disponi pezzo sulla tavola macchina +Button2=Slicing.lua,Images\Slicing.png,Calcola lo slicing, i solidi e i percorsi utensile +Button3=MachiningParamCalc.lua,Images\MachiningParamCalc.png,Calcola parametri di lavorazione (Tempo layer, F, S) +Button4=GcodeGenerate.lua,Images\GcodeGenerate.png,Genera codice CN +Button5=ShowManager.lua,Images\ShowManager.png,Gestore visualizzazione +Button6=ViewManager.lua,Images\ViewManager.png,Nascondi Visualizza strato +Button7=SliceAdvancement.lua,Images\SliceAdvancement.png,Mostra avanzamento strato +Button8=MachiningParamEdit.lua,Images\MachiningParamEdit.png,Edita i parametri di stampa +Button9=MaterialParamEdit.lua,Images\MaterialParamEdit.png,Edita i parametri del materiale +ParamFile=C:\EgtData\3dPrinting\Machinings\Params.ini +ResultReadProg="C:\Program Files\Microsoft Office\root\Office16\EXCEL.EXE" +MachiningEditProg="C:\Windows\System32\notepad.exe" \ No newline at end of file diff --git a/Esempi/ExSetti.nge b/Esempi/ExSetti.nge new file mode 100644 index 0000000000000000000000000000000000000000..26107668186310dd0cb2fdb2b01ba9d13b9396c3 GIT binary patch literal 966 zcmV;%13CO3iwFP!000003Wb)A7HHBU9pEmry11(% zo4!AKK2owhX=j22W1BjpN$R6!ejKl#j&*hS|F8T1UVh$w46%vRQdb{7eEs+7pS%0x z-OcAi(==T(9A3V?+`fFOtB333^X(lsF->9ULW5I-kL+K+e5@-yTtDAGeFwQ}>gv9( z4iPgXtbOjT8=S77-h^+SZyt!;UM1eb8;D5Eg+Gr=E=qtnaj2^sQhKbbcjf&H>*65% zs=ERau`KHv=iv<4I_N-bhWAaAF5sQ;Jyf2~CDLyWLehntsj)2UdOqjTK?l;CIZwj( zIhUt%InSGekoH2(5mA(NUC$>S*|&{o-^@C)g{M?`I+u22FZWD$DQ`Bitm|rx|ErQB zJGc=SNj9*o|EWwb@u?@#RJ;dRl%{Rj}itmDpVwAaNcS`?0>S>|jp%4M##iI$_V&as4+7Xqx31V3;`O16P3=Z|b!k|NvT-!am@P(mRcSJt>mC=g z&8y8wudJ2WGUs)*5}YhXc~z9B{ae}?4jkhETwIVY(HK%7K|T+Etm1|pQOXImnzmKD ztG5kZU^Dr|^>ndYddvd|o>b;uVLF6u^lP##}FU0}cr-8E=~2+$kE5oDd#IOd#+ zE)@W12n?X1`Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!TQ64HQE90nk$(vMdQ0#+`mxts< zxkYx9jwW)Q+$YCz!DF~QVZ#hV9tz>Lvkxc4=>|;a2XvyqcEa{GyvZ-_szqeru z61gBpN&dcFI=CNQ_)5;?LNT0^{x~@=58E($DBa-ZX=m6l#Z9^1hEZopi;gsBHdzLG zNwkzlBwfZ#;kZk-kT6@i?mWu{k8P6KmxRRm&an8H^oA^niumZ$K=Qiy8yJ_q{|I$e z-|}H*U%g8#kWjwb=U62t+c3o~>Aw(1NLTv?$(@qf8T#EIg=!xxkz5NUHC29)%woqA z$vdl~d5ykV3T&nDYDOM;S^AcwO)g16str_qxbsHZ(kv$%hS6sP=)I!jyOmYWav<_Oil?@GBPzxJ`3bXDI`sHH+MD_JBuSYaf4 zCPOkQm?)V!Jf*9B%$_+i2}QP482s-f4^CmG_ekDdt}#;U zbT_7as#}nOa^+-G%4hq_?vl;N!dNyWDctN!Qd0%l!PI{yDJQ^Moqb^PEuSKkR81CS zU}Le`h6WynEj;)5EmK=|mk^dGGONjgyitCZ%gvePg`~w<=naMMZoJQJsR!vN(l*@3K5M&Z5}mMJZ(8 bKZ^bUfz@+8#Q6Fa00000NkvXXu0mjf{R!}5 literal 0 HcmV?d00001 diff --git a/Images/MachiningParamCalc.png b/Images/MachiningParamCalc.png new file mode 100644 index 0000000000000000000000000000000000000000..d94842b1db55892a459228960f9dc624afeb1ef4 GIT binary patch literal 497 zcmeAS@N?(olHy`uVBq!ia0vp^svyk41|*NpQ(y*CEa{HEjtmSN`?>!lvI6;>1s;*b z3=DjSL74G){)!Z!AbW|YuPgf_7D-WNgNO@jIDkTuC9V-A!TD(=<%vb93~dIow%h94C&r!p`wMtizAhD5lZo%T?$S%JrGW_RO^_RNU3#7iv^rXL)$&zt@I z`0h)iqLTx&;9uE*D(0o;U?S{_&&1Ff0>!FYCwGK!EiIe7qF{opSn#AD9-k!acYNKv zWybP!mg3}z3g;VEZ%f{=BrPt(fXcRWSPMBQh3{uAKSr~o0 zusZjzXV9jS<7WRugFeie#d}S?)aLt>N0v|7r`&UR$%{m6Hh%g?ynt80f4}nreRE|? zTMPR|L4AMQr$5$@D-bx<>zON`d6shv^MXIed}1T3G!l6^x~(EMt8P0UwclXM_j6Y~ zeoMyayi}O-UhS*aKZPmMlP5X7pB`IRA5(rm!2eK{xf6Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!2kdb!2!6DYwZ941RF_2K~z{r?U-q- zokJLa54A*!M3hEq50%u~+69T7D$x=YwbWK(`yu?|mq_r#9ziUjEeSi-Xvy zKXS1rC!!0(&zarw_IP%;d^DbiU*l#t8Q;LY@dkVhhfxl-omzf-P-{BtkQ>sBzr{X5E6*>ZT>TVku*uQf&xd0PlHFs%2c@$LC_g5!xviM-rVHi;jY8%jsxa z=sxA|xM!*j;hOpecTBY*F2vh&v2zTr$i-&rk=h*ldHd#~(^G0FSXi~GBPzZO&!VGy zoDFN54H}eQ?SWyVUYDb+TNt@xAK(( z@Q_?gn8#*dTw@OVD;In61e$V8!c*~5Eb)yt0~qt><1=^`4#OJ+#;0R(9-8UZXlrLb z$7}IrG$x&n2ULEA*P-8e{U_+#npF z#OHAW?$+S8Xi_yE8Skz}<57vz?~XwX5!+yyI~(~PC*l$`nj1?TYJdDQ29f(pO(}LL zQi$o~u3Q{}9r6KhO|=$W3zwlc4?e@$=q66gcXbZ5nF}eZln~l&L&q}q7(_x$6wJ`_1_Gx?~&NDKVw^6kDg-aQx1kW{&jGDL#zR-ovFiuqjzf zbV#P42a8s`xe-=8#k%Eiq@vA{Iwuzs9z5;1kvk5WQYUIHxeeWs^rUH|#AAh z3*BkID%JYL>5C^0T*T${`7a!IpKjt@U*hz+^<5PnbRz+W-{Km>|1p)s6t>Z4BJOnl Y1%h7Y-Vbk{hX4Qo07*qoM6N<$f@Py6bpQYW literal 0 HcmV?d00001 diff --git a/Images/MaterialParamEdit.png b/Images/MaterialParamEdit.png new file mode 100644 index 0000000000000000000000000000000000000000..f65d28caa8e65a055e7ec1a89d370b00c1e4f5be GIT binary patch literal 1158 zcmV;11bO?3P)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!2kdb!2!6DYwZ941RF_2K~z{r?U-q- zokJLa54A*!M3hEq50%u~+69T7D$x=YwbWK(`yu?|mq_r#9ziUjEeSi-Xvy zKXS1rC!!0(&zarw_IP%;d^DbiU*l#t8Q;LY@dkVhhfxl-omzf-P-{BtkQ>sBzr{X5E6*>ZT>TVku*uQf&xd0PlHFs%2c@$LC_g5!xviM-rVHi;jY8%jsxa z=sxA|xM!*j;hOpecTBY*F2vh&v2zTr$i-&rk=h*ldHd#~(^G0FSXi~GBPzZO&!VGy zoDFN54H}eQ?SWyVUYDb+TNt@xAK(( z@Q_?gn8#*dTw@OVD;In61e$V8!c*~5Eb)yt0~qt><1=^`4#OJ+#;0R(9-8UZXlrLb z$7}IrG$x&n2ULEA*P-8e{U_+#npF z#OHAW?$+S8Xi_yE8Skz}<57vz?~XwX5!+yyI~(~PC*l$`nj1?TYJdDQ29f(pO(}LL zQi$o~u3Q{}9r6KhO|=$W3zwlc4?e@$=q66gcXbZ5nF}eZln~l&L&q}q7(_x$6wJ`_1_Gx?~&NDKVw^6kDg-aQx1kW{&jGDL#zR-ovFiuqjzf zbV#P42a8s`xe-=8#k%Eiq@vA{Iwuzs9z5;1kvk5WQYUIHxeeWs^rUH|#AAh z3*BkID%JYL>5C^0T*T${`7a!IpKjt@U*hz+^<5PnbRz+W-{Km>|1p)s6t>Z4BJOnl Y1%h7Y-Vbk{hX4Qo07*qoM6N<$f@Py6bpQYW literal 0 HcmV?d00001 diff --git a/Images/PartPositioning.png b/Images/PartPositioning.png new file mode 100644 index 0000000000000000000000000000000000000000..860306adf354aa32f8e0feb6e0367d11800b65b3 GIT binary patch literal 913 zcmV;C18)3@P)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!2kdb!2!6DYwZ94113pCK~z{r&6ZC{ zR6!WPzcF1_X;)iP%q=0%gh&WNFXbU9-2ULHL+YVhf82t)*&zrD>L3JJ3U%qC(kY5U zC8%Wc;MQ#;C`Hj)qx`#W?uMq*d~av;y|=T^_uiVjKlu1&zBfDj+c*2>4WX1mwvoeg zR*{ubwwA9e7^VyHWvKSLdBr~cpQqq_T{-O8kxzKZx>Pq4YUv5_-sW)S=w7(hP-Ra_ z2$i@T@GH6m^Y?sf6Ita_cZl|U2rKQE{#rOv;aQu@^nXeS9Vl}_Q|)eEwTBRDtnu=S z7E@Acp;wn{!I^9S`A`dWHdRaS^oFzRg$ncY(q1wnA;eHB6GBKzsZ0qWQmIS|AxTnP zhzg;i0taD$It2QV%2mbqpdxT;n-H7n4L41G{ zWg#7>0+-YlGAR$w3OX6lcCjcF*JQzvF25OMAI#BBzUA2dHUE?JqzGw{L@B>&8{1N& zkI!Oyu8-F>$9}M!7P&lI!uPZdJd4Q>U$A^1Jo`BVgM^ep`;bz@%~5F>5DG8g=E-|j zrTnCC>PO$F$JYG#; z^-k5bOm!t%m5C&1`&b3rBgre*>Z?e4#YE!E^wfi(BGl1X%}%mj%^1`FDSWx|W?BfL zPm@up5MoM7yzSG)j1aP+l=}E#hL~$7ra`5n!mJQtC}rh5DlSd?;Bijb00000NkvXXu0mjfCeo_a literal 0 HcmV?d00001 diff --git a/Images/ShowManager.png b/Images/ShowManager.png new file mode 100644 index 0000000000000000000000000000000000000000..ad9d17b43275c5b4a87c4040d7ab3fa4938733da GIT binary patch literal 919 zcmV;I18Dq-P)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!~g&e!~vBn4jTXf11w2IK~z{r?N&=q z6HyrbZVN4i7Fs}>fFT5o4>m0HKd>;7m>71j(47gaOpJ*!(S9=0 z6(+hNDn4RBG@ukn3Y2#{*K?+ilsbiJQ^zhi$;mhO`)+&BeD|K2QCe#$H@H%`)Du-pV!1dynV{vbTlmxP1Yz7NjUf=Hj4Z$cREGz96)K zKF|+VgI+L%+9yQQ2w*K3N-@YBYo$c)0p{Wq#tx;sH4Zvzgk67zj!Yq}gLNRgw1C`q zL?Q%I5YHLKvYQmnF-=l3SlwX^yyBe=4H@c)Gq2qXGZcDR@OV@VH zoNF7!Y+qg@Y&=o(u1a|WSsuM50lg#sgdrXN^ExBmju8qLMdUNW=bNg#twrt`hD6kk z`0&?(p9|7|?5cjnx?Lj_C2B7$4XM#8mz?4j;>&O>bW!&)Ux*QkIa7P0)+MtZoF#9C z)CYXRm%NEWj8Jk>w_eKl@T6RS^iHl_8I{c47h;5xZ=VXb_exFc2A*PZiB0?U>dbJe zl-CG>3rQEJwUoS5Iy&{(H8mq6oKA0|-V! t>pL8mg{WMVrKnsu?mjy>5M>V{e*llQitu(}xcvYC002ovPDHLkV1h%4k|+QG literal 0 HcmV?d00001 diff --git a/Images/SliceAdvancement.png b/Images/SliceAdvancement.png new file mode 100644 index 0000000000000000000000000000000000000000..4ced7f5349138988c8145a0ed9334258d8ef930e GIT binary patch literal 443 zcmeAS@N?(olHy`uVBq!ia0vp^svyk41|*NpQ(y*CEa{HEjtmSN`?>!lvI6;>1s;*b z3=DjSL74G){)!Z!pk#?_L`iUdT1k0gQ7S`0VrE{6US4X6f{C7io{`~4h0Li842%|@ zE{-7)?r*0U@*OhZajh0`<2!ob7}s=%j%bCAjO~wk7S@ZRdw;63$8XOo^A2je8Iv%;=ZcnYoVv)A{?ximIpRO}On fdiv(HE42)!RawX8obb#81~h}GtDnm{r-UW|-hi^0 literal 0 HcmV?d00001 diff --git a/Images/Slicing.png b/Images/Slicing.png new file mode 100644 index 0000000000000000000000000000000000000000..58e76e2bf0999f5b3649a2afcf13543ce33b17fa GIT binary patch literal 485 zcmeAS@N?(olHy`uVBq!ia0vp^svyk41|*NpQ(y*CEa{HEjtmSN`?>!lvI6;>1s;*b z3=DjSL74G){)!Z!pk#?_L`iUdT1k0gQ7S`0VrE{6US4X6f{C7io{`~4h0Li842(&h zE{-7)?q@Fa|V=JaCa9eR@ zK}HB)fQXj(i}X@mo~gnjEvI-7Z5B73VSD-6MbTWD@2f3y$I1mY3U4+qe&yh(@q3|**i+_*me#Af9KY?Id$q14TC^o3 zP){JpS(kaO{I`r>7UtK}-F`Y;-_HN+)uo0T6PQG~opKmX$tg{AJ=!239kd|Hv4dB$ z{!4&BlCxKc2FFH4Q7yI>sJaPmZ?~UY!lvI6;>1s;*b z3=DjSL74G){)!Z!pk#?_L`iUdT1k0gQ7S`0VrE{6US4X6f{C7io{`~4h0Li842%Ju zE{-7)?r$#{dNDhS9Q(MpQGCOeZvyiU7`4uw>msnnk>lP0H;*mdWn7G$P8|tOP9`k^ zj#~teTr#$Ku08Fm>iN4fQ}3PO605)QUBTG?go;bZ&LgRBz$ozWQSMUtW%sIT|C=07 zd%pQ}PFDXs&CI=lMgJZy-TO@S>o4Wvk}~$)8#L}Oi2B@R)|YpB@fL@rfwL9_Y2;2Y z)?zuqDazHdCP2|~g@CA3OHtt8mvhSe*JnOo^L*)Fw`^X8sohdN>Lms-RjcbR2@0P*Isj?7QFoN^en{!Z) string.len(s) + return t +end + +function read_file( path) + local file = io.open( path, "r") -- r read mode and b binary mode + if not file then return nil end + local CSVTable = {} + + for line in io.lines( path) do + CSVTable[#CSVTable + 1] = fromCSV( line) + end + + file:close() + + return CSVTable +end + +return CSVManager diff --git a/LuaLibs/CalcPaths.lua b/LuaLibs/CalcPaths.lua new file mode 100644 index 0000000..718d627 --- /dev/null +++ b/LuaLibs/CalcPaths.lua @@ -0,0 +1,164 @@ +-- CalcPaths.lua by Egaltech s.r.l. 2022/03/30 +-- Calcolo percorsi di lavoro per Stampa 3d + +-- Tabella per definizione modulo +local CalcPaths = {} + +-- Intestazioni +require( 'EgtBase') + +EgtOutLog( ' CalcPaths started', 1) + +-- Dati +local AMD = require( 'AddManData') + +--------------------------------------------------------------------- +local function GetLayerParamsForPathCalc() + local nParamsGrp = EgtGetFirstNameInGroup( GDB_ID.ROOT, PARAMS_GRP) + local LayerParams = {} + LayerParams.nShellsNbr = EgtGetInfo( nParamsGrp, KEY_SHELLS_NBR, 'i') + LayerParams.dStrand = EgtGetInfo( nParamsGrp, KEY_STRAND, 'd') + LayerParams.dOffs = EgtGetInfo( nParamsGrp, KEY_OFFSET_SLICE, 'd') + LayerParams.nFloorNbr = EgtGetInfo( nParamsGrp, KEY_FLOOR_NBR, 'i') + return LayerParams +end + +--------------------------------------------------------------------- +local function GetLayerStartPoint() + local nParamsGrp = EgtGetFirstNameInGroup( GDB_ID.ROOT, PARAMS_GRP) + local ptStart = EgtGetInfo( nParamsGrp, KEY_START_POINT, 'p') + return ptStart +end + +--------------------------------------------------------------------- +local function GetPathsFromSurf( nSrfId, sName, nType, nGrpId, nLayId, dStrand) + + local nChunks = EgtSurfFrChunkCount( nSrfId) + for nC = 0, nChunks - 1 do + -- estraggo i contorni + local nCrvId, nCrvCnt = EgtExtractSurfFrChunkLoops( nSrfId, nC, nGrpId) + for nInd = 0, nCrvCnt - 1 do + EgtSetName( nCrvId + nInd, sName) + EgtSetInfo( nCrvId + nInd, KEY_TYPE, nType) + + -- se è loop interno lo inverto per averlo orientato in senso antiorario + if nInd > 0 then + EgtInvertCurve( nCrvId + nInd) + end + + -- verifico soddisfi i requisiti (lunghezza e area) + local dLen = EgtCurveLength( nCrvId + nInd) + local _ , _ , dArea = EgtCurveArea( nCrvId + nInd) + if dLen < MIN_LEN or dArea < MIN_AREA then + EgtErase( nCrvId + nInd) + return + end + + -- scelta start point + local ptStart = GetLayerStartPoint( nLayId) + EgtChangeClosedCurveStartPoint( nCrvId + nInd, ptStart) + end + end +end + +-------------------------------------------------------------------- +local function AddFloor( nSrfId, nGrpId, LayerParams, nFloorNbr) + + -- local nSrfCopy = EgtCopyGlob( nSrfId, nGrpId) + -- local dOffs = 0.5 * LayerParams.dStrand - LayerParams.dOffs + LayerParams.nShellsNbr * LayerParams.dStrand + -- local dAng = 0 + -- + -- if EgtSurfFrOffset( nSrfCopy, - dOffs) and EgtSurfFrChunkCount( nSrfCopy) > 0 then + -- local nCrvId, nCnt = EgtGetSurfFrZigZagInfill( nSrfCopy, nGrpId, LayerParams.dStrand + 10 * GEO.EPS_SMALL, dAng, false, false) + -- for nInd = 0, nCnt - 1 do + -- local dLen = EgtCurveLength( nCrvId + nInd) + -- if dLen < MIN_LEN then + -- EgtErase( nCrvId + nInd) + -- else + -- EgtSetName( nCrvId + nInd, INFILL_CRV) + -- EgtSetInfo( nCrvId + nInd, KEY_TYPE, TYPE.INFILL) + -- end + -- end + -- EgtErase( nSrfCopy) + -- end + + +end + +--------------------------------------------------------------------- +function CalcPaths.Exec( nPartId) + + local vLayIds = EgtGetNameInGroup( nPartId, SLICE_LAYER.."*") + if not vLayIds then + EgtOutBox( 'Error no slice', 'PathCalc') + return + end + + -- scorro tutti i suoi layer + for nIdx = 1, #vLayIds do + + -- recupero i parametri relativi al layer + local LayerParams = GetLayerParamsForPathCalc() + + -- scorro tutti i gruppi di contorni + local nCrvGrpId = EgtGetFirstNameInGroup( vLayIds[nIdx], CONTOUR_GRP.."*") or GDB_ID.NULL + while nCrvGrpId ~= GDB_ID.NULL do + + -- verifico se il path e il solido sono già stati calcolati + local nGrpId = EgtGetFirstNameInGroup( nCrvGrpId, PATH_GRP) or GDB_ID.NULL + if nGrpId == GDB_ID.NULL then + nGrpId = EgtGroup( nCrvGrpId) + EgtSetName( nGrpId, PATH_GRP) + else + EgtEmptyGroup( nGrpId) + EgtSetStatus( nGrpId, GDB_ST.ON) + end + local nSolidGrpId = EgtGetFirstNameInGroup( nCrvGrpId, SOLID_GRP) or GDB_ID.NULL + if nSolidGrpId ~= GDB_ID.NULL then + EgtErase( nSolidGrpId) + end + + -- recupero la superficie ottenuta dallo slicing + local nSrf = EgtGetFirstNameInGroup( nCrvGrpId, LAYER_SRF) + if nSrf then + -- esterno + local nSrfId = EgtCopyGlob( nSrf, nCrvGrpId) + local dOffs = 0.5 * LayerParams.dStrand - LayerParams.dOffs + EgtSurfFrOffset( nSrfId, - dOffs) + -- estraggo i contorni (pareti esterne) + GetPathsFromSurf( nSrfId, SHELL_CRV..'0', TYPE.OUTER_SHELL, nGrpId, nLayId, LayerParams.dStrand) + EgtErase( nSrfId) + + -- calcolo pareti interne + for nInd2 = 1, LayerParams.nShellsNbr - 1 do + -- offset della superficie originale + local nSrfId = EgtCopy( nSrf, nGrpId) + if EgtSurfFrOffset( nSrfId, - dOffs - nInd2 * LayerParams.dStrand) then + -- estraggo i contorni ( pareti interne) + GetPathsFromSurf( nSrfId, SHELL_CRV..tostring( nInd2), TYPE.INNER_SHELL, nGrpId, nLayId, LayerParams.dStrand) + end + EgtErase( nSrfId) + end + + -- gestione eventuale floor + if nIdx <= LayerParams.nFloorNbr then + AddFloor( nSrf, nGrpId, LayerParams, nIdx) + end + + end + + --passo al gruppo di contorni successivo + nCrvGrpId = EgtGetNextName( nCrvGrpId, CONTOUR_GRP.."*") or GDB_ID.NULL + end + + if EgtProcessEvents( nIdx / #vLayIds * 100, 0) == 1 then + EgtDraw() + return + end + + end +end + + +--------------------------------------------------------------------- +return CalcPaths diff --git a/LuaLibs/CalcSlices.lua b/LuaLibs/CalcSlices.lua new file mode 100644 index 0000000..6eed2e5 --- /dev/null +++ b/LuaLibs/CalcSlices.lua @@ -0,0 +1,141 @@ +-- CalcSlices.lua by Egaltech s.r.l. 2022/03/30 +-- Calcolo percorsi di lavoro per Stampa 3d + +-- Tabella per definizione modulo +local CalcSlices = {} + +-- Intestazioni +require( 'EgtBase') + +EgtOutLog( ' CalcSlices started', 1) + +-- Dati +local AMD = require( 'AddManData') + +--------------------------------------------------------------------- +local function GetSliceStep() + local nParamsGrp = EgtGetFirstNameInGroup( GDB_ID.ROOT, PARAMS_GRP) + local dStep = EgtGetInfo( nParamsGrp, KEY_SLICE_STEP, 'd') + return dStep +end + +--------------------------------------------------------------------- +function CalcSlices.Exec( nPartId, nStmId) + + local dTol = 0.05 + -- recuper il box della superficie + local b3Box = EgtGetBBoxRef( nStmId, GDB_BB.STANDARD, EgtGetGridFrame()) + if not b3Box or b3Box:isEmpty() then + EgtOutText( 'La superficie selezionata è vuota') + EgtPause( 1000) + return + end + + -- Parametri di slicing + local dZmin = b3Box:getMin():getZ() + 0.1 --0.1 * dStep + local dZmax = b3Box:getMax():getZ() - 0.1 -- 0.1 * dStep + + -- se slicing già presente lo cancello + local nOldSliceId = EgtGetFirstNameInGroup( nPartId, SLICE_LAYER .."*") or GDB_ID.NULL + while nOldSliceId ~= GDB_ID.NULL do + EgtErase( nOldSliceId) + nOldSliceId = EgtGetFirstNameInGroup( nPartId, SLICE_LAYER .."*") or GDB_ID.NULL + end + + EgtStartCounter() + + -- Eseguo slicing + local dPosZ = dZmin + local nLayCnt = 1 + while dPosZ < dZmax do + -- nuovo layer + local nLayId = EgtGroup( nPartId) + EgtSetInfo( nLayId, KEY_SLICE_Z, dPosZ) + EgtSetInfo( nLayId, KEY_SLICE_NBR, nLayCnt) + + -- calcolo intersezione + nNewId, nPntCnt, nCrvCnt, nSrfCnt = EgtPlaneSurfTmInters( Point3d( 0, 0, dPosZ), Z_AX(), nStmId, nLayId, GDB_RT.GRID) + -- verifico se ricalcolare con piccolo spostamento + local bRecalc = not nNewId or ( nSrfCnt ~= 0) + if not bRecalc then + for Id = nNewId + nPntCnt, nNewId + nPntCnt + nCrvCnt - 1 do + if not EgtCurveIsClosed( Id) then + bRecalc = true + break + end + end + end + -- se richiesto, eseguo ricalcolo + if bRecalc then + local vtN = EgtSurfTmFacetNormVersor( nNewId or 0 + nPntCnt or 0 + nCrvCnt or 0, 0) + local dDeltaZ = EgtIf( vtN and vtN:getZ() < 0, 0.005, - 0.005) + EgtEmptyGroup( nLayId) + nNewId, nPntCnt, nCrvCnt, nSrfCnt = EgtPlaneSurfTmInters( Point3d( 0, 0, dPosZ + dDeltaZ), Z_AX(), nStmId, nLayId, GDB_RT.GRID) + end + + -- salvo i risultati nel layer + if nNewId then + -- verifico presenza contorni aperti + local bAllClosed = true + for Id = nNewId + nPntCnt, nNewId + nPntCnt + nCrvCnt - 1 do + if not EgtCurveIsClosed( Id) then + bAllClosed = false + break + end + end + + -- salvo + EgtSetName( nLayId, EgtIf( bAllClosed, '', '**') .. SLICE_LAYER .. EgtNumToString( nLayCnt)) + EgtSetInfo( nLayId, 'PntCnt', nPntCnt) + EgtSetInfo( nLayId, 'CrvCnt', nCrvCnt) + EgtSetInfo( nLayId, 'SrfCnt', nSrfCnt) + EgtSetColor( EgtTableFill( nNewId, nPntCnt) or {}, 'BLUE') + EgtSetColor( EgtTableFill( nNewId + nPntCnt, nCrvCnt) or {}, 'BLACK') + EgtSetColor( EgtTableFill( nNewId + nPntCnt + nCrvCnt, nSrfCnt) or {}, 'AQUA') + + -- creo flat region a partire dalle curve ottenute con lo slicing + local vCrvs = {} + for nInd = 0, nCrvCnt - 1 do + table.insert( vCrvs, nNewId + nPntCnt + nInd) + EgtApproxCurve( nNewId + nPntCnt + nInd, GDB_CA.ARCS, dTol) + end + local nSurfFR = EgtSurfFlatRegion( nLayId, vCrvs) + for nInd = 1, #vCrvs do + EgtErase( vCrvs[nInd]) + end + + if nSurfFR then + -- analizzo i singoli chunks + local nSfrId, nSrfCnt = EgtExplodeSurf( nSurfFR) + for nInd = 0, nSrfCnt - 1 do + -- per ogni chunk creo un gruppo di percorsi + local nGrpCrv = EgtGroup( nLayId) + EgtSetName( nGrpCrv, CONTOUR_GRP .. EgtNumToString( nInd + 1, 1)) + EgtRelocateGlob( nSfrId + nInd, nGrpCrv) + EgtSetName( nSfrId + nInd, LAYER_SRF) + EgtSetStatus( nSfrId + nInd, GDB_ST.OFF) + -- estraggo i contorni della superficie + local nCrvId, nCrvCnt = EgtExtractSurfFrChunkLoops( nSfrId + nInd, 0, nGrpCrv) + for nInd2 = 0, nCrvCnt - 1 do + EgtSetName( nCrvId + nInd2, OUTER_CRV) + EgtSetColor( nCrvId + nInd2, 'BLACK') + end + end + else + -- errore + EgtSetName( nLayId, EgtIf( bAllClosed, '', '**') .. SLICE_LAYER .. EgtNumToString( nLayCnt)) + end + + -- errore + else + EgtSetName( nLayId, EgtIf( bAllClosed, '', '**') .. SLICE_LAYER .. EgtNumToString( nLayCnt)) + end + + local dStep = GetSliceStep( dPosZ, dStep) + dPosZ = dPosZ + dStep + nLayCnt = nLayCnt + 1 + end +end + +--------------------------------------------------------------------- +return CalcSlices diff --git a/LuaLibs/CalcSolids.lua b/LuaLibs/CalcSolids.lua new file mode 100644 index 0000000..05847eb --- /dev/null +++ b/LuaLibs/CalcSolids.lua @@ -0,0 +1,242 @@ +-- CalcSolids.lua by Egaltech s.r.l. 2022/03/30 +-- Calcolo percorsi di lavoro per Stampa 3d + +-- Tabella per definizione modulo +local CalcSolids = {} + +-- Intestazioni +require( 'EgtBase') + +EgtOutLog( ' CalcSolids started', 1) + +-- Dati +local AMD = require( 'AddManData') + +--------------------------------------------------------------------- +local function GetLayerParamsForSolidCalc() + local nParamsGrp = EgtGetFirstNameInGroup( GDB_ID.ROOT, PARAMS_GRP) + local LayerParams = {} + LayerParams.bInvert = EgtGetInfo( nParamsGrp, KEY_PRINT_DIRECTION, 'b') + LayerParams.dLayHeight = EgtGetInfo( nParamsGrp, KEY_SLICE_STEP, 'd') + LayerParams.dStrand = EgtGetInfo( nParamsGrp, KEY_STRAND, 'd') + LayerParams.nOrder = EgtGetInfo( nParamsGrp, KEY_PRINT_ORDER, 'i') + return LayerParams +end + +--------------------------------------------------------------------- +local function CreateSection( ptS, vtDir, dStrand, dH, nSolidGrp) + + ptS = ptS - dH * Z_AX() + local dD1 = 0.5 * dStrand - dStrand / 10 + local dD2 = 0.5 * dStrand - dD1 + local dD3 = dH / 6 + local dD4 = dH - 2 * dD3 + + vtDir:rotate( Z_AX(), 90) + + local ptA = ptS + dD1 * vtDir + local ptB = ptA + dD2 * vtDir + dD3 * Z_AX() + local ptC = ptB + dD4 * Z_AX() + local ptD = ptA + dH * Z_AX() + local ptE = ptD - 2 * dD1 * vtDir + local ptF = ptC - 2 * ( dD1 + dD2) * vtDir + local ptG = ptB - 2 * ( dD1 + dD2) * vtDir + local ptH = ptA - 2 * dD1 * vtDir + + local nId = EgtCurveCompoFromPoints( nSolidGrp, {ptA, ptB, ptC, ptD, ptE, ptF, ptG, ptH, ptA}) + + return nId +end + +-------------------------------------------------------------------- +local function CloseSolid( nCrvId, nSrfId, nSolidGrp, LayerParams) + + local ptS = EgtSP( nCrvId) + local vtS = EgtSV( nCrvId) + local nSectS = CreateSection( ptS, vtS, LayerParams.dStrand, LayerParams.dLayHeight, nSolidGrp) + local nSrfS = EgtSurfTmByRevolve( nSolidGrp, nSectS, ptS, Z_AX(), false, 0.1) + EgtCutSurfTmPlane( nSrfS, ptS, EgtSV( nCrvId), true) + + local ptE = EgtEP( nCrvId) + local vtE = EgtEV( nCrvId) + local nSectE = CreateSection( ptE, vtE, LayerParams.dStrand, LayerParams.dLayHeight, nSolidGrp) + local nSrfE = EgtSurfTmByRevolve( nSolidGrp, nSectE, ptE, Z_AX(), false, 0.1) + EgtCutSurfTmPlane( nSrfE, ptE, - EgtEV( nCrvId), true) + + EgtErase( nSectS) + EgtErase( nSectE) + return EgtSurfTmBySewing( nSolidGrp, { nSrfId, nSrfS, nSrfE}) + +end + +--------------------------------------------------------------------- +local function CreateSolidFromCurve( nCrvId, nSolidGrp, LayerParams, nParts) + + local nCopyId = EgtCopyGlob( nCrvId, nSolidGrp) + + -- scelta del colore + local nType = EgtGetInfo( nCrvId, KEY_TYPE, 'i') + local Color = EgtStdColor( 'GRAY') + if nType == TYPE.OUTER_SHELL then + Color = EgtStdColor( 'ORANGE') + elseif nType == TYPE.INNER_SHELL or nType == TYPE.LINK then + Color = EgtStdColor( 'TEAL') + elseif nType == TYPE.INFILL then + Color = EgtStdColor( 'YELLOW') + end + + local nDefaultParts = EgtIf( nType == TYPE.LINK, 1, 10) + if not nParts then + nParts = nDefaultParts + elseif nParts == nDefaultParts then + nParts = nDefaultParts + 1 + end + + local nId = EgtSplitCurve( nCopyId, nParts) + local vIdStm = {} + + for nInd = 0, nParts - 1 do + + if nType == TYPE.INFILL and nInd == 0 then + EgtInvertCurve( nId + nInd) + end + + local ptS = EgtSP( nId + nInd) + local vtS = EgtSV( nId + nInd) + local nSectId = CreateSection( ptS, vtS, LayerParams.dStrand, LayerParams.dLayHeight, nSolidGrp) + EgtInvertCurve( nSectId) + local nSrfId = EgtSurfTmSwept( nSolidGrp, nSectId, nId + nInd, false, 0.1) + + if nSrfId then + table.insert( vIdStm, nSrfId) + else + if nParts < 100 then + -- cancello quando appena fatto e provo a spezzare la curva in un diverso numero di parti + EgtErase( nSectId) + for nInd3 = 0, nParts - 1 do + EgtErase( nId + nInd3) + end + for nInd3 = 0, nInd - 1 do + local nId2 = EgtGetLastInGroup( nSolidGrp) + EgtErase( nId2) + end + local nNewParts = EgtIf( nParts == nDefaultParts, 5, nParts + 1) + CreateSolidFromCurve( nCrvId, nSolidGrp, LayerParams, nNewParts) + return + else + EgtOutBox( 'CalcSolid error', '') + EgtErase( nSectId) + for nInd3 = 0, nParts - 1 do + EgtErase( nId + nInd3) + end + for nInd3 = 0, nInd - 1 do + local nId2 = EgtGetLastInGroup( nSolidGrp) + EgtErase( nId2) + end + return + end + end + + EgtErase( nSectId) + end + + -- se ho creato troppe parts unisco le superfici per ridurne il numero + local vCrvIds = {} + if nParts > nDefaultParts then + local nGroups1 = nParts % nDefaultParts + local nGroups2 = nDefaultParts - nGroups1 + local nElements1 = ceil( nParts / nDefaultParts) + local nElements2 = floor( nParts / nDefaultParts) + local nCnt = 0 + local nInd = 1 + while nInd <= #vIdStm do + local nElements = EgtIf( nCnt < nGroups1, nElements1, nElements2) + local vIds = { vIdStm[nInd]} + local nFirstId = nId + nInd - 1 + for nId2 = 1, nElements - 1 do + nInd = nInd + 1 + table.insert( vIds, vIdStm[nInd]) + EgtAddCurveCompoCurve( nFirstId, nId + nInd - 1) + end + + local nNewSrf = EgtSurfTmByTriangles( nSolidGrp, vIds) + nInd = nInd + 1 + nCnt = nCnt + 1 + + table.insert( vCrvIds, nFirstId) + vIdStm[nCnt] = nNewSrf + end + nParts = nDefaultParts + else + for nInd = 0, nParts - 1 do + table.insert( vCrvIds, nId + nInd) + end + end + + for nInd = 1, nParts do + vIdStm[nInd] = CloseSolid( vCrvIds[nInd], vIdStm[nInd], nSolidGrp, LayerParams) + EgtSetColor( vIdStm[nInd], Color) + EgtSetInfo( vIdStm[nInd], KEY_TYPE, nType) + EgtErase( vCrvIds[nInd]) + end + +end + +--------------------------------------------------------------------- +function CalcSolids.Exec( nPartId) + + local vLayIds = EgtGetNameInGroup( nPartId, SLICE_LAYER.."*") + if not vLayIds then + EgtOutBox( 'Error no slice', 'SolidCalc') + return + end + + for nIdx = 1, #vLayIds do + -- recupero i parametri relativi al layer + local LayerParams = GetLayerParamsForSolidCalc() + + -- scorro tutti i gruppi di contorni + local nCrvGrpId = EgtGetFirstNameInGroup( vLayIds[ nIdx], CONTOUR_GRP.."*") or GDB_ID.NULL + while nCrvGrpId ~= GDB_ID.NULL do + + -- recupero il gruppo dei percorsi utensile + local nTPathGrpId = EgtGetFirstNameInGroup( nCrvGrpId, TOOLPATH_GRP) or GDB_ID.NULL + if nTPathGrpId == GDB_ID.NULL then + EgtOutBox( 'Error no tool paths', 'SolidCalc') + return + end + + -- recupero il gruppo dei soldi + local nSolidGrpId = EgtGetFirstNameInGroup( nCrvGrpId, SOLID_GRP) or GDB_ID.NULL + if nSolidGrpId == GDB_ID.NULL then + nSolidGrpId = EgtGroup( nCrvGrpId) + EgtSetName( nSolidGrpId, SOLID_GRP) + else + EgtEmptyGroup( nSolidGrpId) + end + + -- scorro le curve + local nId = EgtGetFirstInGroup( nTPathGrpId) + while nId do + CreateSolidFromCurve( nId, nSolidGrpId, LayerParams) + nId = EgtGetNext( nId) + end + + -- nascondo ExternCurve del gruppo + local vExtCrvs = EgtGetNameInGroup( nCrvGrpId, OUTER_CRV) + for nInd = 1, #vExtCrvs do + EgtSetStatus( vExtCrvs[nInd], GDB_ST.OFF) + end + + --passo al gruppo di contorni successivo + nCrvGrpId = EgtGetNextName( nCrvGrpId, CONTOUR_GRP.."*") or GDB_ID.NULL + end + if EgtProcessEvents( nIdx / #vLayIds * 100, 0) == 1 then + EgtDraw() + return + end + end +end + +--------------------------------------------------------------------- +return CalcSolids diff --git a/LuaLibs/CalcToolPath.lua b/LuaLibs/CalcToolPath.lua new file mode 100644 index 0000000..45072f4 --- /dev/null +++ b/LuaLibs/CalcToolPath.lua @@ -0,0 +1,105 @@ +-- CalcToolPath.lua by Egaltech s.r.l. 2022/03/29 +-- Calcolo percorsi di lavoro per Stampa 3d + +-- Tabella per definizione modulo +local CalcToolPath = {} + +-- Intestazioni +require( 'EgtBase') + +EgtOutLog( ' CalcToolPath started', 1) + +-- Dati +local AMD = require( 'AddManData') + +--------------------------------------------------------------------- +local function GetLayerParamsForToolPathCalc() + local nParamsGrp = EgtGetFirstNameInGroup( GDB_ID.ROOT, PARAMS_GRP) + local LayerParams = {} + LayerParams.dLayHeight = EgtGetInfo( nParamsGrp, KEY_SLICE_STEP, 'd') + LayerParams.bInvert = EgtGetInfo( nParamsGrp, KEY_PRINT_DIRECTION, 'b') + LayerParams.nOrder = EgtGetInfo( nParamsGrp, KEY_PRINT_ORDER, 'i') + LayerParams.LinkType = EgtGetInfo( nParamsGrp, KEY_LINK_TYPE, 'i') + LayerParams.LinkParam = EgtGetInfo( nParamsGrp, KEY_LINK_PARAM, 'd') + return LayerParams +end + +--------------------------------------------------------------------- +function CalcToolPath.Exec( nPartId) + + -- Verifico il pezzo + if not nPartId then + EgtOutBox( 'Error missing part', 'ToolPathCalc') + return + end + + -- Recupero i layer da processare + local vLayIds = EgtGetNameInGroup( nPartId, SLICE_LAYER.."*") + if not vLayIds then + EgtOutBox( 'Error missing slices', 'ToolPathCalc') + return + end + + -- Ciclo sui layer + for nIdx = 1, #vLayIds do + -- recupero i parametri relativi al layer + local LayerParams = GetLayerParamsForToolPathCalc() + -- scorro tutti i gruppi di contorni + local nCrvGrpId = EgtGetFirstNameInGroup( vLayIds[ nIdx], CONTOUR_GRP.."*") + while nCrvGrpId do + -- recupero il gruppo dei percorsi + local nPathGrpId = EgtGetFirstNameInGroup( nCrvGrpId, PATH_GRP) + if not nPathGrpId then + EgtOutBox( 'Error missing paths', 'ToolPathCalc') + return + else + EgtSetStatus( nPathGrpId, GDB_ST.OFF) + end + -- recupero il gruppo dei percorsi utensile + local nTpathGrpId = EgtGetFirstNameInGroup( nCrvGrpId, TOOLPATH_GRP) + if not nTpathGrpId then + nTpathGrpId = EgtGroup( nCrvGrpId) + EgtSetName( nTpathGrpId, TOOLPATH_GRP) + else + EgtEmptyGroup( nTpathGrpId) + end + -- creo il percorso di lavoro : + -- copio le curve, le ordino, le oriento e le muovo in Z + local nEntId = EgtGetFirstInGroup( nPathGrpId) + while nEntId do + local nNewEntId = EgtCopyGlob( nEntId, nTpathGrpId, EgtIf( LayerParams.nOrder == PRINT_ORDER.INT_EXT_INF, GDB_IN.FIRST_SON, GDB_IN.LAST_SON)) + EgtMove( nNewEntId, Vector3d( 0, 0, LayerParams.dLayHeight), GDB_RT.GLOB) + if LayerParams.bInvert then + EgtInvertCurve( nNewEntId) + end + nEntId = EgtGetNext( nEntId) + end + -- aggiungo gli opportuni raccordi + local nPrevId = EgtGetFirstInGroup( nTpathGrpId) + local nCurrId = EgtGetNext( nPrevId or GDB_ID.NULL) + while nCurrId do + local nLinkId + if LayerParams.LinkType == LINK_TYPE.LINEAR then + nLinkId = EgtLine( nTpathGrpId, EgtEP( nPrevId), EgtSP( nCurrId)) + else + EgtTrimCurveEndAtLen( nPrevId, EgtCurveLength( nPrevId) - LayerParams.LinkParam / 2) + EgtTrimCurveStartAtLen( nCurrId, LayerParams.LinkParam / 2) + local _, _, dAngIni = SphericalFromVector( EgtEV( nPrevId)) + local _, _, dAngFin = SphericalFromVector( EgtSV( nCurrId)) + nLinkId = EgtBiArc( nTpathGrpId, EgtEP( nPrevId), EgtSP( nCurrId), dAngIni, dAngFin, 0.5) + end + EgtRelocate( nLinkId, nCurrId, GDB_IN.BEFORE) + local nType = EgtGetInfo( nCurrId, KEY_TYPE, 'i') + EgtSetInfo( nLinkId, KEY_TYPE, TYPE.LINK) + nPrevId = nCurrId + nCurrId = EgtGetNext( nCurrId) + end + + --passo al gruppo di contorni successivo + nCrvGrpId = EgtGetNextName( nCrvGrpId, CONTOUR_GRP.."*") + end + end +end + +--------------------------------------------------------------------- +return CalcToolPath diff --git a/MachiningParamCalc.lua b/MachiningParamCalc.lua new file mode 100644 index 0000000..68ac196 --- /dev/null +++ b/MachiningParamCalc.lua @@ -0,0 +1,177 @@ +-- MachiningParamCalc.lua by Egaltech s.r.l. 2022/04/05 +-- Gestione visualizzazione per Stampa 3d + +-- Intestazioni +require( 'EgtBase') +_ENV = EgtProtectGlobal() +EgtEnableDebug( false) + +-- Imposto direttorio libreria specializzata per Stampa 3d +local sBaseDir = EgtGetSourceDir() +EgtAddToPackagePath( sBaseDir .. 'LuaLibs\\?.lua') + +-- Costanti generali +local AMD = require( 'AddManData') +local CSV = require( 'CSVManager') + +nParamsGrp = EgtGetFirstNameInGroup( GDB_ID.ROOT, PARAMS_GRP) or GDB_ID.NULL +if nParamsGrp == GDB_ID.NULL then + EgtOutBox( 'Impossible calculating before applying a machining.', 'Error', 'ERROR') + return +end + +local dMachiningFeed = EgtGetInfo( nParamsGrp, KEY_FEED, 'd') +local dSliceStep = EgtGetInfo( nParamsGrp, KEY_SLICE_STEP, 'd') +local dStrand = EgtGetInfo( nParamsGrp, KEY_STRAND, 'd') +local sMaterial = EgtGetInfo( nParamsGrp, KEY_MATERIAL) + +local sMachiningPath = EgtGetStringFromIni( '3dPrinting', 'ParamFile', "", EgtGetIniFile()) +local dCoeffX = tonumber( EgtGetStringFromIni( DEFAULT_SECTION, KEY_COEFF_X, 0, sMachiningPath)) +local dCoeffY = tonumber( EgtGetStringFromIni( DEFAULT_SECTION, KEY_COEFF_Y, 0, sMachiningPath)) +local sCalcBaseDir = EgtGetStringFromIni( '3dPrinting', 'BaseDir', 'C:\\ProgramData\\Egaltech\\EgtCam5\\3dPrinting', EgtGetIniFile()) +local sCurrProjectPath = EgtGetCurrFilePath() +local _, sCurrProjectName = EgtSplitPath( sCurrProjectPath) +local sResultFile = sCalcBaseDir .. '\\Results\\' .. sCurrProjectName .. '.csv' +local bResultFile = EgtExistsFile( sResultFile) + +-- calcolo intervallo tempi consentito +local sMaterialPath = sCalcBaseDir .. '\\Materials\\' .. sMaterial .. '.csv' +local MaterialCSV = read_file( sMaterialPath) +local dMinTime = 0 +local dMaxTime = 0 +if not MaterialCSV then + EgtOutBox( 'Material csv file not found.', 'Error', 'ERROR') + return +end +local bSectionFound = false +for nSectionIndex = 1, #MaterialCSV do + local Section = MaterialCSV[nSectionIndex] + if tonumber( Section[1]) == dStrand and tonumber( Section[2]) == dSliceStep then + dMinTime = tonumber(Section[3]) + dMaxTime = tonumber(Section[4]) + bSectionFound = true + break + end +end +if not bSectionFound then + EgtOutBox( 'Section not found in Material csv file.', 'Error', 'ERROR') + return +end + +-- carico eventuale file dei risultati +local CSVOldResult +if bResultFile then + CSVOldResult = read_file( sResultFile) +end + +-- tabella del csv del risultato +local CSVNewResult = {} + +-- ciclo sui pezzi +local nPartIndex = 1 +local nPartId = EgtGetFirstNameInGroup( GDB_ID.ROOT, PART .. nPartIndex) +while nPartId do + -- ciclo sui layer + local nLayerIndex = 1 + local nLayerId = EgtGetFirstNameInGroup( nPartId, SLICE_LAYER .. nLayerIndex) + while nLayerId do + local sLayerName = EgtGetName( nLayerId) + local nLayerIndex = tonumber( sLayerName:sub( #SLICE_LAYER + 1)) + -- calcolo lunghezza totale del layer + local dTotLayerLength = 0 + local nCrvId = EgtGetFirstGroupInGroup( nLayerId) + while nCrvId do + local nToolPathId = EgtGetFirstNameInGroup( nCrvId, TOOLPATH_GRP) + -- sommo lunghezze percorsi + local dTotCrvLength = 0 + nShellId = EgtGetFirstInGroup( nToolPathId) + while nShellId do + --local nType = EgtGetInfo( nShellId, KEY_TYPE, 'i') + dTotCrvLength = dTotCrvLength + EgtCurveLength( nShellId) + nShellId = EgtGetNext( nShellId) + end + dTotLayerLength = dTotLayerLength + dTotCrvLength + nCrvId = EgtGetNext( nCrvId) + end + -- recupero feed del layer + local dLayerFeed = 0 + if bResultFile then + -- leggo il valore dal file + local bResultFound = false + for nResultIndex = 1, #CSVOldResult do + local OldResult = CSVOldResult[nResultIndex] + if tonumber( OldResult[1]) == nLayerIndex then + dLayerFeed = tonumber( OldResult[5]) + bResultFound = true + break + end + end + if not bResultFound then + -- uso valore di default + dLayerFeed = dMachiningFeed + end + else + -- uso valore di default + dLayerFeed = dMachiningFeed + end + -- calcolo tempo stimato del layer + local dEsteemedTime = dTotLayerLength / dLayerFeed * 60 + -- calcolo speed + local dSpeed = ((( dLayerFeed * dSliceStep * dStrand ) / 60) - dCoeffX) / dCoeffY + -- scrivo info feed e speed in group toolpath + nCrvId = EgtGetFirstGroupInGroup( nLayerId) + while nCrvId do + local nToolPathId = EgtGetFirstNameInGroup( nCrvId, TOOLPATH_GRP) + EgtSetInfo( nToolPathId, KEY_FEED, dLayerFeed) + EgtSetInfo( nToolPathId, KEY_SPEED, dSpeed) + nCrvId = EgtGetNext( nCrvId) + end + -- riporto valori calcolati in tabella per csv + local sStatus = '' + if dEsteemedTime < dMinTime then + sStatus = 'KO(-)' + elseif dEsteemedTime > dMinTime and dEsteemedTime < dMaxTime then + sStatus = 'OK' + elseif dEsteemedTime > dMaxTime then + sStatus = 'KO(+)' + end + --table.insert( CSVOutTable, { Index = nLayerIndex, EsteemedTime = dEsteemedTime, Feed = dLayerFeed, Speed = dSpeed}) + table.insert( CSVNewResult, { nLayerIndex, dTotLayerLength, dEsteemedTime, sStatus, dLayerFeed, dSpeed}) + nLayerIndex = nLayerIndex + 1 + nLayerId = EgtGetFirstNameInGroup( nPartId, SLICE_LAYER .. nLayerIndex) + end + nPartIndex = nPartIndex + 1 + nPartId = EgtGetFirstNameInGroup( GDB_ID.ROOT, PART .. nPartIndex) +end + +-- scrivo nuovo file csv di risultato +local file = io.open( sResultFile, "w") +if file then + file:write('LayerIndex; Len; Time; Status; Feed; Speed') + file:write('\n') + for NewResultIndex = 1, #CSVNewResult do + local CSVOutLine = CSVNewResult[NewResultIndex] + local sParams = '' + for ParamIndex = 1, #CSVOutLine do + if ParamIndex > 1 then + sParams = sParams .. ";" + end + if ParamIndex == 4 then + sParams = sParams .. CSVOutLine[ParamIndex] + else + sParams = sParams .. EgtNumToString( CSVOutLine[ParamIndex], 1) + end + end + file:write(sParams) + file:write('\n') + end + file:close() + local sReadProgPath = EgtGetStringFromIni( '3dPrinting', RESULT_READ_PROG, "", EgtGetIniFile()) + if not sReadProgPath or not EgtWinExec( sReadProgPath .. ' ' .. sResultFile) then + EgtOutBox( 'Impossible opening software to show results. You can find them in ' .. sResultFile, 'Error', 'ERROR') + end +else + EgtOutBox( 'Impossible writing results file in ' .. sResultFile, 'Error', 'ERROR') +end + +------------------------- MAIN -------------------------------------- diff --git a/MachiningParamEdit.lua b/MachiningParamEdit.lua new file mode 100644 index 0000000..d73542c --- /dev/null +++ b/MachiningParamEdit.lua @@ -0,0 +1,53 @@ +-- MachiningParamCalc.lua by Egaltech s.r.l. 2022/04/05 +-- Gestione visualizzazione per Stampa 3d + +-- Intestazioni +require( 'EgtBase') +_ENV = EgtProtectGlobal() +EgtEnableDebug( false) + +-- Imposto direttorio libreria specializzata per Stampa 3d +local sBaseDir = EgtGetSourceDir() +EgtAddToPackagePath( sBaseDir .. 'LuaLibs\\?.lua') + +-- Costanti generali +local AMD = require( 'AddManData') + +-- recupero cartella delle lavorazioni +local sCalcBaseDir = EgtGetStringFromIni( '3dPrinting', 'BaseDir', 'C:\\ProgramData\\Egaltech\\EgtCam5\\3dPrinting', EgtGetIniFile()) +local sMachiningDirPath = sCalcBaseDir .. '\\Machinings\\' + +-- recupero file delle lavorazioni +--local Machinings = {} +local sMachinings = '' + +local f = io.popen("dir " .. sMachiningDirPath .. " /B", "r") +for entry in f:lines() do + --Machinings[#Machinings + 1] = entry + local sDir, sFile, sExt = EgtSplitPath(entry) + if sExt == '.ini' then + if sMachinings ~= "" then + sMachinings = sMachinings .. ',' + end + sMachinings = sMachinings .. sFile + end +end + +-- chiedo quale file aprire +MachiningValues = EgtDialogBox( 'Machinings edit', { 'Machining', 'CB:' .. sMachinings}) +if not MachiningValues or #MachiningValues < 1 then return end + +-- verifico esistenza file +local sSelMachiningPath = sMachiningDirPath .. MachiningValues[1] .. '.ini' +if not EgtExistsFile( sSelMachiningPath) then + EgtOutBox( 'Machining file not found', 'Error', 'ERROR') + return +end + +-- apro programma di edit +local sEditProgPath = EgtGetStringFromIni( '3dPrinting', 'MachiningEditProg', "", EgtGetIniFile()) +if not sEditProgPath or not EgtWinExec( sEditProgPath .. ' ' .. sSelMachiningPath) then + EgtOutBox( 'Impossible opening software to show Machining. You can find it in ' .. sSelMachiningPath, 'Error', 'ERROR') +end + +------------------------- MAIN -------------------------------------- diff --git a/Machinings/Params.ini b/Machinings/Params.ini new file mode 100644 index 0000000..905dee4 --- /dev/null +++ b/Machinings/Params.ini @@ -0,0 +1,17 @@ +[Default] +StrandH=2.0 +StrandW=6.0 +StrandCount=2 +Offset=2.0 +StartingPoint=0,-300 +StrandOrder=in +Direction=CCW +LinkType=sPath +LinkParam=10.0 +FloorCount=2 +Speed= +Feed=4500 +G0Feed=10000 +Material=B461 +CoeffX=-8.68 +CoeffY=12.4865 diff --git a/Machinings/Params3.ini b/Machinings/Params3.ini new file mode 100644 index 0000000..185f0ee --- /dev/null +++ b/Machinings/Params3.ini @@ -0,0 +1,37 @@ +[Default] +StrandH=40.0 +StrandW=6.0 +StrandCount=3 +Offset=2.0 +StartingPoint=0,-300 +StrandOrder=in +Direction=CCW +LinkType=sPath +LinkParam=10.0 +FloorCount=2 +Speed= +Feed=4500 +G0Feed=10000 +Material=B461 +CoeffX=-8.68 +CoeffY=12.4865 + +[LayerX] +StrandH=1 +StrandW=8 +StrandCount=3 +Offset=2 +StartingPoint=(x,y) +StrandOrder=in/out +Direction=CW/CCW +LinkType=straight/sPath +LinkParam=5 +FloorCount=2 +Speed= +ExtFeed= +IntFeed= +InfillFeed= +LeadInFeed= +LeadOutFeed= +SupportFeed= +G0Feed= diff --git a/MaterialParamEdit.lua b/MaterialParamEdit.lua new file mode 100644 index 0000000..6787dba --- /dev/null +++ b/MaterialParamEdit.lua @@ -0,0 +1,52 @@ +-- MachiningParamCalc.lua by Egaltech s.r.l. 2022/04/09 +-- Gestione edit parametri materiali per Stampa 3d + +-- Intestazioni +require( 'EgtBase') +_ENV = EgtProtectGlobal() +EgtEnableDebug( false) + +-- Imposto direttorio libreria specializzata per Stampa 3d +local sBaseDir = EgtGetSourceDir() +EgtAddToPackagePath( sBaseDir .. 'LuaLibs\\?.lua') + +-- Costanti generali +local AMD = require( 'AddManData') + +-- recupero cartella dei materiali +local sCalcBaseDir = EgtGetStringFromIni( '3dPrinting', 'BaseDir', 'C:\\ProgramData\\Egaltech\\EgtCam5\\3dPrinting', EgtGetIniFile()) +local sMaterialDirPath = sCalcBaseDir .. '\\Materials\\' + +-- recupero elenco file dei materiali +local Files = EgtFindAllFiles( sMaterialDirPath..'*.csv') +if not Files then + EgtOutBox( 'Material files not found', 'Error', 'ERROR') + return +end +local sMaterials = '' +for i = 1, #Files do + local sDir, sFile, sExt = EgtSplitPath( Files[i]) + if sMaterials ~= "" then + sMaterials = sMaterials .. ',' + end + sMaterials = sMaterials .. sFile +end + +-- chiedo quale file aprire +MaterialValues = EgtDialogBox( 'Materials edit', { 'Material', 'CB:' .. sMaterials}) +if not MaterialValues or #MaterialValues < 1 then return end + +-- verifico esistenza file +local sSelMaterialPath = sMaterialDirPath .. MaterialValues[1] .. '.csv' +if not EgtExistsFile( sSelMaterialPath) then + EgtOutBox( 'Material file not found', 'Error', 'ERROR') + return +end + +-- apro programma di edit +local sEditProgPath = EgtGetStringFromIni( '3dPrinting', RESULT_READ_PROG, "", EgtGetIniFile()) +if not sEditProgPath or not EgtWinExec( sEditProgPath .. ' ' .. sSelMaterialPath) then + EgtOutBox( 'Impossible opening software to show Material. You can find them it in ' .. sSelMaterialPath, 'Error', 'ERROR') +end + +------------------------- MAIN -------------------------------------- diff --git a/Materials/B461.csv b/Materials/B461.csv new file mode 100644 index 0000000..116186b --- /dev/null +++ b/Materials/B461.csv @@ -0,0 +1,26 @@ +Larghezza strand W [mm];Passo Z [mm];Tempo minimo [sec] ;Tempo massimo [sec] +1;"1";"10";"25" +2;"1";"14";"28" +3;"1";"16";"30" +4;"1";"18";"40" +5;"1";"20";"50" +6;"1";"25";"52" +7;"1";"30";"55" +8;"1";"32";"60" +9;"1";"36";"65" +10;"1";"38";"70" +11;"1";"40";"75" +12;"1";"44";"80" +1;"1.2";"11";"26" +2;"1.2";"15";"29" +3;"1.2";"17";"31" +4;"1.2";"19";"41" +5;"1.2";"21";"51" +6;"1.2";"26";"53" +7;"1.2";"31";"56" +8;"1.2";"33";"61" +9;"1.2";"37";"66" +10;"1.2";"39";"71" +11;"1.2";"41";"76" +12;"1.2";"45";"81" +6;"2";"60";"100" \ No newline at end of file diff --git a/PartPositioning.lua b/PartPositioning.lua new file mode 100644 index 0000000..0bf5713 --- /dev/null +++ b/PartPositioning.lua @@ -0,0 +1,105 @@ +-- PlacePart.lua by Egaltech s.r.l. 2022/04/11 +-- Gestione calcolo disposizione e lavorazioni per stampa 3d +-- 2022/03/21 Creazione file + + +-- Intestazioni +require( 'EgtBase') +_ENV = EgtProtectGlobal() +EgtEnableDebug( false) + +-- Imposto direttorio libreria specializzata per Stampa 3d +local sBaseDir = EgtGetSourceDir() +EgtAddToPackagePath( sBaseDir .. 'LuaLibs\\?.lua') + +-- Costanti generali +local AMD = require( 'AddManData') + +-- Recupero ultimo oggetto selezionato +local nPartId = EgtGetParent(EgtGetParent( EgtGetLastSelectedObj())) +-- verifico sia un pezzo valido +if nPartId then + local nParentId = EgtGetParent( nPartId) + while nParentId ~= GDB_ID.ROOT do + nPartId = nParentId + nParentId = EgtGetParent( nPartId) + end + if EgtIsPart( nPartId) then + local sName = EgtGetName( nPartId) + if sName == TABLE then + EgtOutBox( 'No selected part. Please select a part before moving it on the table.', 'Warning', 'WARNING') + return + end + else + EgtOutBox( 'No selected part. Please select a part before moving it on the table.', 'Warning', 'WARNING') + return + end +else + EgtOutBox( 'No selected part. Please select a part before moving it on the table.', 'Warning', 'WARNING') + return +end + +-- gli assegno nome pezzo e layer +if not EgtGetName( nPartId) then + local nPartIndex = 1 + while EgtGetFirstNameInGroup( GDB_ID.ROOT, PART .. nPartIndex) do + nPartIndex = nPartIndex + 1 + end + EgtSetName( nPartId, PART .. nPartIndex) + local nLayerId = EgtGetFirstInGroup( nPartId) + EgtSetName( nLayerId, ORIGINAL_SOLID) +end + +-- Recupero dati tavola (creando gruppo di lavoro temporaneo) +local nQqqId = EgtAddMachGroup( 'qqq') +EgtSetTable( 'Tab') +local b3Tab = EgtGetTableArea() +dTabX = b3Tab:getDimX() +dTabY = b3Tab:getDimY() +EgtRemoveMachGroup( nQqqId or GDB_ID.NULL) + +-- Richiedo coordinata posizionamento pezzo +local b3Part = EgtGetBBoxGlob( nPartId, GDB_BB.EXACT) +local dPosX = b3Tab:getDimX() / 2 +local dPosY = b3Tab:getDimY() / 2 +local Positions = EgtDialogBox( 'Part position on table:', { 'X', EgtNumToString( EgtToUiUnits(dPosX), 1)}, { 'Y', EgtNumToString( EgtToUiUnits(dPosY), 1)}) +if not Positions then return end +dPosX = EgtFromUiUnits( tonumber( Positions[1])) - b3Part:getDimX() / 2 +dPosY = EgtFromUiUnits( tonumber( Positions[2])) - b3Part:getDimY() / 2 + +-- Creo disegno tavola +local nTabPart = EgtGetFirstNameInGroup( GDB_ID.ROOT, TABLE) +if not nTabPart then + -- Disegno tavola + nTabPart = EgtGroup( GDB_ID.ROOT) + --EgtSetLevel( nTabPart, GDB_LV.SYSTEM) + EgtSetName( nTabPart, TABLE) + local nTabLayer = EgtGroup( nTabPart) + EgtSetName( nTabLayer, TABLE) + local nTabOutlineId = EgtRectangle2P( nTabLayer, Point3d( 0, 0, 0), Point3d( dTabX, dTabY, 0)) + EgtSetName( nTabOutlineId, TABLE_OUTLINE) + local nTabSurfId = EgtSurfFlatRegion( nTabLayer, nTabOutlineId) + EgtSetName( nTabSurfId, TABLE_SURFACE) + EgtSetColor( nTabSurfId, 'ORANGE') + EgtSetAlpha( nTabSurfId, 70) +end + +-- Posiziono il pezzo +EgtMove( nPartId, Point3d( dPosX, dPosY, 0) - b3Part:getMin()) + +local nMchGrpId = EgtGetMachGroupId( '3dPrint') +EgtRemoveMachGroup( nMchGrpId or GDB_ID.NULL) +EgtAddMachGroup( '3dPrint') +EgtSetTable( 'Tab') + +local nRawId = EgtAddRawPartWithPart( nPartId, GDB_ID.NULL, 0, Color3d( 128, 128, 128, 30)) +EgtMoveToCornerRawPart( nRawId, Point3d( dPosX, dPosY, 0), MCH_CR.BL) + +EgtResetCurrMachGroup() + + +EgtSetView( SCE_VD.ISO_SW, false) +EgtZoom( SCE_ZM.ALL) + + +EgtOutLog( ' +++ PlacePart completed') diff --git a/README.md b/README.md index e81c7f1..7cab802 100644 --- a/README.md +++ b/README.md @@ -1,92 +1,7 @@ # 3dPrinting -Script LUA x progetto 3DPrinting +Script LUA x progetto 3DPrinting (CMS Kreator) -## Getting started +# Automazioni -To make it easy for you to get started with GitLab, here's a list of recommended next steps. - -Already a pro? Just edit this README.md and make it your own. Want to make it easy? [Use the template at the bottom](#editing-this-readme)! - -## Add your files - -- [ ] [Create](https://docs.gitlab.com/ee/user/project/repository/web_editor.html#create-a-file) or [upload](https://docs.gitlab.com/ee/user/project/repository/web_editor.html#upload-a-file) files -- [ ] [Add files using the command line](https://docs.gitlab.com/ee/gitlab-basics/add-file.html#add-a-file-using-the-command-line) or push an existing Git repository with the following command: - -``` -cd existing_repo -git remote add origin https://gitlab.steamware.net/egalware/3dprinting.git -git branch -M main -git push -uf origin main -``` - -## Integrate with your tools - -- [ ] [Set up project integrations](https://gitlab.steamware.net/egalware/3dprinting/-/settings/integrations) - -## Collaborate with your team - -- [ ] [Invite team members and collaborators](https://docs.gitlab.com/ee/user/project/members/) -- [ ] [Create a new merge request](https://docs.gitlab.com/ee/user/project/merge_requests/creating_merge_requests.html) -- [ ] [Automatically close issues from merge requests](https://docs.gitlab.com/ee/user/project/issues/managing_issues.html#closing-issues-automatically) -- [ ] [Enable merge request approvals](https://docs.gitlab.com/ee/user/project/merge_requests/approvals/) -- [ ] [Automatically merge when pipeline succeeds](https://docs.gitlab.com/ee/user/project/merge_requests/merge_when_pipeline_succeeds.html) - -## Test and Deploy - -Use the built-in continuous integration in GitLab. - -- [ ] [Get started with GitLab CI/CD](https://docs.gitlab.com/ee/ci/quick_start/index.html) -- [ ] [Analyze your code for known vulnerabilities with Static Application Security Testing(SAST)](https://docs.gitlab.com/ee/user/application_security/sast/) -- [ ] [Deploy to Kubernetes, Amazon EC2, or Amazon ECS using Auto Deploy](https://docs.gitlab.com/ee/topics/autodevops/requirements.html) -- [ ] [Use pull-based deployments for improved Kubernetes management](https://docs.gitlab.com/ee/user/clusters/agent/) -- [ ] [Set up protected environments](https://docs.gitlab.com/ee/ci/environments/protected_environments.html) - -*** - -# Editing this README - -When you're ready to make this README your own, just edit this file and use the handy template below (or feel free to structure it however you want - this is just a starting point!). Thank you to [makeareadme.com](https://www.makeareadme.com/) for this template. - -## Suggestions for a good README -Every project is different, so consider which of these sections apply to yours. The sections used in the template are suggestions for most open source projects. Also keep in mind that while a README can be too long and detailed, too long is better than too short. If you think your README is too long, consider utilizing another form of documentation rather than cutting out information. - -## Name -Choose a self-explaining name for your project. - -## Description -Let people know what your project can do specifically. Provide context and add a link to any reference visitors might be unfamiliar with. A list of Features or a Background subsection can also be added here. If there are alternatives to your project, this is a good place to list differentiating factors. - -## Badges -On some READMEs, you may see small images that convey metadata, such as whether or not all the tests are passing for the project. You can use Shields to add some to your README. Many services also have instructions for adding a badge. - -## Visuals -Depending on what you are making, it can be a good idea to include screenshots or even a video (you'll frequently see GIFs rather than actual videos). Tools like ttygif can help, but check out Asciinema for a more sophisticated method. - -## Installation -Within a particular ecosystem, there may be a common way of installing things, such as using Yarn, NuGet, or Homebrew. However, consider the possibility that whoever is reading your README is a novice and would like more guidance. Listing specific steps helps remove ambiguity and gets people to using your project as quickly as possible. If it only runs in a specific context like a particular programming language version or operating system or has dependencies that have to be installed manually, also add a Requirements subsection. - -## Usage -Use examples liberally, and show the expected output if you can. It's helpful to have inline the smallest example of usage that you can demonstrate, while providing links to more sophisticated examples if they are too long to reasonably include in the README. - -## Support -Tell people where they can go to for help. It can be any combination of an issue tracker, a chat room, an email address, etc. - -## Roadmap -If you have ideas for releases in the future, it is a good idea to list them in the README. - -## Contributing -State if you are open to contributions and what your requirements are for accepting them. - -For people who want to make changes to your project, it's helpful to have some documentation on how to get started. Perhaps there is a script that they should run or some environment variables that they need to set. Make these steps explicit. These instructions could also be useful to your future self. - -You can also document commands to lint the code or run tests. These steps help to ensure high code quality and reduce the likelihood that the changes inadvertently break something. Having instructions for running tests is especially helpful if it requires external setup, such as starting a Selenium server for testing in a browser. - -## Authors and acknowledgment -Show your appreciation to those who have contributed to the project. - -## License -For open source projects, say how it is licensed. - -## Project status -If you have run out of energy or time for your project, put a note at the top of the README saying that development has slowed down or stopped completely. Someone may choose to fork your project or volunteer to step in as a maintainer or owner, allowing your project to keep going. You can also make an explicit request for maintainers. +Come per i progetti EgtBeamWall, alla pubblicazione di ogni push nel ramo principale (MAIN), gli script LUA verranno compilati e resi disponibili in area R:\ e Artifacts per essere impiegati ad esempio negli installers. \ No newline at end of file diff --git a/README.pdf b/README.pdf new file mode 100644 index 0000000000000000000000000000000000000000..b6c692e56649ed84e99756b03af7e293a0f2f689 GIT binary patch literal 29920 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 literal 0 HcmV?d00001 diff --git a/ShowManager.lua b/ShowManager.lua new file mode 100644 index 0000000..3869967 --- /dev/null +++ b/ShowManager.lua @@ -0,0 +1,107 @@ +-- ShowManager.lua by Egaltech s.r.l. 2022/04/05 +-- Gestione visualizzazione per Stampa 3d + +-- Intestazioni +require( 'EgtBase') +_ENV = EgtProtectGlobal() +EgtEnableDebug( false) + +-- Imposto direttorio libreria specializzata per Stampa 3d +local sBaseDir = EgtGetSourceDir() +EgtAddToPackagePath( sBaseDir .. 'LuaLibs\\?.lua') + +-- Costanti generali +local AMD = require( 'AddManData') + +local function ShowImportedSolid( nPartId, bShow) + local nLayerId = EgtGetFirstNameInGroup( nPartId, ORIGINAL_SOLID) + local nItemId = EgtGetFirstInGroup( nLayerId) + while nItemId do + if EgtGetType( nItemId) == GDB_TY.SRF_MESH then + EgtSetStatus( nItemId, EgtIf( bShow, GDB_ST.ON, GDB_ST.OFF)) + end + nItemId = EgtGetNext(nItemId) + end +end + +-- Verifico esistenza gruppo stato visualizzazione progetto +local nViewId = EgtGetFirstNameInGroup( GDB_ID.ROOT, VIEWPARAMS) +local bImportedSolid = false +local bOuterCrv = false +local bPath = false +local bSolid = true +local bToolPath = true + +if not nViewId then + nViewId = EgtGroup( GDB_ID.ROOT) + EgtSetName( nViewId, VIEWPARAMS) +else + bImportedSolid = EgtGetInfo( nViewId, IMPORTED_SOLID, 'b') + bOuterCrv = EgtGetInfo( nViewId, OUTER_CRV, 'b') + bPath = EgtGetInfo( nViewId, PATH_GRP, 'b') + bSolid = EgtGetInfo( nViewId, SOLID_GRP, 'b') + bToolPath = EgtGetInfo( nViewId, TOOLPATH_GRP, 'b') +end + +ViewValues = EgtDialogBox( 'Show Manager', { 'Imported Solid', 'CK:' .. EgtIf( bImportedSolid, '1', '0')}, + { 'OuterCrv', 'CK:' .. EgtIf( bOuterCrv, '1', '0')}, + { 'Path', 'CK:' .. EgtIf( bPath, '1', '0')}, + { 'Solid', 'CK:' .. EgtIf( bSolid, '1', '0')}, + { 'ToolPath', 'CK:' .. EgtIf( bToolPath, '1', '0')}) +if not ViewValues or #ViewValues < 5 then return end + +-- dis/attivo solidi originali +local bCurrImportedSolid = ( ViewValues[1] == '1') +local bCurrOuterCrv = ( ViewValues[2] == '1') +local bCurrPath = ( ViewValues[3] == '1') +local bCurrSolid = ( ViewValues[4] == '1') +local bCurrToolPath = ( ViewValues[5] == '1') + +-- ciclo sui pezzi +local nPartIndex = 1 +local nPartId = EgtGetFirstNameInGroup( GDB_ID.ROOT, PART .. nPartIndex) +while nPartId do + if bImportedSolid ~= bCurrImportedSolid then + ShowImportedSolid( nPartId, bCurrImportedSolid) + end + -- ciclo sui layer per dis/attivare il resto + local nLayerIndex = 1 + local nLayerId = EgtGetFirstNameInGroup( nPartId, SLICE_LAYER .. nLayerIndex) + while nLayerId do + local nCrvId = EgtGetFirstGroupInGroup( nLayerId) + while nCrvId do + if bOuterCrv ~= bCurrOuterCrv then + local nOuterCrvId = EgtGetFirstNameInGroup( nCrvId, OUTER_CRV) + EgtSetStatus( nOuterCrvId, EgtIf( bCurrOuterCrv, GDB_ST.ON, GDB_ST.OFF)) + end + if bPath ~= bCurrPath then + local nPathId = EgtGetFirstNameInGroup( nCrvId, PATH_GRP) + EgtSetStatus( nPathId, EgtIf( bCurrPath, GDB_ST.ON, GDB_ST.OFF)) + end + if bSolid ~= bCurrSolid then + local nSolidId = EgtGetFirstNameInGroup( nCrvId, SOLID_GRP) + EgtSetStatus( nSolidId, EgtIf( bCurrSolid, GDB_ST.ON, GDB_ST.OFF)) + end + if bToolPath ~= bCurrToolPath then + local nToolPathId = EgtGetFirstNameInGroup( nCrvId, TOOLPATH_GRP) + EgtSetStatus( nToolPathId, EgtIf( bCurrToolPath, GDB_ST.ON, GDB_ST.OFF)) + end + nCrvId = EgtGetNext( nCrvId) + end + nLayerIndex = nLayerIndex + 1 + nLayerId = EgtGetFirstNameInGroup( nPartId, SLICE_LAYER .. nLayerIndex) + end + nPartIndex = nPartIndex + 1 + nPartId = EgtGetFirstNameInGroup( GDB_ID.ROOT, PART .. nPartIndex) +end + +-- riporto impostazioni in gruppo apposito +EgtSetInfo( nViewId, IMPORTED_SOLID, bCurrImportedSolid) +EgtSetInfo( nViewId, OUTER_CRV, bCurrOuterCrv) +EgtSetInfo( nViewId, PATH_GRP, bCurrPath) +EgtSetInfo( nViewId, SOLID_GRP, bCurrSolid) +EgtSetInfo( nViewId, TOOLPATH_GRP, bCurrToolPath) + +EgtDraw() + +------------------------- MAIN -------------------------------------- diff --git a/SliceAdvancement.lua b/SliceAdvancement.lua new file mode 100644 index 0000000..c2e3a2e --- /dev/null +++ b/SliceAdvancement.lua @@ -0,0 +1,93 @@ +-- SliceAdvancement.lua by Egaltech s.r.l. 2022/04/05 +-- Gestione visualizzazione per Stampa 3d + +-- Intestazioni +require( 'EgtBase') +_ENV = EgtProtectGlobal() +EgtEnableDebug( false) + +-- Imposto direttorio libreria specializzata per Stampa 3d +local sBaseDir = EgtGetSourceDir() +EgtAddToPackagePath( sBaseDir .. 'LuaLibs\\?.lua') + +-- Costanti generali +local AMD = require( 'AddManData') + +ViewValues = EgtDialogBox( 'Slice advancement', { 'Type', 'CB:*All,Only Outer,Only Inner,Only Infill'}, + { 'Percentage (0-100)', '30'}) +if not ViewValues or #ViewValues < 1 then return end + +local nAdvancementType = 1 -- 1 = All, 2 = Only Outer, 3 = Only Inner, 4 = Only Infill +if ViewValues[1] == 'All' then + nAdvancementType = 1 +elseif ViewValues[1] == 'Only Outer' then + nAdvancementType = 2 +elseif ViewValues[1] == 'Only Inner' then + nAdvancementType = 3 +elseif ViewValues[1] == 'Only Infill' then + nAdvancementType = 4 +end + +local nPercentage = tonumber( ViewValues[2]) + +local function ManageSegmentVisibility( SegmentList, nLastActiveIndex, ToHideList) + for Index = 1, #SegmentList do + EgtSetStatus( SegmentList[Index], EgtIf( Index <= nLastActiveIndex, GDB_ST.ON, GDB_ST.OFF)) + end + if ToHideList and #ToHideList > 0 then + for Index = 1, #ToHideList do + EgtSetStatus( ToHideList[Index], GDB_ST.OFF) + end + end +end + +-- ciclo sui pezzi +local nPartIndex = 1 +local nPartId = EgtGetFirstNameInGroup( GDB_ID.ROOT, PART .. nPartIndex) +while nPartId do + -- ciclo sui layer per dis/attivare il resto + local nLayerIndex = 1 + local nLayerId = EgtGetFirstNameInGroup( nPartId, SLICE_LAYER .. nLayerIndex) + while nLayerId do + local nCrvId = EgtGetFirstGroupInGroup( nLayerId) + while nCrvId do + local nSolidId = EgtGetFirstNameInGroup( nCrvId, SOLID_GRP) + local ShellList = { {}, {}} + local nSurfId = EgtGetFirstInGroup( nSolidId) + while nSurfId do + local nType = EgtGetInfo( nSurfId, KEY_TYPE, 'i') + table.insert( ShellList[nType + 1], nSurfId) + nSurfId = EgtGetNext( nSurfId) + end + local nSegmentQty = 1 + local SegmentList + local ToHideList + if nAdvancementType == 1 then + nSegmentQty = #ShellList[1] + #ShellList[2] + SegmentList = ShellList[1] + for i = 1, #ShellList[2] do + SegmentList[#SegmentList + 1] = ShellList[2][i] + end + elseif nAdvancementType == 2 then + nSegmentQty = #ShellList[1] + SegmentList = ShellList[1] + ToHideList = ShellList[2] + elseif nAdvancementType == 3 then + nSegmentQty = #ShellList[2] + SegmentList = ShellList[2] + ToHideList = ShellList[1] + end + local nLastActiveIndex = ceil( nSegmentQty * nPercentage / 100) + ManageSegmentVisibility( SegmentList, nLastActiveIndex, ToHideList) + nCrvId = EgtGetNext( nCrvId) + end + nLayerIndex = nLayerIndex + 1 + nLayerId = EgtGetFirstNameInGroup( nPartId, SLICE_LAYER .. nLayerIndex) + end + nPartIndex = nPartIndex + 1 + nPartId = EgtGetFirstNameInGroup( GDB_ID.ROOT, PART .. nPartIndex) +end + +EgtDraw() + +------------------------- MAIN -------------------------------------- diff --git a/Slicing.lua b/Slicing.lua new file mode 100644 index 0000000..b1b34b9 --- /dev/null +++ b/Slicing.lua @@ -0,0 +1,136 @@ +-- Slicing.lua by Egaltech s.r.l. 2022/03/30 +-- Calcoli prima fase per Stampa 3d + +-- Intestazioni +require( 'EgtBase') +_ENV = EgtProtectGlobal() +EgtEnableDebug( false) + +-- Imposto direttorio libreria specializzata per Stampa 3d +local sBaseDir = EgtGetSourceDir() +EgtAddToPackagePath( sBaseDir .. 'LuaLibs\\?.lua') + +-- Costanti generali +_G.package.loaded.AddManData = nil +local AMD = require( 'AddManData') + +-- Librerie +_G.package.loaded.CalcSlices = nil +local CSLICES = require( 'CalcSlices') +_G.package.loaded.CalcPaths = nil +local CPATHS = require( 'CalcPaths') +_G.package.loaded.CalcSolids = nil +local CSOLIDS = require( 'CalcSolids') +_G.package.loaded.CalcToolPath = nil +local CTP = require( 'CalcToolPath') + +--------------------------------------------------------------------- +local function SetParamInfo( sFile, nParamsGrp, sSection, sKey, sDefaultVal) + local sVal = EgtGetStringFromIni( sSection, sKey, sDefaultVal, sFile) + EgtSetInfo( nParamsGrp, sKey, sVal) +end + +--------------------------------------------------------------------- +local function LoadParams( sFile, nPartId) + -- creo gruppo dove salvare parametri + local nParamsGrp = EgtGetFirstNameInGroup( GDB_ID.ROOT, PARAMS_GRP) or GDB_ID.NULL + if nParamsGrp == GDB_ID.NULL then + nParamsGrp = EgtGroup( GDB_ID.ROOT) + EgtRelocate( nParamsGrp, GDB_ID.ROOT, GDB_IN.FIRST_SON) + EgtSetName( nParamsGrp, PARAMS_GRP) + EgtSetLevel( nParamsGrp, GDB_LV.SYSTEM) + end + + EgtSetInfo( nParamsGrp, INFO_PARTD_ID, nPartId) + + SetParamInfo( sFile, nParamsGrp, DEFAULT_SECTION, KEY_SLICE_STEP, '1.0') + SetParamInfo( sFile, nParamsGrp, DEFAULT_SECTION, KEY_STRAND, '6.0') + SetParamInfo( sFile, nParamsGrp, DEFAULT_SECTION, KEY_SHELLS_NBR, '3') + SetParamInfo( sFile, nParamsGrp, DEFAULT_SECTION, KEY_OFFSET_SLICE, '0.0') + + local sStartPoint = EgtGetStringFromIni( DEFAULT_SECTION, KEY_START_POINT, '0,0', sFile) + local ptStart = EgtGetVal( 'P='..sStartPoint..',0', 'P', 'p') + EgtSetInfo( nParamsGrp, KEY_START_POINT, ptStart) + + local sStrandOrder = EgtGetStringFromIni( DEFAULT_SECTION, KEY_PRINT_ORDER, 'in', sFile) + if sStrandOrder == 'out' then + EgtSetInfo( nParamsGrp, KEY_PRINT_ORDER, PRINT_ORDER.EXT_INT_INF) + else -- sStrandOrder == 'in' + EgtSetInfo( nParamsGrp, KEY_PRINT_ORDER, PRINT_ORDER.INT_EXT_INF) + end + + local sStrandDirection = EgtGetStringFromIni( DEFAULT_SECTION, KEY_PRINT_DIRECTION, 'CCW', sFile) + if sStrandDirection == 'CW' then + EgtSetInfo( nParamsGrp, KEY_PRINT_DIRECTION, PRINT_DIRECTION.CW) + else -- CCW + EgtSetInfo( nParamsGrp, KEY_PRINT_DIRECTION, PRINT_DIRECTION.CCW) + end + + local sLinkType = EgtGetStringFromIni( DEFAULT_SECTION, KEY_LINK_TYPE, 'straight', sFile) + if sLinkType == 'sPath' then + EgtSetInfo( nParamsGrp, KEY_LINK_TYPE, LINK_TYPE.BIARC) + else -- sStrandOrder == 'sPath' + EgtSetInfo( nParamsGrp, KEY_LINK_TYPE, LINK_TYPE.LINEAR) + end + + SetParamInfo( sFile, nParamsGrp, DEFAULT_SECTION, KEY_LINK_PARAM, '0') + SetParamInfo( sFile, nParamsGrp, DEFAULT_SECTION, KEY_FLOOR_NBR, '0') + SetParamInfo( sFile, nParamsGrp, DEFAULT_SECTION, KEY_SPEED, '0.0') + SetParamInfo( sFile, nParamsGrp, DEFAULT_SECTION, KEY_FEED, '0.0') + SetParamInfo( sFile, nParamsGrp, DEFAULT_SECTION, KEY_EXT_FEED, '0.0') + SetParamInfo( sFile, nParamsGrp, DEFAULT_SECTION, KEY_INT_FEED, '0.0') + SetParamInfo( sFile, nParamsGrp, DEFAULT_SECTION, KEY_INFILL_FEED, '0.0') + SetParamInfo( sFile, nParamsGrp, DEFAULT_SECTION, KEY_LEAD_IN_FEED, '0.0') + SetParamInfo( sFile, nParamsGrp, DEFAULT_SECTION, KEY_LEAD_OUT_FEED, '0.0') + SetParamInfo( sFile, nParamsGrp, DEFAULT_SECTION, KEY_SUPPORT_FEED, '0.0') + SetParamInfo( sFile, nParamsGrp, DEFAULT_SECTION, KEY_G0_FEED, '0.0') + SetParamInfo( sFile, nParamsGrp, DEFAULT_SECTION, KEY_MATERIAL, '') +end + +------------------------- MAIN -------------------------------------- +-- Recupero ultimo oggetto selezionato +local nStmId = EgtGetLastSelectedObj() +-- Verifico sia una superficie +if not nStmId or EgtGetType( nStmId) ~= GDB_TY.SRF_MESH then + EgtOutText( "L'oggetto selezionato non è una superficie") + EgtPause( 1000) + return +end +local nPartId = EgtGetParent( EgtGetParent( nStmId)) + +-- Scelta del file dei parametri +local sLastParamFile = EgtGetStringFromIni( '3dPrinting', 'ParamFile', 'C:\\ProgramData\\Egaltech\\EgtCam5\\3dPrinting\\Machinings\\aaa.ini', EgtGetIniFile()) +local sDir = EgtSplitPath( sLastParamFile) +local sParamFile = EgtFileDialog( true, sDir..'*.ini', '*.ini||') +if not sParamFile then + EgtOutBox('Error no file', '') + return +end +EgtWriteStringToIni( '3dPrinting', 'ParamFile', sParamFile, EgtGetIniFile()) + +-- Elimino eventuale precedente file dei risultati +local sCalcBaseDir = EgtGetStringFromIni( '3dPrinting', 'BaseDir', 'C:\\ProgramData\\Egaltech\\EgtCam5\\3dPrinting', EgtGetIniFile()) +local sCurrProjectPath = EgtGetCurrFilePath() +local _, sCurrProjectName = EgtSplitPath( sCurrProjectPath) +local sResultFile = sCalcBaseDir .. '\\Results\\' .. sCurrProjectName .. '.csv' +EgtEraseFile( sResultFile) + +-- Lettura dei parametri +LoadParams( sParamFile, nPartId) + +-- Calcolo delle fette +CSLICES.Exec( nPartId, nStmId) +EgtDraw() + +-- Calcolo dei percorsi sul centro strand in basso +CPATHS.Exec( nPartId) +EgtDraw() + +-- Calcolo dei percorsi di lavoro +CTP.Exec( nPartId) +EgtDraw() + +-- Calcolo dei solidi degli strand a partire dai percorsi di lavoro +CSOLIDS.Exec( nPartId) +EgtSetStatus( nStmId, GDB_ST.OFF) +EgtDraw() diff --git a/ViewManager.lua b/ViewManager.lua new file mode 100644 index 0000000..81ee06f --- /dev/null +++ b/ViewManager.lua @@ -0,0 +1,114 @@ +-- ViewManager.lua by Egaltech s.r.l. 2022/04/05 +-- Gestione visualizzazione per Stampa 3d + +-- Intestazioni +require( 'EgtBase') +_ENV = EgtProtectGlobal() +EgtEnableDebug( false) + +-- Imposto direttorio libreria specializzata per Stampa 3d +local sBaseDir = EgtGetSourceDir() +EgtAddToPackagePath( sBaseDir .. 'LuaLibs\\?.lua') + +-- Costanti generali +local AMD = require( 'AddManData') + +ViewValues = EgtDialogBox( 'Slicing visibility manager', { 'Visibility Mode', 'CB:*All,Till Selected,Only Selected'}, + { 'Shell type', 'CB:*All,Outer,Inner,Infill'}, + { 'Inner Number', '1'}) +if not ViewValues or #ViewValues < 2 then return end + + +local nVisibilityMode = 1 -- 1 = All, 2 = Till Selected, 3 = Only Selected +if ViewValues[1] == 'All' then + nVisibilityMode = 1 +elseif ViewValues[1] == 'Till Selected' then + nVisibilityMode = 2 +elseif ViewValues[1] == 'Only Selected' then + nVisibilityMode = 3 +end +local nShellType = 0 -- 1 = All, 2 = Outer, 3 = Inner, 4 = infill +if ViewValues[2] == 'All' then + nShellType = 1 +elseif ViewValues[2] == 'Outer' then + nShellType = 2 +elseif ViewValues[2] == 'Inner' then + nShellType = 3 +elseif ViewValues[2] == 'Infill' then + nShellType = 4 +end +local nInnerNumber = tonumber(ViewValues[3]) + +-- Recupero ultimo layer selezionato +-- verifico sia un pezzo valido +local sSelLayerName = '' +local bFound = false +local nSelLayerId = EgtGetLastSelectedObj() +while nSelLayerId do + local sSelLayerName = EgtGetName( nSelLayerId) + if sSelLayerName and sSelLayerName:sub(1, 5) == SLICE_LAYER then + bFound = true + break + end + nSelLayerId = EgtGetParent( nSelLayerId) +end +if not bFound then + if nVisibilityMode ~= 1 then + EgtOutBox( 'No selected element!', 'Warning', 'WARNING') + return + else + nSelLayerId = GDB_ID.NULL + sSelLayerName = '' + end +end + +-- ciclo sui pezzi +local nPartIndex = 1 +local nPartId = EgtGetFirstNameInGroup( GDB_ID.ROOT, PART .. nPartIndex) +while nPartId do + -- ciclo sui layer per dis/attivare il resto + local nLayerIndex = 1 + local nLayerId = EgtGetFirstNameInGroup( nPartId, SLICE_LAYER .. nLayerIndex) + while nLayerId do + if nVisibilityMode == 1 then -- All + EgtSetStatus( nLayerId, GDB_ST.ON) + elseif nVisibilityMode == 2 then -- Till Selected + EgtSetStatus( nLayerId, EgtIf( nLayerId <= nSelLayerId, GDB_ST.ON, GDB_ST.OFF)) + elseif nVisibilityMode == 3 then -- Only Selected + EgtSetStatus( nLayerId, EgtIf( nLayerId == nSelLayerId, GDB_ST.ON, GDB_ST.OFF)) + end + local nCrvId = EgtGetFirstGroupInGroup( nLayerId) + while nCrvId do + local nPathId = EgtGetFirstNameInGroup( nCrvId, PATH_GRP) + local nShellId = EgtGetFirstInGroup( nPathId) + while nShellId do + local nType = EgtGetInfo( nShellId, KEY_TYPE, 'i') + EgtSetStatus( nShellId, EgtIf( nShellType == 1 or ( nShellType == 2 and nType == 0) or (nShellType == 3 and nType == nInnerNumber), GDB_ST.ON, GDB_ST.OFF)) + nShellId = EgtGetNext( nShellId) + end + local nSolidId = EgtGetFirstNameInGroup( nCrvId, SOLID_GRP) + local nSurfId = EgtGetFirstInGroup( nSolidId) + while nSurfId do + local nType = EgtGetInfo( nSurfId, KEY_TYPE, 'i') + EgtSetStatus( nSurfId, EgtIf( nShellType == 1 or ( nShellType == 2 and nType == 0) or (nShellType == 3 and nType == nInnerNumber), GDB_ST.ON, GDB_ST.OFF)) + nSurfId = EgtGetNext( nSurfId) + end + local nToolPathId = EgtGetFirstNameInGroup( nCrvId, TOOLPATH_GRP) + nShellId = EgtGetFirstInGroup( nToolPathId) + while nShellId do + local nType = EgtGetInfo( nShellId, KEY_TYPE, 'i') + EgtSetStatus( nShellId, EgtIf( nType and ( nShellType == 1 or ( nShellType == 2 and nType == 0) or (nShellType == 3 and nType == nInnerNumber)), GDB_ST.ON, GDB_ST.OFF)) + nShellId = EgtGetNext( nShellId) + end + nCrvId = EgtGetNext( nCrvId) + end + nLayerIndex = nLayerIndex + 1 + nLayerId = EgtGetFirstNameInGroup( nPartId, SLICE_LAYER .. nLayerIndex) + end + nPartIndex = nPartIndex + 1 + nPartId = EgtGetFirstNameInGroup( GDB_ID.ROOT, PART .. nPartIndex) +end + +EgtDraw() + +------------------------- MAIN --------------------------------------