From 4a3c0bd1e45302884021bcf5eb56a0647ec9f980 Mon Sep 17 00:00:00 2001 From: howard Date: Mon, 19 Apr 2021 00:30:29 -0700 Subject: [PATCH] remove redux logger for production --- dist/solver.wasm | Bin 139414 -> 139381 bytes lib/STLExporter.js | 209 +++++++++++++++++++++++++++++++++++++++ lib/stl.js | 209 +++++++++++++++++++++++++++++++++++++++ src/Scene.js | 43 ++++---- src/Sketch.js | 13 ++- src/drawArc.js | 4 +- src/drawDimension.js | 6 +- src/mouseEvents.js | 4 +- src/react/app.css | 7 ++ src/react/app.jsx | 31 +++--- src/react/dialog.jsx | 10 +- src/react/fileHelpers.js | 18 +--- src/react/navBar.jsx | 80 ++++++++------- src/react/tree.jsx | 2 +- src/shared.js | 3 +- todo.txt | 27 ++--- wasm/solver.c | 3 +- webpack.prod.js | 10 +- 18 files changed, 549 insertions(+), 130 deletions(-) create mode 100644 lib/STLExporter.js create mode 100644 lib/stl.js diff --git a/dist/solver.wasm b/dist/solver.wasm index c8b41634e1f2cdc2fbcb117066f2e4be539f4740..2a16e2e7c38754cad8c94f2a5a14ee9e416afc17 100755 GIT binary patch delta 11961 zcmc&a33yaR(yw}sOfs2d$N@12^h|;T6p04HVGbIF1d$t7S6%t#atSU1vbyN%1VJ_^ zM}A+V!y!b?FGN5hgAQPXAgJhaBpeDWlAwSbfy59otSEogdy`})$b#3mfth))s=Dr~ z?$`YmZnb<{W+^#gfIRothEV_&YNqK)TY0J@SSSt~wTXjM>{q`w&A$=hPK3wv zc!Z}q5(GHf^90^L+i@d;JMa$t#uOZ|#H^9_Kv+-SQzPw#q_^{4{Pt`|DuUB^8c!wC z!2$DcJecYjgs{PUa3VXL>KKBgL-`OsG}|!@!Nd7*J}iYDb{i~jgB>+^77#iU_)H+> zb_8-%?o?n2p(LRSfEQ?};vhnO5~QJ46KW0cH5%%9E1_0dHPlu@y$}3-4K*>CP;-Mz z?5NkLg!&BlXNWqi-fiP>*!>sVQXt%qgu4vw_iR`#Wc3dONh&WDCzhfx1f$;|9 zdsyunNm55fRx`qFG9d0<1Ao^*xS>&mn;NxB!<{Ewy@A(jxXv+z8x%9iV6RGbylX^U zsgai&6WK9!XIl=(+-KYNWLCu08hMQdzSR+f;DL@W4N$HowQmEt?yUCT0p9fP@HhP4 z*r5h;)Z)aR>{6(B(-uY4@zMNb$BojMz{^(Av}cJQdm{0C=Ydn z@=yfZ5!{Nm;`S8OMbsM{VF(E4;XEvb<)q;%OcsED~~_LVH!+FxP41#m?ev+YNjQ?V(c+9D2_L~fvvf#UxH?GGzfB0ft* z$aZB~3d0M2zmkI2gsIVoTW?22bV_8YQ96~rHpPH99B&mTYPK?sEA}c>(t(=U6syL% z2CQw61XW$bqEX5$^@pyLMwXb*-H|2^YGZe_7`uhWR(Z$PddJo_ z%g@pO8n(E)8%}zeRiz1}Kt-zjnN?|uGxqao6+5nldfCUkVXW^ ztRYREkrLiBFJ1RVAr7a}g;$OyT?)Lz^U{d|hv&I>rBs^R6s3!DC0h$YUt1^z!{T6~ zNZpn;)#eTqpE7YGQ2aAcoKgFvFYSzwAPsPEl-fFQX>ancJ}{>Lgi#(TRSZzC3|nfnUx_F zzB3`BK1BQ&qLueA0jWp-)W%1UK@+4}9vmIw&rSW?gJXQ?bcNIf_jOVuM=e2}-Wp|x zVg5s|rc;Sk>{G-?R#9#hHCCcpWP|`}eznR(ry)UMz3CtIo_sa@p*}uhP1HDw+~Xd4 z8CvRR9~0$Ihz?UH?aEYLV`5s;t{ihbrrEh@Gj`ZScC*7MiqaEVs`|==2sM3N7xm28 z1SnGN<04JI@VC+2`f)*ksLSIcp~xNia5lr6oC&e`{qltEuIux|??x4_rvv(V6^P>)>gF1*eqtKI_j81TvMUk2`CsUpNmjr*jgYbz>_+67@)i#sT{ArxJ;~IGk zo)W9>p7a5_Ve(}3jK+7@`7vDJkohO$0;Dh?w+Uw&H@1FR# zIEZd`c0gZSA`cW%)Vm!fl)rFxrh01nc+_{ulaxW@pS;81!wi+ZiI^ogbYZ2KaZf)Z zDC4%c8vPoZ^JI(rSk*qm;==}Q>g;dR<1;qmn51Wk$Ew#d-SeIu!ysS%W>#09VJJPR z$rLs9xvf4pwB$Bjvqm%SpG`HAGn>p`rT@4OcULZC&-!at1mq zoT>ktAFg(oX;WRf(#K7xZwj|~-K3|~4*#0&A+(%w4}Lz91bvd1>0bRpmanU^G2QMJ zWyOV-QO%p2rVf}_r>hm-QZ1y_xU8KYjV0{we5E!LCuv##Oz{ZyPpilIFhi|IHZjw*;%n3ZZ-CT{6@ONpZ_Y&h zUVroNKBJK9A81r_qsv*_4(q9K?FCXszU5U$HLNT8Z#Qn&FQ3P+Hrf8HNyhbSR};Td z3zYv`tZ9C+7Or1B^0yi2`jv~hU#o@dzw3Uxiyl&cR>ocjEL5M^l!=qumQ8znCSRQH z6`XvRy}QTJ%pdyN7&j%dEQiIr5@HS$2etCOG_`88QQcFz=8l{&D)qTx;-xULJWTW4 zb%D51G#pSeZ3dLO<-N!N?YYPqq%Pkq)Y#2qa6--59EIPDHdo$uT?|D*sOTYzL&dgG z@v-{G77^EM2tJsZIc|U28z0P^poTn{;J&$RAG6`O83u90t`7{}b}zq{JayK#fj$cZ z2-F@J<68vEK zJRkcprL@hzEN#DuRgAXz*{4paSmhHpEx|Ev5tQKcKq~Q(d-~62!B& zB-xM0RULwk-i6zE-V9m1?|L#Mc7KhQA;nBocrzsGGuO2<#PiuuAFEqt$R5P#67c1=5SpDPH${{s&FV z^(OI;R(c*Eshr@BKk_C}dN+gJM=HMq+OhBoz;wjJ2T`pHpp>jV8q;EoN~~slwNnEZ z8^u|#AMQIo#&vy;|J|rsYq9>=$Sf}SyS~|j+dW0sm8VX8_?u<%KTdY?i6=gW zY8yRwJE(o_IQh&l^zxS=w)z$^HD>D05x9e`J+RyR;ASZjey@nLdJ^i@jxG;u7*+OpB))ulB5&@H$li$PSZ!mW zvDg$f=d^JD^UPz+g=)_MF~ctA+r`J4+Wy*Jwdnk8x*AnA0}E~2C240C+MZprYFIpq z`rbJUW_!DXnX3I8s{LDQsP^xwS#s@CG}XR>q$_G2ehj*PL-)ua>AEyr3}ANYim8q| zs?_dvEqmANb-n?^+SMlKEN!3Wbe-zc*AV9o7H)oMeN9no>xBCG`4P$J={+Fc@X4fW zdfGj@9t>3IRVK06TmO^4t3)M-G*EjO-(WEkI^QhTc+pQ?8sDPxp1ah|KbN8Etzs z6F-j-$0EczPXLEy5$*k8n%Q$07_h!HZKIrc28=QOq$}iG_42?&J_JnY1`la~C?}o- zqZ1EwgH?v$#@wK6@yzWBTMV$;b9WlJA-F22AEuIa{CUh{&43(e&Lo`si0R_qupWx! zU;)pf&U*z^KntBq?tlmgBt^2Ep(tY4oe&57N*jb9$P?5LJ_I~<_3X`rEQqR3$7Nko zw*7g)Q%PI_8ad#OrkEvf>kk)ThU|D3Gz3+7iCzGC%Uy7b{Nn)l2jt761E4(=$bh?H zQ}6n8ry0kA!yF8_loU~q(D_DndbW6k3PeD*!))aSj%U?IfkF)^5l?~fI33e;2+D(j zkO8Gq3p%g?d&Cn$og<%RVS_vX62g18COEc)E zD8pf};(@LK1*hPhPVn|1aQ<%0gNFQ$%tsCV{g`{!4}&ts8q($CBjJ%?j3jQPGV)lp z=iEq$2iGi&2c{(k?NdOn;=wkXg)S9%wmvsQG^E?-VfN5~yekL|d0xVT44q`@6(kr- zomY{Uq&nSCoI~c_0|ANEbZU$e>(fP5x_!P^;&#kCq1;X9_d5Slx#b?XvD@}^E#ENw z_^U+P z;uE37!{$LK!vY9f0GW7u-vSUu{9UTTC4d~yqL*M$5R}Q2%V9NCd0r}nN(jrjg-*b^ z!p+=N_$ronp=b81@U$_gER}i-hN(>2R=`Op^ITW~r!25mR+YdaD3?#Z1q<<~)jH%> zE;p}(PGRL;vhjrw=7xg9W3^CLBeb| zOn`rR_Pb$>5ry^G0CVw$7x}?P;Bots9f3Gre2TyL(5)SnD_F>Yo8uLdZGz0OGs&VR z87DA4#c7QZUnPsLJ@;>doB(z{+4IF#Z~|SxHkc2{Ja0QpgRo1>X9n3n0Wqs^W{@>V z5to*GT7QV`6?S;!N04c>I>iv5r*$LvH#3p}%T!oy}*D$nhO%dk?O z+Xwf-e%XIN`~X!l^8n0&Tv>4d+5|4_W{pALio>374!{gB)~8_Wef%>RXM(x%@L}lD zwG?G*YXT#_ir`Rab;j`(APeQ8SWif&nOZC!8;NJQ>4_;=L^A6O?0)$&_Y0VFQ!@h^ zg<<^3QBHiVX|7B?0{7pfF~v1MMz#?7JB*r4d}WGTra3M25(3KNmZ>!0{Ugw=HBlkV zl*01yD%ggR#oCp&N_ZGs@Lwz8IdsMMl^Cu(nOg-fK&dCeK@Pb1+9|i4gkGQpVoB>3GEACp3*_2U z(7HY4A!mAR8ZbNYR#%5Ioa?0d^7JVf0_)}Nry%waJG%Rz>~jwO+_9y? zjXIg8IZb+3!5K#DD*MjCJ6;pCD!7IT>uTUEE*uMMAu{SeRdp76v-LN)$jpw{kW77{vXY@FtP(O8JM{}=4U19&Z6h{l@>-iBWFt(FUm zE?kidA6$UPv4f_52U#x4MsCnE4qrQLk(`R2oJ50(AOKyB%X3X1gwZB7mag8z^()F) zdcClb#D{f@WY$?5^KpQzy$BI9rU5$n*@r9h|772z4bTH8fRzn6SCqqp z(t4CD+X=$OAqIPvtot4wgVl2UB}l_ZuA)njZGrWkP!nqh!TZ+dHCFc4-@86s0s;(f%6n7w{?=KQ{afpLXl5 zk39PDgfXMWO`ZDaRHX`OPa@4uFa6DOL>!BE5I71yG<^89p3|mJ9ye;jr16guPh#Ig z7R0d*fkZY0KUs1I-nOFK9Q;hf5B(J_Y|A=8qD*Yd280t*iA5m(mc-$;*dS-OWl8MP i9?yohECh^)_w)vN^aj=y?DBFu)&(rG3uj}DME(Dw2K3_q delta 12140 zcmc&a31F1P)%#|TY_hw_<|2_0m~RsxK+zx}9OhuCA)o?sS*o=thm-}m(V~_Oiu^%2 zVn516NHG=4p#g&%yMPgh#-lcnfKU?45$=Ei!Xd<(mjBIsn`AeLpx8FaZocomH}8IL z=9~Gx-f3Q5VlF(ThkW;G{b+z=YNqiyTXl+JWje)1Z3*Ory4x5HC)Cr%B^?m%KzJOD zLwJf3&p>HU<7s=R(gDF8X-C>283(L1Nzz^j>rH!0(mqIfAMHc$b1EqaPNk_dMUV~& zSkj>;MH!5+A#_LrsZCKHM$)15VLH^Q3`6j6I-CwmCbe$8`8}|s1}_3aUjq6P2<1Kt zq^R7Pz(RrI0+kCiSE4oq3DoC75>+5j8-Z?=s8=ik^|nQ#N(AadpdU)qB&$FzvKHD= zufGe_0iXvERjWQ^qfqO9+Li|b_iur_4)nUj-4!BmeM0I1PPn^=o`sI6PX(dnMB2ZH zpjCSb-9zYJ;#9s62>JyPF1SCu%7L`Un`loEihqLaq$E2j$VdPU;8#t7Wtm??UDU5fI)0dd6! zT5L!lSJbk$6t1|>we3wTh^sTu3liK-i9zrn<(M9-)x`Eukn0}M{u{o#u3^72#fM!mo8EihpZO$>fTFtrxHjCW?RS5q82I+d0>4 z_yizI-Fk07S9J=j{t}cx8fcGJf{@fgEi@>Z)M#)kwIbYx@L(EDZONoAg;j(oAv6TR zb_9pgP-;&`UDy@95{7_q8cxHKNlq#|XjUQ+5J@9wr2PVEjn}Q1U5TOw8s$`?X>`1f zLMzqTeGD8|cXiKj6(=*W8+4ZLKwNP;W}oCBNJ1zi6D*SilAYwxQygP2fz~XD>g}7L zH6_gMjMrHLbu2H{zMizU4Ahan45*G7oc5!{p|k1OWizWXvZaA+RUj(}v`^4k1o1gR zglxB@CKJ4%kLi-}T3{|{!!7rrA{r&Kl#~u#hE1o(8;Z9&2Wqw@mFn!(sHB3L*>o1k z`T|&@kOWoTNLr(mWom8Gl#x4A70l(Xx{6c=(`~>iQtgE#121&_bUpQ-r7|6hNG3Z| z1!40{88N-vKZFOM4aogR^{YVX*}R8}L$R<;UX$$>g&DC>QWg}pdxkt%&Mg#*=d?FxyZ~VtjWEBTU~ljeNLKYRd$*n zKxWx#epXdW&GNm>3cZ>Y-pEU6w%*GuKaC*;GRsG1%x-som|SIwDoSG&I;RXvhAl({ z$gB`nq`sRv!?rDu{hhFLfoyLeyQFqY%j=4elZ}u{nGBTc#TK^Q z!t&k!Oe4X9Nj_nJl}sw#frDNKn;(_Ba&Rd|O~GVp403Q|kb}P`$P5|R5jHRiDh;WjfrXCs5!(Bdfp%=?N{bbRuh7%KWapx)Y&wC^T6FBuDS{TcukW zIae=07xZjt5L*$%HmL=p_6tb1fz^2-OMY2x$3!XB62%}qQ{^iq&|?eQ_e{@m0FzaHyDrzxb)eYCS`7`+m8${%fq zVg5sIrqdP+`$EUcEv(YQu2}@t>jnrAowQCj$)S(ek-p+rG_pLEJlW4jtWk8KBKL?V z{|GJhyFMn`pAa3UKE5kcoiaA2B`qI&GN#$NXfw9!1oAV*z>3lmNQ#;>F+%M+{vP$q zaq&>3ULO}}^o75N<{lp(1fr0=@iAxE3>pg~s%MzsBsgyB#5VZ7Xkw}B_Wbf6qYBs3 z1O5Isu+3IhVr8GZk6{P$u>d_wg$4173H_!#J;@)Z2wZ{}m#J1yZKIl|q@sC8r$yqo z@^q$}HocAd!IY2jZgdl@dg|O3_i>`r`3@@f5fqqVb7*c1KsScYF#7r!HH_1cnueL` zteI6e8?1)T7@=;NwFRY5pDi>Dosp^Tp8c^8J@Sk9=Xdd$M||+8j2Dl}$nk%Ec9jo4 zD8tsiS=mQ_8w;(Q6CxnPmOukpv}p4R=7jp%oQ%qZO+&-7ma2 zmO!3bJwM537;2c7GiikTAiwb|k7li6#0+=ww-D$5x z3PD?QGTkd*9pD=dY*+VrMOhR=4Ju4eRr@Tyq^T9&QZ1yFTvjbWuQ>$^(>_Av!Wg9^yrH2Ef^1Mju0lh`>T~RMH3pms!^5VRcCxhm@;e+ zHjQu>=YQ(k4KTL{HzQZ9jun30vL+6SRv%pB%LNS@+C(Ueq|e%~Q2!3=F5`FW^+`Tf zU@(WH6{1)CdHrUe6cUIgChn&<1PE!f-x67b#H)|KR)OXrp4K97>s!(RZX0I~p zrOj*p*X`W(<7fMuP02rK>T%uan&S?&K>0t#%I8OG;rh`df0}`=J6!VJsTQvPt^4gR z@m&0aGWHe;iwmR02G(F@OKfbD?UwFw-Pwx!mi(L9qhh6viq$kJ=K7yzzkP!1CwBi2 z4JFq99X#;-0QcWSv7i4Gk6pXA4C{>H{i8|bU2ZVj9V``VUP0oF1Y${Z7cVgcyX%N;l#W6{c@$5KV;YlH71Y&irKp|B8riMy8DAv zbzAY~(b-|5%$J3+KZdb&VN$u<0#O62->=KG>5*&W;}OouKyh0%qDfYex@0?3E!)T9 zRz5OtEg3{j!f}DDNd2I6jt>qEwFsOv)II3q zz|pD3Iop7SnNjIsIIr#`Xg?bznLkU1{%0@wE9 z$=ea27VKr}#J#xER2T0Rd9ikHVRt_sH+2YldKYdac@tyd7dKCgqhH*m7m2Zfuqtn2 z1RQYPIx*HB7>XJ-CPulB-7S-1tonfbYBUw#5UM9gC4D4&Ke+Hf$>$<%#{Ku$T$;kiJK+G<9 zLE9t3U7{kDok~EjI8S}@ljZa?HJ#Dhf2t96e$y>3N{fwY>!8rpI_AfJJZ!CeHxqn0NL!%pUqUm&i3`k6Dh3;UwAg& z|2Y}Auza4A&!3${{pt+2r&t@g8_`&5I(5$(=HB+zOyWYd7Xn*oXUpwukM?xor|nHk z?zX6E37Ez1UZOlFkz0Gss)-FpwcxxNJsn(`$*b=IlWM#ei?{TGDF5CUR^GZUuUz;O zk}j`PZsZboQ2>!k;%(`=0>I?bR8;MkMEpBkYT3j7aLG4xSlM!(9w4`QsxGNM{S9&6 zu;Jc_>~A{t$R(zJetAT9^m#e3cYSioKSRF5=kB3bK=!R_BYV?Z`J=BLK_%1cMPnFQ zZ#IYyu*}5X^P-&%Pqpa4hZ=hLCzjMcLL`>E)4y^_A7pUF#6AsWUxxmmWVmYJZ;XP( z_qsq55i;M@vu$B)dl);+Cli=L7A5h61Qz-TNB79dB0{*1zo3UHA($9c9*y9(60TYJ zH+rb@H-H~8z?e483DoF+X@T@HuP{PC&l^U_Cbv0r_@##DQ8Uaj1zZZFM%0CO3xOCb z)hA=Q8(E^0{hmVz{0uhmyF*~8)f3L5*(c$wJe*bWS3}_UViNZDd@O1-!PC_a&qMz| zM~LOr<_NYef|W+d<4tc!dL1+*8{OW_St?&GFhY2Y`FS^u zlZEOjo{!^WVH%z+zXEvfj7Ru}Wb!adsCx*~p^PUE0v1@5F1(vS3VHcpph<=4n7?F} zeIF=B+29a`Bo!c4}$k&3ev?*QM#hH;CZqhwMfQ0jbP1S zaQt^9eKX|0C28=`|B@un>S3^xknD6mek4q`V)Sv}l?cZ+cn*z(IB+e)7-I5bp#Ki& zd^~<9%h2---vG!iJc`g||p`gDz?;06*5xyGx=OVW_$Cr;t6UqC=Y zgE-AbiSyH0U7CG~SK_`j2fnfKka){L<6p)%{Q^4l*q0`A6te_hf-nsbZyI><{>+6f zWnRwvc;F~_(dLd6J#t4R`z(^}_2iC%T_gfwZ|d2}NOmTYEo>$FW)%_hOq3_*F-Qb4 zrWxq&@iy5rVyu&fcq=Z*uDXV*B0OMso8i;EzHKp}^v zkcqbgmjW~3|5sIL0LbxV{{aREK?OhX1{6S@XMR2$fv}vr#hEo}I$~_~b5+@^x7KfV=BQ`Nge}8TM^= zcD=ip3#U6QG3;`8cFps^HpmJfFC}@(O27f)qV7Xj0?6D|3bP<=QT|Io_RoPW!~d2b z9b1&|F@AzA87e&sK7~w!Iltf|Ydm4OeE;9zd9pZ(4=Y1PZ+K>x!2}Z&@I!myI&9&G zzJN#J1n;#E{)G)Qc|R0QZY!r_%atY&vKZ>ix7COMa?tBfX#=YN2@}lLYOg`tida*4WozE z${P;D1Z>pfj=;-k?%5+4l6?MbHM|OC9{o{>21K?w22Y}HbC1E@NVD-6JaeDmftu+D zYUw1HdsRT-B!`jNC8kjv3N}!^(}D9vA^-Jp=xou{5!JkgtH&Yn?)8GBiRuSQ)$wAI z1LqO}6-AG2-z(ASKog4i#pBTFkt?fT!bT<04S1;-LHw{%<5#*rnAbo_P=GEi7$Lfu+Sn~4iHzBeA)@PH+UbS9CFox!pnH!35aQ1DaZ}e zZF1hynu%0Pk{#sdY9N-IPC`eh=Xalk6pe>?0ZJH9#(#Sfrb7cidlIGvX{<0jm3-VO zxW8{1vZlo8Kn27l=7=0rf!CTx5Fu``!nEHepLm7WoPuty0_h|ah?TD!ViVpFbF=`9 zYDJb5Q>YsGXo!RIin)?Wag(EkPw=HG?>)ZQhWC1*j(!$S(lR%(KxO`kP+(+P1rj?k z);#w#+-uijh8h^0B7{Z!%hM1WFdrR^FMsiWpN9T1!fRSs1+lOj^_?V)U(ZLQ7n8lz zh}4=2c6eL{;H|?vL`x9ODr!>9xIjS;xD-3c->rc@AOo?oRSOwL>D%=j4-L-V1WL{g}c-T zVPZcUvsUZk+Lg#&@rqz032kQGBC$2rsK(`M!2ImOmHYSE_3L`*g{`00<1A6eW52n< zyn)}qoM0g>6Zd;{ROrVmzJcD~nNm2tQ!>jzw3ISXB2((#f5LlReTqZ0Ibl*$THz3V zV;1UhNIsAF7K%e<=W;n6z+4n!u#@ql-@;5N<|7**6^cD-131l4>iM^Uv;*t$qO2?( zKEY&}EuZmDCi1xPH{&Nyp6Z!zB0=C;96(Y{MxFTad}q5u_R6r-~{}L z;lpS3o;7FM_|X%mJT+A?73>G_XJbjnKtc8den#eZ-Y?$zcUum>@z;TElDKS3J-5fg27N*-WPbuT_g!8KirPo1JOK~lCcIs{r`eq B4AcMs diff --git a/lib/STLExporter.js b/lib/STLExporter.js new file mode 100644 index 0000000..606b17c --- /dev/null +++ b/lib/STLExporter.js @@ -0,0 +1,209 @@ +import { + Vector3 +} from '../../../build/three.module.js'; + +/** + * Usage: + * var exporter = new STLExporter(); + * + * // second argument is a list of options + * var data = exporter.parse( mesh, { binary: true } ); + * + */ + +var STLExporter = function () {}; + +STLExporter.prototype = { + + constructor: STLExporter, + + parse: function ( scene, options ) { + + if ( options === undefined ) options = {}; + + var binary = options.binary !== undefined ? options.binary : false; + + // + + var objects = []; + var triangles = 0; + + scene.traverse( function ( object ) { + + if ( object.isMesh ) { + + var geometry = object.geometry; + + if ( geometry.isBufferGeometry !== true ) { + + throw new Error( 'THREE.STLExporter: Geometry is not of type THREE.BufferGeometry.' ); + + } + + var index = geometry.index; + var positionAttribute = geometry.getAttribute( 'position' ); + + triangles += ( index !== null ) ? ( index.count / 3 ) : ( positionAttribute.count / 3 ); + + objects.push( { + object3d: object, + geometry: geometry + } ); + + } + + } ); + + var output; + var offset = 80; // skip header + + if ( binary === true ) { + + var bufferLength = triangles * 2 + triangles * 3 * 4 * 4 + 80 + 4; + var arrayBuffer = new ArrayBuffer( bufferLength ); + output = new DataView( arrayBuffer ); + output.setUint32( offset, triangles, true ); offset += 4; + + } else { + + output = ''; + output += 'solid exported\n'; + + } + + var vA = new Vector3(); + var vB = new Vector3(); + var vC = new Vector3(); + var cb = new Vector3(); + var ab = new Vector3(); + var normal = new Vector3(); + + for ( var i = 0, il = objects.length; i < il; i ++ ) { + + var object = objects[ i ].object3d; + var geometry = objects[ i ].geometry; + + var index = geometry.index; + var positionAttribute = geometry.getAttribute( 'position' ); + + if ( index !== null ) { + + // indexed geometry + + for ( var j = 0; j < index.count; j += 3 ) { + + var a = index.getX( j + 0 ); + var b = index.getX( j + 1 ); + var c = index.getX( j + 2 ); + + writeFace( a, b, c, positionAttribute, object ); + + } + + } else { + + // non-indexed geometry + + for ( var j = 0; j < positionAttribute.count; j += 3 ) { + + var a = j + 0; + var b = j + 1; + var c = j + 2; + + writeFace( a, b, c, positionAttribute, object ); + + } + + } + + } + + if ( binary === false ) { + + output += 'endsolid exported\n'; + + } + + return output; + + function writeFace( a, b, c, positionAttribute, object ) { + + vA.fromBufferAttribute( positionAttribute, a ); + vB.fromBufferAttribute( positionAttribute, b ); + vC.fromBufferAttribute( positionAttribute, c ); + + if ( object.isSkinnedMesh === true ) { + + object.boneTransform( a, vA ); + object.boneTransform( b, vB ); + object.boneTransform( c, vC ); + + } + + vA.applyMatrix4( object.matrixWorld ); + vB.applyMatrix4( object.matrixWorld ); + vC.applyMatrix4( object.matrixWorld ); + + writeNormal( vA, vB, vC ); + + writeVertex( vA ); + writeVertex( vB ); + writeVertex( vC ); + + if ( binary === true ) { + + output.setUint16( offset, 0, true ); offset += 2; + + } else { + + output += '\t\tendloop\n'; + output += '\tendfacet\n'; + + } + + } + + function writeNormal( vA, vB, vC ) { + + cb.subVectors( vC, vB ); + ab.subVectors( vA, vB ); + cb.cross( ab ).normalize(); + + normal.copy( cb ).normalize(); + + if ( binary === true ) { + + output.setFloat32( offset, normal.x, true ); offset += 4; + output.setFloat32( offset, normal.y, true ); offset += 4; + output.setFloat32( offset, normal.z, true ); offset += 4; + + } else { + + output += '\tfacet normal ' + normal.x + ' ' + normal.y + ' ' + normal.z + '\n'; + output += '\t\touter loop\n'; + + } + + } + + function writeVertex( vertex ) { + + if ( binary === true ) { + + output.setFloat32( offset, vertex.x, true ); offset += 4; + output.setFloat32( offset, vertex.y, true ); offset += 4; + output.setFloat32( offset, vertex.z, true ); offset += 4; + + } else { + + output += '\t\t\tvertex ' + vertex.x + ' ' + vertex.y + ' ' + vertex.z + '\n'; + + } + + } + + } + +}; + +export { STLExporter }; diff --git a/lib/stl.js b/lib/stl.js new file mode 100644 index 0000000..937fb47 --- /dev/null +++ b/lib/stl.js @@ -0,0 +1,209 @@ +import { + Vector3 +} from '../node_modules/three/src/Three'; + +/** + * Usage: + * var exporter = new STLExporter(); + * + * // second argument is a list of options + * var data = exporter.parse( mesh, { binary: true } ); + * + */ + +var STLExporter = function () {}; + +STLExporter.prototype = { + + constructor: STLExporter, + + parse: function ( scene, options ) { + + if ( options === undefined ) options = {}; + + var binary = options.binary !== undefined ? options.binary : false; + + // + + var objects = []; + var triangles = 0; + + scene.traverse( function ( object ) { + + if ( object.isMesh ) { + + var geometry = object.geometry; + + if ( geometry.isBufferGeometry !== true ) { + + throw new Error( 'THREE.STLExporter: Geometry is not of type THREE.BufferGeometry.' ); + + } + + var index = geometry.index; + var positionAttribute = geometry.getAttribute( 'position' ); + + triangles += ( index !== null ) ? ( index.count / 3 ) : ( positionAttribute.count / 3 ); + + objects.push( { + object3d: object, + geometry: geometry + } ); + + } + + } ); + + var output; + var offset = 80; // skip header + + if ( binary === true ) { + + var bufferLength = triangles * 2 + triangles * 3 * 4 * 4 + 80 + 4; + var arrayBuffer = new ArrayBuffer( bufferLength ); + output = new DataView( arrayBuffer ); + output.setUint32( offset, triangles, true ); offset += 4; + + } else { + + output = ''; + output += 'solid exported\n'; + + } + + var vA = new Vector3(); + var vB = new Vector3(); + var vC = new Vector3(); + var cb = new Vector3(); + var ab = new Vector3(); + var normal = new Vector3(); + + for ( var i = 0, il = objects.length; i < il; i ++ ) { + + var object = objects[ i ].object3d; + var geometry = objects[ i ].geometry; + + var index = geometry.index; + var positionAttribute = geometry.getAttribute( 'position' ); + + if ( index !== null ) { + + // indexed geometry + + for ( var j = 0; j < index.count; j += 3 ) { + + var a = index.getX( j + 0 ); + var b = index.getX( j + 1 ); + var c = index.getX( j + 2 ); + + writeFace( a, b, c, positionAttribute, object ); + + } + + } else { + + // non-indexed geometry + + for ( var j = 0; j < positionAttribute.count; j += 3 ) { + + var a = j + 0; + var b = j + 1; + var c = j + 2; + + writeFace( a, b, c, positionAttribute, object ); + + } + + } + + } + + if ( binary === false ) { + + output += 'endsolid exported\n'; + + } + + return output; + + function writeFace( a, b, c, positionAttribute, object ) { + + vA.fromBufferAttribute( positionAttribute, a ); + vB.fromBufferAttribute( positionAttribute, b ); + vC.fromBufferAttribute( positionAttribute, c ); + + if ( object.isSkinnedMesh === true ) { + + object.boneTransform( a, vA ); + object.boneTransform( b, vB ); + object.boneTransform( c, vC ); + + } + + vA.applyMatrix4( object.matrixWorld ); + vB.applyMatrix4( object.matrixWorld ); + vC.applyMatrix4( object.matrixWorld ); + + writeNormal( vA, vB, vC ); + + writeVertex( vA ); + writeVertex( vB ); + writeVertex( vC ); + + if ( binary === true ) { + + output.setUint16( offset, 0, true ); offset += 2; + + } else { + + output += '\t\tendloop\n'; + output += '\tendfacet\n'; + + } + + } + + function writeNormal( vA, vB, vC ) { + + cb.subVectors( vC, vB ); + ab.subVectors( vA, vB ); + cb.cross( ab ).normalize(); + + normal.copy( cb ).normalize(); + + if ( binary === true ) { + + output.setFloat32( offset, normal.x, true ); offset += 4; + output.setFloat32( offset, normal.y, true ); offset += 4; + output.setFloat32( offset, normal.z, true ); offset += 4; + + } else { + + output += '\tfacet normal ' + normal.x + ' ' + normal.y + ' ' + normal.z + '\n'; + output += '\t\touter loop\n'; + + } + + } + + function writeVertex( vertex ) { + + if ( binary === true ) { + + output.setFloat32( offset, vertex.x, true ); offset += 4; + output.setFloat32( offset, vertex.y, true ); offset += 4; + output.setFloat32( offset, vertex.z, true ); offset += 4; + + } else { + + output += '\t\t\tvertex ' + vertex.x + ' ' + vertex.y + ' ' + vertex.z + '\n'; + + } + + } + + } + +}; + +export { STLExporter }; diff --git a/src/Scene.js b/src/Scene.js index 8e62d4a..d905c23 100644 --- a/src/Scene.js +++ b/src/Scene.js @@ -1,22 +1,16 @@ - - - import * as THREE from '../node_modules/three/src/Three'; -import { TrackballControls } from '../lib/trackball' -import { Sketch } from './Sketch' -import Stats from '../lib/stats.module.js'; +import { Sketch } from './Sketch' import { extrude, flipBufferGeometryNormals } from './extrude' import { onHover, onPick, clearSelection } from './mouseEvents'; import { _vec2, _vec3, color, awaitSelection, ptObj, setHover } from './shared' - import { AxesHelper } from './axes' +import { TrackballControls } from '../lib/trackball' import CSG from "../lib/three-csg" - -import { STLExporter } from '../node_modules/three/examples/jsm/exporters/STLExporter' - +import { STLExporter } from '../lib/stl' +import Stats from '../lib/stats.module.js'; @@ -376,37 +370,34 @@ function render() { } -async function addSketch() { +function addSketch() { let sketch; - const references = await this.awaitSelection({ selpoint: 3 }, { plane: 1 }); - - if (!references) return; - - if (references[0].userData.type == 'plane') { - sketch = new Sketch(this) - sketch.obj3d.matrix = references[0].matrix - sketch.plane.applyMatrix4(sketch.obj3d.matrix) - sketch.obj3d.inverse = sketch.obj3d.matrix.clone().invert() - this.obj3d.add(sketch.obj3d) - } else { + if (this.selected.length == 3 && this.selected.every(e=>e.userData.type == 'selpoint')) { sketch = new Sketch(this) this.obj3d.add(sketch.obj3d) sketch.align( - ...references.map( + ...this.selected.map( el => new THREE.Vector3(...el.geometry.attributes.position.array).applyMatrix4(el.matrixWorld) ) ) + } else if (this.selected.length && this.selected[0].userData.type == 'plane') { + sketch = new Sketch(this) + sketch.obj3d.matrix = this.selected[0].matrix + sketch.plane.applyMatrix4(sketch.obj3d.matrix) + sketch.obj3d.inverse = sketch.obj3d.matrix.clone().invert() + this.obj3d.add(sketch.obj3d) + + } else { + return } + this.newSketch = true this.clearSelection() - sketch.obj3d.addEventListener('change', this.render); - return sketch - } window.sc = new Scene(store) diff --git a/src/Sketch.js b/src/Sketch.js index d6c2d45..9b3780e 100644 --- a/src/Sketch.js +++ b/src/Sketch.js @@ -5,7 +5,7 @@ import * as THREE from '../node_modules/three/src/Three'; import { _vec2, _vec3, raycaster, awaitSelection, ptObj, setHover } from './shared' import { drawOnClick1, drawOnClick2, drawPreClick2, drawOnClick3, drawPreClick3, drawClear, drawPoint } from './drawEvents' -import { onHover, onDrag, onPick, onRelease, clearSelection} from './mouseEvents' +import { onHover, onDrag, onPick, onRelease, clearSelection } from './mouseEvents' import { setCoincident, setOrdinate, setTangent } from './constraintEvents' import { get3PtArc } from './drawArc' import { replacer, reviver } from './utils' @@ -197,6 +197,9 @@ class Sketch { this.obj3d.traverse(e => e.layers.disable(2)) this.scene.axes.visible = false this.scene.activeSketch = null + if (this.scene.newSketch) { + this.scene.newSketch = false + } this.clearSelection() @@ -255,8 +258,11 @@ class Sketch { this.canvas.addEventListener('pointerdown', this.drawOnClick1, { once: true }) break; case 'd': - drawClear.call(this) - this.drawDimension() + if (this.mode != 'dimension') { + drawClear.call(this) + this.mode = "dimension" + this.drawDimension() + } break; case 'c': drawClear.call(this) @@ -284,6 +290,7 @@ class Sketch { console.log('undo would be nice') break; } + // console.log('this mode:', this.mode) } deleteSelected() { diff --git a/src/drawArc.js b/src/drawArc.js index 6c4c954..d2cc392 100644 --- a/src/drawArc.js +++ b/src/drawArc.js @@ -1,6 +1,8 @@ -import { Vector2 } from 'three'; +import { + Vector2 +} from '../node_modules/three/src/Three'; import { ptObj, lineObj } from './shared' const n = 30 diff --git a/src/drawDimension.js b/src/drawDimension.js index ea7b5fe..ca6a468 100644 --- a/src/drawDimension.js +++ b/src/drawDimension.js @@ -138,7 +138,7 @@ export async function drawDimension() { } else { - this.dimGroup.children.splice(this.dimGroup.length - 2, 2).forEach( + this.dimGroup.children.splice(this.dimGroup.children.length - 2, 2).forEach( e => { e.geometry.dispose() e.material.dispose() @@ -147,6 +147,10 @@ export async function drawDimension() { this.labelContainer.removeChild(this.labelContainer.lastChild); sc.render() } + if (this.mode=="dimension") { + this.drawDimension() + } + return } diff --git a/src/mouseEvents.js b/src/mouseEvents.js index f611e2b..d4fd2d4 100644 --- a/src/mouseEvents.js +++ b/src/mouseEvents.js @@ -5,7 +5,7 @@ import { onDimMoveEnd } from './drawDimension' let ptLoc export function onHover(e) { - if (this.mode || e.buttons) return + if (( this.mode && this.mode!='dimension') || e.buttons) return raycaster.setFromCamera( new THREE.Vector2( @@ -114,7 +114,7 @@ export function onHover(e) { let draggedLabel; export function onPick(e) { - if (this.mode || e.buttons != 1) return + if (( this.mode && this.mode!='dimension') || e.buttons != 1) return // if (this.mode || e.buttons != 1 || e.ctrlKey || e.metaKey) return if (this.hovered.length) { diff --git a/src/react/app.css b/src/react/app.css index ee2f663..807aa48 100644 --- a/src/react/app.css +++ b/src/react/app.css @@ -57,6 +57,13 @@ body { hover:bg-gray-500 hover:text-gray-200; } +.active-btn { + cursor: pointer; + @apply fill-current + bg-green-400 text-gray-200 +} + + .btn-green { cursor: pointer; diff --git a/src/react/app.jsx b/src/react/app.jsx index 4120d03..5e292a7 100644 --- a/src/react/app.jsx +++ b/src/react/app.jsx @@ -1,9 +1,8 @@ - import ReactDOM from 'react-dom' -import React, { } from 'react' +import React from 'react' import { createStore, applyMiddleware } from 'redux' -import { Provider, useSelector } from 'react-redux' +import { Provider } from 'react-redux' import { reducer } from './reducer' import logger from 'redux-logger' @@ -11,27 +10,19 @@ import { Tree } from './tree' import { NavBar } from './navBar' import { ToolTip } from './toolTip' - import './app.css' -const preloadedState = { - treeEntries: { - byId: {}, - allIds: [], - tree: {}, - order: {}, - visible: {}, - activeSketchId: "" - }, + + + +let store +if (process.env.NODE_ENV === 'production') { + store = createStore(reducer) +} else { + const { logger } = require(`redux-logger`); + store = createStore(reducer, {}, applyMiddleware(logger)) } -// const store = createStore(reducer, preloadedState, applyMiddleware(logger)) - - -const store = createStore(reducer, {}, applyMiddleware(logger)) -// const store = createStore(reducer, sc.loadState(), applyMiddleware(logger)) - - const App = ({ store }) => { return diff --git a/src/react/dialog.jsx b/src/react/dialog.jsx index bc78010..7ff8c26 100644 --- a/src/react/dialog.jsx +++ b/src/react/dialog.jsx @@ -111,10 +111,14 @@ export const Dialog = () => { || sc.activeSketch.idOnActivate != id || sc.activeSketch.c_idOnActivate != sc.activeSketch.c_id ) { - dispatch({ type: "restore-sketch" }) - // dispatch({ type: 'set-modified', status: false }) + if (sc.newSketch) { + dispatch({ type: 'delete-node', id: sc.activeSketch.obj3d.name }) + sc.sid -= 1 + } else { + dispatch({ type: "restore-sketch" }) + } } - + dispatch({ type: 'finish-sketch' }) sc.activeSketch.deactivate() diff --git a/src/react/fileHelpers.js b/src/react/fileHelpers.js index 1273704..e0fa7ac 100644 --- a/src/react/fileHelpers.js +++ b/src/react/fileHelpers.js @@ -15,16 +15,12 @@ var tzoffset = (new Date()).getTimezoneOffset() * 60000; export function STLExport(filename) { - if (sc.selected[0] && sc.selected[0].userData.type == 'mesh') { - const result = STLexp.parse(sc.selected[0], { binary: true }); + const result = STLexp.parse(sc.selected[0], { binary: true }); - const time = (new Date(Date.now() - tzoffset)).toISOString().slice(0, -5).replace(/:/g, '-'); + const time = (new Date(Date.now() - tzoffset)).toISOString().slice(0, -5).replace(/:/g, '-'); - saveLegacy(new Blob([result], { type: 'model/stl' }), `${filename}_${time}.stl`); - } else { - alert('please select one body to export') - } + saveLegacy(new Blob([result], { type: 'model/stl' }), `${filename}_${time}.stl`); } @@ -41,7 +37,6 @@ export async function saveFile(fileHandle, file, dispatch) { console.error(msg, ex); alert(msg); } - // app.setFocus(); }; export async function saveFileAs(file, dispatch) { @@ -83,16 +78,11 @@ export async function saveFileAs(file, dispatch) { alert(msg); return; } - - // app.setFocus(); }; export async function openFile(dispatch) { - // if (!app.confirmDiscard()) { - // return; - // } let fileHandle // If a fileHandle is provided, verify we have permission to read/write it, @@ -143,7 +133,7 @@ export function confirmDiscard(modified) { export async function verifyPermission(fileHandle) { const opts = { - mode:'readwrite' + mode: 'readwrite' }; // Check if we already have permission, if so, return true. diff --git a/src/react/navBar.jsx b/src/react/navBar.jsx index 7d0d547..b1a0e3a 100644 --- a/src/react/navBar.jsx +++ b/src/react/navBar.jsx @@ -4,16 +4,13 @@ import React, { useEffect, useReducer } from 'react'; import { useDispatch, useSelector } from 'react-redux' -import { FaEdit } from 'react-icons/fa' +import { FaEdit, FaLinkedin, FaGithub } from 'react-icons/fa' import { MdSave, MdFolder, MdInsertDriveFile } from 'react-icons/md' import * as Icon from "./icons"; import { Dialog } from './dialog' import { STLExport, saveFile, openFile, verifyPermission } from './fileHelpers' - - - export const NavBar = () => { const dispatch = useDispatch() const sketchActive = useSelector(state => state.ui.sketchActive) @@ -22,7 +19,10 @@ export const NavBar = () => { const modified = useSelector(state => state.ui.modified) const boolOp = (code) => { - if (sc.selected.length != 2 || !sc.selected.every(e => e.userData.type == 'mesh')) return + if (sc.selected.length != 2 || !sc.selected.every(e => e.userData.type == 'mesh')) { + alert('please first select two bodies for boolean operation') + return + } const [m1, m2] = sc.selected const mesh = sc.boolOp(m1, m2, code) @@ -46,8 +46,12 @@ export const NavBar = () => { forceUpdate() } - const addSketch = async () => { - const sketch = await sc.addSketch() + const addSketch = () => { + const sketch = sc.addSketch() + if (!sketch) { + alert('please select a plane or 3 points to define sketch plane') + return + } dispatch({ type: 'rx-sketch', obj: sketch }) @@ -100,16 +104,16 @@ export const NavBar = () => { dispatch({ type: 'set-dialog', action: 'extrude', target: sc.activeSketch }) }, 'Extrude [e]'], - [Icon.Dimension, () => sc.activeSketch.command('d'), 'Dimension [d]'], - [Icon.Line, () => sc.activeSketch.command('l'), 'Line [l]'], - [Icon.Arc, () => sc.activeSketch.command('a'), 'Arc [a]'], - [Icon.Coincident, () => sc.activeSketch.command('c'), 'Coincident [c]'], - [Icon.Vertical, () => sc.activeSketch.command('v'), 'Vertical [v]'], - [Icon.Horizontal, () => sc.activeSketch.command('h'), 'Horizontal [h]'], - [Icon.Tangent, () => sc.activeSketch.command('t'), 'Tangent [t]'], + [Icon.Dimension, () => sc.activeSketch.command('d'), 'Dimension [D]'], + [Icon.Line, () => sc.activeSketch.command('l'), 'Line [L]'], + [Icon.Arc, () => sc.activeSketch.command('a'), 'Arc [A]'], + [Icon.Coincident, () => sc.activeSketch.command('c'), 'Coincident [C]'], + [Icon.Vertical, () => sc.activeSketch.command('v'), 'Vertical [V]'], + [Icon.Horizontal, () => sc.activeSketch.command('h'), 'Horizontal [H]'], + [Icon.Tangent, () => sc.activeSketch.command('t'), 'Tangent [T]'], [MdSave, async () => { - if(await verifyPermission(fileHandle) === false) return + if (await verifyPermission(fileHandle) === false) return sc.refreshNode(sc.activeSketch.obj3d.name, treeEntries) sc.activeSketch.clearSelection() saveFile(fileHandle, JSON.stringify([id, sc.sid, sc.mid, treeEntries]), dispatch) @@ -121,9 +125,14 @@ export const NavBar = () => { const partModeButtons = [ - [FaEdit, addSketch, 'Sketch [s]'], + [FaEdit, addSketch, 'Sketch'], [Icon.Extrude, () => { - dispatch({ type: 'set-dialog', action: 'extrude', target: treeEntries.byId[sc.selected[0].name] }) + if (sc.selected[0] && treeEntries.byId[sc.selected[0].name].userData.type == 'sketch') { + dispatch({ type: 'set-dialog', action: 'extrude', target: treeEntries.byId[sc.selected[0].name] }) + } else { + alert('please select a sketch from the left pane extrude') + } + }, 'Extrude'], [Icon.Union, () => boolOp('u'), 'Union'], @@ -147,9 +156,12 @@ export const NavBar = () => { ) }, 'Open'], [Icon.Stl, () => { - STLExport('box') - }, - , 'Export STL'], + if (sc.selected[0] && sc.selected[0].userData.type == 'mesh') { + STLExport(fileHandle ? fileHandle.name.replace(/\.[^/.]+$/, "") : 'untitled') + } else { + alert('please first select one body to export') + } + }, 'Export to STL'], ] const [_, forceUpdate] = useReducer(x => x + 1, 0); @@ -175,30 +187,16 @@ export const NavBar = () => { )) } - } -// app.saveFile = async () => { -// try { -// if (!app.file.handle) { -// return await app.saveFileAs(); -// } -// gaEvent('FileAction', 'Save'); -// await writeFile(app.file.handle, app.getText()); -// app.setModified(false); -// } catch (ex) { -// gaEvent('Error', 'FileSave', ex.name); -// const msg = 'Unable to save file'; -// console.error(msg, ex); -// alert(msg); -// } -// app.setFocus(); -// }; - - - - diff --git a/src/react/tree.jsx b/src/react/tree.jsx index b75acc6..fc83c29 100644 --- a/src/react/tree.jsx +++ b/src/react/tree.jsx @@ -11,7 +11,7 @@ export const Tree = () => { const fileHandle = useSelector(state => state.ui.fileHandle) return
-
+
{fileHandle ? fileHandle.name.replace(/\.[^/.]+$/, "") : 'untitled'}
{treeEntries.allIds.map((entId, idx) => ( diff --git a/src/shared.js b/src/shared.js index 696f1da..9737c63 100644 --- a/src/shared.js +++ b/src/shared.js @@ -128,6 +128,7 @@ async function awaitSelection(...criteria) { references.push(pt) const type = pt.userData.type + if (counter[type]) { counter[type] += 1; } else { @@ -144,7 +145,7 @@ async function awaitSelection(...criteria) { window.removeEventListener('keydown', onKey) } - console.log('fail') + // console.log('fail') return null } diff --git a/todo.txt b/todo.txt index b0e0dc5..c905819 100644 --- a/todo.txt +++ b/todo.txt @@ -35,48 +35,49 @@ dim tag delete //resolved auto update extrude // done extrude edit dialog // done file save, stl export// done +seperate scene from init logic only init cam and rendere // not an issue , ended up just splicing (1) +add download button, different from save button // done -unable cancel out of new sketches //fixed seemingly +-unable to delete arc // fixed seemingly -sometimes unable to hit return and change dimensionk --unable to delete arc hover not clearing sometimes in sketch 0.000 artifact lighting messed up -seperate scene from init logic only init cam and rendere + + + + + + + reattach sketch auto snap - +vertical and horzontal baseline to dimension to / or just smart ordinate dir dimenensing highlight button to indicate active mode - add cancle soft button for line arc - - constraint labels,equal - -add download button, different from save button parallel // need to add antoher button to feature ,or empty placeholder - - tree relation tool tip tree ent renaming -vertical and horzontal baseline to dimension to set pieces +wasm data structure + hover state for sketch await selection 3 point arc implementation - +local file save and mark dirty saerch tree for loop finding // need dev effor - dep tree for biuidling design treee diff --git a/wasm/solver.c b/wasm/solver.c index bab0f14..813d323 100644 --- a/wasm/solver.c +++ b/wasm/solver.c @@ -174,8 +174,7 @@ int main(int argc, char *argv[]) sys.failed = CheckMalloc(500 * sizeof(sys.failed[0])); sys.faileds = 500; - // Example2d(150.0); - printf("hello\n"); + // printf("hello\n"); return 0; } diff --git a/webpack.prod.js b/webpack.prod.js index 1d1feb9..1c143d3 100644 --- a/webpack.prod.js +++ b/webpack.prod.js @@ -1,10 +1,16 @@ const { merge } = require('webpack-merge'); const common = require('./webpack.common.js'); - +const webpack = require('webpack') module.exports = merge(common, { mode: 'production', - + plugins: [ + new webpack.DefinePlugin({ + // 'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV) + 'process.env.NODE_ENV': 'production' + }), + new webpack.IgnorePlugin(/redux-logger/) + ] }); \ No newline at end of file