From 783260a14bb663696e6bb26dcc530bcf8f0e4d92 Mon Sep 17 00:00:00 2001 From: Azalea Colburn Date: Fri, 12 Jul 2024 09:32:05 -0700 Subject: [PATCH 01/10] add execute command --- exporter/SynthesisFusionAddin/Synthesis.py | 11 +++++++++ .../src/UI/ShowAPSAuthCommand.py | 2 -- .../src/UI/ShowWebsiteCommand.py | 24 +++++++++++++++++++ 3 files changed, 35 insertions(+), 2 deletions(-) create mode 100644 exporter/SynthesisFusionAddin/src/UI/ShowWebsiteCommand.py diff --git a/exporter/SynthesisFusionAddin/Synthesis.py b/exporter/SynthesisFusionAddin/Synthesis.py index 37403d9f82..c3461d575e 100644 --- a/exporter/SynthesisFusionAddin/Synthesis.py +++ b/exporter/SynthesisFusionAddin/Synthesis.py @@ -17,6 +17,7 @@ Helper, MarkingMenu, ShowAPSAuthCommand, + ShowWebsiteCommand ) from .src.UI.Toolbar import Toolbar @@ -141,3 +142,13 @@ def register_ui() -> None: ) gm.elements.append(apsButton) + + websiteButton = HUI.HButton( + "Synthesis Website", + work_panel, + Helper.check_solid_open, + ShowWebsiteCommand.ShowWebsiteCommandCreatedHandler, + description=f"WEBSITE TEST", + command=True + ) + gm.elements.append(websiteButton) diff --git a/exporter/SynthesisFusionAddin/src/UI/ShowAPSAuthCommand.py b/exporter/SynthesisFusionAddin/src/UI/ShowAPSAuthCommand.py index bacc6e094b..89f76190dd 100644 --- a/exporter/SynthesisFusionAddin/src/UI/ShowAPSAuthCommand.py +++ b/exporter/SynthesisFusionAddin/src/UI/ShowAPSAuthCommand.py @@ -1,11 +1,9 @@ import json import logging -import os import time import traceback import urllib.parse import urllib.request -import webbrowser import adsk.core diff --git a/exporter/SynthesisFusionAddin/src/UI/ShowWebsiteCommand.py b/exporter/SynthesisFusionAddin/src/UI/ShowWebsiteCommand.py new file mode 100644 index 0000000000..1a225a0845 --- /dev/null +++ b/exporter/SynthesisFusionAddin/src/UI/ShowWebsiteCommand.py @@ -0,0 +1,24 @@ +import webbrowser +import adsk.core +class ShowWebsiteCommandExecuteHandler(adsk.core.CommandEventHandler): + def __init__(self) -> None: + super().__init__() + def notify(self, args): + try: + url = "https://synthesis.autodesk.com/" + res = webbrowser.open(url, new=2) + if not res: + gm.ui.messageBox("Failed\n{}".format(traceback.format_exc())) + except: + gm.ui.messageBox("Failed\n{}".format(traceback.format_exc())) +class ShowWebsiteCommandCreatedHandler(adsk.core.CommandCreatedEventHandler): + def __init__(self, configure) -> None: + super().__init__() + def notify(self, args): + try: + command = args.command + onExecute = ShowWebsiteCommandExecuteHandler() + command.execute.add(onExecute) + gm.handlers.append(onExecute) + except: + gm.ui.messageBox("Failed\n{}".format(traceback.format_exc())) From 6855427b23bd34055d15f48beb049767c87877d4 Mon Sep 17 00:00:00 2001 From: Azalea Colburn Date: Wed, 17 Jul 2024 10:04:02 -0700 Subject: [PATCH 02/10] icons shows up now --- exporter/SynthesisFusionAddin/Synthesis.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/exporter/SynthesisFusionAddin/Synthesis.py b/exporter/SynthesisFusionAddin/Synthesis.py index c3461d575e..e0060d2bca 100644 --- a/exporter/SynthesisFusionAddin/Synthesis.py +++ b/exporter/SynthesisFusionAddin/Synthesis.py @@ -143,12 +143,13 @@ def register_ui() -> None: gm.elements.append(apsButton) + websiteButton = HUI.HButton( "Synthesis Website", work_panel, Helper.check_solid_open, ShowWebsiteCommand.ShowWebsiteCommandCreatedHandler, - description=f"WEBSITE TEST", + description=f"Website Test", command=True ) gm.elements.append(websiteButton) From 84ab146bb9db23b25f57aa1fa4b2b6554e3946e8 Mon Sep 17 00:00:00 2001 From: Azalea Colburn Date: Wed, 17 Jul 2024 10:05:05 -0700 Subject: [PATCH 03/10] added needed resources --- .../FrictionOverride_icon/32x32-normal.png | Bin 0 -> 586 bytes .../SynthesisWebsite/16x16-disabled.png | Bin 0 -> 1469 bytes .../Resources/SynthesisWebsite/16x16-normal.png | Bin 0 -> 1535 bytes .../SynthesisWebsite/32x32-disabled.png | Bin 0 -> 2002 bytes .../Resources/SynthesisWebsite/32x32-normal.png | Bin 0 -> 2176 bytes .../Resources/SynthesisWebsite/64x64-normal.png | Bin 0 -> 3335 bytes 6 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 exporter/SynthesisFusionAddin/src/Resources/FrictionOverride_icon/32x32-normal.png create mode 100644 exporter/SynthesisFusionAddin/src/Resources/SynthesisWebsite/16x16-disabled.png create mode 100644 exporter/SynthesisFusionAddin/src/Resources/SynthesisWebsite/16x16-normal.png create mode 100644 exporter/SynthesisFusionAddin/src/Resources/SynthesisWebsite/32x32-disabled.png create mode 100644 exporter/SynthesisFusionAddin/src/Resources/SynthesisWebsite/32x32-normal.png create mode 100644 exporter/SynthesisFusionAddin/src/Resources/SynthesisWebsite/64x64-normal.png diff --git a/exporter/SynthesisFusionAddin/src/Resources/FrictionOverride_icon/32x32-normal.png b/exporter/SynthesisFusionAddin/src/Resources/FrictionOverride_icon/32x32-normal.png new file mode 100644 index 0000000000000000000000000000000000000000..34f6b927a4769ba9eb525c709ed7a8aa7cb0ab95 GIT binary patch literal 586 zcmV-Q0=4~#P)i}@hQI;js>6EjxGeQUec<))S*R*ZR<>e*bd!C-2$n%`5tE*uGNs@4W zeva0f^?Hqn&@>HNYpk`TX-ZKP7-RapqA0M|(liab-HzF8#&|p)CZLo;DTVi*x3@P$ zgu1Rt(-eTZu6cQR!5D+JmMqKATBDRgYt48(##+l}vl%Av!DKSw=H`YF0?*IS{VC*m z&h_;*Ns@4KazarQeIID8`(7x^@@oRlIX0UOB0^PFD5Ve)x~{`}k5cbrCdNpN5qNLR z7$aJ1(li||AR=tHTkh}g`bgcmaL%z>t=Mk2`~QOZd@e&IKg*yi_}>D*4k@tr3IOKw`A^{YAw`ZHIr4q^ Y1IMisNbTmNO8@`>07*qoM6N<$f)uL|FaQ7m literal 0 HcmV?d00001 diff --git a/exporter/SynthesisFusionAddin/src/Resources/SynthesisWebsite/16x16-disabled.png b/exporter/SynthesisFusionAddin/src/Resources/SynthesisWebsite/16x16-disabled.png new file mode 100644 index 0000000000000000000000000000000000000000..f4ba1b8f8393d4c4dbf6f24a1034a85484b017c6 GIT binary patch literal 1469 zcmaJ>eNYr-7(XI1V89QQ2vN2b$Pf1R^KL)lWbSScxa5#dDr^$nyWNF7xZ9iCMNXnA z%@K()(itJfGG`i)!NG>eaReM8KWNHqCUeY!nub5huxuo2m>lh0;LJZ9clO~e@(J+Fp1vo5El%?mJ50wfWnBk{$E)ogyUEnw zmV8G@0O!PT$!5)DN51@rKgnht3k6Msy@ja4TgcX$y87n4GaES zNr!w=wGy(yH;2x^kRsaPmn|O56Lv~9N=aix+SFK9;cu+^gKKm>%%NyQLxZ`2G^>$n6lYl$#R!xj z5TJo*J3_h;MMB!DIgoi6Uef##C9ErI2r^&=pIWcmU=Z|NHo>sRb00mV%@+-n4~+_8 z6gOjNFleMWtF7r?>Hk}>6dA*Kn61OYVl2s!1Y@`3 zxQl05JMQEyEQ!%p7ful|TX#s)g^*v0`Bi}5d0XOlEnKTq=l^bNg-U%C_w9#uL(0`YQ8(^B%pt zBX4)cft*vei|;DqpX}r(4_{bz=nmg5?RGqqvm}v+7e`N5?VpjUOj~+V!okElZYHaU z$~-R**s%=W+!5dB6?a|<96b8r@JDZsO^(hqUGVj9vpLTEwBYsL&#S^qF;Cjm?aXU+ z>Ak(5-Tdb*>nkG4B)wnuER~s3v3A)-nLOvis}8Ox-We@;r!?>E!WC`BceC;WV=o-J zIwcHEz@4SHZvF7P_3wXA8)(~ZetdOmb;p-IFCDvavgM+hl`!t;N!zM4Y#p31Kb_j_ zn|b5C!tFy_S`rJc1S}GkG2EKf0BPA%cbnG#V*7KZX*}&OxWDzsvJ&_6UEb_HLetxp zRP9x0(TGUIomkg>dCfQ1si#g%S1(-Z`Z;%H>H_MJC%GG$`8;`l0 guh#vM?kKsQJh`PS^W>?4Hsc@ac9rqR9ou&O2Pq5pmjD0& literal 0 HcmV?d00001 diff --git a/exporter/SynthesisFusionAddin/src/Resources/SynthesisWebsite/16x16-normal.png b/exporter/SynthesisFusionAddin/src/Resources/SynthesisWebsite/16x16-normal.png new file mode 100644 index 0000000000000000000000000000000000000000..34948454a985666777913757ecc4a1fa6102867e GIT binary patch literal 1535 zcmaJ>eNYr-7+;VJgU}<tz!T z%C$<=iCjBy2!R#JiB#wLaG&Ou>y(maU9M>MSBlN`A}1jQ`59@B7!MF4vMIo^NH}Wn zF()zx%!Bv17(?JO6|>%nxZ)n+fUgX8tGWy`HUbrK9ETasCQAYtq(XwY5GHYwzzA?N zD8cX~#SvO+@qg?x9DGiK2n>VKG6&2pf(? zBJmW*v<`}#45jkpl zJx&CCu}O-=<2Z{G1ViHtiQ8F%U>Tyw#j+%c({7rhsRYJ@Yzy-^oTFHZWL++TSnT0A z7vc8gaTLzj7ZWs@u=Pd_Q;3Rk!mk4SPS}zUwdLKqESRcZsjA@w8OrKZQ#I;T4R*Uh z=LrU$?-N8N8W%1|bPDupJavz(D-E(#q^l8ltk}HrfM6(+39$l2qIQW2p)|`%sKD59 zloDA9ltt!3d3nf$y>wp@$9W4RAR#Rg7mwRO~2f`{LDbgO>xG+&?o;+I(^*Qu|2enM%P)LrE9gUIpNVcJCa*pD7hsa%RD=JWb1*tG=0PCzx8;%-*xP-wjaNC745&h=I(&}?a93r zndY6HHTHdKO8?)F$yI&Vhnp55wR0P;_Ixe5Ts=>m8k}o)oQq9wS=8fS5$Rsp)Vem( z-;f~}bnLyA>7R1v;+58o*A;6<-^e?kcUJfQa<(mX0C{R!=I)9=0>+vmM{e-$NY>*+ wcwgE6{1Z8?ySKetQZQ>q?u})0*YkZ)-=$sRbA!Vz@xQQlvEQ?=@RfD{0oLsno&W#< literal 0 HcmV?d00001 diff --git a/exporter/SynthesisFusionAddin/src/Resources/SynthesisWebsite/32x32-disabled.png b/exporter/SynthesisFusionAddin/src/Resources/SynthesisWebsite/32x32-disabled.png new file mode 100644 index 0000000000000000000000000000000000000000..770208ec0e4889c412d946e67f8dcd6bc23b24ec GIT binary patch literal 2002 zcmaJ?dsGu=77tR;66t{z&;=^fAQmV|W+v}hB8EgDDbYwH(g+8J$wUGq6DI=+gk_a= zU7$z>!=c+0 zpjaMG0onLYqgl$D?zzMQjCv_+yFd-9Epj}^m{d&S?-Xy=V#RrwM9+%b;Oi4>M`#2S zPN9I^ly9~ob}4Hf7@^2oj5+1esV2!ysSIm+*N@ z7%#Jp7f3(}Pt1eGG8qJIQb;5+NUjh_c%VqQ3F5;`wo0>=Ld_Vy{LCu^oEo-Isc%aO$;zC=0+1@Ov zFo^Xh{q50D4aW^TZ`A2i&+{s7tzp*q<(HRVSF8xq4f_oPWyRVX-IGtwZ%v;2?arZEd{nS-=mD;p_Lt zddf8A<>k9?h1mH?%m+j)YN~?&PFCa^S6E(9v*I6_vX5F-?nY=(49Jc+Mk~7n7G*3 zZzd+Z`~Ldw>5-8XXMO$PosRfJiG>^0ExJ87Z)(@AUw@{gsHoz~6`8rErKPK9eE%D9 zabYzzH8IQOoy*R>%{>QXtlm{xTHV?jalE4g%gbXH_a5s1eUom_!-siM9!jM$CpS0V zZ01aV5Omn(8ec!9`pl;)*Q>g^+G4jyI(A#Io40Q_cXkH)`uZkq*-}q9n{*!V`L?#G zPlt!;>LphfR~-y`Gvb=u*{t&@i}_taK_G@QA7N9z0f;@7P7zQd$JVIHrh zzP^9|_oMeMr@lV8+WttcNPR6?r8%*&uuyocy}eu7OZddj%*>pb?2eB3OKO(Gu|u_S z+qS^u^{Xl?D>a#!)At1369WUU4qnlmxct>uYx9L6(+5g=8yguoj+Y2tX(+pu`_!v7 zYp;{JLbZ{4ops2XLLv=fsq`N}K%}?kZ+_jo@yGX$9|&AgH|ewY+kMY#pZi?Q^>n#h z>1lgC&u}Z7KW2spY#oZI)JpNr3*WT)BY();QS5MB^47%)g+T&=U~0x$qEe~+R;{{v zqO0qJhw|X?3r8ZACxcfu+{r&$`_Jte8KZ>1R;37i9{F`|BTa-|yLN>>8yOi9|7xV! zxjOo-w@)8UUlS9eV9YxtbJaw_NFYag>2KQaF3I-KwN S%~7rU$Ew`4S#dHxtL%T(C<5XD literal 0 HcmV?d00001 diff --git a/exporter/SynthesisFusionAddin/src/Resources/SynthesisWebsite/32x32-normal.png b/exporter/SynthesisFusionAddin/src/Resources/SynthesisWebsite/32x32-normal.png new file mode 100644 index 0000000000000000000000000000000000000000..77458fce7d136cceab5bce620c5501e226f82445 GIT binary patch literal 2176 zcmaJ@dsGu=77w^a2#O*PmHHSG-3pRqW|EKxL=6cEL4q`*Qbl2sOdvuYCL;t8X|+&_ zqJS%u9_kCJwX(PZt!S%gK|w);V^=I%c~b=x1X@^L-3fy2AD+&cZ@&5N+{f?U`@84N zXTd>|1teDzfk0Rw^%u$U9k47LBK|ZbBn;!5l}Rq~B^1{$e}NzV5h;)f2!zYW>?V-8 z_}SLr|DlOMu&=Z%t7`q%Dgt57X-!Bd7AgzmDfL@YKqrkh?%N0QQkP2aU()aN~6YrY4ke4;ucZp_hEc84*E?tT7yjX*1OI$ zQ#8DMbTeY0Lo|@C)ml=V);3{s^iM4B)Ha308&J9&HR<;ml_;)GnKj1C`1gS{2vMJz4@WPABROnBB-sxx7TPKnOO)!=bwY~jDPh%(DcBq)1T)#F8YBbsX=dU;=@u6Kg;j4DJ1xa2Ynd4O z+mW%H-i{rr!)MKi4^_r;>Kc5WHBylvBvkS;H!*PM*5%a|BhS{G%Tfl{me_}Q#eAf5 ze5_i`=tvXi4}8iHGa|9%s2}V0SEbc5H;FRJtNc3ld#1`97kBJ@zpgDUf^6sOBF22Y zBB-TBH+P(FXl}Yb^{OkzVHwr$arlAk@Uij9dQJVv$szAwpVqd8bDHCvD4jfJM~nw@ zp-Z*H>GhGWTZR>fZ*i#fL5r>R0qh?0NpIh1L~*s3M28~X4ZhZ8(q4yLIVq#wck_7#HR~=U z%#{7k-Tt6BE6UF}|1 zV#<3h;57q8Rd{4gnCV-aC3e-(5jP5K$BI_mYt4Qxc}|~KWBJxb~jwp{=hEJ^U5=De6v2$It&^w*)ZQXF87?zqxtwxbp^A$Zk>DvbqBI zh1X7WW!swT+Xq*TgIsLsmhUL50qI={MQ!DFDkFYl{$9szdQFPkION*ke<=Br%f%kI zzb+2FR8!@7)BBNi|8uEJR@zVU&(nJiLrL~U9+OtK%esoty;YuskY6b0J)lREo)eC{ zJl(e+|AJVND_Snx(Mir1_F3C}7Tef)GjZuuJS9fvvSa*uNakdbvwwY({hnR4!(_+O zkE-fOOLfhKpNGA;m1osFGB0Y0lRRmD>F(vsF`sV9Kh;))Q*7sz+dQ+rnjj4prMb}$ z+dwt>7GR992R^{{fjQ^&=6T}U-74Kw>dEG_owqaRt#5L_eN0?utrj0e+Mhn@l(ue7 z;9;>8Rz+$~_kqG)q{Ozq{p~$xoHEupw~hAG+ZDYof%Z2RwwTvVyb3aZ`F?B9g^ypJ zJ0Utyn;?#q<~AmOOrtcQ=SHz*C{;tuIsV7ouu>wC_-TZ9)19+jYc^I_zPR!82zZs) zZ8H!!eo%IQMbC|)*uu(yp$FvQP1(bDs!uV0Sfm*k{bY4fOWBH?eIpweF>9!g)630s z@>WI<^&h-dPP*dsFF~*-^MH_cM8hsgrX2~M9R6}3an~vI*|tC8v)05EHgyL)@;b&J zPxjldfJx~dnK_qT9<>K7&1PhsD0TQ>%9H0Ddu7v5cqLyad6sHioS9+gkRvbn@2bu% zgL|yI@BfzMxx_&bOyQ!e=AAta#tFc+!aTPS-Q4#3zc;s6(?`}Ni6vtnZ2NG*?$D?2 z4W5m&l5815wA}i#hQGJG-hVWXWkKj?1aSNW=f^yHN8{+4rjaOqmuw7xQ+D6G+!1*E$TV=Qu_%r;CZ z9DVV9lf(ScMI>VD#86STW2Ia9t|g66lB^jg_s;+A3UW_&sm~5*x|x5egTK(^9l!Ea qiQ#r$+>(aZK+DGSkp;b01MEuDv9?<8gF7t00aCvpQL%5t!T$q3?qw4I literal 0 HcmV?d00001 diff --git a/exporter/SynthesisFusionAddin/src/Resources/SynthesisWebsite/64x64-normal.png b/exporter/SynthesisFusionAddin/src/Resources/SynthesisWebsite/64x64-normal.png new file mode 100644 index 0000000000000000000000000000000000000000..3076b744ca20f1537e6a0475c423a89d5e862b07 GIT binary patch literal 3335 zcmaJ^c{o)28y{P?i^^7_rXfo;`!EZ#jeSWIk+m^1n3#R+l_aF-P9;jELYHW>lr`D1 zlr6%9Y+a%3U9@0+qvihYANRTEIq&(N_dTC?f8Re&qO+5=oQ#?b005A)wZRjFr|CLL zZ4f^5sH{QZA;KY8n*$!SsZRq5O>of7uyN9uSAn;J?XTd^55 z;P+zVsQ(fS5`p%|5RnM50U7BJMqw~yFcED410zWoval=^tiQfK=%+sUA4U8zw?c_9 zA?B~Ra4-WH(I18I2gChQ7%-NM@&jW~7$O+%hsL1b2o##)4+8_{xMZQ zCic5jII`;-1O0nt*15mejzSmi8e6zj$?D);0D#n-E#Ax}+-Evn&e^3`xlzCfJ6x5j zoD6)Klj*m|;A*bv-c0S$653IRS1uY|4!CZ$;6{F+VIMcIn|zV)f3K&H)#sFyUVokz z@N|w%}wW2R;X9_DACF9z3|H()B)lc>hpMW$o^LgfJ}nkfu??+ z&q~7$&8iER6j1>wG9z*bQeUO<77@M5vAAmhH@o**U55ogkXMM!M%eX=D5DtjG->7} zf3s_Az^Akz{SUI-9@(bugLO~4U?QXMzBcGxuJwHV+AfrFN_yC@buh7Ai+}A1=jmF$ zD=wjILFJS9$q#@lV|ilYyJ|DLZlB*O?@9(;eMOiQ&1p3iz`<4?B*eob6Qc8jIE%kGF{38pn?%ALnVzqNVzu@I6W7XyZZwtVP(Q3(_gvVtS)}+bwDamR1djLApl@$) zToj8v;C=C2URD;17Oj?~>=~{Q=9d781)gTvZ#M^-k_BFa?8fjAi;`;!^Eb?-I~La%u)Y}_oe(i-*ZP`hUahL{(5v*hi8M)E?c(P=zj^6SjGz_-gQ z@!U_XZ%bL+l-?dfQNl7WfhRTm=qm)CIjRGq4m6%ogWWjo%wlYFvQ`XkXn$%@@Hq85 z=t$3w5ikSvbqqLPAu#Jp$)B>@^d?%=8$9q_N_*#~YL~}iOYip#EF|wnNFVQ1)zo_^ z75j(l&b4OnRHx46mKrTB(b9UA*C}m(d|Y*$kxojPek|r|)yc23IsX2)v9mjPz0uu# z4f9Ll(wvj= z>%OStdMYg8>~airq`-liNboV=ZE7fQudntn_(=Cn7m1!5(aMMFq|2$Sx$RYn8U&k? zj@YtY3d@!!&tvwY`C!Ik!F;X}Mm%0NUytzDO0Hze#;lNbw#D|D3V_B1P}ayoWVudL zeBf$))OtDRQjNsD0h98Oh!xgDaG?M*Shp?Vu^RZR#Q@vdLx*>1*!m>Uxd7P^71ctE zdm)<^I0jbm0x_B_IwT&c?Hd7y6;rwA?k#-kuyqDjwkr-W8;NBfUwG$8RRNN7a%EQ1 zJ;Qh^c*VONiDz%t$8F??_}u@ZGHOlF(ru=GoQOH>TQ6+%ik|6C&uEq$dLVJaP%W|S z8$7Uqmfe2u`K_xPvYmD(7=(z-j+}pdJL%z$ChIu~po6R7VTlO^>izv5Nax(lUHPq( zF@Z?a=nsvrFD}EKY{YpdxYKVeT~=0Z+uOGImp7%h1-Gh}S?@E~0wiC{t1MseB`l)1 zgG<)NOkRdn`DOpeU5gm*%PtbZk8b37;g-2P{;L?l4+;5&~+SigMSoOWoy*eJ}1u#>x z?A`FR1_9C=U-dTe49V=Dhpc{fJETmS%C@wz-4WMv0XaWVYvMQm@Ei~~b;f>+U95ZJ zq(smcoof7rW3S*W=Go9Bb!6I`FYOQNPfxyd-w}fU?bDcJMBLu1;uFi$`jOsCOK#Q< zgW#_GtJSBe&raTQ9_H7Wj4bYIcCQHD($c!P1%r~@I@H`4^Y&SsO>9fku?^DAnlK<0 zgRpYI=Re+RDe!53HX&d3#e`DZenTp+RlwO{hadztUHaq-%W#eJ*7+trUlE+he+cl2jAK zxSlm_WHkmk5?fG=dPJ98UXhotP|j*>vp6&;dZpR7a+Vf)PqR^hmO0D5=xo1nYxf&f zu$W@8)aP))hLwm_rR)0&6b}_`Do=56h*}HT>l>!l=dSUwE3h<1(b7{-&uXWUxkYTW zqzdO6M&oWCCeD7$I&ki|jW~7YrM0s-&m4QI&87Qs7r!cE-%F8Mnn(3T-{5Ctql`uM zS?TM0R(U1aOV*WRiL%y9Rn1FSMU^LIWRR|CeZ98d+a8a5g8Z1xUfNTk$hH%O=i2C+ zh7V+91EQq$iu)(|OMkvdd!Axwcbo9`%RO~*O91J(J|u$?_5Ap&7qM4L!VP7j51RKb zU@+?U1tvY%zARIpQz>Fz{3_~pJNq>=j$!)6f!}!sT9Vzp?Zke=qB+OK8~P`x9w_~u zN3D}wXy2WefBcz-zf{Wfhd%J$*L+Mn>t>oR&bHdlZ_;Z-%ll3Pv&dfe^3hZUb@@FW zVC{v^c?Es#vExd-6B)%Jf0ca8o}G+*s!~W{9Vov2JUgcbePL`?(q8N@eZifzjI~hT zUdf>g)uK|Rt)2>C5s6zkt4P*R@7;(%Dc$M@?+39?Ix4)4%H$V{90jFn0f4$7m)v5I S-@N`eVr%Jye_(#()c*iIn!beq literal 0 HcmV?d00001 From 314547fbbe1bd8280f6e519edffda71678ee4dbe Mon Sep 17 00:00:00 2001 From: Azalea Colburn Date: Wed, 17 Jul 2024 13:53:43 -0700 Subject: [PATCH 04/10] open website with button on toolbar --- exporter/SynthesisFusionAddin/src/UI/ShowWebsiteCommand.py | 1 + 1 file changed, 1 insertion(+) diff --git a/exporter/SynthesisFusionAddin/src/UI/ShowWebsiteCommand.py b/exporter/SynthesisFusionAddin/src/UI/ShowWebsiteCommand.py index 1a225a0845..77ebe018ab 100644 --- a/exporter/SynthesisFusionAddin/src/UI/ShowWebsiteCommand.py +++ b/exporter/SynthesisFusionAddin/src/UI/ShowWebsiteCommand.py @@ -1,5 +1,6 @@ import webbrowser import adsk.core +from ..general_imports import * class ShowWebsiteCommandExecuteHandler(adsk.core.CommandEventHandler): def __init__(self) -> None: super().__init__() From f4cfaaa591ab9b7bc1ba997f46b583cf2f4d17c9 Mon Sep 17 00:00:00 2001 From: Azalea Colburn Date: Wed, 17 Jul 2024 15:28:00 -0700 Subject: [PATCH 05/10] change url to learn page --- exporter/SynthesisFusionAddin/src/UI/ShowWebsiteCommand.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exporter/SynthesisFusionAddin/src/UI/ShowWebsiteCommand.py b/exporter/SynthesisFusionAddin/src/UI/ShowWebsiteCommand.py index 77ebe018ab..14cb233c0c 100644 --- a/exporter/SynthesisFusionAddin/src/UI/ShowWebsiteCommand.py +++ b/exporter/SynthesisFusionAddin/src/UI/ShowWebsiteCommand.py @@ -6,7 +6,7 @@ def __init__(self) -> None: super().__init__() def notify(self, args): try: - url = "https://synthesis.autodesk.com/" + url = "https://synthesis.autodesk.com/tutorials.html" res = webbrowser.open(url, new=2) if not res: gm.ui.messageBox("Failed\n{}".format(traceback.format_exc())) From 1bc8d21aaa2832365a3d193dbaffef2c5dc20a8a Mon Sep 17 00:00:00 2001 From: Azalea Colburn <62953415+azaleacolburn@users.noreply.github.com> Date: Fri, 26 Jul 2024 16:03:20 -0700 Subject: [PATCH 06/10] Update exporter/SynthesisFusionAddin/Synthesis.py Co-authored-by: Brandon Pacewic --- exporter/SynthesisFusionAddin/Synthesis.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exporter/SynthesisFusionAddin/Synthesis.py b/exporter/SynthesisFusionAddin/Synthesis.py index 59dc8459bf..04893eef74 100644 --- a/exporter/SynthesisFusionAddin/Synthesis.py +++ b/exporter/SynthesisFusionAddin/Synthesis.py @@ -135,7 +135,7 @@ def register_ui() -> None: websiteButton = HUI.HButton( "Synthesis Website", work_panel, - Helper.check_solid_open, + lambda *_: True, ShowWebsiteCommand.ShowWebsiteCommandCreatedHandler, description=f"Website Test", command=True From 4fdacf5c10662928275ebc74e47d637883d8f073 Mon Sep 17 00:00:00 2001 From: Azalea Colburn Date: Fri, 26 Jul 2024 16:04:49 -0700 Subject: [PATCH 07/10] ran formatter --- exporter/SynthesisFusionAddin/Synthesis.py | 11 +- exporter/SynthesisFusionAddin/proto/deps.py | 12 +- exporter/SynthesisFusionAddin/src/APS/APS.py | 152 ++++++-- exporter/SynthesisFusionAddin/src/Logging.py | 18 +- .../src/Parser/ExporterOptions.py | 22 +- .../src/Parser/SynthesisParser/Components.py | 28 +- .../Parser/SynthesisParser/JointHierarchy.py | 49 ++- .../src/Parser/SynthesisParser/Joints.py | 73 +++- .../src/Parser/SynthesisParser/Materials.py | 50 ++- .../src/Parser/SynthesisParser/PDMessage.py | 15 +- .../src/Parser/SynthesisParser/Parser.py | 41 +- .../SynthesisParser/PhysicalProperties.py | 4 +- .../src/Parser/SynthesisParser/Utilities.py | 32 +- exporter/SynthesisFusionAddin/src/Types.py | 10 +- .../src/UI/ConfigCommand.py | 223 ++++++++--- .../src/UI/CustomGraphics.py | 12 +- .../SynthesisFusionAddin/src/UI/Events.py | 8 +- .../src/UI/FileDialogConfig.py | 4 +- exporter/SynthesisFusionAddin/src/UI/HUI.py | 24 +- .../SynthesisFusionAddin/src/UI/Helper.py | 12 +- .../SynthesisFusionAddin/src/UI/IconPaths.py | 25 +- .../src/UI/JointConfigTab.py | 365 ++++++++++++++---- .../src/UI/MarkingMenu.py | 12 +- .../src/UI/ShowAPSAuthCommand.py | 25 +- .../src/UI/ShowWebsiteCommand.py | 6 + .../SynthesisFusionAddin/src/UI/Toolbar.py | 4 +- .../src/general_imports.py | 4 +- exporter/SynthesisFusionAddin/tools/format.py | 11 +- 28 files changed, 943 insertions(+), 309 deletions(-) diff --git a/exporter/SynthesisFusionAddin/Synthesis.py b/exporter/SynthesisFusionAddin/Synthesis.py index 04893eef74..3c2b21aafa 100644 --- a/exporter/SynthesisFusionAddin/Synthesis.py +++ b/exporter/SynthesisFusionAddin/Synthesis.py @@ -15,7 +15,7 @@ Helper, MarkingMenu, ShowAPSAuthCommand, - ShowWebsiteCommand + ShowWebsiteCommand, ) from .src.UI.Toolbar import Toolbar @@ -78,7 +78,9 @@ def stop(_): path = os.path.abspath(os.path.dirname(__file__)) - path_proto_files = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "proto", "proto_out")) + path_proto_files = os.path.abspath( + os.path.join(os.path.dirname(__file__), "..", "proto", "proto_out") + ) if path in sys.path: sys.path.remove(path) @@ -131,13 +133,12 @@ def register_ui() -> None: gm.elements.append(apsButton) - websiteButton = HUI.HButton( - "Synthesis Website", + "Synthesis Website", work_panel, lambda *_: True, ShowWebsiteCommand.ShowWebsiteCommandCreatedHandler, description=f"Website Test", - command=True + command=True, ) gm.elements.append(websiteButton) diff --git a/exporter/SynthesisFusionAddin/proto/deps.py b/exporter/SynthesisFusionAddin/proto/deps.py index 10ec7757b3..a046eb8069 100644 --- a/exporter/SynthesisFusionAddin/proto/deps.py +++ b/exporter/SynthesisFusionAddin/proto/deps.py @@ -34,7 +34,9 @@ def getPythonFolder() -> str: elif system == "Darwin": pythonFolder = f"{Path(osPath).parents[2]}/bin" else: - raise ImportError("Unsupported platform! This add-in only supports windows and macos") + raise ImportError( + "Unsupported platform! This add-in only supports windows and macos" + ) logger.debug(f"Python Folder -> {pythonFolder}") return pythonFolder @@ -127,7 +129,9 @@ def installCross(pipDeps: list) -> bool: ] ) if installResult != 0: - logger.warn(f'Dep installation "{depName}" exited with code "{installResult}"') + logger.warn( + f'Dep installation "{depName}" exited with code "{installResult}"' + ) if system == "Darwin": pipAntiDeps = ["dataclasses", "typing"] @@ -148,7 +152,9 @@ def installCross(pipDeps: list) -> bool: ] ) if uninstallResult != 0: - logger.warn(f'AntiDep uninstallation "{depName}" exited with code "{uninstallResult}"') + logger.warn( + f'AntiDep uninstallation "{depName}" exited with code "{uninstallResult}"' + ) progressBar.hide() diff --git a/exporter/SynthesisFusionAddin/src/APS/APS.py b/exporter/SynthesisFusionAddin/src/APS/APS.py index a65728ec23..5a9389cebc 100644 --- a/exporter/SynthesisFusionAddin/src/APS/APS.py +++ b/exporter/SynthesisFusionAddin/src/APS/APS.py @@ -125,7 +125,9 @@ def refreshAuthToken(): "scope": "data:create data:write data:search data:read", } ).encode("utf-8") - req = urllib.request.Request("https://developer.api.autodesk.com/authentication/v2/token", data=body) + req = urllib.request.Request( + "https://developer.api.autodesk.com/authentication/v2/token", data=body + ) req.method = "POST" req.add_header(key="Content-Type", val="application/x-www-form-urlencoded") try: @@ -186,7 +188,9 @@ def getUserInfo() -> APSUserInfo | None: return loadUserInfo() -def create_folder(auth: str, project_id: str, parent_folder_id: str, folder_display_name: str) -> str | None: +def create_folder( + auth: str, project_id: str, parent_folder_id: str, folder_display_name: str +) -> str | None: """ creates a folder on an APS project @@ -199,7 +203,10 @@ def create_folder(auth: str, project_id: str, parent_folder_id: str, folder_disp success - the href of the new folder ; might be changed to the id in the future failure - none if the API request fails ; the failure text will be printed """ - headers = {"Authorization": f"Bearer {auth}", "Content-Type": "application/vnd.api+json"} + headers = { + "Authorization": f"Bearer {auth}", + "Content-Type": "application/vnd.api+json", + } data: dict[str, Any] = { "jsonapi": {"version": "1.0"}, "data": { @@ -208,12 +215,16 @@ def create_folder(auth: str, project_id: str, parent_folder_id: str, folder_disp "name": folder_display_name, "extension": {"type": "folders:autodesk.core:Folder", "version": "1.0"}, }, - "relationships": {"parent": {"data": {"type": "folders", "id": f"{parent_folder_id}"}}}, + "relationships": { + "parent": {"data": {"type": "folders", "id": f"{parent_folder_id}"}} + }, }, } res = requests.post( - f"https://developer.api.autodesk.com/data/v1/projects/{project_id}/folders", headers=headers, json=data + f"https://developer.api.autodesk.com/data/v1/projects/{project_id}/folders", + headers=headers, + json=data, ) if not res.ok: gm.ui.messageBox(f"Failed to create new folder: {res.text}", "ERROR") @@ -227,7 +238,9 @@ def file_path_to_file_name(file_path: str) -> str: return file_path.split("/").pop() -def upload_mirabuf(project_id: str, folder_id: str, file_name: str, file_contents: str) -> str | None: +def upload_mirabuf( + project_id: str, folder_id: str, file_name: str, file_contents: str +) -> str | None: """ uploads mirabuf file to a specific folder in an APS project the folder and project must be created and valid @@ -267,14 +280,18 @@ def upload_mirabuf(project_id: str, folder_id: str, file_name: str, file_content folder_id = create_folder(auth, project_id, folder_id, "MirabufDir") else: folder_id = new_folder_id - (lineage_id, file_id, file_version) = get_file_id(auth, project_id, folder_id, file_name) + (lineage_id, file_id, file_version) = get_file_id( + auth, project_id, folder_id, file_name + ) """ Create APS Storage Location """ object_id = create_storage_location(auth, project_id, folder_id, file_name) if object_id is None: - gm.ui.messageBox("UPLOAD ERROR", "Object id is none; check create storage location") + gm.ui.messageBox( + "UPLOAD ERROR", "Object id is none; check create storage location" + ) return None (prefix, object_key) = str(object_id).split("/", 1) bucket_key = prefix.split(":", 3)[3] # gets the last element smth like: wip.dm.prod @@ -297,10 +314,20 @@ def upload_mirabuf(project_id: str, folder_id: str, file_name: str, file_content return None if file_id != "": update_file_version( - auth, project_id, folder_id, lineage_id, file_id, file_name, file_contents, file_version, object_id + auth, + project_id, + folder_id, + lineage_id, + file_id, + file_name, + file_contents, + file_version, + object_id, ) else: - _lineage_info = create_first_file_version(auth, str(object_id), project_id, str(folder_id), file_name) + _lineage_info = create_first_file_version( + auth, str(object_id), project_id, str(folder_id), file_name + ) return "" @@ -318,9 +345,13 @@ def get_hub_id(auth: str, hub_name: str) -> str | None: """ headers = {"Authorization": f"Bearer {auth}"} - hub_list_res = requests.get("https://developer.api.autodesk.com/project/v1/hubs", headers=headers) + hub_list_res = requests.get( + "https://developer.api.autodesk.com/project/v1/hubs", headers=headers + ) if not hub_list_res.ok: - gm.ui.messageBox("UPLOAD ERROR", f"Failed to retrieve hubs: {hub_list_res.text}") + gm.ui.messageBox( + "UPLOAD ERROR", f"Failed to retrieve hubs: {hub_list_res.text}" + ) return None hub_list: list[dict[str, Any]] = hub_list_res.json() for hub in hub_list: @@ -349,10 +380,13 @@ def get_project_id(auth: str, hub_id: str, project_name: str) -> str | None: headers = {"Authorization": f"Bearer {auth}"} project_list_res = requests.get( - f"https://developer.api.autodesk.com/project/v1/hubs/{hub_id}/projects", headers=headers + f"https://developer.api.autodesk.com/project/v1/hubs/{hub_id}/projects", + headers=headers, ) if not project_list_res.ok: - gm.ui.messageBox("UPLOAD ERROR", f"Failed to retrieve hubs: {project_list_res.text}") + gm.ui.messageBox( + "UPLOAD ERROR", f"Failed to retrieve hubs: {project_list_res.text}" + ) return None project_list: list[dict[str, Any]] = project_list_res.json() for project in project_list: @@ -362,7 +396,9 @@ def get_project_id(auth: str, hub_id: str, project_name: str) -> str | None: return "" -def get_item_id(auth: str, project_id: str, parent_folder_id: str, folder_name: str, item_type: str) -> str | None: +def get_item_id( + auth: str, project_id: str, parent_folder_id: str, folder_name: str, item_type: str +) -> str | None: headers = {"Authorization": f"Bearer {auth}"} res = requests.get( f"https://developer.api.autodesk.com/data/v1/projects/{project_id}/folders/{parent_folder_id}/contents", @@ -431,7 +467,10 @@ def update_file_version( "Content-Type": "application/vnd.api+json", } - attributes = {"name": file_name, "extension": {"type": "versions:autodesk.core:File", "version": f"1.0"}} + attributes = { + "name": file_name, + "extension": {"type": "versions:autodesk.core:File", "version": f"1.0"}, + } relationships: dict[str, Any] = { "item": { @@ -450,22 +489,33 @@ def update_file_version( data = { "jsonapi": {"version": "1.0"}, - "data": {"type": "versions", "attributes": attributes, "relationships": relationships}, + "data": { + "type": "versions", + "attributes": attributes, + "relationships": relationships, + }, } update_res = requests.post( - f"https://developer.api.autodesk.com/data/v1/projects/{project_id}/versions", headers=headers, json=data + f"https://developer.api.autodesk.com/data/v1/projects/{project_id}/versions", + headers=headers, + json=data, ) if not update_res.ok: - gm.ui.messageBox(f"UPLOAD ERROR:\n{update_res.text}", "Updating file to new version failed") + gm.ui.messageBox( + f"UPLOAD ERROR:\n{update_res.text}", "Updating file to new version failed" + ) return None gm.ui.messageBox( - f"Successfully updated file {file_name} to version {int(curr_file_version) + 1} on APS", "UPLOAD SUCCESS" + f"Successfully updated file {file_name} to version {int(curr_file_version) + 1} on APS", + "UPLOAD SUCCESS", ) new_id: str = update_res.json()["data"]["id"] return new_id -def get_file_id(auth: str, project_id: str, folder_id: str, file_name: str) -> tuple[str, str, str] | None: +def get_file_id( + auth: str, project_id: str, folder_id: str, file_name: str +) -> tuple[str, str, str] | None: """ gets the file id given a file name @@ -509,7 +559,9 @@ def get_file_id(auth: str, project_id: str, folder_id: str, file_name: str) -> t return (lineage, id, version) -def create_storage_location(auth: str, project_id: str, folder_id: str, file_name: str) -> str | None: +def create_storage_location( + auth: str, project_id: str, folder_id: str, file_name: str +) -> str | None: """ creates a storage location (a bucket) the bucket can be used to upload a file to @@ -536,7 +588,9 @@ def create_storage_location(auth: str, project_id: str, folder_id: str, file_nam "data": { "type": "objects", "attributes": {"name": file_name}, - "relationships": {"target": {"data": {"type": "folders", "id": f"{folder_id}"}}}, + "relationships": { + "target": {"data": {"type": "folders", "id": f"{folder_id}"}} + }, }, } headers = { @@ -544,17 +598,24 @@ def create_storage_location(auth: str, project_id: str, folder_id: str, file_nam "Content-Type": "application/vnd.api+json", } storage_location_res = requests.post( - f"https://developer.api.autodesk.com/data/v1/projects/{project_id}/storage", json=data, headers=headers + f"https://developer.api.autodesk.com/data/v1/projects/{project_id}/storage", + json=data, + headers=headers, ) if not storage_location_res.ok: - gm.ui.messageBox(f"UPLOAD ERROR: {storage_location_res.text}", f"Failed to create storage location") + gm.ui.messageBox( + f"UPLOAD ERROR: {storage_location_res.text}", + f"Failed to create storage location", + ) return None storage_location_json: dict[str, Any] = storage_location_res.json() object_id: str = storage_location_json["data"]["id"] return object_id -def generate_signed_url(auth: str, bucket_key: str, object_key: str) -> tuple[str, str] | None: +def generate_signed_url( + auth: str, bucket_key: str, object_key: str +) -> tuple[str, str] | None: """ generates a signed_url for a bucket, given a bucket_key and object_key @@ -580,7 +641,9 @@ def generate_signed_url(auth: str, bucket_key: str, object_key: str) -> tuple[st headers=headers, ) if not signed_url_res.ok: - gm.ui.messageBox(f"UPLOAD ERROR: {signed_url_res.text}", "Failed to get signed url") + gm.ui.messageBox( + f"UPLOAD ERROR: {signed_url_res.text}", "Failed to get signed url" + ) return None signed_url_json: dict[str, str] = signed_url_res.json() return (signed_url_json["uploadKey"], signed_url_json["urls"][0]) @@ -603,12 +666,16 @@ def upload_file(signed_url: str, file_contents: str) -> str | None: """ upload_response = requests.put(url=signed_url, data=file_contents) if not upload_response.ok: - gm.ui.messageBox("UPLOAD ERROR", f"Failed to upload to signed url: {upload_response.text}") + gm.ui.messageBox( + "UPLOAD ERROR", f"Failed to upload to signed url: {upload_response.text}" + ) return None return "" -def complete_upload(auth: str, upload_key: str, object_key: str, bucket_key: str) -> str | None: +def complete_upload( + auth: str, upload_key: str, object_key: str, bucket_key: str +) -> str | None: """ completes and verifies the APS file upload given the upload_key @@ -635,7 +702,8 @@ def complete_upload(auth: str, upload_key: str, object_key: str, bucket_key: str ) if not completed_res.ok: gm.ui.messageBox( - f"UPLOAD ERROR: {completed_res.text}\n{completed_res.status_code}", "Failed to complete upload" + f"UPLOAD ERROR: {completed_res.text}\n{completed_res.status_code}", + "Failed to complete upload", ) return None return "" @@ -673,7 +741,10 @@ def create_first_file_version( "Accept": "application/vnd.api+json", } - included_attributes = {"name": file_name, "extension": {"type": "versions:autodesk.core:File", "version": "1.0"}} + included_attributes = { + "name": file_name, + "extension": {"type": "versions:autodesk.core:File", "version": "1.0"}, + } attributes = { "displayName": file_name, @@ -693,21 +764,32 @@ def create_first_file_version( "type": "versions", "id": "1", "attributes": included_attributes, - "relationships": {"storage": {"data": {"type": "objects", "id": object_id}}}, + "relationships": { + "storage": {"data": {"type": "objects", "id": object_id}} + }, }, ] data = { "jsonapi": {"version": "1.0"}, - "data": {"type": "items", "attributes": attributes, "relationships": relationships}, + "data": { + "type": "items", + "attributes": attributes, + "relationships": relationships, + }, "included": included, } first_version_res = requests.post( - f"https://developer.api.autodesk.com/data/v1/projects/{project_id}/items", json=data, headers=headers + f"https://developer.api.autodesk.com/data/v1/projects/{project_id}/items", + json=data, + headers=headers, ) if not first_version_res.ok: - gm.ui.messageBox(f"Failed to create first file version: {first_version_res.text}", "UPLOAD ERROR") + gm.ui.messageBox( + f"Failed to create first file version: {first_version_res.text}", + "UPLOAD ERROR", + ) return None first_version_json: dict[str, Any] = first_version_res.json() diff --git a/exporter/SynthesisFusionAddin/src/Logging.py b/exporter/SynthesisFusionAddin/src/Logging.py index 2bf9ce191b..2a59a88cec 100644 --- a/exporter/SynthesisFusionAddin/src/Logging.py +++ b/exporter/SynthesisFusionAddin/src/Logging.py @@ -31,7 +31,11 @@ def setupLogger() -> None: now = datetime.now().strftime("%H-%M-%S") today = date.today() logFileFolder = getOSPath(f"{pathlib.Path(__file__).parent.parent}", "logs") - logFiles = [os.path.join(logFileFolder, file) for file in os.listdir(logFileFolder) if file.endswith(".log")] + logFiles = [ + os.path.join(logFileFolder, file) + for file in os.listdir(logFileFolder) + if file.endswith(".log") + ] logFiles.sort() if len(logFiles) >= MAX_LOG_FILES_TO_KEEP: for file in logFiles[: len(logFiles) - MAX_LOG_FILES_TO_KEEP]: @@ -66,15 +70,21 @@ def wrapper(*args: any, **kwargs: any) -> any: except BaseException: excType, excValue, excTrace = sys.exc_info() tb = traceback.TracebackException(excType, excValue, excTrace) - formattedTb = "".join(list(tb.format())[2:]) # Remove the wrapper func from the traceback. + formattedTb = "".join( + list(tb.format())[2:] + ) # Remove the wrapper func from the traceback. clsName = "" if args and hasattr(args[0], "__class__"): clsName = args[0].__class__.__name__ + "." - getLogger(f"{INTERNAL_ID}.{clsName}{func.__name__}").error(f"Failed:\n{formattedTb}") + getLogger(f"{INTERNAL_ID}.{clsName}{func.__name__}").error( + f"Failed:\n{formattedTb}" + ) if messageBox: ui = adsk.core.Application.get().userInterface - ui.messageBox(f"Internal Failure: {formattedTb}", "Synthesis: Error") + ui.messageBox( + f"Internal Failure: {formattedTb}", "Synthesis: Error" + ) return wrapper diff --git a/exporter/SynthesisFusionAddin/src/Parser/ExporterOptions.py b/exporter/SynthesisFusionAddin/src/Parser/ExporterOptions.py index 52ccd255bf..c287720b56 100644 --- a/exporter/SynthesisFusionAddin/src/Parser/ExporterOptions.py +++ b/exporter/SynthesisFusionAddin/src/Parser/ExporterOptions.py @@ -34,7 +34,11 @@ class ExporterOptions: # user's computer has conflicting configs of some sort. This has happened and should be accounted # for accordingly. fileLocation: str | None = field( - default=(os.getenv("HOME") if platform.system() == "Windows" else os.path.expanduser("~")) + default=( + os.getenv("HOME") + if platform.system() == "Windows" + else os.path.expanduser("~") + ) ) name: str = field(default=None) version: str = field(default=None) @@ -57,9 +61,13 @@ class ExporterOptions: exportLocation: ExportLocation = field(default=ExportLocation.UPLOAD) hierarchy: ModelHierarchy = field(default=ModelHierarchy.FusionAssembly) - visualQuality: TriangleMeshQualityOptions = field(default=TriangleMeshQualityOptions.LowQualityTriangleMesh) + visualQuality: TriangleMeshQualityOptions = field( + default=TriangleMeshQualityOptions.LowQualityTriangleMesh + ) physicalDepth: PhysicalDepth = field(default=PhysicalDepth.AllOccurrence) - physicalCalculationLevel: CalculationAccuracy = field(default=CalculationAccuracy.LowCalculationAccuracy) + physicalCalculationLevel: CalculationAccuracy = field( + default=CalculationAccuracy.LowCalculationAccuracy + ) @logFailure @timed @@ -68,7 +76,9 @@ def readFromDesign(self) -> "ExporterOptions": for field in fields(self): attribute = designAttributes.itemByName(INTERNAL_ID, field.name) if attribute: - attrJsonData = makeObjectFromJson(field.type, json.loads(attribute.value)) + attrJsonData = makeObjectFromJson( + field.type, json.loads(attribute.value) + ) setattr(self, field.name, attrJsonData) return self @@ -78,5 +88,7 @@ def readFromDesign(self) -> "ExporterOptions": def writeToDesign(self) -> None: designAttributes = adsk.core.Application.get().activeProduct.attributes for field in fields(self): - data = json.dumps(getattr(self, field.name), default=encodeNestedObjects, indent=4) + data = json.dumps( + getattr(self, field.name), default=encodeNestedObjects, indent=4 + ) designAttributes.add(INTERNAL_ID, field.name, data) diff --git a/exporter/SynthesisFusionAddin/src/Parser/SynthesisParser/Components.py b/exporter/SynthesisFusionAddin/src/Parser/SynthesisParser/Components.py index aa77cac500..78819dfbeb 100644 --- a/exporter/SynthesisFusionAddin/src/Parser/SynthesisParser/Components.py +++ b/exporter/SynthesisFusionAddin/src/Parser/SynthesisParser/Components.py @@ -40,7 +40,9 @@ def _MapAllComponents( fill_info(partDefinition, component, comp_ref) - PhysicalProperties.GetPhysicalProperties(component, partDefinition.physical_data) + PhysicalProperties.GetPhysicalProperties( + component, partDefinition.physical_data + ) if options.exportMode == ExportMode.FIELD: partDefinition.dynamic = False @@ -60,7 +62,9 @@ def processBody(body: adsk.fusion.BRepBody | adsk.fusion.MeshBody): else: _ParseMesh(body, options, part_body.triangle_mesh) - appearance_key = "{}_{}".format(body.appearance.name, body.appearance.id) + appearance_key = "{}_{}".format( + body.appearance.name, body.appearance.id + ) # this should be appearance if appearance_key in materials.appearances: part_body.appearance_override = appearance_key @@ -101,7 +105,9 @@ def _ParseComponentRoot( if occur.isLightBulbOn: child_node = types_pb2.Node() - __parseChildOccurrence(occur, progressDialog, options, partsData, material_map, child_node) + __parseChildOccurrence( + occur, progressDialog, options, partsData, material_map, child_node + ) node.children.append(child_node) @@ -134,7 +140,9 @@ def __parseChildOccurrence( if occurrence.appearance: try: - part.appearance = "{}_{}".format(occurrence.appearance.name, occurrence.appearance.id) + part.appearance = "{}_{}".format( + occurrence.appearance.name, occurrence.appearance.id + ) except: part.appearance = "default" # TODO: Add phyical_material parser @@ -151,7 +159,9 @@ def __parseChildOccurrence( if options.exportMode == ExportMode.FIELD: for x in options.gamepieces: if x.occurrenceToken == mapConstant: - partsData.part_definitions[part.part_definition_reference].dynamic = True + partsData.part_definitions[part.part_definition_reference].dynamic = ( + True + ) break part.transform.spatial_matrix.extend(occurrence.transform.asArray()) @@ -167,7 +177,9 @@ def __parseChildOccurrence( if occur.isLightBulbOn: child_node = types_pb2.Node() - __parseChildOccurrence(occur, progressDialog, options, partsData, material_map, child_node) + __parseChildOccurrence( + occur, progressDialog, options, partsData, material_map, child_node + ) node.children.append(child_node) @@ -223,7 +235,9 @@ def _ParseMesh( plainmesh_out.uv.extend(mesh.textureCoordinatesAsFloat) -def _MapRigidGroups(rootComponent: adsk.fusion.Component, joints: joint_pb2.Joints) -> None: +def _MapRigidGroups( + rootComponent: adsk.fusion.Component, joints: joint_pb2.Joints +) -> None: groups = rootComponent.allRigidGroups for group in groups: mira_group = joint_pb2.RigidGroup() diff --git a/exporter/SynthesisFusionAddin/src/Parser/SynthesisParser/JointHierarchy.py b/exporter/SynthesisFusionAddin/src/Parser/SynthesisParser/JointHierarchy.py index 53dd3d10fa..cd8f9e06b0 100644 --- a/exporter/SynthesisFusionAddin/src/Parser/SynthesisParser/JointHierarchy.py +++ b/exporter/SynthesisFusionAddin/src/Parser/SynthesisParser/JointHierarchy.py @@ -91,7 +91,9 @@ class JointRelationship(enum.Enum): class DynamicOccurrenceNode(GraphNode): - def __init__(self, occurrence: adsk.fusion.Occurrence, isGround=False, previous=None): + def __init__( + self, occurrence: adsk.fusion.Occurrence, isGround=False, previous=None + ): super().__init__(occurrence) self.isGround = isGround self.name = occurrence.name @@ -131,7 +133,9 @@ def getConnectedAxisTokens(self) -> list: class DynamicEdge(GraphEdge): - def __init__(self, relationship: OccurrenceRelationship, node: DynamicOccurrenceNode): + def __init__( + self, relationship: OccurrenceRelationship, node: DynamicOccurrenceNode + ): super().__init__(relationship, node) # should print all in this class @@ -211,7 +215,9 @@ def __init__(self, design): self.grounded = searchForGrounded(design.rootComponent) if self.grounded is None: - gm.ui.messageBox("There is not currently a Grounded Component in the assembly, stopping kinematic export.") + gm.ui.messageBox( + "There is not currently a Grounded Component in the assembly, stopping kinematic export." + ) raise RuntimeWarning("There is no grounded component") self.currentTraversal = dict() @@ -247,7 +253,9 @@ def __init__(self, design): @logFailure def __getAllJoints(self): - for joint in list(self.design.rootComponent.allJoints) + list(self.design.rootComponent.allAsBuiltJoints): + for joint in list(self.design.rootComponent.allJoints) + list( + self.design.rootComponent.allAsBuiltJoints + ): if joint and joint.occurrenceOne and joint.occurrenceTwo: occurrenceOne = joint.occurrenceOne occurrenceTwo = joint.occurrenceTwo @@ -303,7 +311,8 @@ def _linkAllAxis(self): def _recurseLink(self, simNode: SimulationNode): connectedAxisNodes = [ - self.simulationNodesRef.get(componentKeys, None) for componentKeys in simNode.data.getConnectedAxisTokens() + self.simulationNodesRef.get(componentKeys, None) + for componentKeys in simNode.data.getConnectedAxisTokens() ] for connectedAxis in connectedAxisNodes: # connected is the occurrence @@ -353,9 +362,9 @@ def _populateNode( edge = DynamicEdge(relationship, node) prev.edges.append(edge) return - elif ((occ.entityToken in self.dynamicJoints.keys()) and (prev is not None)) or self.currentTraversal.get( - occ.entityToken - ) is not None: + elif ( + (occ.entityToken in self.dynamicJoints.keys()) and (prev is not None) + ) or self.currentTraversal.get(occ.entityToken) is not None: return node = DynamicOccurrenceNode(occ) @@ -363,7 +372,9 @@ def _populateNode( self.currentTraversal[occ.entityToken] = True for occurrence in occ.childOccurrences: - self._populateNode(occurrence, node, OccurrenceRelationship.TRANSFORM, is_ground=is_ground) + self._populateNode( + occurrence, node, OccurrenceRelationship.TRANSFORM, is_ground=is_ground + ) # if not is_ground: # THIS IS A BUG - OCCURRENCE ACCESS VIOLATION try: @@ -384,11 +395,18 @@ def _populateNode( connection = joint.occurrenceOne if connection is not None: - if prev is None or connection.entityToken != prev.data.entityToken: + if ( + prev is None + or connection.entityToken != prev.data.entityToken + ): self._populateNode( connection, node, - (OccurrenceRelationship.CONNECTION if rigid else OccurrenceRelationship.NEXT), + ( + OccurrenceRelationship.CONNECTION + if rigid + else OccurrenceRelationship.NEXT + ), is_ground=is_ground, ) else: @@ -491,7 +509,9 @@ def populateJoint(simNode: SimulationNode, joints: joint_pb2.Joints, progressDia root = types_pb2.Node() # construct body tree if possible - createTreeParts(simNode.data, OccurrenceRelationship.CONNECTION, root, progressDialog) + createTreeParts( + simNode.data, OccurrenceRelationship.CONNECTION, root, progressDialog + ) proto_joint.parts.nodes.append(root) @@ -510,7 +530,10 @@ def createTreeParts( raise RuntimeError("User canceled export") # if it's the next part just exit early for our own sanity - if relationship == OccurrenceRelationship.NEXT or dynNode.data.isLightBulbOn == False: + if ( + relationship == OccurrenceRelationship.NEXT + or dynNode.data.isLightBulbOn == False + ): return # set the occurrence / component id to reference the part diff --git a/exporter/SynthesisFusionAddin/src/Parser/SynthesisParser/Joints.py b/exporter/SynthesisFusionAddin/src/Parser/SynthesisParser/Joints.py index c79a0240d0..6caa82e6df 100644 --- a/exporter/SynthesisFusionAddin/src/Parser/SynthesisParser/Joints.py +++ b/exporter/SynthesisFusionAddin/src/Parser/SynthesisParser/Joints.py @@ -88,7 +88,9 @@ def populateJoints( # Add the rest of the dynamic objects - for joint in list(design.rootComponent.allJoints) + list(design.rootComponent.allAsBuiltJoints): + for joint in list(design.rootComponent.allJoints) + list( + design.rootComponent.allAsBuiltJoints + ): if joint.isSuppressed: continue @@ -122,7 +124,10 @@ def populateJoints( signal.io = signal_pb2.IOType.OUTPUT # really could just map the enum to a friggin string - if parse_joints.signalType != SignalType.PASSIVE and assembly.dynamic: + if ( + parse_joints.signalType != SignalType.PASSIVE + and assembly.dynamic + ): if parse_joints.signalType == SignalType.CAN: signal.device_type = signal_pb2.DeviceType.CANBUS elif parse_joints.signalType == SignalType.PWM: @@ -209,7 +214,9 @@ def _addJointInstance( joint_definition.user_data.data["wheel"] = "true" # Must convert type 'enum' to int to store wheelType in mirabuf - joint_definition.user_data.data["wheelType"] = str(wheel.wheelType.value - 1) + joint_definition.user_data.data["wheelType"] = str( + wheel.wheelType.value - 1 + ) # if it exists get it and overwrite the signal type if joint_instance.signal_reference: @@ -243,7 +250,9 @@ def _addRigidGroup(joint: adsk.fusion.Joint, assembly: assembly_pb2.Assembly): assembly.data.joints.rigid_groups.append(mira_group) -def _motionFromJoint(fusionMotionDefinition: adsk.fusion.JointMotion, proto_joint: joint_pb2.Joint) -> None: +def _motionFromJoint( + fusionMotionDefinition: adsk.fusion.JointMotion, proto_joint: joint_pb2.Joint +) -> None: # if fusionJoint.geometryOrOriginOne.objectType == "adsk::fusion::JointGeometry" # create the DOF depending on what kind of information the joint has @@ -257,12 +266,16 @@ def _motionFromJoint(fusionMotionDefinition: adsk.fusion.JointMotion, proto_join 6: noop, # TODO: Implement } - fillJointMotionFunc = fillJointMotionFuncSwitcher.get(fusionMotionDefinition.jointType, lambda: None) + fillJointMotionFunc = fillJointMotionFuncSwitcher.get( + fusionMotionDefinition.jointType, lambda: None + ) fillJointMotionFunc(fusionMotionDefinition, proto_joint) -def fillRevoluteJointMotion(revoluteMotion: adsk.fusion.RevoluteJointMotion, proto_joint: joint_pb2.Joint): +def fillRevoluteJointMotion( + revoluteMotion: adsk.fusion.RevoluteJointMotion, proto_joint: joint_pb2.Joint +): """#### Fill Protobuf revolute joint motion data Args: @@ -304,7 +317,9 @@ def fillRevoluteJointMotion(revoluteMotion: adsk.fusion.RevoluteJointMotion, pro dof.axis.z = int(rotationAxis == 1) -def fillSliderJointMotion(sliderMotion: adsk.fusion.SliderJointMotion, proto_joint: joint_pb2.Joint) -> None: +def fillSliderJointMotion( + sliderMotion: adsk.fusion.SliderJointMotion, proto_joint: joint_pb2.Joint +) -> None: """#### Fill Protobuf slider joint motion data Args: @@ -375,7 +390,9 @@ def _searchForGrounded( return None -def _jointOrigin(fusionJoint: Union[adsk.fusion.Joint, adsk.fusion.AsBuiltJoint]) -> adsk.core.Point3D: +def _jointOrigin( + fusionJoint: Union[adsk.fusion.Joint, adsk.fusion.AsBuiltJoint] +) -> adsk.core.Point3D: """#### Joint Origin Internal Finder that was orignally created for Synthesis by Liam Wang Args: @@ -387,7 +404,8 @@ def _jointOrigin(fusionJoint: Union[adsk.fusion.Joint, adsk.fusion.AsBuiltJoint] geometryOrOrigin = ( ( fusionJoint.geometryOrOriginOne - if fusionJoint.geometryOrOriginOne.objectType == "adsk::fusion::JointGeometry" + if fusionJoint.geometryOrOriginOne.objectType + == "adsk::fusion::JointGeometry" else fusionJoint.geometryOrOriginTwo ) if fusionJoint.objectType == "adsk::fusion::Joint" @@ -406,7 +424,9 @@ def _jointOrigin(fusionJoint: Union[adsk.fusion.Joint, adsk.fusion.AsBuiltJoint] newEnt = ent.createForAssemblyContext(fusionJoint.occurrenceOne) min = newEnt.boundingBox.minPoint max = newEnt.boundingBox.maxPoint - org = adsk.core.Point3D.create((max.x + min.x) / 2.0, (max.y + min.y) / 2.0, (max.z + min.z) / 2.0) + org = adsk.core.Point3D.create( + (max.x + min.x) / 2.0, (max.y + min.y) / 2.0, (max.z + min.z) / 2.0 + ) return org # ent.startVertex.geometry else: return geometryOrOrigin.origin @@ -421,11 +441,19 @@ def _jointOrigin(fusionJoint: Union[adsk.fusion.Joint, adsk.fusion.AsBuiltJoint] else: # adsk::fusion::JointOrigin origin = geometryOrOrigin.geometry.origin # todo: Is this the correct way to calculate a joint origin's true location? Why isn't this exposed in the API? - offsetX = 0 if geometryOrOrigin.offsetX is None else geometryOrOrigin.offsetX.value - offsetY = 0 if geometryOrOrigin.offsetY is None else geometryOrOrigin.offsetY.value - offsetZ = 0 if geometryOrOrigin.offsetZ is None else geometryOrOrigin.offsetZ.value + offsetX = ( + 0 if geometryOrOrigin.offsetX is None else geometryOrOrigin.offsetX.value + ) + offsetY = ( + 0 if geometryOrOrigin.offsetY is None else geometryOrOrigin.offsetY.value + ) + offsetZ = ( + 0 if geometryOrOrigin.offsetZ is None else geometryOrOrigin.offsetZ.value + ) # noinspection PyArgumentList - return adsk.core.Point3D.create(origin.x + offsetX, origin.y + offsetY, origin.z + offsetZ) + return adsk.core.Point3D.create( + origin.x + offsetX, origin.y + offsetY, origin.z + offsetZ + ) def createJointGraph( @@ -461,17 +489,26 @@ def createJointGraph( current_node = node_map[supplied_joint.jointToken] if supplied_joint.parent == JointParentType.ROOT: node_map["ground"].children.append(node_map[supplied_joint.jointToken]) - elif node_map[supplied_joint.parent.value] is not None and node_map[supplied_joint.jointToken] is not None: - node_map[supplied_joint.parent].children.append(node_map[supplied_joint.jointToken]) + elif ( + node_map[supplied_joint.parent.value] is not None + and node_map[supplied_joint.jointToken] is not None + ): + node_map[supplied_joint.parent].children.append( + node_map[supplied_joint.jointToken] + ) else: - logger.error(f"Cannot construct hierarhcy because of detached tree at : {supplied_joint.jointToken}") + logger.error( + f"Cannot construct hierarhcy because of detached tree at : {supplied_joint.jointToken}" + ) for node in node_map.values(): # append everything at top level to isolate kinematics joint_tree.nodes.append(node) -def addWheelsToGraph(wheels: list, rootNode: types_pb2.Node, joint_tree: types_pb2.GraphContainer): +def addWheelsToGraph( + wheels: list, rootNode: types_pb2.Node, joint_tree: types_pb2.GraphContainer +): for wheel in wheels: # wheel name # wheel signal diff --git a/exporter/SynthesisFusionAddin/src/Parser/SynthesisParser/Materials.py b/exporter/SynthesisFusionAddin/src/Parser/SynthesisParser/Materials.py index 97d8d47f57..3b8a019d71 100644 --- a/exporter/SynthesisFusionAddin/src/Parser/SynthesisParser/Materials.py +++ b/exporter/SynthesisFusionAddin/src/Parser/SynthesisParser/Materials.py @@ -52,7 +52,9 @@ def _MapAllPhysicalMaterials( getPhysicalMaterialData(material, newmaterial, options) -def setDefaultMaterial(physical_material: material_pb2.PhysicalMaterial, options: ExporterOptions): +def setDefaultMaterial( + physical_material: material_pb2.PhysicalMaterial, options: ExporterOptions +): construct_info("default", physical_material) physical_material.description = "A default physical material" @@ -92,8 +94,12 @@ def getPhysicalMaterialData(fusion_material, proto_material, options): proto_material.dynamic_friction = options.frictionOverrideCoeff proto_material.static_friction = options.frictionOverrideCoeff else: - proto_material.dynamic_friction = DYNAMIC_FRICTION_COEFFS.get(fusion_material.name, 0.5) - proto_material.static_friction = STATIC_FRICTION_COEFFS.get(fusion_material.name, 0.5) + proto_material.dynamic_friction = DYNAMIC_FRICTION_COEFFS.get( + fusion_material.name, 0.5 + ) + proto_material.static_friction = STATIC_FRICTION_COEFFS.get( + fusion_material.name, 0.5 + ) proto_material.restitution = 0.5 proto_material.description = f"{fusion_material.name} exported from FUSION" @@ -127,17 +133,31 @@ def getPhysicalMaterialData(fusion_material, proto_material, options): """ Mechanical Properties """ - mechanicalProperties.young_mod = materialProperties.itemById("structural_Young_modulus").value - mechanicalProperties.poisson_ratio = materialProperties.itemById("structural_Poisson_ratio").value - mechanicalProperties.shear_mod = materialProperties.itemById("structural_Shear_modulus").value - mechanicalProperties.density = materialProperties.itemById("structural_Density").value - mechanicalProperties.damping_coefficient = materialProperties.itemById("structural_Damping_coefficient").value + mechanicalProperties.young_mod = materialProperties.itemById( + "structural_Young_modulus" + ).value + mechanicalProperties.poisson_ratio = materialProperties.itemById( + "structural_Poisson_ratio" + ).value + mechanicalProperties.shear_mod = materialProperties.itemById( + "structural_Shear_modulus" + ).value + mechanicalProperties.density = materialProperties.itemById( + "structural_Density" + ).value + mechanicalProperties.damping_coefficient = materialProperties.itemById( + "structural_Damping_coefficient" + ).value """ Strength Properties """ - strengthProperties.yield_strength = materialProperties.itemById("structural_Minimum_yield_stress").value - strengthProperties.tensile_strength = materialProperties.itemById("structural_Minimum_tensile_strength").value + strengthProperties.yield_strength = materialProperties.itemById( + "structural_Minimum_yield_stress" + ).value + strengthProperties.tensile_strength = materialProperties.itemById( + "structural_Minimum_tensile_strength" + ).value """ strengthProperties.thermal_treatment = materialProperties.itemById( "structural_Thermally_treated" @@ -235,7 +255,9 @@ def getMaterialAppearance( baseColor = properties.itemById("transparent_color").value transparent_distance = properties.itemById("transparent_distance").value - opac = (255.0 * transparent_distance) / (transparent_distance + OPACITY_RAMPING_CONSTANT) + opac = (255.0 * transparent_distance) / ( + transparent_distance + OPACITY_RAMPING_CONSTANT + ) if opac > 255: opac = 255 elif opac < 0: @@ -251,7 +273,11 @@ def getMaterialAppearance( color.A = baseColor.opacity else: for prop in fusionAppearance.appearanceProperties: - if (prop.name == "Color") and (prop.value is not None) and (prop.id != "surface_albedo"): + if ( + (prop.name == "Color") + and (prop.value is not None) + and (prop.id != "surface_albedo") + ): baseColor = prop.value color.R = baseColor.red color.G = baseColor.green diff --git a/exporter/SynthesisFusionAddin/src/Parser/SynthesisParser/PDMessage.py b/exporter/SynthesisFusionAddin/src/Parser/SynthesisParser/PDMessage.py index ad441fc901..d5057709da 100644 --- a/exporter/SynthesisFusionAddin/src/Parser/SynthesisParser/PDMessage.py +++ b/exporter/SynthesisFusionAddin/src/Parser/SynthesisParser/PDMessage.py @@ -28,7 +28,12 @@ def __init__( self.currentMessage = "working..." - self.finalValue = self.componentCount + self.occurrenceCount + self.materialCount + self.appearanceCount + self.finalValue = ( + self.componentCount + + self.occurrenceCount + + self.materialCount + + self.appearanceCount + ) self.currentValue = 0 self.progressDialog = progressDialog @@ -38,9 +43,13 @@ def _format(self): # TABS DO NOTHING HALP out = f"{self.assemblyName} parsing:\n" out += f"\t Components: \t[ {self.currentCompCount} / {self.componentCount} ]\n" - out += f"\t Occurrences: \t[ {self.currentOccCount} / {self.occurrenceCount} ]\n" + out += ( + f"\t Occurrences: \t[ {self.currentOccCount} / {self.occurrenceCount} ]\n" + ) out += f"\t Materials: \t[ {self.currentMatCount} / {self.materialCount} ]\n" - out += f"\t Appearances: \t[ {self.currentAppCount} / {self.appearanceCount} ]\n" + out += ( + f"\t Appearances: \t[ {self.currentAppCount} / {self.appearanceCount} ]\n" + ) out += f"{self.currentMessage}" return out diff --git a/exporter/SynthesisFusionAddin/src/Parser/SynthesisParser/Parser.py b/exporter/SynthesisFusionAddin/src/Parser/SynthesisParser/Parser.py index b59f391f0b..e483adedaa 100644 --- a/exporter/SynthesisFusionAddin/src/Parser/SynthesisParser/Parser.py +++ b/exporter/SynthesisFusionAddin/src/Parser/SynthesisParser/Parser.py @@ -35,7 +35,9 @@ def export(self) -> None: design: adsk.fusion.Design = app.activeDocument.design if not getAuth(): - app.userInterface.messageBox("APS Login Required for Uploading.", "APS Login") + app.userInterface.messageBox( + "APS Login Required for Uploading.", "APS Login" + ) return assembly_out = assembly_pb2.Assembly() @@ -60,7 +62,9 @@ def export(self) -> None: progressDialog.title = "Exporting to Synthesis Format" progressDialog.minimumValue = 0 progressDialog.maximumValue = totalIterations - progressDialog.show("Synthesis Export", "Currently on %v of %m", 0, totalIterations) + progressDialog.show( + "Synthesis Export", "Currently on %v of %m", 0, totalIterations + ) # this is the formatter for the progress dialog now self.pdMessage = PDMessage.PDMessage( @@ -130,7 +134,9 @@ def export(self) -> None: self.pdMessage, ) - JointHierarchy.BuildJointPartHierarchy(design, assembly_out.data.joints, self.exporterOptions, self.pdMessage) + JointHierarchy.BuildJointPartHierarchy( + design, assembly_out.data.joints, self.exporterOptions, self.pdMessage + ) # These don't have an effect, I forgot how this is suppose to work # progressDialog.message = "Taking Photo for thumbnail..." @@ -179,7 +185,12 @@ def export(self) -> None: project_id = project.id folder_id = project.rootFolder.id file_name = f"{self.exporterOptions.fileLocation}.mira" - if upload_mirabuf(project_id, folder_id, file_name, assembly_out.SerializeToString()) is None: + if ( + upload_mirabuf( + project_id, folder_id, file_name, assembly_out.SerializeToString() + ) + is None + ): raise RuntimeError("Could not upload to APS") else: assert self.exporterOptions.exportLocation == ExportLocation.DOWNLOAD @@ -214,9 +225,15 @@ def export(self) -> None: joint_hierarchy_out = f"{joint_hierarchy_out} |- ground\n" else: newNode = assembly_out.data.joints.joint_instances[node.value] - jointDefinition = assembly_out.data.joints.joint_definitions[newNode.joint_reference] - - wheel_ = " wheel : true" if (jointDefinition.user_data.data["wheel"] != "") else "" + jointDefinition = assembly_out.data.joints.joint_definitions[ + newNode.joint_reference + ] + + wheel_ = ( + " wheel : true" + if (jointDefinition.user_data.data["wheel"] != "") + else "" + ) joint_hierarchy_out = ( f"{joint_hierarchy_out} |---> {jointDefinition.info.name} " @@ -227,8 +244,14 @@ def export(self) -> None: joint_hierarchy_out = f"{joint_hierarchy_out} |---> ground\n" else: newNode = assembly_out.data.joints.joint_instances[child.value] - jointDefinition = assembly_out.data.joints.joint_definitions[newNode.joint_reference] - wheel_ = " wheel : true" if (jointDefinition.user_data.data["wheel"] != "") else "" + jointDefinition = assembly_out.data.joints.joint_definitions[ + newNode.joint_reference + ] + wheel_ = ( + " wheel : true" + if (jointDefinition.user_data.data["wheel"] != "") + else "" + ) joint_hierarchy_out = ( f"{joint_hierarchy_out} |- {jointDefinition.info.name} " f"type: {jointDefinition.joint_motion_type} {wheel_}\n" diff --git a/exporter/SynthesisFusionAddin/src/Parser/SynthesisParser/PhysicalProperties.py b/exporter/SynthesisFusionAddin/src/Parser/SynthesisParser/PhysicalProperties.py index db488c115a..395231ccbf 100644 --- a/exporter/SynthesisFusionAddin/src/Parser/SynthesisParser/PhysicalProperties.py +++ b/exporter/SynthesisFusionAddin/src/Parser/SynthesisParser/PhysicalProperties.py @@ -30,7 +30,9 @@ @logFailure def GetPhysicalProperties( - fusionObject: Union[adsk.fusion.BRepBody, adsk.fusion.Occurrence, adsk.fusion.Component], + fusionObject: Union[ + adsk.fusion.BRepBody, adsk.fusion.Occurrence, adsk.fusion.Component + ], physicalProperties: types_pb2.PhysicalProperties, level=1, ): diff --git a/exporter/SynthesisFusionAddin/src/Parser/SynthesisParser/Utilities.py b/exporter/SynthesisFusionAddin/src/Parser/SynthesisParser/Utilities.py index f508f32117..14295e9239 100644 --- a/exporter/SynthesisFusionAddin/src/Parser/SynthesisParser/Utilities.py +++ b/exporter/SynthesisFusionAddin/src/Parser/SynthesisParser/Utilities.py @@ -62,18 +62,18 @@ def construct_info(name: str, proto_obj, version=5, fus_object=None, GUID=None) # My previous function was alot more optimized however now I realize the bug was this doesn't work well with degrees def euler_to_quaternion(r): (yaw, pitch, roll) = (r[0], r[1], r[2]) - qx = math.sin(roll / 2) * math.cos(pitch / 2) * math.cos(yaw / 2) - math.cos(roll / 2) * math.sin( - pitch / 2 - ) * math.sin(yaw / 2) - qy = math.cos(roll / 2) * math.sin(pitch / 2) * math.cos(yaw / 2) + math.sin(roll / 2) * math.cos( - pitch / 2 - ) * math.sin(yaw / 2) - qz = math.cos(roll / 2) * math.cos(pitch / 2) * math.sin(yaw / 2) - math.sin(roll / 2) * math.sin( - pitch / 2 - ) * math.cos(yaw / 2) - qw = math.cos(roll / 2) * math.cos(pitch / 2) * math.cos(yaw / 2) + math.sin(roll / 2) * math.sin( - pitch / 2 - ) * math.sin(yaw / 2) + qx = math.sin(roll / 2) * math.cos(pitch / 2) * math.cos(yaw / 2) - math.cos( + roll / 2 + ) * math.sin(pitch / 2) * math.sin(yaw / 2) + qy = math.cos(roll / 2) * math.sin(pitch / 2) * math.cos(yaw / 2) + math.sin( + roll / 2 + ) * math.cos(pitch / 2) * math.sin(yaw / 2) + qz = math.cos(roll / 2) * math.cos(pitch / 2) * math.sin(yaw / 2) - math.sin( + roll / 2 + ) * math.sin(pitch / 2) * math.cos(yaw / 2) + qw = math.cos(roll / 2) * math.cos(pitch / 2) * math.cos(yaw / 2) + math.sin( + roll / 2 + ) * math.sin(pitch / 2) * math.sin(yaw / 2) return [qx, qy, qz, qw] @@ -135,7 +135,9 @@ def throwZero(): Raises: RuntimeError: Error describing the issue """ - raise RuntimeError("While computing the quaternion the trace was reported as 0 which is invalid") + raise RuntimeError( + "While computing the quaternion the trace was reported as 0 which is invalid" + ) def spatial_to_quaternion(mat): @@ -193,7 +195,9 @@ def spatial_to_quaternion(mat): return round(qx, 13), round(-qy, 13), round(-qz, 13), round(qw, 13) else: - raise RuntimeError("Supplied matrix to spatial_to_quaternion is not a 1D spatial matrix in size.") + raise RuntimeError( + "Supplied matrix to spatial_to_quaternion is not a 1D spatial matrix in size." + ) def normalize_quaternion(x, y, z, w): diff --git a/exporter/SynthesisFusionAddin/src/Types.py b/exporter/SynthesisFusionAddin/src/Types.py index 1aca3a5162..d75b916792 100644 --- a/exporter/SynthesisFusionAddin/src/Types.py +++ b/exporter/SynthesisFusionAddin/src/Types.py @@ -110,7 +110,9 @@ def makeObjectFromJson(objType: type, data: any) -> any: return [makeObjectFromJson(objType.__args__[0], item) for item in data] obj = objType() - assert is_dataclass(obj) and isinstance(data, dict), "Found unsupported type to decode." + assert is_dataclass(obj) and isinstance( + data, dict + ), "Found unsupported type to decode." for field in fields(obj): if field.name in data: setattr(obj, field.name, makeObjectFromJson(field.type, data[field.name])) @@ -154,7 +156,11 @@ def __eq__(self, value: object) -> bool: bool: Did the OString objects match? """ if isinstance(value, OString): - if self.path == value.path and self.fileName == value.fileName and self.platform == value.platform: + if ( + self.path == value.path + and self.fileName == value.fileName + and self.platform == value.platform + ): return True return False diff --git a/exporter/SynthesisFusionAddin/src/UI/ConfigCommand.py b/exporter/SynthesisFusionAddin/src/UI/ConfigCommand.py index 4a501b1319..8cec24ef6d 100644 --- a/exporter/SynthesisFusionAddin/src/UI/ConfigCommand.py +++ b/exporter/SynthesisFusionAddin/src/UI/ConfigCommand.py @@ -98,7 +98,9 @@ def bRepMassInRoot(self): for body in gm.app.activeDocument.design.rootComponent.bRepBodies: if not body.isLightBulbOn: continue - physical = body.getPhysicalProperties(adsk.fusion.CalculationAccuracy.LowCalculationAccuracy) + physical = body.getPhysicalProperties( + adsk.fusion.CalculationAccuracy.LowCalculationAccuracy + ) self.totalMass += physical.mass @logFailure(messageBox=True) @@ -110,7 +112,9 @@ def traverseOccurrenceHierarchy(self): for body in occ.component.bRepBodies: if not body.isLightBulbOn: continue - physical = body.getPhysicalProperties(adsk.fusion.CalculationAccuracy.LowCalculationAccuracy) + physical = body.getPhysicalProperties( + adsk.fusion.CalculationAccuracy.LowCalculationAccuracy + ) self.totalMass += physical.mass def getTotalMass(self): @@ -179,7 +183,9 @@ def notify(self, args): # ~~~~~~~~~~~~~~~~ EXPORT LOCATION ~~~~~~~~~~~~~~~~~~ dropdownExportLocation = inputs.addDropDownCommandInput( - "location", "Export Location", dropDownStyle=adsk.core.DropDownStyles.LabeledIconDropDownStyle + "location", + "Export Location", + dropDownStyle=adsk.core.DropDownStyles.LabeledIconDropDownStyle, ) upload: bool = exporterOptions.exportLocation == ExportLocation.UPLOAD @@ -187,9 +193,7 @@ def notify(self, args): dropdownExportLocation.listItems.add("Download", not upload) dropdownExportLocation.tooltip = "Export Location" - dropdownExportLocation.tooltipDescription = ( - "
Do you want to upload this mirabuf file to APS, or download it to your local machine?" - ) + dropdownExportLocation.tooltipDescription = "
Do you want to upload this mirabuf file to APS, or download it to your local machine?" # ~~~~~~~~~~~~~~~~ WEIGHT CONFIGURATION ~~~~~~~~~~~~~~~~ """ @@ -204,7 +208,9 @@ def notify(self, args): "3:2:2:1", 1, ) - weightTableInput.tablePresentationStyle = 2 # set transparent background for table + weightTableInput.tablePresentationStyle = ( + 2 # set transparent background for table + ) weight_name = inputs.addStringValueInput("weight_name", "Weight") weight_name.value = "Weight" @@ -248,12 +254,22 @@ def notify(self, args): weight_unit.listItems.add("‎", imperialUnits, IconPaths.massIcons["LBS"]) weight_unit.listItems.add("‎", not imperialUnits, IconPaths.massIcons["KG"]) weight_unit.tooltip = "Unit of mass" - weight_unit.tooltipDescription = "
Configure the unit of mass for the weight calculation." + weight_unit.tooltipDescription = ( + "
Configure the unit of mass for the weight calculation." + ) - weightTableInput.addCommandInput(weight_name, 0, 0) # add command inputs to table - weightTableInput.addCommandInput(auto_calc_weight, 0, 1) # add command inputs to table - weightTableInput.addCommandInput(weight_input, 0, 2) # add command inputs to table - weightTableInput.addCommandInput(weight_unit, 0, 3) # add command inputs to table + weightTableInput.addCommandInput( + weight_name, 0, 0 + ) # add command inputs to table + weightTableInput.addCommandInput( + auto_calc_weight, 0, 1 + ) # add command inputs to table + weightTableInput.addCommandInput( + weight_input, 0, 2 + ) # add command inputs to table + weightTableInput.addCommandInput( + weight_unit, 0, 3 + ) # add command inputs to table global jointConfigTab jointConfigTab = JointConfigTab(args) @@ -263,7 +279,9 @@ def notify(self, args): # Should investigate changes to improve performance. if exporterOptions.joints: for synJoint in exporterOptions.joints: - fusionJoint = gm.app.activeDocument.design.findEntityByToken(synJoint.jointToken)[0] + fusionJoint = gm.app.activeDocument.design.findEntityByToken( + synJoint.jointToken + )[0] jointConfigTab.addJoint(fusionJoint, synJoint) else: for joint in [ @@ -271,7 +289,8 @@ def notify(self, args): *gm.app.activeDocument.design.rootComponent.allAsBuiltJoints, ]: if ( - joint.jointMotion.jointType in (JointMotions.REVOLUTE.value, JointMotions.SLIDER.value) + joint.jointMotion.jointType + in (JointMotions.REVOLUTE.value, JointMotions.SLIDER.value) and not joint.isSuppressed ): jointConfigTab.addJoint(joint) @@ -281,7 +300,9 @@ def notify(self, args): # Should consider changing how the parser handles wheels and joints to avoid overlap if exporterOptions.wheels: for wheel in exporterOptions.wheels: - fusionJoint = gm.app.activeDocument.design.findEntityByToken(wheel.jointToken)[0] + fusionJoint = gm.app.activeDocument.design.findEntityByToken( + wheel.jointToken + )[0] jointConfigTab.addWheel(fusionJoint, wheel) # ~~~~~~~~~~~~~~~~ GAMEPIECE CONFIGURATION ~~~~~~~~~~~~~~~~ @@ -289,7 +310,9 @@ def notify(self, args): Gamepiece group command input, isVisible=False by default - Container for gamepiece selection table """ - gamepieceConfig = inputs.addGroupCommandInput("gamepiece_config", "Gamepiece Configuration") + gamepieceConfig = inputs.addGroupCommandInput( + "gamepiece_config", "Gamepiece Configuration" + ) gamepieceConfig.isExpanded = True gamepieceConfig.isVisible = False gamepieceConfig.tooltip = "Select and define the gamepieces in your field." @@ -299,7 +322,9 @@ def notify(self, args): """ Mass unit dropdown and calculation for gamepiece elements """ - weightTableInput_f = self.createTableInput("weight_table_f", "Weight Table", gamepiece_inputs, 3, "6:2:1", 1) + weightTableInput_f = self.createTableInput( + "weight_table_f", "Weight Table", gamepiece_inputs, 3, "6:2:1", 1 + ) weightTableInput_f.tablePresentationStyle = 2 # set to clear background weight_name_f = gamepiece_inputs.addStringValueInput("weight_name", "Weight") @@ -323,14 +348,26 @@ def notify(self, args): "Unit of Mass", adsk.core.DropDownStyles.LabeledIconDropDownStyle, ) - weight_unit_f.listItems.add("‎", True, IconPaths.massIcons["LBS"]) # add listdropdown mass options - weight_unit_f.listItems.add("‎", False, IconPaths.massIcons["KG"]) # add listdropdown mass options + weight_unit_f.listItems.add( + "‎", True, IconPaths.massIcons["LBS"] + ) # add listdropdown mass options + weight_unit_f.listItems.add( + "‎", False, IconPaths.massIcons["KG"] + ) # add listdropdown mass options weight_unit_f.tooltip = "Unit of mass" - weight_unit_f.tooltipDescription = "
Configure the unit of mass for for the weight calculation." + weight_unit_f.tooltipDescription = ( + "
Configure the unit of mass for for the weight calculation." + ) - weightTableInput_f.addCommandInput(weight_name_f, 0, 0) # add command inputs to table - weightTableInput_f.addCommandInput(auto_calc_weight_f, 0, 1) # add command inputs to table - weightTableInput_f.addCommandInput(weight_unit_f, 0, 2) # add command inputs to table + weightTableInput_f.addCommandInput( + weight_name_f, 0, 0 + ) # add command inputs to table + weightTableInput_f.addCommandInput( + auto_calc_weight_f, 0, 1 + ) # add command inputs to table + weightTableInput_f.addCommandInput( + weight_unit_f, 0, 2 + ) # add command inputs to table # GAMEPIECE SELECTION TABLE """ @@ -347,7 +384,9 @@ def notify(self, args): addFieldInput = gamepiece_inputs.addBoolValueInput("field_add", "Add", False) - removeFieldInput = gamepiece_inputs.addBoolValueInput("field_delete", "Remove", False) + removeFieldInput = gamepiece_inputs.addBoolValueInput( + "field_delete", "Remove", False + ) addFieldInput.isEnabled = removeFieldInput.isEnabled = True removeFieldInput.tooltip = "Remove a field element" @@ -409,17 +448,19 @@ def notify(self, args): """ Creates the advanced tab, which is the parent container for internal command inputs """ - advancedSettings: adsk.core.TabCommandInput = INPUTS_ROOT.addTabCommandInput("advanced_settings", "Advanced") - advancedSettings.tooltip = ( - "Additional Advanced Settings to change how your model will be translated into Unity." + advancedSettings: adsk.core.TabCommandInput = INPUTS_ROOT.addTabCommandInput( + "advanced_settings", "Advanced" ) + advancedSettings.tooltip = "Additional Advanced Settings to change how your model will be translated into Unity." a_input: adsk.core.CommandInputs = advancedSettings.children # ~~~~~~~~~~~~~~~~ EXPORTER SETTINGS ~~~~~~~~~~~~~~~~ """ Exporter settings group command """ - exporterSettings = a_input.addGroupCommandInput("exporter_settings", "Exporter Settings") + exporterSettings = a_input.addGroupCommandInput( + "exporter_settings", "Exporter Settings" + ) exporterSettings.isExpanded = True exporterSettings.isEnabled = True exporterSettings.tooltip = "tooltip" # TODO: update tooltip @@ -466,20 +507,26 @@ def notify(self, args): enabled=True, isCheckBox=False, ) - frictionOverrideInput.resourceFolder = IconPaths.stringIcons["friction_override-enabled"] + frictionOverrideInput.resourceFolder = IconPaths.stringIcons[ + "friction_override-enabled" + ] frictionOverrideInput.isFullWidth = True valueList = [1] for i in range(20): valueList.append(i / 20) - frictionCoeffSlider: adsk.core.FloatSliderCommandInput = physics_settings.addFloatSliderListCommandInput( - "friction_override_coeff", "Friction Coefficient", "", valueList + frictionCoeffSlider: adsk.core.FloatSliderCommandInput = ( + physics_settings.addFloatSliderListCommandInput( + "friction_override_coeff", "Friction Coefficient", "", valueList + ) ) frictionCoeffSlider.isVisible = True frictionCoeffSlider.valueOne = 0.5 frictionCoeffSlider.tooltip = "Friction coefficient of field element." - frictionCoeffSlider.tooltipDescription = "Friction coefficients range from 0 (ice) to 1 (rubber)." + frictionCoeffSlider.tooltipDescription = ( + "Friction coefficients range from 0 (ice) to 1 (rubber)." + ) # ~~~~~~~~~~~~~~~~ JOINT SETTINGS ~~~~~~~~~~~~~~~~ """ @@ -553,7 +600,8 @@ def notify(self, args): getAuth() user_info = getUserInfo() apsSettings = INPUTS_ROOT.addTabCommandInput( - "aps_settings", f"APS Settings ({user_info.given_name if user_info else 'Not Signed In'})" + "aps_settings", + f"APS Settings ({user_info.given_name if user_info else 'Not Signed In'})", ) apsSettings.tooltip = "Configuration settings for Autodesk Platform Services." @@ -777,7 +825,9 @@ def notify(self, args): isRobot = False dropdownExportLocation = INPUTS_ROOT.itemById("location") if dropdownExportLocation.selectedItem.index == 1: # Download - savepath = FileDialogConfig.saveFileDialog(defaultPath=exporterOptions.fileLocation) + savepath = FileDialogConfig.saveFileDialog( + defaultPath=exporterOptions.fileLocation + ) if savepath == False: # save was canceled @@ -809,12 +859,16 @@ def notify(self, args): if row == 0: continue - weightValue = gamepieceTableInput.getInputAtPosition(row, 2).value # weight/mass input, float + weightValue = gamepieceTableInput.getInputAtPosition( + row, 2 + ).value # weight/mass input, float if weight_unit_f.selectedItem.index == 0: weightValue /= 2.2046226218 - frictionValue = gamepieceTableInput.getInputAtPosition(row, 3).valueOne # friction value, float + frictionValue = gamepieceTableInput.getInputAtPosition( + row, 3 + ).valueOne # friction value, float _exportGamepieces.append( Gamepiece( @@ -970,7 +1024,9 @@ def __init__(self, cmd): self.cmd = cmd self.allWheelPreselections = [] # all child occurrences of selections - self.allGamepiecePreselections = [] # all child gamepiece occurrences of selections + self.allGamepiecePreselections = ( + [] + ) # all child gamepiece occurrences of selections self.selectedOcc = None # selected occurrence (if there is one) self.selectedJoint = None # selected joint (if there is one) @@ -1027,12 +1083,18 @@ def wheelParent(self, occ: adsk.fusion.Occurrence): try: for joint in occ.joints: - if joint.jointMotion.jointType == adsk.fusion.JointTypes.RevoluteJointType: + if ( + joint.jointMotion.jointType + == adsk.fusion.JointTypes.RevoluteJointType + ): # gm.ui.messageBox("Selection is directly jointed.\nReturning selection.\n\n" + "Occurrence:\n--> " + occ.name + "\nJoint:\n--> " + joint.name) return [joint.entityToken, occ] except: for joint in occ.component.joints: - if joint.jointMotion.jointType == adsk.fusion.JointTypes.RevoluteJointType: + if ( + joint.jointMotion.jointType + == adsk.fusion.JointTypes.RevoluteJointType + ): # gm.ui.messageBox("Selection is directly jointed.\nReturning selection.\n\n" + "Occurrence:\n--> " + occ.name + "\nJoint:\n--> " + joint.name) return [joint.entityToken, occ] @@ -1184,7 +1246,9 @@ def notify(self, args): preSelectedJoint = adsk.fusion.Joint.cast(args.selection.entity) if (preSelectedOcc or preSelectedJoint) and design: - self.cmd.setCursor("", 0, 0) # if preselection ends (mouse off of design), reset the mouse icon to default + self.cmd.setCursor( + "", 0, 0 + ) # if preselection ends (mouse off of design), reset the mouse icon to default class ConfigureCommandInputChanged(adsk.core.InputChangedEventHandler): @@ -1285,7 +1349,11 @@ def notify(self, args): gm.ui.activeSelections.clear() gm.app.activeDocument.design.rootComponent.opacity = 1 - elif cmdInput.id == "blank_gp" or cmdInput.id == "name_gp" or cmdInput.id == "weight_gp": + elif ( + cmdInput.id == "blank_gp" + or cmdInput.id == "name_gp" + or cmdInput.id == "weight_gp" + ): self.reset() gamepieceSelect.isEnabled = False @@ -1294,13 +1362,33 @@ def notify(self, args): cmdInput_str = cmdInput.id if cmdInput_str == "name_gp": - position = gamepieceTableInput.getPosition(adsk.core.TextBoxCommandInput.cast(cmdInput))[1] - 1 + position = ( + gamepieceTableInput.getPosition( + adsk.core.TextBoxCommandInput.cast(cmdInput) + )[1] + - 1 + ) elif cmdInput_str == "weight_gp": - position = gamepieceTableInput.getPosition(adsk.core.ValueCommandInput.cast(cmdInput))[1] - 1 + position = ( + gamepieceTableInput.getPosition( + adsk.core.ValueCommandInput.cast(cmdInput) + )[1] + - 1 + ) elif cmdInput_str == "blank_gp": - position = gamepieceTableInput.getPosition(adsk.core.ImageCommandInput.cast(cmdInput))[1] - 1 + position = ( + gamepieceTableInput.getPosition( + adsk.core.ImageCommandInput.cast(cmdInput) + )[1] + - 1 + ) else: - position = gamepieceTableInput.getPosition(adsk.core.FloatSliderCommandInput.cast(cmdInput))[1] - 1 + position = ( + gamepieceTableInput.getPosition( + adsk.core.FloatSliderCommandInput.cast(cmdInput) + )[1] + - 1 + ) gm.ui.activeSelections.add(GamepieceListGlobal[position]) @@ -1317,7 +1405,10 @@ def notify(self, args): addFieldInput.isEnabled = True - if gamepieceTableInput.selectedRow == -1 or gamepieceTableInput.selectedRow == 0: + if ( + gamepieceTableInput.selectedRow == -1 + or gamepieceTableInput.selectedRow == 0 + ): gamepieceTableInput.selectedRow = gamepieceTableInput.rowCount - 1 gm.ui.messageBox("Select a row to delete.") else: @@ -1341,15 +1432,11 @@ def notify(self, args): if unitDropdown.selectedItem.index == 0: self.isLbs = True - weightInput.tooltipDescription = ( - """(in pounds)
This is the weight of the entire robot assembly.""" - ) + weightInput.tooltipDescription = """(in pounds)
This is the weight of the entire robot assembly.""" elif unitDropdown.selectedItem.index == 1: self.isLbs = False - weightInput.tooltipDescription = ( - """(in kilograms)
This is the weight of the entire robot assembly.""" - ) + weightInput.tooltipDescription = """(in kilograms)
This is the weight of the entire robot assembly.""" elif cmdInput.id == "weight_unit_f": unitDropdown = adsk.core.DropDownCommandInput.cast(cmdInput) @@ -1374,7 +1461,9 @@ def notify(self, args): button = adsk.core.BoolValueCommandInput.cast(cmdInput) if button.value == True: # CALCULATE button pressed - if self.allWeights.count(None) == 2: # if button is pressed for the first time + if ( + self.allWeights.count(None) == 2 + ): # if button is pressed for the first time if self.isLbs: # if pounds unit selected self.allWeights[0] = self.weight() weight_input.value = self.allWeights[0] @@ -1401,7 +1490,9 @@ def notify(self, args): if row == 0: continue weightInput = gamepieceTableInput.getInputAtPosition(row, 2) - physical = GamepieceListGlobal[row - 1].component.getPhysicalProperties( + physical = GamepieceListGlobal[ + row - 1 + ].component.getPhysicalProperties( adsk.fusion.CalculationAccuracy.LowCalculationAccuracy ) value = round(physical.mass * 2.2046226218, 2) @@ -1412,7 +1503,9 @@ def notify(self, args): if row == 0: continue weightInput = gamepieceTableInput.getInputAtPosition(row, 2) - physical = GamepieceListGlobal[row - 1].component.getPhysicalProperties( + physical = GamepieceListGlobal[ + row - 1 + ].component.getPhysicalProperties( adsk.fusion.CalculationAccuracy.LowCalculationAccuracy ) value = round(physical.mass, 2) @@ -1475,12 +1568,18 @@ def addPreselections(child_occurrences): GamepieceListGlobal.append(gamepiece) cmdInputs = adsk.core.CommandInputs.cast(gamepieceTableInput.commandInputs) - blankIcon = cmdInputs.addImageCommandInput("blank_gp", "Blank", IconPaths.gamepieceIcons["blank"]) + blankIcon = cmdInputs.addImageCommandInput( + "blank_gp", "Blank", IconPaths.gamepieceIcons["blank"] + ) - type = cmdInputs.addTextBoxCommandInput("name_gp", "Occurrence name", gamepiece.name, 1, True) + type = cmdInputs.addTextBoxCommandInput( + "name_gp", "Occurrence name", gamepiece.name, 1, True + ) value = 0.0 - physical = gamepiece.component.getPhysicalProperties(adsk.fusion.CalculationAccuracy.LowCalculationAccuracy) + physical = gamepiece.component.getPhysicalProperties( + adsk.fusion.CalculationAccuracy.LowCalculationAccuracy + ) value = physical.mass # check if dropdown unit is kg or lbs. bool value taken from ConfigureCommandInputChanged @@ -1504,7 +1603,9 @@ def addPreselections(child_occurrences): for i in range(20): valueList.append(i / 20) - friction_coeff = cmdInputs.addFloatSliderListCommandInput("friction_coeff", "", "", valueList) + friction_coeff = cmdInputs.addFloatSliderListCommandInput( + "friction_coeff", "", "", valueList + ) friction_coeff.valueOne = 0.5 type.tooltip = gamepiece.name @@ -1513,7 +1614,9 @@ def addPreselections(child_occurrences): weight.tooltipDescription = massUnitInString friction_coeff.tooltip = "Friction coefficient of field element" - friction_coeff.tooltipDescription = "Friction coefficients range from 0 (ice) to 1 (rubber)." + friction_coeff.tooltipDescription = ( + "Friction coefficients range from 0 (ice) to 1 (rubber)." + ) row = gamepieceTableInput.rowCount gamepieceTableInput.addCommandInput(blankIcon, row, 0) diff --git a/exporter/SynthesisFusionAddin/src/UI/CustomGraphics.py b/exporter/SynthesisFusionAddin/src/UI/CustomGraphics.py index 52a49fa5d4..1c6a5c8b3f 100644 --- a/exporter/SynthesisFusionAddin/src/UI/CustomGraphics.py +++ b/exporter/SynthesisFusionAddin/src/UI/CustomGraphics.py @@ -22,14 +22,20 @@ def createTextGraphics(wheel: adsk.fusion.Occurrence, _wheels) -> None: matrix = adsk.core.Matrix3D.create() matrix.translation = adsk.core.Vector3D.create(min[0], min[1] - 5, min[2]) - billBoard = adsk.fusion.CustomGraphicsBillBoard.create(adsk.core.Point3D.create(0, 0, 0)) - billBoard.billBoardStyle = adsk.fusion.CustomGraphicsBillBoardStyles.ScreenBillBoardStyle + billBoard = adsk.fusion.CustomGraphicsBillBoard.create( + adsk.core.Point3D.create(0, 0, 0) + ) + billBoard.billBoardStyle = ( + adsk.fusion.CustomGraphicsBillBoardStyles.ScreenBillBoardStyle + ) text = str(_wheels.index(wheel) + 1) graphicsText = graphics.addText(text, "Arial Black", 6, matrix) graphicsText.billBoarding = billBoard # make the text follow the camera graphicsText.isSelectable = False # make it non-selectable - graphicsText.cullMode = adsk.fusion.CustomGraphicsCullModes.CustomGraphicsCullBack + graphicsText.cullMode = ( + adsk.fusion.CustomGraphicsCullModes.CustomGraphicsCullBack + ) graphicsText.color = adsk.fusion.CustomGraphicsShowThroughColorEffect.create( adsk.core.Color.create(230, 146, 18, 255), 1 ) # orange/synthesis theme diff --git a/exporter/SynthesisFusionAddin/src/UI/Events.py b/exporter/SynthesisFusionAddin/src/UI/Events.py index 281ebf3f0e..bf96f5b9cc 100644 --- a/exporter/SynthesisFusionAddin/src/UI/Events.py +++ b/exporter/SynthesisFusionAddin/src/UI/Events.py @@ -53,8 +53,12 @@ def openDocument(json_data: str) -> str: """ data = json.loads(json_data) data = data["arguments"] - gm.ui.messageBox(f"Attempting to open and focus on a given document: {data}\n TODO: Implement") - logger.info(f"Attempting to open and focus on a given document: {data}\n TODO: Implement") + gm.ui.messageBox( + f"Attempting to open and focus on a given document: {data}\n TODO: Implement" + ) + logger.info( + f"Attempting to open and focus on a given document: {data}\n TODO: Implement" + ) return "" diff --git a/exporter/SynthesisFusionAddin/src/UI/FileDialogConfig.py b/exporter/SynthesisFusionAddin/src/UI/FileDialogConfig.py index 6f6f764cd9..47f7aba3eb 100644 --- a/exporter/SynthesisFusionAddin/src/UI/FileDialogConfig.py +++ b/exporter/SynthesisFusionAddin/src/UI/FileDialogConfig.py @@ -9,7 +9,9 @@ from ..Types import OString -def saveFileDialog(defaultPath: str | None = None, defaultName: str | None = None) -> str | bool: +def saveFileDialog( + defaultPath: str | None = None, defaultName: str | None = None +) -> str | bool: """Function to generate the Save File Dialog for the Hellion Data files Args: diff --git a/exporter/SynthesisFusionAddin/src/UI/HUI.py b/exporter/SynthesisFusionAddin/src/UI/HUI.py index 3b52de9999..2842e70a78 100644 --- a/exporter/SynthesisFusionAddin/src/UI/HUI.py +++ b/exporter/SynthesisFusionAddin/src/UI/HUI.py @@ -44,7 +44,9 @@ def __init__( self.events.append(arg) if self.uid in gm.uniqueIds: - raise ValueError(f"Cannot create two UI Elements with the same ID {self.uid}\n") + raise ValueError( + f"Cannot create two UI Elements with the same ID {self.uid}\n" + ) if gm.ui.palettes is None: raise RuntimeError(f"No Palette object exists yet") @@ -52,7 +54,9 @@ def __init__( self.palette = gm.ui.palettes.itemById(self.uid) if self.palette is None: - path = OsHelper.getOSPathPalette("src", "Resources", "Palette", f'{self.name.replace(" ", "")}') + path = OsHelper.getOSPathPalette( + "src", "Resources", "Palette", f'{self.name.replace(" ", "")}' + ) self.palette = gm.ui.palettes.add( self.uid, @@ -65,7 +69,9 @@ def __init__( height, ) - self.palette.dockingState = adsk.core.PaletteDockingStates.PaletteDockStateLeft + self.palette.dockingState = ( + adsk.core.PaletteDockingStates.PaletteDockStateLeft + ) onHTML = Handlers.HPaletteHTMLEventHandler(self) self.palette.incomingFromHTML.add(onHTML) @@ -112,7 +118,9 @@ def __init__( self.uid = name.replace(" ", "") + f"_{INTERNAL_ID}" if self.uid in gm.uniqueIds: - raise ValueError(f"Cannot create two UI Elements with the same ID {self.uid}\n") + raise ValueError( + f"Cannot create two UI Elements with the same ID {self.uid}\n" + ) self.name = name @@ -130,7 +138,9 @@ def __init__( self.uid, f"{name}", f"{description}", - OsHelper.getOSPath(".", "src", "Resources", f'{self.name.replace(" ", "")}'), + OsHelper.getOSPath( + ".", "src", "Resources", f'{self.name.replace(" ", "")}' + ), ) """ Button Command Definition stored as a member """ @@ -180,7 +190,9 @@ def deleteMe(self): if cmdDef: cmdDef.deleteMe() - ctrl = gm.ui.allToolbarPanels.itemById(self.location).controls.itemById(self.uid) + ctrl = gm.ui.allToolbarPanels.itemById(self.location).controls.itemById( + self.uid + ) if ctrl: ctrl.deleteMe() diff --git a/exporter/SynthesisFusionAddin/src/UI/Helper.py b/exporter/SynthesisFusionAddin/src/UI/Helper.py index 7c8e3a5930..560f69f9df 100644 --- a/exporter/SynthesisFusionAddin/src/UI/Helper.py +++ b/exporter/SynthesisFusionAddin/src/UI/Helper.py @@ -25,7 +25,9 @@ def checkAttribute() -> bool: return connected.value return False except: - app.userInterface.messageBox(f"Could not access the attributes of the file \n -- {traceback.format_exc()}.") + app.userInterface.messageBox( + f"Could not access the attributes of the file \n -- {traceback.format_exc()}." + ) return False @@ -46,7 +48,9 @@ def addUnityAttribute() -> bool or None: return None except: - app.userInterface.messageBox(f"Could not access the attributes of the file \n -- {traceback.format_exc()}.") + app.userInterface.messageBox( + f"Could not access the attributes of the file \n -- {traceback.format_exc()}." + ) return False @@ -67,7 +71,9 @@ def openPanel() -> None: gm.app.data.isDataPanelVisible = False else: func_list = [o for o in getmembers(Events, isfunction)] - palette_new = HUI.HPalette(name, APP_TITLE, True, True, False, 400, 500, func_list) + palette_new = HUI.HPalette( + name, APP_TITLE, True, True, False, 400, 500, func_list + ) gm.elements.append(palette_new) return diff --git a/exporter/SynthesisFusionAddin/src/UI/IconPaths.py b/exporter/SynthesisFusionAddin/src/UI/IconPaths.py index 261720494c..f5f9017b4e 100644 --- a/exporter/SynthesisFusionAddin/src/UI/IconPaths.py +++ b/exporter/SynthesisFusionAddin/src/UI/IconPaths.py @@ -5,20 +5,27 @@ """ Dictionaries that store all the icon paths in ConfigCommand. All path strings are OS-independent """ -resources = OsHelper.getOSPath(".", "src", "Resources") # str shortcut with primary directories to all images in file +resources = OsHelper.getOSPath( + ".", "src", "Resources" +) # str shortcut with primary directories to all images in file wheelIcons = { "omni": resources + os.path.join("WheelIcons", "omni-wheel-preview190x24.png"), - "standard": resources + os.path.join("WheelIcons", "standard-wheel-preview190x24.png"), - "mecanum": resources + os.path.join("WheelIcons", "mecanum-wheel-preview190x24.png"), + "standard": resources + + os.path.join("WheelIcons", "standard-wheel-preview190x24.png"), + "mecanum": resources + + os.path.join("WheelIcons", "mecanum-wheel-preview190x24.png"), } jointIcons = { "rigid": resources + os.path.join("JointIcons", "JointRigid", "rigid190x24.png"), - "revolute": resources + os.path.join("JointIcons", "JointRev", "revolute190x24.png"), + "revolute": resources + + os.path.join("JointIcons", "JointRev", "revolute190x24.png"), "slider": resources + os.path.join("JointIcons", "JointSlider", "slider190x24.png"), - "cylindrical": resources + os.path.join("JointIcons", "JointCyl", "cylindrical190x24.png"), - "pin_slot": resources + os.path.join("JointIcons", "JointPinSlot", "pin_slot190x24.png"), + "cylindrical": resources + + os.path.join("JointIcons", "JointCyl", "cylindrical190x24.png"), + "pin_slot": resources + + os.path.join("JointIcons", "JointPinSlot", "pin_slot190x24.png"), "planar": resources + os.path.join("JointIcons", "JointPlanar", "planar190x24.png"), "ball": resources + os.path.join("JointIcons", "JointBall", "ball190x24.png"), } @@ -44,6 +51,8 @@ } stringIcons = { - "calculate-enabled": resources + os.path.join("AutoCalcWeight_icon"), # resource folder - "friction_override-enabled": resources + os.path.join("FrictionOverride_icon"), # resource folder + "calculate-enabled": resources + + os.path.join("AutoCalcWeight_icon"), # resource folder + "friction_override-enabled": resources + + os.path.join("FrictionOverride_icon"), # resource folder } diff --git a/exporter/SynthesisFusionAddin/src/UI/JointConfigTab.py b/exporter/SynthesisFusionAddin/src/UI/JointConfigTab.py index 4f25ebfe01..30304f8b90 100644 --- a/exporter/SynthesisFusionAddin/src/UI/JointConfigTab.py +++ b/exporter/SynthesisFusionAddin/src/UI/JointConfigTab.py @@ -26,38 +26,84 @@ class JointConfigTab: @logFailure def __init__(self, args: adsk.core.CommandCreatedEventArgs) -> None: inputs = args.command.commandInputs - self.jointConfigTab = inputs.addTabCommandInput("jointSettings", "Joint Settings") + self.jointConfigTab = inputs.addTabCommandInput( + "jointSettings", "Joint Settings" + ) self.jointConfigTab.tooltip = "Select and configure robot joints." jointConfigTabInputs = self.jointConfigTab.children - self.jointConfigTable = createTableInput("jointTable", "Joint Table", jointConfigTabInputs, 7, "1:2:2:2:2:2:2") + self.jointConfigTable = createTableInput( + "jointTable", "Joint Table", jointConfigTabInputs, 7, "1:2:2:2:2:2:2" + ) self.jointConfigTable.addCommandInput( - createTextBoxInput("jointMotionHeader", "Motion", jointConfigTabInputs, "Motion", bold=False), 0, 0 + createTextBoxInput( + "jointMotionHeader", + "Motion", + jointConfigTabInputs, + "Motion", + bold=False, + ), + 0, + 0, ) self.jointConfigTable.addCommandInput( - createTextBoxInput("nameHeader", "Name", jointConfigTabInputs, "Joint name", bold=False), 0, 1 + createTextBoxInput( + "nameHeader", "Name", jointConfigTabInputs, "Joint name", bold=False + ), + 0, + 1, ) self.jointConfigTable.addCommandInput( - createTextBoxInput("parentHeader", "Parent", jointConfigTabInputs, "Parent joint", background="#d9d9d9"), + createTextBoxInput( + "parentHeader", + "Parent", + jointConfigTabInputs, + "Parent joint", + background="#d9d9d9", + ), 0, 2, ) self.jointConfigTable.addCommandInput( - createTextBoxInput("signalHeader", "Signal", jointConfigTabInputs, "Signal type", background="#d9d9d9"), + createTextBoxInput( + "signalHeader", + "Signal", + jointConfigTabInputs, + "Signal type", + background="#d9d9d9", + ), 0, 3, ) self.jointConfigTable.addCommandInput( - createTextBoxInput("speedHeader", "Speed", jointConfigTabInputs, "Joint Speed", background="#d9d9d9"), + createTextBoxInput( + "speedHeader", + "Speed", + jointConfigTabInputs, + "Joint Speed", + background="#d9d9d9", + ), 0, 4, ) self.jointConfigTable.addCommandInput( - createTextBoxInput("forceHeader", "Force", jointConfigTabInputs, "Joint Force", background="#d9d9d9"), + createTextBoxInput( + "forceHeader", + "Force", + jointConfigTabInputs, + "Joint Force", + background="#d9d9d9", + ), 0, 5, ) self.jointConfigTable.addCommandInput( - createTextBoxInput("wheelHeader", "Is Wheel", jointConfigTabInputs, "Is Wheel", background="#d9d9d9"), + createTextBoxInput( + "wheelHeader", + "Is Wheel", + jointConfigTabInputs, + "Is Wheel", + background="#d9d9d9", + ), 0, 6, ) @@ -67,37 +113,69 @@ def __init__(self, args: adsk.core.CommandCreatedEventArgs) -> None: ) jointSelect.addSelectionFilter("Joints") jointSelect.setSelectionLimits(0) - jointSelect.isEnabled = jointSelect.isVisible = False # Visibility is triggered by `addJointInputButton` + jointSelect.isEnabled = jointSelect.isVisible = ( + False # Visibility is triggered by `addJointInputButton` + ) - jointConfigTabInputs.addTextBoxCommandInput("jointTabBlankSpacer", "", "", 1, True) + jointConfigTabInputs.addTextBoxCommandInput( + "jointTabBlankSpacer", "", "", 1, True + ) - self.wheelConfigTable = createTableInput("wheelTable", "Wheel Table", jointConfigTabInputs, 4, "1:2:2:2") + self.wheelConfigTable = createTableInput( + "wheelTable", "Wheel Table", jointConfigTabInputs, 4, "1:2:2:2" + ) self.wheelConfigTable.addCommandInput( - createTextBoxInput("wheelMotionHeader", "Motion", jointConfigTabInputs, "Motion", bold=False), 0, 0 + createTextBoxInput( + "wheelMotionHeader", + "Motion", + jointConfigTabInputs, + "Motion", + bold=False, + ), + 0, + 0, ) self.wheelConfigTable.addCommandInput( - createTextBoxInput("name_header", "Name", jointConfigTabInputs, "Joint name", bold=False), 0, 1 + createTextBoxInput( + "name_header", "Name", jointConfigTabInputs, "Joint name", bold=False + ), + 0, + 1, ) self.wheelConfigTable.addCommandInput( createTextBoxInput( - "wheelTypeHeader", "WheelType", jointConfigTabInputs, "Wheel type", background="#d9d9d9" + "wheelTypeHeader", + "WheelType", + jointConfigTabInputs, + "Wheel type", + background="#d9d9d9", ), 0, 2, ) self.wheelConfigTable.addCommandInput( createTextBoxInput( - "signalTypeHeader", "SignalType", jointConfigTabInputs, "Signal type", background="#d9d9d9" + "signalTypeHeader", + "SignalType", + jointConfigTabInputs, + "Signal type", + background="#d9d9d9", ), 0, 3, ) - jointSelectCancelButton = jointConfigTabInputs.addBoolValueInput("jointSelectCancelButton", "Cancel", False) + jointSelectCancelButton = jointConfigTabInputs.addBoolValueInput( + "jointSelectCancelButton", "Cancel", False + ) jointSelectCancelButton.isEnabled = jointSelectCancelButton.isVisible = False - addJointInputButton = jointConfigTabInputs.addBoolValueInput("jointAddButton", "Add", False) - removeJointInputButton = jointConfigTabInputs.addBoolValueInput("jointRemoveButton", "Remove", False) + addJointInputButton = jointConfigTabInputs.addBoolValueInput( + "jointAddButton", "Add", False + ) + removeJointInputButton = jointConfigTabInputs.addBoolValueInput( + "jointRemoveButton", "Remove", False + ) addJointInputButton.isEnabled = removeJointInputButton.isEnabled = True self.jointConfigTable.addToolbarCommandInput(addJointInputButton) @@ -107,7 +185,9 @@ def __init__(self, args: adsk.core.CommandCreatedEventArgs) -> None: self.reset() @logFailure - def addJoint(self, fusionJoint: adsk.fusion.Joint, synJoint: Joint | None = None) -> bool: + def addJoint( + self, fusionJoint: adsk.fusion.Joint, synJoint: Joint | None = None + ) -> bool: if fusionJoint in self.selectedJointList: return False @@ -115,34 +195,62 @@ def addJoint(self, fusionJoint: adsk.fusion.Joint, synJoint: Joint | None = None commandInputs = self.jointConfigTable.commandInputs if fusionJoint.jointMotion.jointType == adsk.fusion.JointTypes.RigidJointType: - icon = commandInputs.addImageCommandInput("placeholder", "Rigid", IconPaths.jointIcons["rigid"]) + icon = commandInputs.addImageCommandInput( + "placeholder", "Rigid", IconPaths.jointIcons["rigid"] + ) icon.tooltip = "Rigid joint" - elif fusionJoint.jointMotion.jointType == adsk.fusion.JointTypes.RevoluteJointType: - icon = commandInputs.addImageCommandInput("placeholder", "Revolute", IconPaths.jointIcons["revolute"]) + elif ( + fusionJoint.jointMotion.jointType + == adsk.fusion.JointTypes.RevoluteJointType + ): + icon = commandInputs.addImageCommandInput( + "placeholder", "Revolute", IconPaths.jointIcons["revolute"] + ) icon.tooltip = "Revolute joint" - elif fusionJoint.jointMotion.jointType == adsk.fusion.JointTypes.SliderJointType: - icon = commandInputs.addImageCommandInput("placeholder", "Slider", IconPaths.jointIcons["slider"]) + elif ( + fusionJoint.jointMotion.jointType == adsk.fusion.JointTypes.SliderJointType + ): + icon = commandInputs.addImageCommandInput( + "placeholder", "Slider", IconPaths.jointIcons["slider"] + ) icon.tooltip = "Slider joint" - elif fusionJoint.jointMotion.jointType == adsk.fusion.JointTypes.PlanarJointType: - icon = commandInputs.addImageCommandInput("placeholder", "Planar", IconPaths.jointIcons["planar"]) + elif ( + fusionJoint.jointMotion.jointType == adsk.fusion.JointTypes.PlanarJointType + ): + icon = commandInputs.addImageCommandInput( + "placeholder", "Planar", IconPaths.jointIcons["planar"] + ) icon.tooltip = "Planar joint" - elif fusionJoint.jointMotion.jointType == adsk.fusion.JointTypes.PinSlotJointType: - icon = commandInputs.addImageCommandInput("placeholder", "Pin Slot", IconPaths.jointIcons["pin_slot"]) + elif ( + fusionJoint.jointMotion.jointType == adsk.fusion.JointTypes.PinSlotJointType + ): + icon = commandInputs.addImageCommandInput( + "placeholder", "Pin Slot", IconPaths.jointIcons["pin_slot"] + ) icon.tooltip = "Pin slot joint" - elif fusionJoint.jointMotion.jointType == adsk.fusion.JointTypes.CylindricalJointType: - icon = commandInputs.addImageCommandInput("placeholder", "Cylindrical", IconPaths.jointIcons["cylindrical"]) + elif ( + fusionJoint.jointMotion.jointType + == adsk.fusion.JointTypes.CylindricalJointType + ): + icon = commandInputs.addImageCommandInput( + "placeholder", "Cylindrical", IconPaths.jointIcons["cylindrical"] + ) icon.tooltip = "Cylindrical joint" elif fusionJoint.jointMotion.jointType == adsk.fusion.JointTypes.BallJointType: - icon = commandInputs.addImageCommandInput("placeholder", "Ball", IconPaths.jointIcons["ball"]) + icon = commandInputs.addImageCommandInput( + "placeholder", "Ball", IconPaths.jointIcons["ball"] + ) icon.tooltip = "Ball joint" - name = commandInputs.addTextBoxCommandInput("name_j", "Occurrence name", "", 1, True) + name = commandInputs.addTextBoxCommandInput( + "name_j", "Occurrence name", "", 1, True + ) name.tooltip = fusionJoint.name name.formattedText = f"

{fusionJoint.name}

" @@ -166,7 +274,9 @@ def addJoint(self, fusionJoint: adsk.fusion.Joint, synJoint: Joint | None = None jointType.listItems.add(fusionJoint.name, False) jointType.tooltip = "Possible parent joints" - jointType.tooltipDescription = "
The root component is usually the parent." + jointType.tooltipDescription = ( + "
The root component is usually the parent." + ) signalType = commandInputs.addDropDownCommandInput( "signalTypeJoint", @@ -177,9 +287,17 @@ def addJoint(self, fusionJoint: adsk.fusion.Joint, synJoint: Joint | None = None # Invisible white space characters are required in the list item name field to make this work. # I have no idea why, Fusion API needs some special education help - Brandon if synJoint: - signalType.listItems.add("‎", synJoint.signalType is SignalType.PWM, IconPaths.signalIcons["PWM"]) - signalType.listItems.add("‎", synJoint.signalType is SignalType.CAN, IconPaths.signalIcons["CAN"]) - signalType.listItems.add("‎", synJoint.signalType is SignalType.PASSIVE, IconPaths.signalIcons["PASSIVE"]) + signalType.listItems.add( + "‎", synJoint.signalType is SignalType.PWM, IconPaths.signalIcons["PWM"] + ) + signalType.listItems.add( + "‎", synJoint.signalType is SignalType.CAN, IconPaths.signalIcons["CAN"] + ) + signalType.listItems.add( + "‎", + synJoint.signalType is SignalType.PASSIVE, + IconPaths.signalIcons["PASSIVE"], + ) else: signalType.listItems.add("‎", True, IconPaths.signalIcons["PWM"]) signalType.listItems.add("‎", False, IconPaths.signalIcons["CAN"]) @@ -194,7 +312,10 @@ def addJoint(self, fusionJoint: adsk.fusion.Joint, synJoint: Joint | None = None self.jointConfigTable.addCommandInput(signalType, row, 3) # Comparison by `==` over `is` because the Autodesk API does not use `Enum` for their enum classes - if fusionJoint.jointMotion.jointType == adsk.fusion.JointTypes.RevoluteJointType: + if ( + fusionJoint.jointMotion.jointType + == adsk.fusion.JointTypes.RevoluteJointType + ): if synJoint: jointSpeedValue = synJoint.speed else: @@ -209,7 +330,9 @@ def addJoint(self, fusionJoint: adsk.fusion.Joint, synJoint: Joint | None = None jointSpeed.tooltip = "Degrees per second" self.jointConfigTable.addCommandInput(jointSpeed, row, 4) - elif fusionJoint.jointMotion.jointType == adsk.fusion.JointTypes.SliderJointType: + elif ( + fusionJoint.jointMotion.jointType == adsk.fusion.JointTypes.SliderJointType + ): if synJoint: jointSpeedValue = synJoint.speed else: @@ -225,19 +348,29 @@ def addJoint(self, fusionJoint: adsk.fusion.Joint, synJoint: Joint | None = None self.jointConfigTable.addCommandInput(jointSpeed, row, 4) if synJoint: - jointForceValue = synJoint.force * 100 # Currently a factor of 100 - Should be investigated + jointForceValue = ( + synJoint.force * 100 + ) # Currently a factor of 100 - Should be investigated else: jointForceValue = 5 jointForce = commandInputs.addValueInput( - "jointForce", "Force", "N", adsk.core.ValueInput.createByReal(jointForceValue) + "jointForce", + "Force", + "N", + adsk.core.ValueInput.createByReal(jointForceValue), ) jointForce.tooltip = "Newtons" self.jointConfigTable.addCommandInput(jointForce, row, 5) - if fusionJoint.jointMotion.jointType == adsk.fusion.JointTypes.RevoluteJointType: + if ( + fusionJoint.jointMotion.jointType + == adsk.fusion.JointTypes.RevoluteJointType + ): wheelCheckboxEnabled = True - wheelCheckboxTooltip = "Determines if this joint should be counted as a wheel." + wheelCheckboxTooltip = ( + "Determines if this joint should be counted as a wheel." + ) else: wheelCheckboxEnabled = False wheelCheckboxTooltip = "Only Revolute joints can be treated as wheels." @@ -270,10 +403,14 @@ def addWheel(self, joint: adsk.fusion.Joint, wheel: Wheel | None = None) -> None "wheelPlaceholder", "Placeholder", IconPaths.wheelIcons["standard"] ) wheelIcon.tooltip = "Standard wheel" - wheelName = commandInputs.addTextBoxCommandInput("wheelName", "Joint Name", joint.name, 1, True) + wheelName = commandInputs.addTextBoxCommandInput( + "wheelName", "Joint Name", joint.name, 1, True + ) wheelName.tooltip = joint.name # TODO: Should this be the same? wheelType = commandInputs.addDropDownCommandInput( - "wheelType", "Wheel Type", dropDownStyle=adsk.core.DropDownStyles.LabeledIconDropDownStyle + "wheelType", + "Wheel Type", + dropDownStyle=adsk.core.DropDownStyles.LabeledIconDropDownStyle, ) selectedWheelType = wheel.wheelType if wheel else WheelType.STANDARD @@ -290,16 +427,28 @@ def addWheel(self, joint: adsk.fusion.Joint, wheel: Wheel | None = None) -> None ) signalType = commandInputs.addDropDownCommandInput( - "wheelSignalType", "Signal Type", dropDownStyle=adsk.core.DropDownStyles.LabeledIconDropDownStyle + "wheelSignalType", + "Signal Type", + dropDownStyle=adsk.core.DropDownStyles.LabeledIconDropDownStyle, ) signalType.isFullWidth = True signalType.isEnabled = False - signalType.tooltip = "Wheel signal type is linked with the respective joint signal type." + signalType.tooltip = ( + "Wheel signal type is linked with the respective joint signal type." + ) i = self.selectedJointList.index(joint) - jointSignalType = SignalType(self.jointConfigTable.getInputAtPosition(i + 1, 3).selectedItem.index + 1) - signalType.listItems.add("‎", jointSignalType is SignalType.PWM, IconPaths.signalIcons["PWM"]) - signalType.listItems.add("‎", jointSignalType is SignalType.CAN, IconPaths.signalIcons["CAN"]) - signalType.listItems.add("‎", jointSignalType is SignalType.PASSIVE, IconPaths.signalIcons["PASSIVE"]) + jointSignalType = SignalType( + self.jointConfigTable.getInputAtPosition(i + 1, 3).selectedItem.index + 1 + ) + signalType.listItems.add( + "‎", jointSignalType is SignalType.PWM, IconPaths.signalIcons["PWM"] + ) + signalType.listItems.add( + "‎", jointSignalType is SignalType.CAN, IconPaths.signalIcons["CAN"] + ) + signalType.listItems.add( + "‎", jointSignalType is SignalType.PASSIVE, IconPaths.signalIcons["PASSIVE"] + ) row = self.wheelConfigTable.rowCount self.wheelConfigTable.addCommandInput(wheelIcon, row, 0) @@ -351,7 +500,9 @@ def getSelectedJointsAndWheels(self) -> tuple[list[Joint], list[Wheel]]: wheels: list[Wheel] = [] for row in range(1, self.jointConfigTable.rowCount): # Row is 1 indexed jointEntityToken = self.selectedJointList[row - 1].entityToken - signalTypeIndex = self.jointConfigTable.getInputAtPosition(row, 3).selectedItem.index + signalTypeIndex = self.jointConfigTable.getInputAtPosition( + row, 3 + ).selectedItem.index signalType = SignalType(signalTypeIndex + 1) jointSpeed: float = self.jointConfigTable.getInputAtPosition(row, 4).value jointForce: float = self.jointConfigTable.getInputAtPosition(row, 5).value @@ -370,7 +521,9 @@ def getSelectedJointsAndWheels(self) -> tuple[list[Joint], list[Wheel]]: if isWheel: wheelRow = self.jointWheelIndexMap[jointEntityToken] - wheelTypeIndex = self.wheelConfigTable.getInputAtPosition(wheelRow, 2).selectedItem.index + wheelTypeIndex = self.wheelConfigTable.getInputAtPosition( + wheelRow, 2 + ).selectedItem.index wheels.append( Wheel( jointEntityToken, @@ -393,13 +546,17 @@ def reset(self) -> None: # commandInput in a input changed handle for some reason. @logFailure def handleInputChanged( - self, args: adsk.core.InputChangedEventArgs, globalCommandInputs: adsk.core.CommandInputs + self, + args: adsk.core.InputChangedEventArgs, + globalCommandInputs: adsk.core.CommandInputs, ) -> None: commandInput = args.input if commandInput.id == "wheelType": wheelTypeDropdown = adsk.core.DropDownCommandInput.cast(commandInput) position = self.wheelConfigTable.getPosition(wheelTypeDropdown)[1] - iconInput: adsk.core.ImageCommandInput = self.wheelConfigTable.getInputAtPosition(position, 0) + iconInput: adsk.core.ImageCommandInput = ( + self.wheelConfigTable.getInputAtPosition(position, 0) + ) if wheelTypeDropdown.selectedItem.index == 0: iconInput.imageFile = IconPaths.wheelIcons["standard"] @@ -414,7 +571,11 @@ def handleInputChanged( elif commandInput.id == "isWheel": isWheelCheckbox = adsk.core.BoolValueCommandInput.cast(commandInput) position = self.jointConfigTable.getPosition(isWheelCheckbox)[1] - 1 - isAlreadyWheel = bool(self.jointWheelIndexMap.get(self.selectedJointList[position].entityToken)) + isAlreadyWheel = bool( + self.jointWheelIndexMap.get( + self.selectedJointList[position].entityToken + ) + ) if isWheelCheckbox.value != self.previousWheelCheckboxState[position]: if not isAlreadyWheel: @@ -426,22 +587,34 @@ def handleInputChanged( elif commandInput.id == "signalTypeJoint": signalTypeDropdown = adsk.core.DropDownCommandInput.cast(commandInput) - jointTabPosition = self.jointConfigTable.getPosition(signalTypeDropdown)[1] # 1 indexed - wheelTabPosition = self.jointWheelIndexMap.get(self.selectedJointList[jointTabPosition - 1].entityToken) + jointTabPosition = self.jointConfigTable.getPosition(signalTypeDropdown)[ + 1 + ] # 1 indexed + wheelTabPosition = self.jointWheelIndexMap.get( + self.selectedJointList[jointTabPosition - 1].entityToken + ) if wheelTabPosition: - wheelSignalItems: adsk.core.DropDownCommandInput = self.wheelConfigTable.getInputAtPosition( - wheelTabPosition, 3 + wheelSignalItems: adsk.core.DropDownCommandInput = ( + self.wheelConfigTable.getInputAtPosition(wheelTabPosition, 3) ) - wheelSignalItems.listItems.item(signalTypeDropdown.selectedItem.index).isSelected = True + wheelSignalItems.listItems.item( + signalTypeDropdown.selectedItem.index + ).isSelected = True elif commandInput.id == "jointAddButton": - jointAddButton: adsk.core.BoolValueCommandInput = globalCommandInputs.itemById("jointAddButton") - jointRemoveButton: adsk.core.BoolValueCommandInput = globalCommandInputs.itemById("jointRemoveButton") - jointSelectCancelButton: adsk.core.BoolValueCommandInput = globalCommandInputs.itemById( - "jointSelectCancelButton" + jointAddButton: adsk.core.BoolValueCommandInput = ( + globalCommandInputs.itemById("jointAddButton") + ) + jointRemoveButton: adsk.core.BoolValueCommandInput = ( + globalCommandInputs.itemById("jointRemoveButton") + ) + jointSelectCancelButton: adsk.core.BoolValueCommandInput = ( + globalCommandInputs.itemById("jointSelectCancelButton") + ) + jointSelection: adsk.core.SelectionCommandInput = ( + globalCommandInputs.itemById("jointSelection") ) - jointSelection: adsk.core.SelectionCommandInput = globalCommandInputs.itemById("jointSelection") jointSelection.isVisible = jointSelection.isEnabled = True jointSelection.clearSelection() @@ -449,7 +622,9 @@ def handleInputChanged( jointSelectCancelButton.isVisible = jointSelectCancelButton.isEnabled = True elif commandInput.id == "jointRemoveButton": - jointAddButton: adsk.core.BoolValueCommandInput = globalCommandInputs.itemById("jointAddButton") + jointAddButton: adsk.core.BoolValueCommandInput = ( + globalCommandInputs.itemById("jointAddButton") + ) jointTable: adsk.core.TableCommandInput = args.inputs.itemById("jointTable") jointAddButton.isEnabled = True @@ -458,28 +633,44 @@ def handleInputChanged( ui = adsk.core.Application.get().userInterface ui.messageBox("Select a row to delete.") else: - self.removeIndexedJoint(jointTable.selectedRow - 1) # selectedRow is 1 indexed + self.removeIndexedJoint( + jointTable.selectedRow - 1 + ) # selectedRow is 1 indexed elif commandInput.id == "jointSelectCancelButton": - jointAddButton: adsk.core.BoolValueCommandInput = globalCommandInputs.itemById("jointAddButton") - jointRemoveButton: adsk.core.BoolValueCommandInput = globalCommandInputs.itemById("jointRemoveButton") - jointSelectCancelButton: adsk.core.BoolValueCommandInput = globalCommandInputs.itemById( - "jointSelectCancelButton" + jointAddButton: adsk.core.BoolValueCommandInput = ( + globalCommandInputs.itemById("jointAddButton") + ) + jointRemoveButton: adsk.core.BoolValueCommandInput = ( + globalCommandInputs.itemById("jointRemoveButton") + ) + jointSelectCancelButton: adsk.core.BoolValueCommandInput = ( + globalCommandInputs.itemById("jointSelectCancelButton") + ) + jointSelection: adsk.core.SelectionCommandInput = ( + globalCommandInputs.itemById("jointSelection") ) - jointSelection: adsk.core.SelectionCommandInput = globalCommandInputs.itemById("jointSelection") jointSelection.isEnabled = jointSelection.isVisible = False - jointSelectCancelButton.isEnabled = jointSelectCancelButton.isVisible = False + jointSelectCancelButton.isEnabled = jointSelectCancelButton.isVisible = ( + False + ) jointAddButton.isEnabled = jointRemoveButton.isEnabled = True @logFailure - def handleSelectionEvent(self, args: adsk.core.SelectionEventArgs, selectedJoint: adsk.fusion.Joint) -> None: + def handleSelectionEvent( + self, args: adsk.core.SelectionEventArgs, selectedJoint: adsk.fusion.Joint + ) -> None: selectionInput = args.activeInput jointType = selectedJoint.jointMotion.jointType - if jointType == adsk.fusion.JointTypes.RevoluteJointType or jointType == adsk.fusion.JointTypes.SliderJointType: + if ( + jointType == adsk.fusion.JointTypes.RevoluteJointType + or jointType == adsk.fusion.JointTypes.SliderJointType + ): if not self.addJoint(selectedJoint): ui = adsk.core.Application.get().userInterface result = ui.messageBox( - "You have already selected this joint.\n" "Would you like to remove it?", + "You have already selected this joint.\n" + "Would you like to remove it?", "Synthesis: Remove Joint Confirmation", adsk.core.MessageBoxButtonTypes.YesNoButtonType, adsk.core.MessageBoxIconTypes.QuestionIconType, @@ -493,14 +684,24 @@ def handleSelectionEvent(self, args: adsk.core.SelectionEventArgs, selectedJoint @logFailure def handlePreviewEvent(self, args: adsk.core.CommandEventArgs) -> None: commandInputs = args.command.commandInputs - jointAddButton: adsk.core.BoolValueCommandInput = commandInputs.itemById("jointAddButton") - jointRemoveButton: adsk.core.BoolValueCommandInput = commandInputs.itemById("jointRemoveButton") - jointSelectCancelButton: adsk.core.BoolValueCommandInput = commandInputs.itemById("jointSelectCancelButton") - jointSelection: adsk.core.SelectionCommandInput = commandInputs.itemById("jointSelection") + jointAddButton: adsk.core.BoolValueCommandInput = commandInputs.itemById( + "jointAddButton" + ) + jointRemoveButton: adsk.core.BoolValueCommandInput = commandInputs.itemById( + "jointRemoveButton" + ) + jointSelectCancelButton: adsk.core.BoolValueCommandInput = ( + commandInputs.itemById("jointSelectCancelButton") + ) + jointSelection: adsk.core.SelectionCommandInput = commandInputs.itemById( + "jointSelection" + ) if self.jointConfigTable.rowCount <= 1: jointRemoveButton.isEnabled = False if not jointSelection.isEnabled: jointAddButton.isEnabled = jointRemoveButton.isEnabled = True - jointSelectCancelButton.isVisible = jointSelectCancelButton.isEnabled = False + jointSelectCancelButton.isVisible = jointSelectCancelButton.isEnabled = ( + False + ) diff --git a/exporter/SynthesisFusionAddin/src/UI/MarkingMenu.py b/exporter/SynthesisFusionAddin/src/UI/MarkingMenu.py index 30c9f078e6..3899e616f9 100644 --- a/exporter/SynthesisFusionAddin/src/UI/MarkingMenu.py +++ b/exporter/SynthesisFusionAddin/src/UI/MarkingMenu.py @@ -44,10 +44,14 @@ def setLinearMarkingMenu(args): if occ: if occ.attributes.itemByName("synthesis", "collision_off") == None: - cmdDisableCollision = ui.commandDefinitions.itemById("DisableCollision") + cmdDisableCollision = ui.commandDefinitions.itemById( + "DisableCollision" + ) synthDropDown.controls.addCommand(cmdDisableCollision) else: - cmdEnableCollision = ui.commandDefinitions.itemById("EnableCollision") + cmdEnableCollision = ui.commandDefinitions.itemById( + "EnableCollision" + ) synthDropDown.controls.addCommand(cmdEnableCollision) def setCollisionAttribute(occ: adsk.fusion.Occurrence, isEnabled: bool = True): @@ -114,7 +118,9 @@ def notify(self, args): if design: attrs = design.findAttributes("synthesis", "collision_off") for attr in attrs: - for b in adsk.fusion.Occurrence.cast(attr.parent).bRepBodies: + for b in adsk.fusion.Occurrence.cast( + attr.parent + ).bRepBodies: ui.activeSelections.add(b) elif cmdDef.id == "EnableAllCollision": app = adsk.core.Application.get() diff --git a/exporter/SynthesisFusionAddin/src/UI/ShowAPSAuthCommand.py b/exporter/SynthesisFusionAddin/src/UI/ShowAPSAuthCommand.py index bd45cfc062..c68f4b5fdf 100644 --- a/exporter/SynthesisFusionAddin/src/UI/ShowAPSAuthCommand.py +++ b/exporter/SynthesisFusionAddin/src/UI/ShowAPSAuthCommand.py @@ -28,7 +28,9 @@ def notify(self, args): callbackUrl = "https://synthesis.autodesk.com/api/aps/exporter/" challenge = getCodeChallenge() if challenge is None: - logger.error("Code challenge is None when attempting to authorize for APS.") + logger.error( + "Code challenge is None when attempting to authorize for APS." + ) return params = { "response_type": "code", @@ -40,10 +42,19 @@ def notify(self, args): "code_challenge": challenge, "code_challenge_method": "S256", } - query = "&".join(map(lambda pair: f"{pair[0]}={pair[1]}", params.items())) - url = "https://developer.api.autodesk.com/authentication/v2/authorize?" + query - palette = gm.ui.palettes.add("authPalette", "APS Authentication", url, True, True, True, 400, 400) - palette.dockingState = adsk.core.PaletteDockingStates.PaletteDockStateRight + query = "&".join( + map(lambda pair: f"{pair[0]}={pair[1]}", params.items()) + ) + url = ( + "https://developer.api.autodesk.com/authentication/v2/authorize?" + + query + ) + palette = gm.ui.palettes.add( + "authPalette", "APS Authentication", url, True, True, True, 400, 400 + ) + palette.dockingState = ( + adsk.core.PaletteDockingStates.PaletteDockStateRight + ) # register events onHTMLEvent = MyHTMLEventHandler() palette.incomingFromHTML.add(onHTMLEvent) @@ -55,7 +66,9 @@ def notify(self, args): else: palette.isVisible = True except: - gm.ui.messageBox("Command executed failed: {}".format(traceback.format_exc())) + gm.ui.messageBox( + "Command executed failed: {}".format(traceback.format_exc()) + ) logger.error("Command executed failed: {}".format(traceback.format_exc())) if palette: palette.deleteMe() diff --git a/exporter/SynthesisFusionAddin/src/UI/ShowWebsiteCommand.py b/exporter/SynthesisFusionAddin/src/UI/ShowWebsiteCommand.py index 14cb233c0c..ad7267fc12 100644 --- a/exporter/SynthesisFusionAddin/src/UI/ShowWebsiteCommand.py +++ b/exporter/SynthesisFusionAddin/src/UI/ShowWebsiteCommand.py @@ -1,9 +1,12 @@ import webbrowser import adsk.core from ..general_imports import * + + class ShowWebsiteCommandExecuteHandler(adsk.core.CommandEventHandler): def __init__(self) -> None: super().__init__() + def notify(self, args): try: url = "https://synthesis.autodesk.com/tutorials.html" @@ -12,9 +15,12 @@ def notify(self, args): gm.ui.messageBox("Failed\n{}".format(traceback.format_exc())) except: gm.ui.messageBox("Failed\n{}".format(traceback.format_exc())) + + class ShowWebsiteCommandCreatedHandler(adsk.core.CommandCreatedEventHandler): def __init__(self, configure) -> None: super().__init__() + def notify(self, args): try: command = args.command diff --git a/exporter/SynthesisFusionAddin/src/UI/Toolbar.py b/exporter/SynthesisFusionAddin/src/UI/Toolbar.py index bfcc34189a..95527df003 100644 --- a/exporter/SynthesisFusionAddin/src/UI/Toolbar.py +++ b/exporter/SynthesisFusionAddin/src/UI/Toolbar.py @@ -51,7 +51,9 @@ def getPanel(self, name: str, visibility: bool = True) -> str | None: @logFailure @staticmethod - def getNewPanel(name: str, tab_id: str, toolbar_id: str, visibility: bool = True) -> str | None: + def getNewPanel( + name: str, tab_id: str, toolbar_id: str, visibility: bool = True + ) -> str | None: """# Gets a control for a panel to the tabbed toolbar visibility""" designWorkspace = gm.ui.workspaces.itemById("FusionSolidEnvironment") allDesignTabs = designWorkspace.toolbarTabs diff --git a/exporter/SynthesisFusionAddin/src/general_imports.py b/exporter/SynthesisFusionAddin/src/general_imports.py index 67d5e3b3cc..551f49c0cd 100644 --- a/exporter/SynthesisFusionAddin/src/general_imports.py +++ b/exporter/SynthesisFusionAddin/src/general_imports.py @@ -24,7 +24,9 @@ try: path = os.path.abspath(os.path.join(os.path.dirname(__file__), "..")) - path_proto_files = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "proto", "proto_out")) + path_proto_files = os.path.abspath( + os.path.join(os.path.dirname(__file__), "..", "proto", "proto_out") + ) if not path in sys.path: sys.path.insert(1, path) diff --git a/exporter/SynthesisFusionAddin/tools/format.py b/exporter/SynthesisFusionAddin/tools/format.py index 7531b93de7..0b4796e3cd 100644 --- a/exporter/SynthesisFusionAddin/tools/format.py +++ b/exporter/SynthesisFusionAddin/tools/format.py @@ -6,12 +6,19 @@ def main(args: list[str] = sys.argv[1:]) -> None: dir = args[0] if len(args) else "." if "pyproject.toml" not in os.listdir(dir): - print("WARNING: Configuration file for autoformatters was not found. Are you sure you specified the root DIR?") + print( + "WARNING: Configuration file for autoformatters was not found. Are you sure you specified the root DIR?" + ) for command in ["isort", "black"]: try: print(f"Formatting with {command}...") - subprocess.call([command, dir], shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + subprocess.call( + [command, dir], + shell=False, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + ) except FileNotFoundError: print(f'"{command}" could not be found. Please resolve dependencies.') return From 0bfc19a9ff95b1a41f6114a2286efb412969819e Mon Sep 17 00:00:00 2001 From: Azalea Colburn Date: Fri, 26 Jul 2024 16:18:05 -0700 Subject: [PATCH 08/10] ran formatter in correct dir :( --- exporter/SynthesisFusionAddin/Synthesis.py | 4 +- exporter/SynthesisFusionAddin/proto/deps.py | 12 +- exporter/SynthesisFusionAddin/src/APS/APS.py | 80 ++---- exporter/SynthesisFusionAddin/src/Logging.py | 18 +- .../src/Parser/ExporterOptions.py | 22 +- .../src/Parser/SynthesisParser/Components.py | 28 +- .../Parser/SynthesisParser/JointHierarchy.py | 49 +--- .../src/Parser/SynthesisParser/Joints.py | 73 ++--- .../src/Parser/SynthesisParser/Materials.py | 50 +--- .../src/Parser/SynthesisParser/PDMessage.py | 15 +- .../src/Parser/SynthesisParser/Parser.py | 41 +-- .../SynthesisParser/PhysicalProperties.py | 4 +- .../src/Parser/SynthesisParser/Utilities.py | 32 +-- exporter/SynthesisFusionAddin/src/Types.py | 10 +- .../src/UI/ConfigCommand.py | 216 ++++---------- .../src/UI/CustomGraphics.py | 12 +- .../SynthesisFusionAddin/src/UI/Events.py | 8 +- .../src/UI/FileDialogConfig.py | 4 +- exporter/SynthesisFusionAddin/src/UI/HUI.py | 24 +- .../SynthesisFusionAddin/src/UI/Helper.py | 12 +- .../SynthesisFusionAddin/src/UI/IconPaths.py | 25 +- .../src/UI/JointConfigTab.py | 266 +++++------------- .../src/UI/MarkingMenu.py | 12 +- .../src/UI/ShowAPSAuthCommand.py | 25 +- .../SynthesisFusionAddin/src/UI/Toolbar.py | 4 +- .../src/general_imports.py | 4 +- exporter/SynthesisFusionAddin/tools/format.py | 4 +- 27 files changed, 273 insertions(+), 781 deletions(-) diff --git a/exporter/SynthesisFusionAddin/Synthesis.py b/exporter/SynthesisFusionAddin/Synthesis.py index 3c2b21aafa..b90e678f50 100644 --- a/exporter/SynthesisFusionAddin/Synthesis.py +++ b/exporter/SynthesisFusionAddin/Synthesis.py @@ -78,9 +78,7 @@ def stop(_): path = os.path.abspath(os.path.dirname(__file__)) - path_proto_files = os.path.abspath( - os.path.join(os.path.dirname(__file__), "..", "proto", "proto_out") - ) + path_proto_files = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "proto", "proto_out")) if path in sys.path: sys.path.remove(path) diff --git a/exporter/SynthesisFusionAddin/proto/deps.py b/exporter/SynthesisFusionAddin/proto/deps.py index a046eb8069..10ec7757b3 100644 --- a/exporter/SynthesisFusionAddin/proto/deps.py +++ b/exporter/SynthesisFusionAddin/proto/deps.py @@ -34,9 +34,7 @@ def getPythonFolder() -> str: elif system == "Darwin": pythonFolder = f"{Path(osPath).parents[2]}/bin" else: - raise ImportError( - "Unsupported platform! This add-in only supports windows and macos" - ) + raise ImportError("Unsupported platform! This add-in only supports windows and macos") logger.debug(f"Python Folder -> {pythonFolder}") return pythonFolder @@ -129,9 +127,7 @@ def installCross(pipDeps: list) -> bool: ] ) if installResult != 0: - logger.warn( - f'Dep installation "{depName}" exited with code "{installResult}"' - ) + logger.warn(f'Dep installation "{depName}" exited with code "{installResult}"') if system == "Darwin": pipAntiDeps = ["dataclasses", "typing"] @@ -152,9 +148,7 @@ def installCross(pipDeps: list) -> bool: ] ) if uninstallResult != 0: - logger.warn( - f'AntiDep uninstallation "{depName}" exited with code "{uninstallResult}"' - ) + logger.warn(f'AntiDep uninstallation "{depName}" exited with code "{uninstallResult}"') progressBar.hide() diff --git a/exporter/SynthesisFusionAddin/src/APS/APS.py b/exporter/SynthesisFusionAddin/src/APS/APS.py index 5a9389cebc..346ae439f7 100644 --- a/exporter/SynthesisFusionAddin/src/APS/APS.py +++ b/exporter/SynthesisFusionAddin/src/APS/APS.py @@ -125,9 +125,7 @@ def refreshAuthToken(): "scope": "data:create data:write data:search data:read", } ).encode("utf-8") - req = urllib.request.Request( - "https://developer.api.autodesk.com/authentication/v2/token", data=body - ) + req = urllib.request.Request("https://developer.api.autodesk.com/authentication/v2/token", data=body) req.method = "POST" req.add_header(key="Content-Type", val="application/x-www-form-urlencoded") try: @@ -188,9 +186,7 @@ def getUserInfo() -> APSUserInfo | None: return loadUserInfo() -def create_folder( - auth: str, project_id: str, parent_folder_id: str, folder_display_name: str -) -> str | None: +def create_folder(auth: str, project_id: str, parent_folder_id: str, folder_display_name: str) -> str | None: """ creates a folder on an APS project @@ -215,9 +211,7 @@ def create_folder( "name": folder_display_name, "extension": {"type": "folders:autodesk.core:Folder", "version": "1.0"}, }, - "relationships": { - "parent": {"data": {"type": "folders", "id": f"{parent_folder_id}"}} - }, + "relationships": {"parent": {"data": {"type": "folders", "id": f"{parent_folder_id}"}}}, }, } @@ -238,9 +232,7 @@ def file_path_to_file_name(file_path: str) -> str: return file_path.split("/").pop() -def upload_mirabuf( - project_id: str, folder_id: str, file_name: str, file_contents: str -) -> str | None: +def upload_mirabuf(project_id: str, folder_id: str, file_name: str, file_contents: str) -> str | None: """ uploads mirabuf file to a specific folder in an APS project the folder and project must be created and valid @@ -280,18 +272,14 @@ def upload_mirabuf( folder_id = create_folder(auth, project_id, folder_id, "MirabufDir") else: folder_id = new_folder_id - (lineage_id, file_id, file_version) = get_file_id( - auth, project_id, folder_id, file_name - ) + (lineage_id, file_id, file_version) = get_file_id(auth, project_id, folder_id, file_name) """ Create APS Storage Location """ object_id = create_storage_location(auth, project_id, folder_id, file_name) if object_id is None: - gm.ui.messageBox( - "UPLOAD ERROR", "Object id is none; check create storage location" - ) + gm.ui.messageBox("UPLOAD ERROR", "Object id is none; check create storage location") return None (prefix, object_key) = str(object_id).split("/", 1) bucket_key = prefix.split(":", 3)[3] # gets the last element smth like: wip.dm.prod @@ -325,9 +313,7 @@ def upload_mirabuf( object_id, ) else: - _lineage_info = create_first_file_version( - auth, str(object_id), project_id, str(folder_id), file_name - ) + _lineage_info = create_first_file_version(auth, str(object_id), project_id, str(folder_id), file_name) return "" @@ -345,13 +331,9 @@ def get_hub_id(auth: str, hub_name: str) -> str | None: """ headers = {"Authorization": f"Bearer {auth}"} - hub_list_res = requests.get( - "https://developer.api.autodesk.com/project/v1/hubs", headers=headers - ) + hub_list_res = requests.get("https://developer.api.autodesk.com/project/v1/hubs", headers=headers) if not hub_list_res.ok: - gm.ui.messageBox( - "UPLOAD ERROR", f"Failed to retrieve hubs: {hub_list_res.text}" - ) + gm.ui.messageBox("UPLOAD ERROR", f"Failed to retrieve hubs: {hub_list_res.text}") return None hub_list: list[dict[str, Any]] = hub_list_res.json() for hub in hub_list: @@ -384,9 +366,7 @@ def get_project_id(auth: str, hub_id: str, project_name: str) -> str | None: headers=headers, ) if not project_list_res.ok: - gm.ui.messageBox( - "UPLOAD ERROR", f"Failed to retrieve hubs: {project_list_res.text}" - ) + gm.ui.messageBox("UPLOAD ERROR", f"Failed to retrieve hubs: {project_list_res.text}") return None project_list: list[dict[str, Any]] = project_list_res.json() for project in project_list: @@ -396,9 +376,7 @@ def get_project_id(auth: str, hub_id: str, project_name: str) -> str | None: return "" -def get_item_id( - auth: str, project_id: str, parent_folder_id: str, folder_name: str, item_type: str -) -> str | None: +def get_item_id(auth: str, project_id: str, parent_folder_id: str, folder_name: str, item_type: str) -> str | None: headers = {"Authorization": f"Bearer {auth}"} res = requests.get( f"https://developer.api.autodesk.com/data/v1/projects/{project_id}/folders/{parent_folder_id}/contents", @@ -501,9 +479,7 @@ def update_file_version( json=data, ) if not update_res.ok: - gm.ui.messageBox( - f"UPLOAD ERROR:\n{update_res.text}", "Updating file to new version failed" - ) + gm.ui.messageBox(f"UPLOAD ERROR:\n{update_res.text}", "Updating file to new version failed") return None gm.ui.messageBox( f"Successfully updated file {file_name} to version {int(curr_file_version) + 1} on APS", @@ -513,9 +489,7 @@ def update_file_version( return new_id -def get_file_id( - auth: str, project_id: str, folder_id: str, file_name: str -) -> tuple[str, str, str] | None: +def get_file_id(auth: str, project_id: str, folder_id: str, file_name: str) -> tuple[str, str, str] | None: """ gets the file id given a file name @@ -559,9 +533,7 @@ def get_file_id( return (lineage, id, version) -def create_storage_location( - auth: str, project_id: str, folder_id: str, file_name: str -) -> str | None: +def create_storage_location(auth: str, project_id: str, folder_id: str, file_name: str) -> str | None: """ creates a storage location (a bucket) the bucket can be used to upload a file to @@ -588,9 +560,7 @@ def create_storage_location( "data": { "type": "objects", "attributes": {"name": file_name}, - "relationships": { - "target": {"data": {"type": "folders", "id": f"{folder_id}"}} - }, + "relationships": {"target": {"data": {"type": "folders", "id": f"{folder_id}"}}}, }, } headers = { @@ -613,9 +583,7 @@ def create_storage_location( return object_id -def generate_signed_url( - auth: str, bucket_key: str, object_key: str -) -> tuple[str, str] | None: +def generate_signed_url(auth: str, bucket_key: str, object_key: str) -> tuple[str, str] | None: """ generates a signed_url for a bucket, given a bucket_key and object_key @@ -641,9 +609,7 @@ def generate_signed_url( headers=headers, ) if not signed_url_res.ok: - gm.ui.messageBox( - f"UPLOAD ERROR: {signed_url_res.text}", "Failed to get signed url" - ) + gm.ui.messageBox(f"UPLOAD ERROR: {signed_url_res.text}", "Failed to get signed url") return None signed_url_json: dict[str, str] = signed_url_res.json() return (signed_url_json["uploadKey"], signed_url_json["urls"][0]) @@ -666,16 +632,12 @@ def upload_file(signed_url: str, file_contents: str) -> str | None: """ upload_response = requests.put(url=signed_url, data=file_contents) if not upload_response.ok: - gm.ui.messageBox( - "UPLOAD ERROR", f"Failed to upload to signed url: {upload_response.text}" - ) + gm.ui.messageBox("UPLOAD ERROR", f"Failed to upload to signed url: {upload_response.text}") return None return "" -def complete_upload( - auth: str, upload_key: str, object_key: str, bucket_key: str -) -> str | None: +def complete_upload(auth: str, upload_key: str, object_key: str, bucket_key: str) -> str | None: """ completes and verifies the APS file upload given the upload_key @@ -764,9 +726,7 @@ def create_first_file_version( "type": "versions", "id": "1", "attributes": included_attributes, - "relationships": { - "storage": {"data": {"type": "objects", "id": object_id}} - }, + "relationships": {"storage": {"data": {"type": "objects", "id": object_id}}}, }, ] diff --git a/exporter/SynthesisFusionAddin/src/Logging.py b/exporter/SynthesisFusionAddin/src/Logging.py index 2a59a88cec..2bf9ce191b 100644 --- a/exporter/SynthesisFusionAddin/src/Logging.py +++ b/exporter/SynthesisFusionAddin/src/Logging.py @@ -31,11 +31,7 @@ def setupLogger() -> None: now = datetime.now().strftime("%H-%M-%S") today = date.today() logFileFolder = getOSPath(f"{pathlib.Path(__file__).parent.parent}", "logs") - logFiles = [ - os.path.join(logFileFolder, file) - for file in os.listdir(logFileFolder) - if file.endswith(".log") - ] + logFiles = [os.path.join(logFileFolder, file) for file in os.listdir(logFileFolder) if file.endswith(".log")] logFiles.sort() if len(logFiles) >= MAX_LOG_FILES_TO_KEEP: for file in logFiles[: len(logFiles) - MAX_LOG_FILES_TO_KEEP]: @@ -70,21 +66,15 @@ def wrapper(*args: any, **kwargs: any) -> any: except BaseException: excType, excValue, excTrace = sys.exc_info() tb = traceback.TracebackException(excType, excValue, excTrace) - formattedTb = "".join( - list(tb.format())[2:] - ) # Remove the wrapper func from the traceback. + formattedTb = "".join(list(tb.format())[2:]) # Remove the wrapper func from the traceback. clsName = "" if args and hasattr(args[0], "__class__"): clsName = args[0].__class__.__name__ + "." - getLogger(f"{INTERNAL_ID}.{clsName}{func.__name__}").error( - f"Failed:\n{formattedTb}" - ) + getLogger(f"{INTERNAL_ID}.{clsName}{func.__name__}").error(f"Failed:\n{formattedTb}") if messageBox: ui = adsk.core.Application.get().userInterface - ui.messageBox( - f"Internal Failure: {formattedTb}", "Synthesis: Error" - ) + ui.messageBox(f"Internal Failure: {formattedTb}", "Synthesis: Error") return wrapper diff --git a/exporter/SynthesisFusionAddin/src/Parser/ExporterOptions.py b/exporter/SynthesisFusionAddin/src/Parser/ExporterOptions.py index c287720b56..52ccd255bf 100644 --- a/exporter/SynthesisFusionAddin/src/Parser/ExporterOptions.py +++ b/exporter/SynthesisFusionAddin/src/Parser/ExporterOptions.py @@ -34,11 +34,7 @@ class ExporterOptions: # user's computer has conflicting configs of some sort. This has happened and should be accounted # for accordingly. fileLocation: str | None = field( - default=( - os.getenv("HOME") - if platform.system() == "Windows" - else os.path.expanduser("~") - ) + default=(os.getenv("HOME") if platform.system() == "Windows" else os.path.expanduser("~")) ) name: str = field(default=None) version: str = field(default=None) @@ -61,13 +57,9 @@ class ExporterOptions: exportLocation: ExportLocation = field(default=ExportLocation.UPLOAD) hierarchy: ModelHierarchy = field(default=ModelHierarchy.FusionAssembly) - visualQuality: TriangleMeshQualityOptions = field( - default=TriangleMeshQualityOptions.LowQualityTriangleMesh - ) + visualQuality: TriangleMeshQualityOptions = field(default=TriangleMeshQualityOptions.LowQualityTriangleMesh) physicalDepth: PhysicalDepth = field(default=PhysicalDepth.AllOccurrence) - physicalCalculationLevel: CalculationAccuracy = field( - default=CalculationAccuracy.LowCalculationAccuracy - ) + physicalCalculationLevel: CalculationAccuracy = field(default=CalculationAccuracy.LowCalculationAccuracy) @logFailure @timed @@ -76,9 +68,7 @@ def readFromDesign(self) -> "ExporterOptions": for field in fields(self): attribute = designAttributes.itemByName(INTERNAL_ID, field.name) if attribute: - attrJsonData = makeObjectFromJson( - field.type, json.loads(attribute.value) - ) + attrJsonData = makeObjectFromJson(field.type, json.loads(attribute.value)) setattr(self, field.name, attrJsonData) return self @@ -88,7 +78,5 @@ def readFromDesign(self) -> "ExporterOptions": def writeToDesign(self) -> None: designAttributes = adsk.core.Application.get().activeProduct.attributes for field in fields(self): - data = json.dumps( - getattr(self, field.name), default=encodeNestedObjects, indent=4 - ) + data = json.dumps(getattr(self, field.name), default=encodeNestedObjects, indent=4) designAttributes.add(INTERNAL_ID, field.name, data) diff --git a/exporter/SynthesisFusionAddin/src/Parser/SynthesisParser/Components.py b/exporter/SynthesisFusionAddin/src/Parser/SynthesisParser/Components.py index 78819dfbeb..aa77cac500 100644 --- a/exporter/SynthesisFusionAddin/src/Parser/SynthesisParser/Components.py +++ b/exporter/SynthesisFusionAddin/src/Parser/SynthesisParser/Components.py @@ -40,9 +40,7 @@ def _MapAllComponents( fill_info(partDefinition, component, comp_ref) - PhysicalProperties.GetPhysicalProperties( - component, partDefinition.physical_data - ) + PhysicalProperties.GetPhysicalProperties(component, partDefinition.physical_data) if options.exportMode == ExportMode.FIELD: partDefinition.dynamic = False @@ -62,9 +60,7 @@ def processBody(body: adsk.fusion.BRepBody | adsk.fusion.MeshBody): else: _ParseMesh(body, options, part_body.triangle_mesh) - appearance_key = "{}_{}".format( - body.appearance.name, body.appearance.id - ) + appearance_key = "{}_{}".format(body.appearance.name, body.appearance.id) # this should be appearance if appearance_key in materials.appearances: part_body.appearance_override = appearance_key @@ -105,9 +101,7 @@ def _ParseComponentRoot( if occur.isLightBulbOn: child_node = types_pb2.Node() - __parseChildOccurrence( - occur, progressDialog, options, partsData, material_map, child_node - ) + __parseChildOccurrence(occur, progressDialog, options, partsData, material_map, child_node) node.children.append(child_node) @@ -140,9 +134,7 @@ def __parseChildOccurrence( if occurrence.appearance: try: - part.appearance = "{}_{}".format( - occurrence.appearance.name, occurrence.appearance.id - ) + part.appearance = "{}_{}".format(occurrence.appearance.name, occurrence.appearance.id) except: part.appearance = "default" # TODO: Add phyical_material parser @@ -159,9 +151,7 @@ def __parseChildOccurrence( if options.exportMode == ExportMode.FIELD: for x in options.gamepieces: if x.occurrenceToken == mapConstant: - partsData.part_definitions[part.part_definition_reference].dynamic = ( - True - ) + partsData.part_definitions[part.part_definition_reference].dynamic = True break part.transform.spatial_matrix.extend(occurrence.transform.asArray()) @@ -177,9 +167,7 @@ def __parseChildOccurrence( if occur.isLightBulbOn: child_node = types_pb2.Node() - __parseChildOccurrence( - occur, progressDialog, options, partsData, material_map, child_node - ) + __parseChildOccurrence(occur, progressDialog, options, partsData, material_map, child_node) node.children.append(child_node) @@ -235,9 +223,7 @@ def _ParseMesh( plainmesh_out.uv.extend(mesh.textureCoordinatesAsFloat) -def _MapRigidGroups( - rootComponent: adsk.fusion.Component, joints: joint_pb2.Joints -) -> None: +def _MapRigidGroups(rootComponent: adsk.fusion.Component, joints: joint_pb2.Joints) -> None: groups = rootComponent.allRigidGroups for group in groups: mira_group = joint_pb2.RigidGroup() diff --git a/exporter/SynthesisFusionAddin/src/Parser/SynthesisParser/JointHierarchy.py b/exporter/SynthesisFusionAddin/src/Parser/SynthesisParser/JointHierarchy.py index cd8f9e06b0..53dd3d10fa 100644 --- a/exporter/SynthesisFusionAddin/src/Parser/SynthesisParser/JointHierarchy.py +++ b/exporter/SynthesisFusionAddin/src/Parser/SynthesisParser/JointHierarchy.py @@ -91,9 +91,7 @@ class JointRelationship(enum.Enum): class DynamicOccurrenceNode(GraphNode): - def __init__( - self, occurrence: adsk.fusion.Occurrence, isGround=False, previous=None - ): + def __init__(self, occurrence: adsk.fusion.Occurrence, isGround=False, previous=None): super().__init__(occurrence) self.isGround = isGround self.name = occurrence.name @@ -133,9 +131,7 @@ def getConnectedAxisTokens(self) -> list: class DynamicEdge(GraphEdge): - def __init__( - self, relationship: OccurrenceRelationship, node: DynamicOccurrenceNode - ): + def __init__(self, relationship: OccurrenceRelationship, node: DynamicOccurrenceNode): super().__init__(relationship, node) # should print all in this class @@ -215,9 +211,7 @@ def __init__(self, design): self.grounded = searchForGrounded(design.rootComponent) if self.grounded is None: - gm.ui.messageBox( - "There is not currently a Grounded Component in the assembly, stopping kinematic export." - ) + gm.ui.messageBox("There is not currently a Grounded Component in the assembly, stopping kinematic export.") raise RuntimeWarning("There is no grounded component") self.currentTraversal = dict() @@ -253,9 +247,7 @@ def __init__(self, design): @logFailure def __getAllJoints(self): - for joint in list(self.design.rootComponent.allJoints) + list( - self.design.rootComponent.allAsBuiltJoints - ): + for joint in list(self.design.rootComponent.allJoints) + list(self.design.rootComponent.allAsBuiltJoints): if joint and joint.occurrenceOne and joint.occurrenceTwo: occurrenceOne = joint.occurrenceOne occurrenceTwo = joint.occurrenceTwo @@ -311,8 +303,7 @@ def _linkAllAxis(self): def _recurseLink(self, simNode: SimulationNode): connectedAxisNodes = [ - self.simulationNodesRef.get(componentKeys, None) - for componentKeys in simNode.data.getConnectedAxisTokens() + self.simulationNodesRef.get(componentKeys, None) for componentKeys in simNode.data.getConnectedAxisTokens() ] for connectedAxis in connectedAxisNodes: # connected is the occurrence @@ -362,9 +353,9 @@ def _populateNode( edge = DynamicEdge(relationship, node) prev.edges.append(edge) return - elif ( - (occ.entityToken in self.dynamicJoints.keys()) and (prev is not None) - ) or self.currentTraversal.get(occ.entityToken) is not None: + elif ((occ.entityToken in self.dynamicJoints.keys()) and (prev is not None)) or self.currentTraversal.get( + occ.entityToken + ) is not None: return node = DynamicOccurrenceNode(occ) @@ -372,9 +363,7 @@ def _populateNode( self.currentTraversal[occ.entityToken] = True for occurrence in occ.childOccurrences: - self._populateNode( - occurrence, node, OccurrenceRelationship.TRANSFORM, is_ground=is_ground - ) + self._populateNode(occurrence, node, OccurrenceRelationship.TRANSFORM, is_ground=is_ground) # if not is_ground: # THIS IS A BUG - OCCURRENCE ACCESS VIOLATION try: @@ -395,18 +384,11 @@ def _populateNode( connection = joint.occurrenceOne if connection is not None: - if ( - prev is None - or connection.entityToken != prev.data.entityToken - ): + if prev is None or connection.entityToken != prev.data.entityToken: self._populateNode( connection, node, - ( - OccurrenceRelationship.CONNECTION - if rigid - else OccurrenceRelationship.NEXT - ), + (OccurrenceRelationship.CONNECTION if rigid else OccurrenceRelationship.NEXT), is_ground=is_ground, ) else: @@ -509,9 +491,7 @@ def populateJoint(simNode: SimulationNode, joints: joint_pb2.Joints, progressDia root = types_pb2.Node() # construct body tree if possible - createTreeParts( - simNode.data, OccurrenceRelationship.CONNECTION, root, progressDialog - ) + createTreeParts(simNode.data, OccurrenceRelationship.CONNECTION, root, progressDialog) proto_joint.parts.nodes.append(root) @@ -530,10 +510,7 @@ def createTreeParts( raise RuntimeError("User canceled export") # if it's the next part just exit early for our own sanity - if ( - relationship == OccurrenceRelationship.NEXT - or dynNode.data.isLightBulbOn == False - ): + if relationship == OccurrenceRelationship.NEXT or dynNode.data.isLightBulbOn == False: return # set the occurrence / component id to reference the part diff --git a/exporter/SynthesisFusionAddin/src/Parser/SynthesisParser/Joints.py b/exporter/SynthesisFusionAddin/src/Parser/SynthesisParser/Joints.py index 6caa82e6df..c79a0240d0 100644 --- a/exporter/SynthesisFusionAddin/src/Parser/SynthesisParser/Joints.py +++ b/exporter/SynthesisFusionAddin/src/Parser/SynthesisParser/Joints.py @@ -88,9 +88,7 @@ def populateJoints( # Add the rest of the dynamic objects - for joint in list(design.rootComponent.allJoints) + list( - design.rootComponent.allAsBuiltJoints - ): + for joint in list(design.rootComponent.allJoints) + list(design.rootComponent.allAsBuiltJoints): if joint.isSuppressed: continue @@ -124,10 +122,7 @@ def populateJoints( signal.io = signal_pb2.IOType.OUTPUT # really could just map the enum to a friggin string - if ( - parse_joints.signalType != SignalType.PASSIVE - and assembly.dynamic - ): + if parse_joints.signalType != SignalType.PASSIVE and assembly.dynamic: if parse_joints.signalType == SignalType.CAN: signal.device_type = signal_pb2.DeviceType.CANBUS elif parse_joints.signalType == SignalType.PWM: @@ -214,9 +209,7 @@ def _addJointInstance( joint_definition.user_data.data["wheel"] = "true" # Must convert type 'enum' to int to store wheelType in mirabuf - joint_definition.user_data.data["wheelType"] = str( - wheel.wheelType.value - 1 - ) + joint_definition.user_data.data["wheelType"] = str(wheel.wheelType.value - 1) # if it exists get it and overwrite the signal type if joint_instance.signal_reference: @@ -250,9 +243,7 @@ def _addRigidGroup(joint: adsk.fusion.Joint, assembly: assembly_pb2.Assembly): assembly.data.joints.rigid_groups.append(mira_group) -def _motionFromJoint( - fusionMotionDefinition: adsk.fusion.JointMotion, proto_joint: joint_pb2.Joint -) -> None: +def _motionFromJoint(fusionMotionDefinition: adsk.fusion.JointMotion, proto_joint: joint_pb2.Joint) -> None: # if fusionJoint.geometryOrOriginOne.objectType == "adsk::fusion::JointGeometry" # create the DOF depending on what kind of information the joint has @@ -266,16 +257,12 @@ def _motionFromJoint( 6: noop, # TODO: Implement } - fillJointMotionFunc = fillJointMotionFuncSwitcher.get( - fusionMotionDefinition.jointType, lambda: None - ) + fillJointMotionFunc = fillJointMotionFuncSwitcher.get(fusionMotionDefinition.jointType, lambda: None) fillJointMotionFunc(fusionMotionDefinition, proto_joint) -def fillRevoluteJointMotion( - revoluteMotion: adsk.fusion.RevoluteJointMotion, proto_joint: joint_pb2.Joint -): +def fillRevoluteJointMotion(revoluteMotion: adsk.fusion.RevoluteJointMotion, proto_joint: joint_pb2.Joint): """#### Fill Protobuf revolute joint motion data Args: @@ -317,9 +304,7 @@ def fillRevoluteJointMotion( dof.axis.z = int(rotationAxis == 1) -def fillSliderJointMotion( - sliderMotion: adsk.fusion.SliderJointMotion, proto_joint: joint_pb2.Joint -) -> None: +def fillSliderJointMotion(sliderMotion: adsk.fusion.SliderJointMotion, proto_joint: joint_pb2.Joint) -> None: """#### Fill Protobuf slider joint motion data Args: @@ -390,9 +375,7 @@ def _searchForGrounded( return None -def _jointOrigin( - fusionJoint: Union[adsk.fusion.Joint, adsk.fusion.AsBuiltJoint] -) -> adsk.core.Point3D: +def _jointOrigin(fusionJoint: Union[adsk.fusion.Joint, adsk.fusion.AsBuiltJoint]) -> adsk.core.Point3D: """#### Joint Origin Internal Finder that was orignally created for Synthesis by Liam Wang Args: @@ -404,8 +387,7 @@ def _jointOrigin( geometryOrOrigin = ( ( fusionJoint.geometryOrOriginOne - if fusionJoint.geometryOrOriginOne.objectType - == "adsk::fusion::JointGeometry" + if fusionJoint.geometryOrOriginOne.objectType == "adsk::fusion::JointGeometry" else fusionJoint.geometryOrOriginTwo ) if fusionJoint.objectType == "adsk::fusion::Joint" @@ -424,9 +406,7 @@ def _jointOrigin( newEnt = ent.createForAssemblyContext(fusionJoint.occurrenceOne) min = newEnt.boundingBox.minPoint max = newEnt.boundingBox.maxPoint - org = adsk.core.Point3D.create( - (max.x + min.x) / 2.0, (max.y + min.y) / 2.0, (max.z + min.z) / 2.0 - ) + org = adsk.core.Point3D.create((max.x + min.x) / 2.0, (max.y + min.y) / 2.0, (max.z + min.z) / 2.0) return org # ent.startVertex.geometry else: return geometryOrOrigin.origin @@ -441,19 +421,11 @@ def _jointOrigin( else: # adsk::fusion::JointOrigin origin = geometryOrOrigin.geometry.origin # todo: Is this the correct way to calculate a joint origin's true location? Why isn't this exposed in the API? - offsetX = ( - 0 if geometryOrOrigin.offsetX is None else geometryOrOrigin.offsetX.value - ) - offsetY = ( - 0 if geometryOrOrigin.offsetY is None else geometryOrOrigin.offsetY.value - ) - offsetZ = ( - 0 if geometryOrOrigin.offsetZ is None else geometryOrOrigin.offsetZ.value - ) + offsetX = 0 if geometryOrOrigin.offsetX is None else geometryOrOrigin.offsetX.value + offsetY = 0 if geometryOrOrigin.offsetY is None else geometryOrOrigin.offsetY.value + offsetZ = 0 if geometryOrOrigin.offsetZ is None else geometryOrOrigin.offsetZ.value # noinspection PyArgumentList - return adsk.core.Point3D.create( - origin.x + offsetX, origin.y + offsetY, origin.z + offsetZ - ) + return adsk.core.Point3D.create(origin.x + offsetX, origin.y + offsetY, origin.z + offsetZ) def createJointGraph( @@ -489,26 +461,17 @@ def createJointGraph( current_node = node_map[supplied_joint.jointToken] if supplied_joint.parent == JointParentType.ROOT: node_map["ground"].children.append(node_map[supplied_joint.jointToken]) - elif ( - node_map[supplied_joint.parent.value] is not None - and node_map[supplied_joint.jointToken] is not None - ): - node_map[supplied_joint.parent].children.append( - node_map[supplied_joint.jointToken] - ) + elif node_map[supplied_joint.parent.value] is not None and node_map[supplied_joint.jointToken] is not None: + node_map[supplied_joint.parent].children.append(node_map[supplied_joint.jointToken]) else: - logger.error( - f"Cannot construct hierarhcy because of detached tree at : {supplied_joint.jointToken}" - ) + logger.error(f"Cannot construct hierarhcy because of detached tree at : {supplied_joint.jointToken}") for node in node_map.values(): # append everything at top level to isolate kinematics joint_tree.nodes.append(node) -def addWheelsToGraph( - wheels: list, rootNode: types_pb2.Node, joint_tree: types_pb2.GraphContainer -): +def addWheelsToGraph(wheels: list, rootNode: types_pb2.Node, joint_tree: types_pb2.GraphContainer): for wheel in wheels: # wheel name # wheel signal diff --git a/exporter/SynthesisFusionAddin/src/Parser/SynthesisParser/Materials.py b/exporter/SynthesisFusionAddin/src/Parser/SynthesisParser/Materials.py index 3b8a019d71..97d8d47f57 100644 --- a/exporter/SynthesisFusionAddin/src/Parser/SynthesisParser/Materials.py +++ b/exporter/SynthesisFusionAddin/src/Parser/SynthesisParser/Materials.py @@ -52,9 +52,7 @@ def _MapAllPhysicalMaterials( getPhysicalMaterialData(material, newmaterial, options) -def setDefaultMaterial( - physical_material: material_pb2.PhysicalMaterial, options: ExporterOptions -): +def setDefaultMaterial(physical_material: material_pb2.PhysicalMaterial, options: ExporterOptions): construct_info("default", physical_material) physical_material.description = "A default physical material" @@ -94,12 +92,8 @@ def getPhysicalMaterialData(fusion_material, proto_material, options): proto_material.dynamic_friction = options.frictionOverrideCoeff proto_material.static_friction = options.frictionOverrideCoeff else: - proto_material.dynamic_friction = DYNAMIC_FRICTION_COEFFS.get( - fusion_material.name, 0.5 - ) - proto_material.static_friction = STATIC_FRICTION_COEFFS.get( - fusion_material.name, 0.5 - ) + proto_material.dynamic_friction = DYNAMIC_FRICTION_COEFFS.get(fusion_material.name, 0.5) + proto_material.static_friction = STATIC_FRICTION_COEFFS.get(fusion_material.name, 0.5) proto_material.restitution = 0.5 proto_material.description = f"{fusion_material.name} exported from FUSION" @@ -133,31 +127,17 @@ def getPhysicalMaterialData(fusion_material, proto_material, options): """ Mechanical Properties """ - mechanicalProperties.young_mod = materialProperties.itemById( - "structural_Young_modulus" - ).value - mechanicalProperties.poisson_ratio = materialProperties.itemById( - "structural_Poisson_ratio" - ).value - mechanicalProperties.shear_mod = materialProperties.itemById( - "structural_Shear_modulus" - ).value - mechanicalProperties.density = materialProperties.itemById( - "structural_Density" - ).value - mechanicalProperties.damping_coefficient = materialProperties.itemById( - "structural_Damping_coefficient" - ).value + mechanicalProperties.young_mod = materialProperties.itemById("structural_Young_modulus").value + mechanicalProperties.poisson_ratio = materialProperties.itemById("structural_Poisson_ratio").value + mechanicalProperties.shear_mod = materialProperties.itemById("structural_Shear_modulus").value + mechanicalProperties.density = materialProperties.itemById("structural_Density").value + mechanicalProperties.damping_coefficient = materialProperties.itemById("structural_Damping_coefficient").value """ Strength Properties """ - strengthProperties.yield_strength = materialProperties.itemById( - "structural_Minimum_yield_stress" - ).value - strengthProperties.tensile_strength = materialProperties.itemById( - "structural_Minimum_tensile_strength" - ).value + strengthProperties.yield_strength = materialProperties.itemById("structural_Minimum_yield_stress").value + strengthProperties.tensile_strength = materialProperties.itemById("structural_Minimum_tensile_strength").value """ strengthProperties.thermal_treatment = materialProperties.itemById( "structural_Thermally_treated" @@ -255,9 +235,7 @@ def getMaterialAppearance( baseColor = properties.itemById("transparent_color").value transparent_distance = properties.itemById("transparent_distance").value - opac = (255.0 * transparent_distance) / ( - transparent_distance + OPACITY_RAMPING_CONSTANT - ) + opac = (255.0 * transparent_distance) / (transparent_distance + OPACITY_RAMPING_CONSTANT) if opac > 255: opac = 255 elif opac < 0: @@ -273,11 +251,7 @@ def getMaterialAppearance( color.A = baseColor.opacity else: for prop in fusionAppearance.appearanceProperties: - if ( - (prop.name == "Color") - and (prop.value is not None) - and (prop.id != "surface_albedo") - ): + if (prop.name == "Color") and (prop.value is not None) and (prop.id != "surface_albedo"): baseColor = prop.value color.R = baseColor.red color.G = baseColor.green diff --git a/exporter/SynthesisFusionAddin/src/Parser/SynthesisParser/PDMessage.py b/exporter/SynthesisFusionAddin/src/Parser/SynthesisParser/PDMessage.py index d5057709da..ad441fc901 100644 --- a/exporter/SynthesisFusionAddin/src/Parser/SynthesisParser/PDMessage.py +++ b/exporter/SynthesisFusionAddin/src/Parser/SynthesisParser/PDMessage.py @@ -28,12 +28,7 @@ def __init__( self.currentMessage = "working..." - self.finalValue = ( - self.componentCount - + self.occurrenceCount - + self.materialCount - + self.appearanceCount - ) + self.finalValue = self.componentCount + self.occurrenceCount + self.materialCount + self.appearanceCount self.currentValue = 0 self.progressDialog = progressDialog @@ -43,13 +38,9 @@ def _format(self): # TABS DO NOTHING HALP out = f"{self.assemblyName} parsing:\n" out += f"\t Components: \t[ {self.currentCompCount} / {self.componentCount} ]\n" - out += ( - f"\t Occurrences: \t[ {self.currentOccCount} / {self.occurrenceCount} ]\n" - ) + out += f"\t Occurrences: \t[ {self.currentOccCount} / {self.occurrenceCount} ]\n" out += f"\t Materials: \t[ {self.currentMatCount} / {self.materialCount} ]\n" - out += ( - f"\t Appearances: \t[ {self.currentAppCount} / {self.appearanceCount} ]\n" - ) + out += f"\t Appearances: \t[ {self.currentAppCount} / {self.appearanceCount} ]\n" out += f"{self.currentMessage}" return out diff --git a/exporter/SynthesisFusionAddin/src/Parser/SynthesisParser/Parser.py b/exporter/SynthesisFusionAddin/src/Parser/SynthesisParser/Parser.py index e483adedaa..b59f391f0b 100644 --- a/exporter/SynthesisFusionAddin/src/Parser/SynthesisParser/Parser.py +++ b/exporter/SynthesisFusionAddin/src/Parser/SynthesisParser/Parser.py @@ -35,9 +35,7 @@ def export(self) -> None: design: adsk.fusion.Design = app.activeDocument.design if not getAuth(): - app.userInterface.messageBox( - "APS Login Required for Uploading.", "APS Login" - ) + app.userInterface.messageBox("APS Login Required for Uploading.", "APS Login") return assembly_out = assembly_pb2.Assembly() @@ -62,9 +60,7 @@ def export(self) -> None: progressDialog.title = "Exporting to Synthesis Format" progressDialog.minimumValue = 0 progressDialog.maximumValue = totalIterations - progressDialog.show( - "Synthesis Export", "Currently on %v of %m", 0, totalIterations - ) + progressDialog.show("Synthesis Export", "Currently on %v of %m", 0, totalIterations) # this is the formatter for the progress dialog now self.pdMessage = PDMessage.PDMessage( @@ -134,9 +130,7 @@ def export(self) -> None: self.pdMessage, ) - JointHierarchy.BuildJointPartHierarchy( - design, assembly_out.data.joints, self.exporterOptions, self.pdMessage - ) + JointHierarchy.BuildJointPartHierarchy(design, assembly_out.data.joints, self.exporterOptions, self.pdMessage) # These don't have an effect, I forgot how this is suppose to work # progressDialog.message = "Taking Photo for thumbnail..." @@ -185,12 +179,7 @@ def export(self) -> None: project_id = project.id folder_id = project.rootFolder.id file_name = f"{self.exporterOptions.fileLocation}.mira" - if ( - upload_mirabuf( - project_id, folder_id, file_name, assembly_out.SerializeToString() - ) - is None - ): + if upload_mirabuf(project_id, folder_id, file_name, assembly_out.SerializeToString()) is None: raise RuntimeError("Could not upload to APS") else: assert self.exporterOptions.exportLocation == ExportLocation.DOWNLOAD @@ -225,15 +214,9 @@ def export(self) -> None: joint_hierarchy_out = f"{joint_hierarchy_out} |- ground\n" else: newNode = assembly_out.data.joints.joint_instances[node.value] - jointDefinition = assembly_out.data.joints.joint_definitions[ - newNode.joint_reference - ] - - wheel_ = ( - " wheel : true" - if (jointDefinition.user_data.data["wheel"] != "") - else "" - ) + jointDefinition = assembly_out.data.joints.joint_definitions[newNode.joint_reference] + + wheel_ = " wheel : true" if (jointDefinition.user_data.data["wheel"] != "") else "" joint_hierarchy_out = ( f"{joint_hierarchy_out} |---> {jointDefinition.info.name} " @@ -244,14 +227,8 @@ def export(self) -> None: joint_hierarchy_out = f"{joint_hierarchy_out} |---> ground\n" else: newNode = assembly_out.data.joints.joint_instances[child.value] - jointDefinition = assembly_out.data.joints.joint_definitions[ - newNode.joint_reference - ] - wheel_ = ( - " wheel : true" - if (jointDefinition.user_data.data["wheel"] != "") - else "" - ) + jointDefinition = assembly_out.data.joints.joint_definitions[newNode.joint_reference] + wheel_ = " wheel : true" if (jointDefinition.user_data.data["wheel"] != "") else "" joint_hierarchy_out = ( f"{joint_hierarchy_out} |- {jointDefinition.info.name} " f"type: {jointDefinition.joint_motion_type} {wheel_}\n" diff --git a/exporter/SynthesisFusionAddin/src/Parser/SynthesisParser/PhysicalProperties.py b/exporter/SynthesisFusionAddin/src/Parser/SynthesisParser/PhysicalProperties.py index 395231ccbf..db488c115a 100644 --- a/exporter/SynthesisFusionAddin/src/Parser/SynthesisParser/PhysicalProperties.py +++ b/exporter/SynthesisFusionAddin/src/Parser/SynthesisParser/PhysicalProperties.py @@ -30,9 +30,7 @@ @logFailure def GetPhysicalProperties( - fusionObject: Union[ - adsk.fusion.BRepBody, adsk.fusion.Occurrence, adsk.fusion.Component - ], + fusionObject: Union[adsk.fusion.BRepBody, adsk.fusion.Occurrence, adsk.fusion.Component], physicalProperties: types_pb2.PhysicalProperties, level=1, ): diff --git a/exporter/SynthesisFusionAddin/src/Parser/SynthesisParser/Utilities.py b/exporter/SynthesisFusionAddin/src/Parser/SynthesisParser/Utilities.py index 14295e9239..f508f32117 100644 --- a/exporter/SynthesisFusionAddin/src/Parser/SynthesisParser/Utilities.py +++ b/exporter/SynthesisFusionAddin/src/Parser/SynthesisParser/Utilities.py @@ -62,18 +62,18 @@ def construct_info(name: str, proto_obj, version=5, fus_object=None, GUID=None) # My previous function was alot more optimized however now I realize the bug was this doesn't work well with degrees def euler_to_quaternion(r): (yaw, pitch, roll) = (r[0], r[1], r[2]) - qx = math.sin(roll / 2) * math.cos(pitch / 2) * math.cos(yaw / 2) - math.cos( - roll / 2 - ) * math.sin(pitch / 2) * math.sin(yaw / 2) - qy = math.cos(roll / 2) * math.sin(pitch / 2) * math.cos(yaw / 2) + math.sin( - roll / 2 - ) * math.cos(pitch / 2) * math.sin(yaw / 2) - qz = math.cos(roll / 2) * math.cos(pitch / 2) * math.sin(yaw / 2) - math.sin( - roll / 2 - ) * math.sin(pitch / 2) * math.cos(yaw / 2) - qw = math.cos(roll / 2) * math.cos(pitch / 2) * math.cos(yaw / 2) + math.sin( - roll / 2 - ) * math.sin(pitch / 2) * math.sin(yaw / 2) + qx = math.sin(roll / 2) * math.cos(pitch / 2) * math.cos(yaw / 2) - math.cos(roll / 2) * math.sin( + pitch / 2 + ) * math.sin(yaw / 2) + qy = math.cos(roll / 2) * math.sin(pitch / 2) * math.cos(yaw / 2) + math.sin(roll / 2) * math.cos( + pitch / 2 + ) * math.sin(yaw / 2) + qz = math.cos(roll / 2) * math.cos(pitch / 2) * math.sin(yaw / 2) - math.sin(roll / 2) * math.sin( + pitch / 2 + ) * math.cos(yaw / 2) + qw = math.cos(roll / 2) * math.cos(pitch / 2) * math.cos(yaw / 2) + math.sin(roll / 2) * math.sin( + pitch / 2 + ) * math.sin(yaw / 2) return [qx, qy, qz, qw] @@ -135,9 +135,7 @@ def throwZero(): Raises: RuntimeError: Error describing the issue """ - raise RuntimeError( - "While computing the quaternion the trace was reported as 0 which is invalid" - ) + raise RuntimeError("While computing the quaternion the trace was reported as 0 which is invalid") def spatial_to_quaternion(mat): @@ -195,9 +193,7 @@ def spatial_to_quaternion(mat): return round(qx, 13), round(-qy, 13), round(-qz, 13), round(qw, 13) else: - raise RuntimeError( - "Supplied matrix to spatial_to_quaternion is not a 1D spatial matrix in size." - ) + raise RuntimeError("Supplied matrix to spatial_to_quaternion is not a 1D spatial matrix in size.") def normalize_quaternion(x, y, z, w): diff --git a/exporter/SynthesisFusionAddin/src/Types.py b/exporter/SynthesisFusionAddin/src/Types.py index d75b916792..1aca3a5162 100644 --- a/exporter/SynthesisFusionAddin/src/Types.py +++ b/exporter/SynthesisFusionAddin/src/Types.py @@ -110,9 +110,7 @@ def makeObjectFromJson(objType: type, data: any) -> any: return [makeObjectFromJson(objType.__args__[0], item) for item in data] obj = objType() - assert is_dataclass(obj) and isinstance( - data, dict - ), "Found unsupported type to decode." + assert is_dataclass(obj) and isinstance(data, dict), "Found unsupported type to decode." for field in fields(obj): if field.name in data: setattr(obj, field.name, makeObjectFromJson(field.type, data[field.name])) @@ -156,11 +154,7 @@ def __eq__(self, value: object) -> bool: bool: Did the OString objects match? """ if isinstance(value, OString): - if ( - self.path == value.path - and self.fileName == value.fileName - and self.platform == value.platform - ): + if self.path == value.path and self.fileName == value.fileName and self.platform == value.platform: return True return False diff --git a/exporter/SynthesisFusionAddin/src/UI/ConfigCommand.py b/exporter/SynthesisFusionAddin/src/UI/ConfigCommand.py index 8cec24ef6d..774d8eb53f 100644 --- a/exporter/SynthesisFusionAddin/src/UI/ConfigCommand.py +++ b/exporter/SynthesisFusionAddin/src/UI/ConfigCommand.py @@ -98,9 +98,7 @@ def bRepMassInRoot(self): for body in gm.app.activeDocument.design.rootComponent.bRepBodies: if not body.isLightBulbOn: continue - physical = body.getPhysicalProperties( - adsk.fusion.CalculationAccuracy.LowCalculationAccuracy - ) + physical = body.getPhysicalProperties(adsk.fusion.CalculationAccuracy.LowCalculationAccuracy) self.totalMass += physical.mass @logFailure(messageBox=True) @@ -112,9 +110,7 @@ def traverseOccurrenceHierarchy(self): for body in occ.component.bRepBodies: if not body.isLightBulbOn: continue - physical = body.getPhysicalProperties( - adsk.fusion.CalculationAccuracy.LowCalculationAccuracy - ) + physical = body.getPhysicalProperties(adsk.fusion.CalculationAccuracy.LowCalculationAccuracy) self.totalMass += physical.mass def getTotalMass(self): @@ -193,7 +189,9 @@ def notify(self, args): dropdownExportLocation.listItems.add("Download", not upload) dropdownExportLocation.tooltip = "Export Location" - dropdownExportLocation.tooltipDescription = "
Do you want to upload this mirabuf file to APS, or download it to your local machine?" + dropdownExportLocation.tooltipDescription = ( + "
Do you want to upload this mirabuf file to APS, or download it to your local machine?" + ) # ~~~~~~~~~~~~~~~~ WEIGHT CONFIGURATION ~~~~~~~~~~~~~~~~ """ @@ -208,9 +206,7 @@ def notify(self, args): "3:2:2:1", 1, ) - weightTableInput.tablePresentationStyle = ( - 2 # set transparent background for table - ) + weightTableInput.tablePresentationStyle = 2 # set transparent background for table weight_name = inputs.addStringValueInput("weight_name", "Weight") weight_name.value = "Weight" @@ -254,22 +250,12 @@ def notify(self, args): weight_unit.listItems.add("‎", imperialUnits, IconPaths.massIcons["LBS"]) weight_unit.listItems.add("‎", not imperialUnits, IconPaths.massIcons["KG"]) weight_unit.tooltip = "Unit of mass" - weight_unit.tooltipDescription = ( - "
Configure the unit of mass for the weight calculation." - ) + weight_unit.tooltipDescription = "
Configure the unit of mass for the weight calculation." - weightTableInput.addCommandInput( - weight_name, 0, 0 - ) # add command inputs to table - weightTableInput.addCommandInput( - auto_calc_weight, 0, 1 - ) # add command inputs to table - weightTableInput.addCommandInput( - weight_input, 0, 2 - ) # add command inputs to table - weightTableInput.addCommandInput( - weight_unit, 0, 3 - ) # add command inputs to table + weightTableInput.addCommandInput(weight_name, 0, 0) # add command inputs to table + weightTableInput.addCommandInput(auto_calc_weight, 0, 1) # add command inputs to table + weightTableInput.addCommandInput(weight_input, 0, 2) # add command inputs to table + weightTableInput.addCommandInput(weight_unit, 0, 3) # add command inputs to table global jointConfigTab jointConfigTab = JointConfigTab(args) @@ -279,9 +265,7 @@ def notify(self, args): # Should investigate changes to improve performance. if exporterOptions.joints: for synJoint in exporterOptions.joints: - fusionJoint = gm.app.activeDocument.design.findEntityByToken( - synJoint.jointToken - )[0] + fusionJoint = gm.app.activeDocument.design.findEntityByToken(synJoint.jointToken)[0] jointConfigTab.addJoint(fusionJoint, synJoint) else: for joint in [ @@ -289,8 +273,7 @@ def notify(self, args): *gm.app.activeDocument.design.rootComponent.allAsBuiltJoints, ]: if ( - joint.jointMotion.jointType - in (JointMotions.REVOLUTE.value, JointMotions.SLIDER.value) + joint.jointMotion.jointType in (JointMotions.REVOLUTE.value, JointMotions.SLIDER.value) and not joint.isSuppressed ): jointConfigTab.addJoint(joint) @@ -300,9 +283,7 @@ def notify(self, args): # Should consider changing how the parser handles wheels and joints to avoid overlap if exporterOptions.wheels: for wheel in exporterOptions.wheels: - fusionJoint = gm.app.activeDocument.design.findEntityByToken( - wheel.jointToken - )[0] + fusionJoint = gm.app.activeDocument.design.findEntityByToken(wheel.jointToken)[0] jointConfigTab.addWheel(fusionJoint, wheel) # ~~~~~~~~~~~~~~~~ GAMEPIECE CONFIGURATION ~~~~~~~~~~~~~~~~ @@ -310,9 +291,7 @@ def notify(self, args): Gamepiece group command input, isVisible=False by default - Container for gamepiece selection table """ - gamepieceConfig = inputs.addGroupCommandInput( - "gamepiece_config", "Gamepiece Configuration" - ) + gamepieceConfig = inputs.addGroupCommandInput("gamepiece_config", "Gamepiece Configuration") gamepieceConfig.isExpanded = True gamepieceConfig.isVisible = False gamepieceConfig.tooltip = "Select and define the gamepieces in your field." @@ -322,9 +301,7 @@ def notify(self, args): """ Mass unit dropdown and calculation for gamepiece elements """ - weightTableInput_f = self.createTableInput( - "weight_table_f", "Weight Table", gamepiece_inputs, 3, "6:2:1", 1 - ) + weightTableInput_f = self.createTableInput("weight_table_f", "Weight Table", gamepiece_inputs, 3, "6:2:1", 1) weightTableInput_f.tablePresentationStyle = 2 # set to clear background weight_name_f = gamepiece_inputs.addStringValueInput("weight_name", "Weight") @@ -348,26 +325,14 @@ def notify(self, args): "Unit of Mass", adsk.core.DropDownStyles.LabeledIconDropDownStyle, ) - weight_unit_f.listItems.add( - "‎", True, IconPaths.massIcons["LBS"] - ) # add listdropdown mass options - weight_unit_f.listItems.add( - "‎", False, IconPaths.massIcons["KG"] - ) # add listdropdown mass options + weight_unit_f.listItems.add("‎", True, IconPaths.massIcons["LBS"]) # add listdropdown mass options + weight_unit_f.listItems.add("‎", False, IconPaths.massIcons["KG"]) # add listdropdown mass options weight_unit_f.tooltip = "Unit of mass" - weight_unit_f.tooltipDescription = ( - "
Configure the unit of mass for for the weight calculation." - ) + weight_unit_f.tooltipDescription = "
Configure the unit of mass for for the weight calculation." - weightTableInput_f.addCommandInput( - weight_name_f, 0, 0 - ) # add command inputs to table - weightTableInput_f.addCommandInput( - auto_calc_weight_f, 0, 1 - ) # add command inputs to table - weightTableInput_f.addCommandInput( - weight_unit_f, 0, 2 - ) # add command inputs to table + weightTableInput_f.addCommandInput(weight_name_f, 0, 0) # add command inputs to table + weightTableInput_f.addCommandInput(auto_calc_weight_f, 0, 1) # add command inputs to table + weightTableInput_f.addCommandInput(weight_unit_f, 0, 2) # add command inputs to table # GAMEPIECE SELECTION TABLE """ @@ -384,9 +349,7 @@ def notify(self, args): addFieldInput = gamepiece_inputs.addBoolValueInput("field_add", "Add", False) - removeFieldInput = gamepiece_inputs.addBoolValueInput( - "field_delete", "Remove", False - ) + removeFieldInput = gamepiece_inputs.addBoolValueInput("field_delete", "Remove", False) addFieldInput.isEnabled = removeFieldInput.isEnabled = True removeFieldInput.tooltip = "Remove a field element" @@ -448,19 +411,17 @@ def notify(self, args): """ Creates the advanced tab, which is the parent container for internal command inputs """ - advancedSettings: adsk.core.TabCommandInput = INPUTS_ROOT.addTabCommandInput( - "advanced_settings", "Advanced" + advancedSettings: adsk.core.TabCommandInput = INPUTS_ROOT.addTabCommandInput("advanced_settings", "Advanced") + advancedSettings.tooltip = ( + "Additional Advanced Settings to change how your model will be translated into Unity." ) - advancedSettings.tooltip = "Additional Advanced Settings to change how your model will be translated into Unity." a_input: adsk.core.CommandInputs = advancedSettings.children # ~~~~~~~~~~~~~~~~ EXPORTER SETTINGS ~~~~~~~~~~~~~~~~ """ Exporter settings group command """ - exporterSettings = a_input.addGroupCommandInput( - "exporter_settings", "Exporter Settings" - ) + exporterSettings = a_input.addGroupCommandInput("exporter_settings", "Exporter Settings") exporterSettings.isExpanded = True exporterSettings.isEnabled = True exporterSettings.tooltip = "tooltip" # TODO: update tooltip @@ -507,26 +468,20 @@ def notify(self, args): enabled=True, isCheckBox=False, ) - frictionOverrideInput.resourceFolder = IconPaths.stringIcons[ - "friction_override-enabled" - ] + frictionOverrideInput.resourceFolder = IconPaths.stringIcons["friction_override-enabled"] frictionOverrideInput.isFullWidth = True valueList = [1] for i in range(20): valueList.append(i / 20) - frictionCoeffSlider: adsk.core.FloatSliderCommandInput = ( - physics_settings.addFloatSliderListCommandInput( - "friction_override_coeff", "Friction Coefficient", "", valueList - ) + frictionCoeffSlider: adsk.core.FloatSliderCommandInput = physics_settings.addFloatSliderListCommandInput( + "friction_override_coeff", "Friction Coefficient", "", valueList ) frictionCoeffSlider.isVisible = True frictionCoeffSlider.valueOne = 0.5 frictionCoeffSlider.tooltip = "Friction coefficient of field element." - frictionCoeffSlider.tooltipDescription = ( - "Friction coefficients range from 0 (ice) to 1 (rubber)." - ) + frictionCoeffSlider.tooltipDescription = "Friction coefficients range from 0 (ice) to 1 (rubber)." # ~~~~~~~~~~~~~~~~ JOINT SETTINGS ~~~~~~~~~~~~~~~~ """ @@ -825,9 +780,7 @@ def notify(self, args): isRobot = False dropdownExportLocation = INPUTS_ROOT.itemById("location") if dropdownExportLocation.selectedItem.index == 1: # Download - savepath = FileDialogConfig.saveFileDialog( - defaultPath=exporterOptions.fileLocation - ) + savepath = FileDialogConfig.saveFileDialog(defaultPath=exporterOptions.fileLocation) if savepath == False: # save was canceled @@ -859,16 +812,12 @@ def notify(self, args): if row == 0: continue - weightValue = gamepieceTableInput.getInputAtPosition( - row, 2 - ).value # weight/mass input, float + weightValue = gamepieceTableInput.getInputAtPosition(row, 2).value # weight/mass input, float if weight_unit_f.selectedItem.index == 0: weightValue /= 2.2046226218 - frictionValue = gamepieceTableInput.getInputAtPosition( - row, 3 - ).valueOne # friction value, float + frictionValue = gamepieceTableInput.getInputAtPosition(row, 3).valueOne # friction value, float _exportGamepieces.append( Gamepiece( @@ -1024,9 +973,7 @@ def __init__(self, cmd): self.cmd = cmd self.allWheelPreselections = [] # all child occurrences of selections - self.allGamepiecePreselections = ( - [] - ) # all child gamepiece occurrences of selections + self.allGamepiecePreselections = [] # all child gamepiece occurrences of selections self.selectedOcc = None # selected occurrence (if there is one) self.selectedJoint = None # selected joint (if there is one) @@ -1083,18 +1030,12 @@ def wheelParent(self, occ: adsk.fusion.Occurrence): try: for joint in occ.joints: - if ( - joint.jointMotion.jointType - == adsk.fusion.JointTypes.RevoluteJointType - ): + if joint.jointMotion.jointType == adsk.fusion.JointTypes.RevoluteJointType: # gm.ui.messageBox("Selection is directly jointed.\nReturning selection.\n\n" + "Occurrence:\n--> " + occ.name + "\nJoint:\n--> " + joint.name) return [joint.entityToken, occ] except: for joint in occ.component.joints: - if ( - joint.jointMotion.jointType - == adsk.fusion.JointTypes.RevoluteJointType - ): + if joint.jointMotion.jointType == adsk.fusion.JointTypes.RevoluteJointType: # gm.ui.messageBox("Selection is directly jointed.\nReturning selection.\n\n" + "Occurrence:\n--> " + occ.name + "\nJoint:\n--> " + joint.name) return [joint.entityToken, occ] @@ -1246,9 +1187,7 @@ def notify(self, args): preSelectedJoint = adsk.fusion.Joint.cast(args.selection.entity) if (preSelectedOcc or preSelectedJoint) and design: - self.cmd.setCursor( - "", 0, 0 - ) # if preselection ends (mouse off of design), reset the mouse icon to default + self.cmd.setCursor("", 0, 0) # if preselection ends (mouse off of design), reset the mouse icon to default class ConfigureCommandInputChanged(adsk.core.InputChangedEventHandler): @@ -1349,11 +1288,7 @@ def notify(self, args): gm.ui.activeSelections.clear() gm.app.activeDocument.design.rootComponent.opacity = 1 - elif ( - cmdInput.id == "blank_gp" - or cmdInput.id == "name_gp" - or cmdInput.id == "weight_gp" - ): + elif cmdInput.id == "blank_gp" or cmdInput.id == "name_gp" or cmdInput.id == "weight_gp": self.reset() gamepieceSelect.isEnabled = False @@ -1362,33 +1297,13 @@ def notify(self, args): cmdInput_str = cmdInput.id if cmdInput_str == "name_gp": - position = ( - gamepieceTableInput.getPosition( - adsk.core.TextBoxCommandInput.cast(cmdInput) - )[1] - - 1 - ) + position = gamepieceTableInput.getPosition(adsk.core.TextBoxCommandInput.cast(cmdInput))[1] - 1 elif cmdInput_str == "weight_gp": - position = ( - gamepieceTableInput.getPosition( - adsk.core.ValueCommandInput.cast(cmdInput) - )[1] - - 1 - ) + position = gamepieceTableInput.getPosition(adsk.core.ValueCommandInput.cast(cmdInput))[1] - 1 elif cmdInput_str == "blank_gp": - position = ( - gamepieceTableInput.getPosition( - adsk.core.ImageCommandInput.cast(cmdInput) - )[1] - - 1 - ) + position = gamepieceTableInput.getPosition(adsk.core.ImageCommandInput.cast(cmdInput))[1] - 1 else: - position = ( - gamepieceTableInput.getPosition( - adsk.core.FloatSliderCommandInput.cast(cmdInput) - )[1] - - 1 - ) + position = gamepieceTableInput.getPosition(adsk.core.FloatSliderCommandInput.cast(cmdInput))[1] - 1 gm.ui.activeSelections.add(GamepieceListGlobal[position]) @@ -1405,10 +1320,7 @@ def notify(self, args): addFieldInput.isEnabled = True - if ( - gamepieceTableInput.selectedRow == -1 - or gamepieceTableInput.selectedRow == 0 - ): + if gamepieceTableInput.selectedRow == -1 or gamepieceTableInput.selectedRow == 0: gamepieceTableInput.selectedRow = gamepieceTableInput.rowCount - 1 gm.ui.messageBox("Select a row to delete.") else: @@ -1432,11 +1344,15 @@ def notify(self, args): if unitDropdown.selectedItem.index == 0: self.isLbs = True - weightInput.tooltipDescription = """(in pounds)
This is the weight of the entire robot assembly.""" + weightInput.tooltipDescription = ( + """(in pounds)
This is the weight of the entire robot assembly.""" + ) elif unitDropdown.selectedItem.index == 1: self.isLbs = False - weightInput.tooltipDescription = """(in kilograms)
This is the weight of the entire robot assembly.""" + weightInput.tooltipDescription = ( + """(in kilograms)
This is the weight of the entire robot assembly.""" + ) elif cmdInput.id == "weight_unit_f": unitDropdown = adsk.core.DropDownCommandInput.cast(cmdInput) @@ -1461,9 +1377,7 @@ def notify(self, args): button = adsk.core.BoolValueCommandInput.cast(cmdInput) if button.value == True: # CALCULATE button pressed - if ( - self.allWeights.count(None) == 2 - ): # if button is pressed for the first time + if self.allWeights.count(None) == 2: # if button is pressed for the first time if self.isLbs: # if pounds unit selected self.allWeights[0] = self.weight() weight_input.value = self.allWeights[0] @@ -1490,9 +1404,7 @@ def notify(self, args): if row == 0: continue weightInput = gamepieceTableInput.getInputAtPosition(row, 2) - physical = GamepieceListGlobal[ - row - 1 - ].component.getPhysicalProperties( + physical = GamepieceListGlobal[row - 1].component.getPhysicalProperties( adsk.fusion.CalculationAccuracy.LowCalculationAccuracy ) value = round(physical.mass * 2.2046226218, 2) @@ -1503,9 +1415,7 @@ def notify(self, args): if row == 0: continue weightInput = gamepieceTableInput.getInputAtPosition(row, 2) - physical = GamepieceListGlobal[ - row - 1 - ].component.getPhysicalProperties( + physical = GamepieceListGlobal[row - 1].component.getPhysicalProperties( adsk.fusion.CalculationAccuracy.LowCalculationAccuracy ) value = round(physical.mass, 2) @@ -1568,18 +1478,12 @@ def addPreselections(child_occurrences): GamepieceListGlobal.append(gamepiece) cmdInputs = adsk.core.CommandInputs.cast(gamepieceTableInput.commandInputs) - blankIcon = cmdInputs.addImageCommandInput( - "blank_gp", "Blank", IconPaths.gamepieceIcons["blank"] - ) + blankIcon = cmdInputs.addImageCommandInput("blank_gp", "Blank", IconPaths.gamepieceIcons["blank"]) - type = cmdInputs.addTextBoxCommandInput( - "name_gp", "Occurrence name", gamepiece.name, 1, True - ) + type = cmdInputs.addTextBoxCommandInput("name_gp", "Occurrence name", gamepiece.name, 1, True) value = 0.0 - physical = gamepiece.component.getPhysicalProperties( - adsk.fusion.CalculationAccuracy.LowCalculationAccuracy - ) + physical = gamepiece.component.getPhysicalProperties(adsk.fusion.CalculationAccuracy.LowCalculationAccuracy) value = physical.mass # check if dropdown unit is kg or lbs. bool value taken from ConfigureCommandInputChanged @@ -1603,9 +1507,7 @@ def addPreselections(child_occurrences): for i in range(20): valueList.append(i / 20) - friction_coeff = cmdInputs.addFloatSliderListCommandInput( - "friction_coeff", "", "", valueList - ) + friction_coeff = cmdInputs.addFloatSliderListCommandInput("friction_coeff", "", "", valueList) friction_coeff.valueOne = 0.5 type.tooltip = gamepiece.name @@ -1614,9 +1516,7 @@ def addPreselections(child_occurrences): weight.tooltipDescription = massUnitInString friction_coeff.tooltip = "Friction coefficient of field element" - friction_coeff.tooltipDescription = ( - "Friction coefficients range from 0 (ice) to 1 (rubber)." - ) + friction_coeff.tooltipDescription = "Friction coefficients range from 0 (ice) to 1 (rubber)." row = gamepieceTableInput.rowCount gamepieceTableInput.addCommandInput(blankIcon, row, 0) diff --git a/exporter/SynthesisFusionAddin/src/UI/CustomGraphics.py b/exporter/SynthesisFusionAddin/src/UI/CustomGraphics.py index 1c6a5c8b3f..52a49fa5d4 100644 --- a/exporter/SynthesisFusionAddin/src/UI/CustomGraphics.py +++ b/exporter/SynthesisFusionAddin/src/UI/CustomGraphics.py @@ -22,20 +22,14 @@ def createTextGraphics(wheel: adsk.fusion.Occurrence, _wheels) -> None: matrix = adsk.core.Matrix3D.create() matrix.translation = adsk.core.Vector3D.create(min[0], min[1] - 5, min[2]) - billBoard = adsk.fusion.CustomGraphicsBillBoard.create( - adsk.core.Point3D.create(0, 0, 0) - ) - billBoard.billBoardStyle = ( - adsk.fusion.CustomGraphicsBillBoardStyles.ScreenBillBoardStyle - ) + billBoard = adsk.fusion.CustomGraphicsBillBoard.create(adsk.core.Point3D.create(0, 0, 0)) + billBoard.billBoardStyle = adsk.fusion.CustomGraphicsBillBoardStyles.ScreenBillBoardStyle text = str(_wheels.index(wheel) + 1) graphicsText = graphics.addText(text, "Arial Black", 6, matrix) graphicsText.billBoarding = billBoard # make the text follow the camera graphicsText.isSelectable = False # make it non-selectable - graphicsText.cullMode = ( - adsk.fusion.CustomGraphicsCullModes.CustomGraphicsCullBack - ) + graphicsText.cullMode = adsk.fusion.CustomGraphicsCullModes.CustomGraphicsCullBack graphicsText.color = adsk.fusion.CustomGraphicsShowThroughColorEffect.create( adsk.core.Color.create(230, 146, 18, 255), 1 ) # orange/synthesis theme diff --git a/exporter/SynthesisFusionAddin/src/UI/Events.py b/exporter/SynthesisFusionAddin/src/UI/Events.py index bf96f5b9cc..281ebf3f0e 100644 --- a/exporter/SynthesisFusionAddin/src/UI/Events.py +++ b/exporter/SynthesisFusionAddin/src/UI/Events.py @@ -53,12 +53,8 @@ def openDocument(json_data: str) -> str: """ data = json.loads(json_data) data = data["arguments"] - gm.ui.messageBox( - f"Attempting to open and focus on a given document: {data}\n TODO: Implement" - ) - logger.info( - f"Attempting to open and focus on a given document: {data}\n TODO: Implement" - ) + gm.ui.messageBox(f"Attempting to open and focus on a given document: {data}\n TODO: Implement") + logger.info(f"Attempting to open and focus on a given document: {data}\n TODO: Implement") return "" diff --git a/exporter/SynthesisFusionAddin/src/UI/FileDialogConfig.py b/exporter/SynthesisFusionAddin/src/UI/FileDialogConfig.py index 47f7aba3eb..6f6f764cd9 100644 --- a/exporter/SynthesisFusionAddin/src/UI/FileDialogConfig.py +++ b/exporter/SynthesisFusionAddin/src/UI/FileDialogConfig.py @@ -9,9 +9,7 @@ from ..Types import OString -def saveFileDialog( - defaultPath: str | None = None, defaultName: str | None = None -) -> str | bool: +def saveFileDialog(defaultPath: str | None = None, defaultName: str | None = None) -> str | bool: """Function to generate the Save File Dialog for the Hellion Data files Args: diff --git a/exporter/SynthesisFusionAddin/src/UI/HUI.py b/exporter/SynthesisFusionAddin/src/UI/HUI.py index 2842e70a78..3b52de9999 100644 --- a/exporter/SynthesisFusionAddin/src/UI/HUI.py +++ b/exporter/SynthesisFusionAddin/src/UI/HUI.py @@ -44,9 +44,7 @@ def __init__( self.events.append(arg) if self.uid in gm.uniqueIds: - raise ValueError( - f"Cannot create two UI Elements with the same ID {self.uid}\n" - ) + raise ValueError(f"Cannot create two UI Elements with the same ID {self.uid}\n") if gm.ui.palettes is None: raise RuntimeError(f"No Palette object exists yet") @@ -54,9 +52,7 @@ def __init__( self.palette = gm.ui.palettes.itemById(self.uid) if self.palette is None: - path = OsHelper.getOSPathPalette( - "src", "Resources", "Palette", f'{self.name.replace(" ", "")}' - ) + path = OsHelper.getOSPathPalette("src", "Resources", "Palette", f'{self.name.replace(" ", "")}') self.palette = gm.ui.palettes.add( self.uid, @@ -69,9 +65,7 @@ def __init__( height, ) - self.palette.dockingState = ( - adsk.core.PaletteDockingStates.PaletteDockStateLeft - ) + self.palette.dockingState = adsk.core.PaletteDockingStates.PaletteDockStateLeft onHTML = Handlers.HPaletteHTMLEventHandler(self) self.palette.incomingFromHTML.add(onHTML) @@ -118,9 +112,7 @@ def __init__( self.uid = name.replace(" ", "") + f"_{INTERNAL_ID}" if self.uid in gm.uniqueIds: - raise ValueError( - f"Cannot create two UI Elements with the same ID {self.uid}\n" - ) + raise ValueError(f"Cannot create two UI Elements with the same ID {self.uid}\n") self.name = name @@ -138,9 +130,7 @@ def __init__( self.uid, f"{name}", f"{description}", - OsHelper.getOSPath( - ".", "src", "Resources", f'{self.name.replace(" ", "")}' - ), + OsHelper.getOSPath(".", "src", "Resources", f'{self.name.replace(" ", "")}'), ) """ Button Command Definition stored as a member """ @@ -190,9 +180,7 @@ def deleteMe(self): if cmdDef: cmdDef.deleteMe() - ctrl = gm.ui.allToolbarPanels.itemById(self.location).controls.itemById( - self.uid - ) + ctrl = gm.ui.allToolbarPanels.itemById(self.location).controls.itemById(self.uid) if ctrl: ctrl.deleteMe() diff --git a/exporter/SynthesisFusionAddin/src/UI/Helper.py b/exporter/SynthesisFusionAddin/src/UI/Helper.py index 560f69f9df..7c8e3a5930 100644 --- a/exporter/SynthesisFusionAddin/src/UI/Helper.py +++ b/exporter/SynthesisFusionAddin/src/UI/Helper.py @@ -25,9 +25,7 @@ def checkAttribute() -> bool: return connected.value return False except: - app.userInterface.messageBox( - f"Could not access the attributes of the file \n -- {traceback.format_exc()}." - ) + app.userInterface.messageBox(f"Could not access the attributes of the file \n -- {traceback.format_exc()}.") return False @@ -48,9 +46,7 @@ def addUnityAttribute() -> bool or None: return None except: - app.userInterface.messageBox( - f"Could not access the attributes of the file \n -- {traceback.format_exc()}." - ) + app.userInterface.messageBox(f"Could not access the attributes of the file \n -- {traceback.format_exc()}.") return False @@ -71,9 +67,7 @@ def openPanel() -> None: gm.app.data.isDataPanelVisible = False else: func_list = [o for o in getmembers(Events, isfunction)] - palette_new = HUI.HPalette( - name, APP_TITLE, True, True, False, 400, 500, func_list - ) + palette_new = HUI.HPalette(name, APP_TITLE, True, True, False, 400, 500, func_list) gm.elements.append(palette_new) return diff --git a/exporter/SynthesisFusionAddin/src/UI/IconPaths.py b/exporter/SynthesisFusionAddin/src/UI/IconPaths.py index f5f9017b4e..261720494c 100644 --- a/exporter/SynthesisFusionAddin/src/UI/IconPaths.py +++ b/exporter/SynthesisFusionAddin/src/UI/IconPaths.py @@ -5,27 +5,20 @@ """ Dictionaries that store all the icon paths in ConfigCommand. All path strings are OS-independent """ -resources = OsHelper.getOSPath( - ".", "src", "Resources" -) # str shortcut with primary directories to all images in file +resources = OsHelper.getOSPath(".", "src", "Resources") # str shortcut with primary directories to all images in file wheelIcons = { "omni": resources + os.path.join("WheelIcons", "omni-wheel-preview190x24.png"), - "standard": resources - + os.path.join("WheelIcons", "standard-wheel-preview190x24.png"), - "mecanum": resources - + os.path.join("WheelIcons", "mecanum-wheel-preview190x24.png"), + "standard": resources + os.path.join("WheelIcons", "standard-wheel-preview190x24.png"), + "mecanum": resources + os.path.join("WheelIcons", "mecanum-wheel-preview190x24.png"), } jointIcons = { "rigid": resources + os.path.join("JointIcons", "JointRigid", "rigid190x24.png"), - "revolute": resources - + os.path.join("JointIcons", "JointRev", "revolute190x24.png"), + "revolute": resources + os.path.join("JointIcons", "JointRev", "revolute190x24.png"), "slider": resources + os.path.join("JointIcons", "JointSlider", "slider190x24.png"), - "cylindrical": resources - + os.path.join("JointIcons", "JointCyl", "cylindrical190x24.png"), - "pin_slot": resources - + os.path.join("JointIcons", "JointPinSlot", "pin_slot190x24.png"), + "cylindrical": resources + os.path.join("JointIcons", "JointCyl", "cylindrical190x24.png"), + "pin_slot": resources + os.path.join("JointIcons", "JointPinSlot", "pin_slot190x24.png"), "planar": resources + os.path.join("JointIcons", "JointPlanar", "planar190x24.png"), "ball": resources + os.path.join("JointIcons", "JointBall", "ball190x24.png"), } @@ -51,8 +44,6 @@ } stringIcons = { - "calculate-enabled": resources - + os.path.join("AutoCalcWeight_icon"), # resource folder - "friction_override-enabled": resources - + os.path.join("FrictionOverride_icon"), # resource folder + "calculate-enabled": resources + os.path.join("AutoCalcWeight_icon"), # resource folder + "friction_override-enabled": resources + os.path.join("FrictionOverride_icon"), # resource folder } diff --git a/exporter/SynthesisFusionAddin/src/UI/JointConfigTab.py b/exporter/SynthesisFusionAddin/src/UI/JointConfigTab.py index 30304f8b90..9332f11d01 100644 --- a/exporter/SynthesisFusionAddin/src/UI/JointConfigTab.py +++ b/exporter/SynthesisFusionAddin/src/UI/JointConfigTab.py @@ -26,14 +26,10 @@ class JointConfigTab: @logFailure def __init__(self, args: adsk.core.CommandCreatedEventArgs) -> None: inputs = args.command.commandInputs - self.jointConfigTab = inputs.addTabCommandInput( - "jointSettings", "Joint Settings" - ) + self.jointConfigTab = inputs.addTabCommandInput("jointSettings", "Joint Settings") self.jointConfigTab.tooltip = "Select and configure robot joints." jointConfigTabInputs = self.jointConfigTab.children - self.jointConfigTable = createTableInput( - "jointTable", "Joint Table", jointConfigTabInputs, 7, "1:2:2:2:2:2:2" - ) + self.jointConfigTable = createTableInput("jointTable", "Joint Table", jointConfigTabInputs, 7, "1:2:2:2:2:2:2") self.jointConfigTable.addCommandInput( createTextBoxInput( "jointMotionHeader", @@ -46,9 +42,7 @@ def __init__(self, args: adsk.core.CommandCreatedEventArgs) -> None: 0, ) self.jointConfigTable.addCommandInput( - createTextBoxInput( - "nameHeader", "Name", jointConfigTabInputs, "Joint name", bold=False - ), + createTextBoxInput("nameHeader", "Name", jointConfigTabInputs, "Joint name", bold=False), 0, 1, ) @@ -113,17 +107,11 @@ def __init__(self, args: adsk.core.CommandCreatedEventArgs) -> None: ) jointSelect.addSelectionFilter("Joints") jointSelect.setSelectionLimits(0) - jointSelect.isEnabled = jointSelect.isVisible = ( - False # Visibility is triggered by `addJointInputButton` - ) + jointSelect.isEnabled = jointSelect.isVisible = False # Visibility is triggered by `addJointInputButton` - jointConfigTabInputs.addTextBoxCommandInput( - "jointTabBlankSpacer", "", "", 1, True - ) + jointConfigTabInputs.addTextBoxCommandInput("jointTabBlankSpacer", "", "", 1, True) - self.wheelConfigTable = createTableInput( - "wheelTable", "Wheel Table", jointConfigTabInputs, 4, "1:2:2:2" - ) + self.wheelConfigTable = createTableInput("wheelTable", "Wheel Table", jointConfigTabInputs, 4, "1:2:2:2") self.wheelConfigTable.addCommandInput( createTextBoxInput( "wheelMotionHeader", @@ -136,9 +124,7 @@ def __init__(self, args: adsk.core.CommandCreatedEventArgs) -> None: 0, ) self.wheelConfigTable.addCommandInput( - createTextBoxInput( - "name_header", "Name", jointConfigTabInputs, "Joint name", bold=False - ), + createTextBoxInput("name_header", "Name", jointConfigTabInputs, "Joint name", bold=False), 0, 1, ) @@ -165,17 +151,11 @@ def __init__(self, args: adsk.core.CommandCreatedEventArgs) -> None: 3, ) - jointSelectCancelButton = jointConfigTabInputs.addBoolValueInput( - "jointSelectCancelButton", "Cancel", False - ) + jointSelectCancelButton = jointConfigTabInputs.addBoolValueInput("jointSelectCancelButton", "Cancel", False) jointSelectCancelButton.isEnabled = jointSelectCancelButton.isVisible = False - addJointInputButton = jointConfigTabInputs.addBoolValueInput( - "jointAddButton", "Add", False - ) - removeJointInputButton = jointConfigTabInputs.addBoolValueInput( - "jointRemoveButton", "Remove", False - ) + addJointInputButton = jointConfigTabInputs.addBoolValueInput("jointAddButton", "Add", False) + removeJointInputButton = jointConfigTabInputs.addBoolValueInput("jointRemoveButton", "Remove", False) addJointInputButton.isEnabled = removeJointInputButton.isEnabled = True self.jointConfigTable.addToolbarCommandInput(addJointInputButton) @@ -185,9 +165,7 @@ def __init__(self, args: adsk.core.CommandCreatedEventArgs) -> None: self.reset() @logFailure - def addJoint( - self, fusionJoint: adsk.fusion.Joint, synJoint: Joint | None = None - ) -> bool: + def addJoint(self, fusionJoint: adsk.fusion.Joint, synJoint: Joint | None = None) -> bool: if fusionJoint in self.selectedJointList: return False @@ -195,62 +173,34 @@ def addJoint( commandInputs = self.jointConfigTable.commandInputs if fusionJoint.jointMotion.jointType == adsk.fusion.JointTypes.RigidJointType: - icon = commandInputs.addImageCommandInput( - "placeholder", "Rigid", IconPaths.jointIcons["rigid"] - ) + icon = commandInputs.addImageCommandInput("placeholder", "Rigid", IconPaths.jointIcons["rigid"]) icon.tooltip = "Rigid joint" - elif ( - fusionJoint.jointMotion.jointType - == adsk.fusion.JointTypes.RevoluteJointType - ): - icon = commandInputs.addImageCommandInput( - "placeholder", "Revolute", IconPaths.jointIcons["revolute"] - ) + elif fusionJoint.jointMotion.jointType == adsk.fusion.JointTypes.RevoluteJointType: + icon = commandInputs.addImageCommandInput("placeholder", "Revolute", IconPaths.jointIcons["revolute"]) icon.tooltip = "Revolute joint" - elif ( - fusionJoint.jointMotion.jointType == adsk.fusion.JointTypes.SliderJointType - ): - icon = commandInputs.addImageCommandInput( - "placeholder", "Slider", IconPaths.jointIcons["slider"] - ) + elif fusionJoint.jointMotion.jointType == adsk.fusion.JointTypes.SliderJointType: + icon = commandInputs.addImageCommandInput("placeholder", "Slider", IconPaths.jointIcons["slider"]) icon.tooltip = "Slider joint" - elif ( - fusionJoint.jointMotion.jointType == adsk.fusion.JointTypes.PlanarJointType - ): - icon = commandInputs.addImageCommandInput( - "placeholder", "Planar", IconPaths.jointIcons["planar"] - ) + elif fusionJoint.jointMotion.jointType == adsk.fusion.JointTypes.PlanarJointType: + icon = commandInputs.addImageCommandInput("placeholder", "Planar", IconPaths.jointIcons["planar"]) icon.tooltip = "Planar joint" - elif ( - fusionJoint.jointMotion.jointType == adsk.fusion.JointTypes.PinSlotJointType - ): - icon = commandInputs.addImageCommandInput( - "placeholder", "Pin Slot", IconPaths.jointIcons["pin_slot"] - ) + elif fusionJoint.jointMotion.jointType == adsk.fusion.JointTypes.PinSlotJointType: + icon = commandInputs.addImageCommandInput("placeholder", "Pin Slot", IconPaths.jointIcons["pin_slot"]) icon.tooltip = "Pin slot joint" - elif ( - fusionJoint.jointMotion.jointType - == adsk.fusion.JointTypes.CylindricalJointType - ): - icon = commandInputs.addImageCommandInput( - "placeholder", "Cylindrical", IconPaths.jointIcons["cylindrical"] - ) + elif fusionJoint.jointMotion.jointType == adsk.fusion.JointTypes.CylindricalJointType: + icon = commandInputs.addImageCommandInput("placeholder", "Cylindrical", IconPaths.jointIcons["cylindrical"]) icon.tooltip = "Cylindrical joint" elif fusionJoint.jointMotion.jointType == adsk.fusion.JointTypes.BallJointType: - icon = commandInputs.addImageCommandInput( - "placeholder", "Ball", IconPaths.jointIcons["ball"] - ) + icon = commandInputs.addImageCommandInput("placeholder", "Ball", IconPaths.jointIcons["ball"]) icon.tooltip = "Ball joint" - name = commandInputs.addTextBoxCommandInput( - "name_j", "Occurrence name", "", 1, True - ) + name = commandInputs.addTextBoxCommandInput("name_j", "Occurrence name", "", 1, True) name.tooltip = fusionJoint.name name.formattedText = f"

{fusionJoint.name}

" @@ -274,9 +224,7 @@ def addJoint( jointType.listItems.add(fusionJoint.name, False) jointType.tooltip = "Possible parent joints" - jointType.tooltipDescription = ( - "
The root component is usually the parent." - ) + jointType.tooltipDescription = "
The root component is usually the parent." signalType = commandInputs.addDropDownCommandInput( "signalTypeJoint", @@ -287,12 +235,8 @@ def addJoint( # Invisible white space characters are required in the list item name field to make this work. # I have no idea why, Fusion API needs some special education help - Brandon if synJoint: - signalType.listItems.add( - "‎", synJoint.signalType is SignalType.PWM, IconPaths.signalIcons["PWM"] - ) - signalType.listItems.add( - "‎", synJoint.signalType is SignalType.CAN, IconPaths.signalIcons["CAN"] - ) + signalType.listItems.add("‎", synJoint.signalType is SignalType.PWM, IconPaths.signalIcons["PWM"]) + signalType.listItems.add("‎", synJoint.signalType is SignalType.CAN, IconPaths.signalIcons["CAN"]) signalType.listItems.add( "‎", synJoint.signalType is SignalType.PASSIVE, @@ -312,10 +256,7 @@ def addJoint( self.jointConfigTable.addCommandInput(signalType, row, 3) # Comparison by `==` over `is` because the Autodesk API does not use `Enum` for their enum classes - if ( - fusionJoint.jointMotion.jointType - == adsk.fusion.JointTypes.RevoluteJointType - ): + if fusionJoint.jointMotion.jointType == adsk.fusion.JointTypes.RevoluteJointType: if synJoint: jointSpeedValue = synJoint.speed else: @@ -330,9 +271,7 @@ def addJoint( jointSpeed.tooltip = "Degrees per second" self.jointConfigTable.addCommandInput(jointSpeed, row, 4) - elif ( - fusionJoint.jointMotion.jointType == adsk.fusion.JointTypes.SliderJointType - ): + elif fusionJoint.jointMotion.jointType == adsk.fusion.JointTypes.SliderJointType: if synJoint: jointSpeedValue = synJoint.speed else: @@ -348,9 +287,7 @@ def addJoint( self.jointConfigTable.addCommandInput(jointSpeed, row, 4) if synJoint: - jointForceValue = ( - synJoint.force * 100 - ) # Currently a factor of 100 - Should be investigated + jointForceValue = synJoint.force * 100 # Currently a factor of 100 - Should be investigated else: jointForceValue = 5 @@ -363,14 +300,9 @@ def addJoint( jointForce.tooltip = "Newtons" self.jointConfigTable.addCommandInput(jointForce, row, 5) - if ( - fusionJoint.jointMotion.jointType - == adsk.fusion.JointTypes.RevoluteJointType - ): + if fusionJoint.jointMotion.jointType == adsk.fusion.JointTypes.RevoluteJointType: wheelCheckboxEnabled = True - wheelCheckboxTooltip = ( - "Determines if this joint should be counted as a wheel." - ) + wheelCheckboxTooltip = "Determines if this joint should be counted as a wheel." else: wheelCheckboxEnabled = False wheelCheckboxTooltip = "Only Revolute joints can be treated as wheels." @@ -403,9 +335,7 @@ def addWheel(self, joint: adsk.fusion.Joint, wheel: Wheel | None = None) -> None "wheelPlaceholder", "Placeholder", IconPaths.wheelIcons["standard"] ) wheelIcon.tooltip = "Standard wheel" - wheelName = commandInputs.addTextBoxCommandInput( - "wheelName", "Joint Name", joint.name, 1, True - ) + wheelName = commandInputs.addTextBoxCommandInput("wheelName", "Joint Name", joint.name, 1, True) wheelName.tooltip = joint.name # TODO: Should this be the same? wheelType = commandInputs.addDropDownCommandInput( "wheelType", @@ -433,22 +363,12 @@ def addWheel(self, joint: adsk.fusion.Joint, wheel: Wheel | None = None) -> None ) signalType.isFullWidth = True signalType.isEnabled = False - signalType.tooltip = ( - "Wheel signal type is linked with the respective joint signal type." - ) + signalType.tooltip = "Wheel signal type is linked with the respective joint signal type." i = self.selectedJointList.index(joint) - jointSignalType = SignalType( - self.jointConfigTable.getInputAtPosition(i + 1, 3).selectedItem.index + 1 - ) - signalType.listItems.add( - "‎", jointSignalType is SignalType.PWM, IconPaths.signalIcons["PWM"] - ) - signalType.listItems.add( - "‎", jointSignalType is SignalType.CAN, IconPaths.signalIcons["CAN"] - ) - signalType.listItems.add( - "‎", jointSignalType is SignalType.PASSIVE, IconPaths.signalIcons["PASSIVE"] - ) + jointSignalType = SignalType(self.jointConfigTable.getInputAtPosition(i + 1, 3).selectedItem.index + 1) + signalType.listItems.add("‎", jointSignalType is SignalType.PWM, IconPaths.signalIcons["PWM"]) + signalType.listItems.add("‎", jointSignalType is SignalType.CAN, IconPaths.signalIcons["CAN"]) + signalType.listItems.add("‎", jointSignalType is SignalType.PASSIVE, IconPaths.signalIcons["PASSIVE"]) row = self.wheelConfigTable.rowCount self.wheelConfigTable.addCommandInput(wheelIcon, row, 0) @@ -500,9 +420,7 @@ def getSelectedJointsAndWheels(self) -> tuple[list[Joint], list[Wheel]]: wheels: list[Wheel] = [] for row in range(1, self.jointConfigTable.rowCount): # Row is 1 indexed jointEntityToken = self.selectedJointList[row - 1].entityToken - signalTypeIndex = self.jointConfigTable.getInputAtPosition( - row, 3 - ).selectedItem.index + signalTypeIndex = self.jointConfigTable.getInputAtPosition(row, 3).selectedItem.index signalType = SignalType(signalTypeIndex + 1) jointSpeed: float = self.jointConfigTable.getInputAtPosition(row, 4).value jointForce: float = self.jointConfigTable.getInputAtPosition(row, 5).value @@ -521,9 +439,7 @@ def getSelectedJointsAndWheels(self) -> tuple[list[Joint], list[Wheel]]: if isWheel: wheelRow = self.jointWheelIndexMap[jointEntityToken] - wheelTypeIndex = self.wheelConfigTable.getInputAtPosition( - wheelRow, 2 - ).selectedItem.index + wheelTypeIndex = self.wheelConfigTable.getInputAtPosition(wheelRow, 2).selectedItem.index wheels.append( Wheel( jointEntityToken, @@ -554,9 +470,7 @@ def handleInputChanged( if commandInput.id == "wheelType": wheelTypeDropdown = adsk.core.DropDownCommandInput.cast(commandInput) position = self.wheelConfigTable.getPosition(wheelTypeDropdown)[1] - iconInput: adsk.core.ImageCommandInput = ( - self.wheelConfigTable.getInputAtPosition(position, 0) - ) + iconInput: adsk.core.ImageCommandInput = self.wheelConfigTable.getInputAtPosition(position, 0) if wheelTypeDropdown.selectedItem.index == 0: iconInput.imageFile = IconPaths.wheelIcons["standard"] @@ -571,11 +485,7 @@ def handleInputChanged( elif commandInput.id == "isWheel": isWheelCheckbox = adsk.core.BoolValueCommandInput.cast(commandInput) position = self.jointConfigTable.getPosition(isWheelCheckbox)[1] - 1 - isAlreadyWheel = bool( - self.jointWheelIndexMap.get( - self.selectedJointList[position].entityToken - ) - ) + isAlreadyWheel = bool(self.jointWheelIndexMap.get(self.selectedJointList[position].entityToken)) if isWheelCheckbox.value != self.previousWheelCheckboxState[position]: if not isAlreadyWheel: @@ -587,34 +497,22 @@ def handleInputChanged( elif commandInput.id == "signalTypeJoint": signalTypeDropdown = adsk.core.DropDownCommandInput.cast(commandInput) - jointTabPosition = self.jointConfigTable.getPosition(signalTypeDropdown)[ - 1 - ] # 1 indexed - wheelTabPosition = self.jointWheelIndexMap.get( - self.selectedJointList[jointTabPosition - 1].entityToken - ) + jointTabPosition = self.jointConfigTable.getPosition(signalTypeDropdown)[1] # 1 indexed + wheelTabPosition = self.jointWheelIndexMap.get(self.selectedJointList[jointTabPosition - 1].entityToken) if wheelTabPosition: - wheelSignalItems: adsk.core.DropDownCommandInput = ( - self.wheelConfigTable.getInputAtPosition(wheelTabPosition, 3) + wheelSignalItems: adsk.core.DropDownCommandInput = self.wheelConfigTable.getInputAtPosition( + wheelTabPosition, 3 ) - wheelSignalItems.listItems.item( - signalTypeDropdown.selectedItem.index - ).isSelected = True + wheelSignalItems.listItems.item(signalTypeDropdown.selectedItem.index).isSelected = True elif commandInput.id == "jointAddButton": - jointAddButton: adsk.core.BoolValueCommandInput = ( - globalCommandInputs.itemById("jointAddButton") - ) - jointRemoveButton: adsk.core.BoolValueCommandInput = ( - globalCommandInputs.itemById("jointRemoveButton") - ) - jointSelectCancelButton: adsk.core.BoolValueCommandInput = ( - globalCommandInputs.itemById("jointSelectCancelButton") - ) - jointSelection: adsk.core.SelectionCommandInput = ( - globalCommandInputs.itemById("jointSelection") + jointAddButton: adsk.core.BoolValueCommandInput = globalCommandInputs.itemById("jointAddButton") + jointRemoveButton: adsk.core.BoolValueCommandInput = globalCommandInputs.itemById("jointRemoveButton") + jointSelectCancelButton: adsk.core.BoolValueCommandInput = globalCommandInputs.itemById( + "jointSelectCancelButton" ) + jointSelection: adsk.core.SelectionCommandInput = globalCommandInputs.itemById("jointSelection") jointSelection.isVisible = jointSelection.isEnabled = True jointSelection.clearSelection() @@ -622,9 +520,7 @@ def handleInputChanged( jointSelectCancelButton.isVisible = jointSelectCancelButton.isEnabled = True elif commandInput.id == "jointRemoveButton": - jointAddButton: adsk.core.BoolValueCommandInput = ( - globalCommandInputs.itemById("jointAddButton") - ) + jointAddButton: adsk.core.BoolValueCommandInput = globalCommandInputs.itemById("jointAddButton") jointTable: adsk.core.TableCommandInput = args.inputs.itemById("jointTable") jointAddButton.isEnabled = True @@ -633,44 +529,28 @@ def handleInputChanged( ui = adsk.core.Application.get().userInterface ui.messageBox("Select a row to delete.") else: - self.removeIndexedJoint( - jointTable.selectedRow - 1 - ) # selectedRow is 1 indexed + self.removeIndexedJoint(jointTable.selectedRow - 1) # selectedRow is 1 indexed elif commandInput.id == "jointSelectCancelButton": - jointAddButton: adsk.core.BoolValueCommandInput = ( - globalCommandInputs.itemById("jointAddButton") - ) - jointRemoveButton: adsk.core.BoolValueCommandInput = ( - globalCommandInputs.itemById("jointRemoveButton") - ) - jointSelectCancelButton: adsk.core.BoolValueCommandInput = ( - globalCommandInputs.itemById("jointSelectCancelButton") - ) - jointSelection: adsk.core.SelectionCommandInput = ( - globalCommandInputs.itemById("jointSelection") + jointAddButton: adsk.core.BoolValueCommandInput = globalCommandInputs.itemById("jointAddButton") + jointRemoveButton: adsk.core.BoolValueCommandInput = globalCommandInputs.itemById("jointRemoveButton") + jointSelectCancelButton: adsk.core.BoolValueCommandInput = globalCommandInputs.itemById( + "jointSelectCancelButton" ) + jointSelection: adsk.core.SelectionCommandInput = globalCommandInputs.itemById("jointSelection") jointSelection.isEnabled = jointSelection.isVisible = False - jointSelectCancelButton.isEnabled = jointSelectCancelButton.isVisible = ( - False - ) + jointSelectCancelButton.isEnabled = jointSelectCancelButton.isVisible = False jointAddButton.isEnabled = jointRemoveButton.isEnabled = True @logFailure - def handleSelectionEvent( - self, args: adsk.core.SelectionEventArgs, selectedJoint: adsk.fusion.Joint - ) -> None: + def handleSelectionEvent(self, args: adsk.core.SelectionEventArgs, selectedJoint: adsk.fusion.Joint) -> None: selectionInput = args.activeInput jointType = selectedJoint.jointMotion.jointType - if ( - jointType == adsk.fusion.JointTypes.RevoluteJointType - or jointType == adsk.fusion.JointTypes.SliderJointType - ): + if jointType == adsk.fusion.JointTypes.RevoluteJointType or jointType == adsk.fusion.JointTypes.SliderJointType: if not self.addJoint(selectedJoint): ui = adsk.core.Application.get().userInterface result = ui.messageBox( - "You have already selected this joint.\n" - "Would you like to remove it?", + "You have already selected this joint.\n" "Would you like to remove it?", "Synthesis: Remove Joint Confirmation", adsk.core.MessageBoxButtonTypes.YesNoButtonType, adsk.core.MessageBoxIconTypes.QuestionIconType, @@ -684,24 +564,14 @@ def handleSelectionEvent( @logFailure def handlePreviewEvent(self, args: adsk.core.CommandEventArgs) -> None: commandInputs = args.command.commandInputs - jointAddButton: adsk.core.BoolValueCommandInput = commandInputs.itemById( - "jointAddButton" - ) - jointRemoveButton: adsk.core.BoolValueCommandInput = commandInputs.itemById( - "jointRemoveButton" - ) - jointSelectCancelButton: adsk.core.BoolValueCommandInput = ( - commandInputs.itemById("jointSelectCancelButton") - ) - jointSelection: adsk.core.SelectionCommandInput = commandInputs.itemById( - "jointSelection" - ) + jointAddButton: adsk.core.BoolValueCommandInput = commandInputs.itemById("jointAddButton") + jointRemoveButton: adsk.core.BoolValueCommandInput = commandInputs.itemById("jointRemoveButton") + jointSelectCancelButton: adsk.core.BoolValueCommandInput = commandInputs.itemById("jointSelectCancelButton") + jointSelection: adsk.core.SelectionCommandInput = commandInputs.itemById("jointSelection") if self.jointConfigTable.rowCount <= 1: jointRemoveButton.isEnabled = False if not jointSelection.isEnabled: jointAddButton.isEnabled = jointRemoveButton.isEnabled = True - jointSelectCancelButton.isVisible = jointSelectCancelButton.isEnabled = ( - False - ) + jointSelectCancelButton.isVisible = jointSelectCancelButton.isEnabled = False diff --git a/exporter/SynthesisFusionAddin/src/UI/MarkingMenu.py b/exporter/SynthesisFusionAddin/src/UI/MarkingMenu.py index 3899e616f9..30c9f078e6 100644 --- a/exporter/SynthesisFusionAddin/src/UI/MarkingMenu.py +++ b/exporter/SynthesisFusionAddin/src/UI/MarkingMenu.py @@ -44,14 +44,10 @@ def setLinearMarkingMenu(args): if occ: if occ.attributes.itemByName("synthesis", "collision_off") == None: - cmdDisableCollision = ui.commandDefinitions.itemById( - "DisableCollision" - ) + cmdDisableCollision = ui.commandDefinitions.itemById("DisableCollision") synthDropDown.controls.addCommand(cmdDisableCollision) else: - cmdEnableCollision = ui.commandDefinitions.itemById( - "EnableCollision" - ) + cmdEnableCollision = ui.commandDefinitions.itemById("EnableCollision") synthDropDown.controls.addCommand(cmdEnableCollision) def setCollisionAttribute(occ: adsk.fusion.Occurrence, isEnabled: bool = True): @@ -118,9 +114,7 @@ def notify(self, args): if design: attrs = design.findAttributes("synthesis", "collision_off") for attr in attrs: - for b in adsk.fusion.Occurrence.cast( - attr.parent - ).bRepBodies: + for b in adsk.fusion.Occurrence.cast(attr.parent).bRepBodies: ui.activeSelections.add(b) elif cmdDef.id == "EnableAllCollision": app = adsk.core.Application.get() diff --git a/exporter/SynthesisFusionAddin/src/UI/ShowAPSAuthCommand.py b/exporter/SynthesisFusionAddin/src/UI/ShowAPSAuthCommand.py index c68f4b5fdf..bd45cfc062 100644 --- a/exporter/SynthesisFusionAddin/src/UI/ShowAPSAuthCommand.py +++ b/exporter/SynthesisFusionAddin/src/UI/ShowAPSAuthCommand.py @@ -28,9 +28,7 @@ def notify(self, args): callbackUrl = "https://synthesis.autodesk.com/api/aps/exporter/" challenge = getCodeChallenge() if challenge is None: - logger.error( - "Code challenge is None when attempting to authorize for APS." - ) + logger.error("Code challenge is None when attempting to authorize for APS.") return params = { "response_type": "code", @@ -42,19 +40,10 @@ def notify(self, args): "code_challenge": challenge, "code_challenge_method": "S256", } - query = "&".join( - map(lambda pair: f"{pair[0]}={pair[1]}", params.items()) - ) - url = ( - "https://developer.api.autodesk.com/authentication/v2/authorize?" - + query - ) - palette = gm.ui.palettes.add( - "authPalette", "APS Authentication", url, True, True, True, 400, 400 - ) - palette.dockingState = ( - adsk.core.PaletteDockingStates.PaletteDockStateRight - ) + query = "&".join(map(lambda pair: f"{pair[0]}={pair[1]}", params.items())) + url = "https://developer.api.autodesk.com/authentication/v2/authorize?" + query + palette = gm.ui.palettes.add("authPalette", "APS Authentication", url, True, True, True, 400, 400) + palette.dockingState = adsk.core.PaletteDockingStates.PaletteDockStateRight # register events onHTMLEvent = MyHTMLEventHandler() palette.incomingFromHTML.add(onHTMLEvent) @@ -66,9 +55,7 @@ def notify(self, args): else: palette.isVisible = True except: - gm.ui.messageBox( - "Command executed failed: {}".format(traceback.format_exc()) - ) + gm.ui.messageBox("Command executed failed: {}".format(traceback.format_exc())) logger.error("Command executed failed: {}".format(traceback.format_exc())) if palette: palette.deleteMe() diff --git a/exporter/SynthesisFusionAddin/src/UI/Toolbar.py b/exporter/SynthesisFusionAddin/src/UI/Toolbar.py index 95527df003..bfcc34189a 100644 --- a/exporter/SynthesisFusionAddin/src/UI/Toolbar.py +++ b/exporter/SynthesisFusionAddin/src/UI/Toolbar.py @@ -51,9 +51,7 @@ def getPanel(self, name: str, visibility: bool = True) -> str | None: @logFailure @staticmethod - def getNewPanel( - name: str, tab_id: str, toolbar_id: str, visibility: bool = True - ) -> str | None: + def getNewPanel(name: str, tab_id: str, toolbar_id: str, visibility: bool = True) -> str | None: """# Gets a control for a panel to the tabbed toolbar visibility""" designWorkspace = gm.ui.workspaces.itemById("FusionSolidEnvironment") allDesignTabs = designWorkspace.toolbarTabs diff --git a/exporter/SynthesisFusionAddin/src/general_imports.py b/exporter/SynthesisFusionAddin/src/general_imports.py index 551f49c0cd..67d5e3b3cc 100644 --- a/exporter/SynthesisFusionAddin/src/general_imports.py +++ b/exporter/SynthesisFusionAddin/src/general_imports.py @@ -24,9 +24,7 @@ try: path = os.path.abspath(os.path.join(os.path.dirname(__file__), "..")) - path_proto_files = os.path.abspath( - os.path.join(os.path.dirname(__file__), "..", "proto", "proto_out") - ) + path_proto_files = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "proto", "proto_out")) if not path in sys.path: sys.path.insert(1, path) diff --git a/exporter/SynthesisFusionAddin/tools/format.py b/exporter/SynthesisFusionAddin/tools/format.py index 0b4796e3cd..60d9ba7063 100644 --- a/exporter/SynthesisFusionAddin/tools/format.py +++ b/exporter/SynthesisFusionAddin/tools/format.py @@ -6,9 +6,7 @@ def main(args: list[str] = sys.argv[1:]) -> None: dir = args[0] if len(args) else "." if "pyproject.toml" not in os.listdir(dir): - print( - "WARNING: Configuration file for autoformatters was not found. Are you sure you specified the root DIR?" - ) + print("WARNING: Configuration file for autoformatters was not found. Are you sure you specified the root DIR?") for command in ["isort", "black"]: try: From f47c6339d12a464ed10d38c30b66f73f6f63d187 Mon Sep 17 00:00:00 2001 From: Azalea Colburn Date: Fri, 26 Jul 2024 16:20:00 -0700 Subject: [PATCH 09/10] ran isort formatter --- exporter/SynthesisFusionAddin/src/UI/ShowWebsiteCommand.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/exporter/SynthesisFusionAddin/src/UI/ShowWebsiteCommand.py b/exporter/SynthesisFusionAddin/src/UI/ShowWebsiteCommand.py index ad7267fc12..d7e1539e5e 100644 --- a/exporter/SynthesisFusionAddin/src/UI/ShowWebsiteCommand.py +++ b/exporter/SynthesisFusionAddin/src/UI/ShowWebsiteCommand.py @@ -1,5 +1,7 @@ import webbrowser + import adsk.core + from ..general_imports import * From 7a3e84940a718dbcfdbf2ac64ab449d1b8c86854 Mon Sep 17 00:00:00 2001 From: BrandonPacewic Date: Mon, 29 Jul 2024 16:42:13 -0700 Subject: [PATCH 10/10] Revert bad formatting changes Co-authored-by: azaleacolburn --- exporter/SynthesisFusionAddin/src/APS/APS.py | 72 +++--------- .../src/UI/ConfigCommand.py | 7 +- .../src/UI/JointConfigTab.py | 103 +++--------------- exporter/SynthesisFusionAddin/tools/format.py | 7 +- 4 files changed, 34 insertions(+), 155 deletions(-) diff --git a/exporter/SynthesisFusionAddin/src/APS/APS.py b/exporter/SynthesisFusionAddin/src/APS/APS.py index 346ae439f7..a65728ec23 100644 --- a/exporter/SynthesisFusionAddin/src/APS/APS.py +++ b/exporter/SynthesisFusionAddin/src/APS/APS.py @@ -199,10 +199,7 @@ def create_folder(auth: str, project_id: str, parent_folder_id: str, folder_disp success - the href of the new folder ; might be changed to the id in the future failure - none if the API request fails ; the failure text will be printed """ - headers = { - "Authorization": f"Bearer {auth}", - "Content-Type": "application/vnd.api+json", - } + headers = {"Authorization": f"Bearer {auth}", "Content-Type": "application/vnd.api+json"} data: dict[str, Any] = { "jsonapi": {"version": "1.0"}, "data": { @@ -216,9 +213,7 @@ def create_folder(auth: str, project_id: str, parent_folder_id: str, folder_disp } res = requests.post( - f"https://developer.api.autodesk.com/data/v1/projects/{project_id}/folders", - headers=headers, - json=data, + f"https://developer.api.autodesk.com/data/v1/projects/{project_id}/folders", headers=headers, json=data ) if not res.ok: gm.ui.messageBox(f"Failed to create new folder: {res.text}", "ERROR") @@ -302,15 +297,7 @@ def upload_mirabuf(project_id: str, folder_id: str, file_name: str, file_content return None if file_id != "": update_file_version( - auth, - project_id, - folder_id, - lineage_id, - file_id, - file_name, - file_contents, - file_version, - object_id, + auth, project_id, folder_id, lineage_id, file_id, file_name, file_contents, file_version, object_id ) else: _lineage_info = create_first_file_version(auth, str(object_id), project_id, str(folder_id), file_name) @@ -362,8 +349,7 @@ def get_project_id(auth: str, hub_id: str, project_name: str) -> str | None: headers = {"Authorization": f"Bearer {auth}"} project_list_res = requests.get( - f"https://developer.api.autodesk.com/project/v1/hubs/{hub_id}/projects", - headers=headers, + f"https://developer.api.autodesk.com/project/v1/hubs/{hub_id}/projects", headers=headers ) if not project_list_res.ok: gm.ui.messageBox("UPLOAD ERROR", f"Failed to retrieve hubs: {project_list_res.text}") @@ -445,10 +431,7 @@ def update_file_version( "Content-Type": "application/vnd.api+json", } - attributes = { - "name": file_name, - "extension": {"type": "versions:autodesk.core:File", "version": f"1.0"}, - } + attributes = {"name": file_name, "extension": {"type": "versions:autodesk.core:File", "version": f"1.0"}} relationships: dict[str, Any] = { "item": { @@ -467,23 +450,16 @@ def update_file_version( data = { "jsonapi": {"version": "1.0"}, - "data": { - "type": "versions", - "attributes": attributes, - "relationships": relationships, - }, + "data": {"type": "versions", "attributes": attributes, "relationships": relationships}, } update_res = requests.post( - f"https://developer.api.autodesk.com/data/v1/projects/{project_id}/versions", - headers=headers, - json=data, + f"https://developer.api.autodesk.com/data/v1/projects/{project_id}/versions", headers=headers, json=data ) if not update_res.ok: gm.ui.messageBox(f"UPLOAD ERROR:\n{update_res.text}", "Updating file to new version failed") return None gm.ui.messageBox( - f"Successfully updated file {file_name} to version {int(curr_file_version) + 1} on APS", - "UPLOAD SUCCESS", + f"Successfully updated file {file_name} to version {int(curr_file_version) + 1} on APS", "UPLOAD SUCCESS" ) new_id: str = update_res.json()["data"]["id"] return new_id @@ -568,15 +544,10 @@ def create_storage_location(auth: str, project_id: str, folder_id: str, file_nam "Content-Type": "application/vnd.api+json", } storage_location_res = requests.post( - f"https://developer.api.autodesk.com/data/v1/projects/{project_id}/storage", - json=data, - headers=headers, + f"https://developer.api.autodesk.com/data/v1/projects/{project_id}/storage", json=data, headers=headers ) if not storage_location_res.ok: - gm.ui.messageBox( - f"UPLOAD ERROR: {storage_location_res.text}", - f"Failed to create storage location", - ) + gm.ui.messageBox(f"UPLOAD ERROR: {storage_location_res.text}", f"Failed to create storage location") return None storage_location_json: dict[str, Any] = storage_location_res.json() object_id: str = storage_location_json["data"]["id"] @@ -664,8 +635,7 @@ def complete_upload(auth: str, upload_key: str, object_key: str, bucket_key: str ) if not completed_res.ok: gm.ui.messageBox( - f"UPLOAD ERROR: {completed_res.text}\n{completed_res.status_code}", - "Failed to complete upload", + f"UPLOAD ERROR: {completed_res.text}\n{completed_res.status_code}", "Failed to complete upload" ) return None return "" @@ -703,10 +673,7 @@ def create_first_file_version( "Accept": "application/vnd.api+json", } - included_attributes = { - "name": file_name, - "extension": {"type": "versions:autodesk.core:File", "version": "1.0"}, - } + included_attributes = {"name": file_name, "extension": {"type": "versions:autodesk.core:File", "version": "1.0"}} attributes = { "displayName": file_name, @@ -732,24 +699,15 @@ def create_first_file_version( data = { "jsonapi": {"version": "1.0"}, - "data": { - "type": "items", - "attributes": attributes, - "relationships": relationships, - }, + "data": {"type": "items", "attributes": attributes, "relationships": relationships}, "included": included, } first_version_res = requests.post( - f"https://developer.api.autodesk.com/data/v1/projects/{project_id}/items", - json=data, - headers=headers, + f"https://developer.api.autodesk.com/data/v1/projects/{project_id}/items", json=data, headers=headers ) if not first_version_res.ok: - gm.ui.messageBox( - f"Failed to create first file version: {first_version_res.text}", - "UPLOAD ERROR", - ) + gm.ui.messageBox(f"Failed to create first file version: {first_version_res.text}", "UPLOAD ERROR") return None first_version_json: dict[str, Any] = first_version_res.json() diff --git a/exporter/SynthesisFusionAddin/src/UI/ConfigCommand.py b/exporter/SynthesisFusionAddin/src/UI/ConfigCommand.py index 774d8eb53f..4a501b1319 100644 --- a/exporter/SynthesisFusionAddin/src/UI/ConfigCommand.py +++ b/exporter/SynthesisFusionAddin/src/UI/ConfigCommand.py @@ -179,9 +179,7 @@ def notify(self, args): # ~~~~~~~~~~~~~~~~ EXPORT LOCATION ~~~~~~~~~~~~~~~~~~ dropdownExportLocation = inputs.addDropDownCommandInput( - "location", - "Export Location", - dropDownStyle=adsk.core.DropDownStyles.LabeledIconDropDownStyle, + "location", "Export Location", dropDownStyle=adsk.core.DropDownStyles.LabeledIconDropDownStyle ) upload: bool = exporterOptions.exportLocation == ExportLocation.UPLOAD @@ -555,8 +553,7 @@ def notify(self, args): getAuth() user_info = getUserInfo() apsSettings = INPUTS_ROOT.addTabCommandInput( - "aps_settings", - f"APS Settings ({user_info.given_name if user_info else 'Not Signed In'})", + "aps_settings", f"APS Settings ({user_info.given_name if user_info else 'Not Signed In'})" ) apsSettings.tooltip = "Configuration settings for Autodesk Platform Services." diff --git a/exporter/SynthesisFusionAddin/src/UI/JointConfigTab.py b/exporter/SynthesisFusionAddin/src/UI/JointConfigTab.py index 9332f11d01..4f25ebfe01 100644 --- a/exporter/SynthesisFusionAddin/src/UI/JointConfigTab.py +++ b/exporter/SynthesisFusionAddin/src/UI/JointConfigTab.py @@ -31,73 +31,33 @@ def __init__(self, args: adsk.core.CommandCreatedEventArgs) -> None: jointConfigTabInputs = self.jointConfigTab.children self.jointConfigTable = createTableInput("jointTable", "Joint Table", jointConfigTabInputs, 7, "1:2:2:2:2:2:2") self.jointConfigTable.addCommandInput( - createTextBoxInput( - "jointMotionHeader", - "Motion", - jointConfigTabInputs, - "Motion", - bold=False, - ), - 0, - 0, + createTextBoxInput("jointMotionHeader", "Motion", jointConfigTabInputs, "Motion", bold=False), 0, 0 ) self.jointConfigTable.addCommandInput( - createTextBoxInput("nameHeader", "Name", jointConfigTabInputs, "Joint name", bold=False), - 0, - 1, + createTextBoxInput("nameHeader", "Name", jointConfigTabInputs, "Joint name", bold=False), 0, 1 ) self.jointConfigTable.addCommandInput( - createTextBoxInput( - "parentHeader", - "Parent", - jointConfigTabInputs, - "Parent joint", - background="#d9d9d9", - ), + createTextBoxInput("parentHeader", "Parent", jointConfigTabInputs, "Parent joint", background="#d9d9d9"), 0, 2, ) self.jointConfigTable.addCommandInput( - createTextBoxInput( - "signalHeader", - "Signal", - jointConfigTabInputs, - "Signal type", - background="#d9d9d9", - ), + createTextBoxInput("signalHeader", "Signal", jointConfigTabInputs, "Signal type", background="#d9d9d9"), 0, 3, ) self.jointConfigTable.addCommandInput( - createTextBoxInput( - "speedHeader", - "Speed", - jointConfigTabInputs, - "Joint Speed", - background="#d9d9d9", - ), + createTextBoxInput("speedHeader", "Speed", jointConfigTabInputs, "Joint Speed", background="#d9d9d9"), 0, 4, ) self.jointConfigTable.addCommandInput( - createTextBoxInput( - "forceHeader", - "Force", - jointConfigTabInputs, - "Joint Force", - background="#d9d9d9", - ), + createTextBoxInput("forceHeader", "Force", jointConfigTabInputs, "Joint Force", background="#d9d9d9"), 0, 5, ) self.jointConfigTable.addCommandInput( - createTextBoxInput( - "wheelHeader", - "Is Wheel", - jointConfigTabInputs, - "Is Wheel", - background="#d9d9d9", - ), + createTextBoxInput("wheelHeader", "Is Wheel", jointConfigTabInputs, "Is Wheel", background="#d9d9d9"), 0, 6, ) @@ -113,39 +73,21 @@ def __init__(self, args: adsk.core.CommandCreatedEventArgs) -> None: self.wheelConfigTable = createTableInput("wheelTable", "Wheel Table", jointConfigTabInputs, 4, "1:2:2:2") self.wheelConfigTable.addCommandInput( - createTextBoxInput( - "wheelMotionHeader", - "Motion", - jointConfigTabInputs, - "Motion", - bold=False, - ), - 0, - 0, + createTextBoxInput("wheelMotionHeader", "Motion", jointConfigTabInputs, "Motion", bold=False), 0, 0 ) self.wheelConfigTable.addCommandInput( - createTextBoxInput("name_header", "Name", jointConfigTabInputs, "Joint name", bold=False), - 0, - 1, + createTextBoxInput("name_header", "Name", jointConfigTabInputs, "Joint name", bold=False), 0, 1 ) self.wheelConfigTable.addCommandInput( createTextBoxInput( - "wheelTypeHeader", - "WheelType", - jointConfigTabInputs, - "Wheel type", - background="#d9d9d9", + "wheelTypeHeader", "WheelType", jointConfigTabInputs, "Wheel type", background="#d9d9d9" ), 0, 2, ) self.wheelConfigTable.addCommandInput( createTextBoxInput( - "signalTypeHeader", - "SignalType", - jointConfigTabInputs, - "Signal type", - background="#d9d9d9", + "signalTypeHeader", "SignalType", jointConfigTabInputs, "Signal type", background="#d9d9d9" ), 0, 3, @@ -237,11 +179,7 @@ def addJoint(self, fusionJoint: adsk.fusion.Joint, synJoint: Joint | None = None if synJoint: signalType.listItems.add("‎", synJoint.signalType is SignalType.PWM, IconPaths.signalIcons["PWM"]) signalType.listItems.add("‎", synJoint.signalType is SignalType.CAN, IconPaths.signalIcons["CAN"]) - signalType.listItems.add( - "‎", - synJoint.signalType is SignalType.PASSIVE, - IconPaths.signalIcons["PASSIVE"], - ) + signalType.listItems.add("‎", synJoint.signalType is SignalType.PASSIVE, IconPaths.signalIcons["PASSIVE"]) else: signalType.listItems.add("‎", True, IconPaths.signalIcons["PWM"]) signalType.listItems.add("‎", False, IconPaths.signalIcons["CAN"]) @@ -292,10 +230,7 @@ def addJoint(self, fusionJoint: adsk.fusion.Joint, synJoint: Joint | None = None jointForceValue = 5 jointForce = commandInputs.addValueInput( - "jointForce", - "Force", - "N", - adsk.core.ValueInput.createByReal(jointForceValue), + "jointForce", "Force", "N", adsk.core.ValueInput.createByReal(jointForceValue) ) jointForce.tooltip = "Newtons" self.jointConfigTable.addCommandInput(jointForce, row, 5) @@ -338,9 +273,7 @@ def addWheel(self, joint: adsk.fusion.Joint, wheel: Wheel | None = None) -> None wheelName = commandInputs.addTextBoxCommandInput("wheelName", "Joint Name", joint.name, 1, True) wheelName.tooltip = joint.name # TODO: Should this be the same? wheelType = commandInputs.addDropDownCommandInput( - "wheelType", - "Wheel Type", - dropDownStyle=adsk.core.DropDownStyles.LabeledIconDropDownStyle, + "wheelType", "Wheel Type", dropDownStyle=adsk.core.DropDownStyles.LabeledIconDropDownStyle ) selectedWheelType = wheel.wheelType if wheel else WheelType.STANDARD @@ -357,9 +290,7 @@ def addWheel(self, joint: adsk.fusion.Joint, wheel: Wheel | None = None) -> None ) signalType = commandInputs.addDropDownCommandInput( - "wheelSignalType", - "Signal Type", - dropDownStyle=adsk.core.DropDownStyles.LabeledIconDropDownStyle, + "wheelSignalType", "Signal Type", dropDownStyle=adsk.core.DropDownStyles.LabeledIconDropDownStyle ) signalType.isFullWidth = True signalType.isEnabled = False @@ -462,9 +393,7 @@ def reset(self) -> None: # commandInput in a input changed handle for some reason. @logFailure def handleInputChanged( - self, - args: adsk.core.InputChangedEventArgs, - globalCommandInputs: adsk.core.CommandInputs, + self, args: adsk.core.InputChangedEventArgs, globalCommandInputs: adsk.core.CommandInputs ) -> None: commandInput = args.input if commandInput.id == "wheelType": diff --git a/exporter/SynthesisFusionAddin/tools/format.py b/exporter/SynthesisFusionAddin/tools/format.py index 60d9ba7063..7531b93de7 100644 --- a/exporter/SynthesisFusionAddin/tools/format.py +++ b/exporter/SynthesisFusionAddin/tools/format.py @@ -11,12 +11,7 @@ def main(args: list[str] = sys.argv[1:]) -> None: for command in ["isort", "black"]: try: print(f"Formatting with {command}...") - subprocess.call( - [command, dir], - shell=False, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - ) + subprocess.call([command, dir], shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE) except FileNotFoundError: print(f'"{command}" could not be found. Please resolve dependencies.') return