From ffd3a7133a13aaa7d1eb5c0e4f1b81a3698bc71a Mon Sep 17 00:00:00 2001 From: CHARRAS Date: Fri, 4 Jan 2008 12:27:16 +0000 Subject: [PATCH] more about zones. current No DRC for outlines --- bitmaps/Add_Zone_Cutout.xpm | 12 +- change_log.txt | 8 + include/wxPcbStruct.h | 25 + internat/fr/kicad.mo | Bin 140177 -> 140822 bytes internat/fr/kicad.po | 605 ++++++++------- pcbnew/class_board.h | 117 +++ pcbnew/class_zone.cpp | 143 ++-- pcbnew/class_zone.h | 7 +- pcbnew/dialog_zones_by_polygon.cpp | 2 +- pcbnew/edit.cpp | 24 +- pcbnew/makefile.include | 2 + pcbnew/onrightclick.cpp | 4 +- pcbnew/zone_filling_algorithm.cpp | 38 +- pcbnew/zones_by_polygon.cpp | 319 ++++++-- pcbnew/zones_test_and_combine_areas.cpp | 975 ++++++++++++++++++++++++ polygon/PolyLine.cpp | 13 + polygon/PolyLine.h | 8 +- 17 files changed, 1844 insertions(+), 458 deletions(-) create mode 100644 pcbnew/zones_test_and_combine_areas.cpp diff --git a/bitmaps/Add_Zone_Cutout.xpm b/bitmaps/Add_Zone_Cutout.xpm index 171878213c..d106f039b4 100644 --- a/bitmaps/Add_Zone_Cutout.xpm +++ b/bitmaps/Add_Zone_Cutout.xpm @@ -11,12 +11,12 @@ const char * add_zone_cutout[] = { " ..............", ".... ........", "... ++++ .......", -".. + + .....", -". + + ...", -". + + ..", -". + + ..", -". + + .", -".. + + ..", +".. +++++++ .....", +". ++ ++ ...", +". ++ ++ ..", +". ++ ++ ..", +". ++ ++ .", +".. ++++++++++ ..", "... +++++++ ... ", ".... .... ", "............ ", diff --git a/change_log.txt b/change_log.txt index 2a497955d5..efe4ec7afe 100644 --- a/change_log.txt +++ b/change_log.txt @@ -4,6 +4,14 @@ Started 2007-June-11 Please add newer entries at the top, list the date and your name with email address. +2008-jan-04 UPDATE Jean-Pierre Charras +================================================================================ ++pcbnew: + More about zones: + Outlines can be edited. Outlines are merged if needeed. + Current No DRC for outlines + + 2008-jan-01 UPDATE Jean-Pierre Charras ================================================================================ +all diff --git a/include/wxPcbStruct.h b/include/wxPcbStruct.h index 8fe30bd10e..0d9bfcbbfd 100644 --- a/include/wxPcbStruct.h +++ b/include/wxPcbStruct.h @@ -529,6 +529,24 @@ public: */ int Fill_All_Zones( wxDC* DC, bool verbose = TRUE ); + + /** + * Function Add_Zone_Cutout + * Add a cutout zone to a given zone outline + * @param DC = current Device Context + * @param zone_container = parent zone outline + */ + void Add_Zone_Cutout( wxDC* DC , ZONE_CONTAINER * zone_container ); + + /** + * Function Add_Similar_Zone + * Add a zone to a given zone outline. + * if the zones are overlappeing they will be merged + * @param DC = current Device Context + * @param zone_container = parent zone outline + */ + void Add_Similar_Zone( wxDC* DC , ZONE_CONTAINER * zone_container ); + /** * Function Edit_Zone_Params * Edit params (layer, clearance, ...) for a zone outline @@ -548,6 +566,13 @@ public: */ void End_Move_Zone_Corner( wxDC* DC , ZONE_CONTAINER * zone_container ); + /** + * Function End_Move_Zone_Corner + * Remove the currently selected corner in a zone outline + * the .m_CornerSelection is used as corner selection + */ + void Remove_Zone_Corner( wxDC* DC, ZONE_CONTAINER * zone_container ); + // Target handling MIREPCB* Create_Mire( wxDC* DC ); void Delete_Mire( MIREPCB* MirePcb, wxDC* DC ); diff --git a/internat/fr/kicad.mo b/internat/fr/kicad.mo index 9fb260b2d33fc501eb4805f9b212be3ffa880916..23fa1270cb31188061a35ffefb5286e44bfed242 100644 GIT binary patch delta 50417 zcmZ793EYiU+qnO2o+BAD#Er}%ghY{~NE1a!(uk6T24pLwfkMcbLM19RAe9i(6D5_( z5Sda6p%SX!aqR2#|MY+N=iTpjt#z&8T+?;m)bl)JKh8UGUEcKfMRQI_@i`-3DpeNW zzC4wxTribtJJ!-vYR8IHswn<|h43hr!0anisbW|P%V2FRiEXd|-h#F99;}Dcu{dtP zvv4mmUOJWYqokt>Xa@~3H(rJL@p?QBZ;pH)B-YeGEP}%^4^D{k>6n-NE0JG-xyUb# z^5tm%pJ0B*Pi-LK09(+Gf5sMg6rEY4RjJenY>zhl4h?Jv8u0$e=UAOefIHEp{ReGdY)ukK z`S5IX>#Ac#Y=qYDjA;kHmjqj$dIYoM)8SYwOny8%quFS^H?RV}hmCO?w!)Ghr&0~@ zCTxV`(e~@G8g51RKG)h*sw!4m%lbRu6%^#atHO3+hp=;aQ+P{wN7yU8C%g~s_x{K~ z6h0h25{_8Q`aAFwQ7}3ji*_&pUFu1ZpB=su&JAA=7ldzNZrUwE&%g)h3a*RtO_+!L zwloR%W)E8NNIb~?Nzy@nwBqUL^HP`(tD)`cp7!j@L)|ooK!OSQ#HhCo~7$ z`t;i*a*R{5hTKFo&?MftEOpMa$(pBCkd(DrN5YxXs|Li^DP z96={|3=4Sw^Q=oEJp)~Vs#pM2cJ`Ek{)yOYI173#KUyDv; zGurM4Oy?(Yh=emgfi88v^+_N_(R>ZGUj6W*ur<1J*P$!W8GT{(N6*4&EQHh1Et-ef za6TH?!u71b58k7|J^e7;816xzA440SM6cyP=uESHmMm#LwEQ&m(4CI9tB6jZO62Q= z^`pGeXL0|V$AgyWOfN^bqCFbeU04W*pplOXC!$;R0y@xZXdv&P0WU%OTZ*UQYCIpm zLf?>u(w`@Le<_xxpcC3*|8OYU;V5)Q&!C6sS@ab=32Wn0Y=}Rh17&SUu5%qUuvX~G zT#fdBGdi*K-6ZTdjRkQSy0l{=KM8#=ycFf{qd$yRp)>mqU76kCVRV4h7s*N$MDr!k zek)=TtdW$bQ%y)X@MY-IUWcy4O=#o~Mfsy>N2AclC!rnAL+ia2`S;QORz>+2XrPf}&_-Wzi1L2^*pvG>d#2^jfw@JL-x46zqph@O8BPPiTOL(SeVn z6Da&;vPEUEkoUg^2?stO3u9|6ik;A(?{~-Z$I+FUjG156usr!M&>8=R2J{bFFYi~$ z)>T3Wz5wmF6`p~eFmwNVlkm_yh(|N6N+gC*;J`D{7s@>JP%cCRdk5WuRgwQ3ox%6$8|^Tjj(8!PGk6RQbR3qzsdyp2iM|03p-Y_q z8-C*9Sy&T$p%a)GzKEWU*U}`s&u^n0zl+XnB^Jj`=*)gWJNPHc^L?8yB>K>?nT&y{4B|HZWumu`$2Xq46(0*>i zs@MbVXAHW+GtsS>6Zs{`cV`UYK@y-|J$9q=T2`0{K?20jg4 znR4hr_0aa0p!M3J?K)v*rF`!F??J+)d;qOD6b)n~mcsF9fN#X}Md1hGD)g*;8u=g4 zt=fkM^f%hy>06V-Sq@#Hx|q&HNW#5t7v79ExCdQ{LE*?Ke-@p|3uwD}SQ6hwXZ{6x z26m#q@8{o^1X2xs-W1)cE4Q)!2GErPf12Hmt?_BJ<8Lvu^yq+x(1A{16FlSlWW}yV z`{{tr_;$42L)adNp#y(|&U_y_vE$#f{#8ii-X5nLt=IyqV|y%(4`UWi!fN;~*210W zK!tZCr@Rz4B3~Ze(vIl!o6!J!p%Zxsy%odLBwXqz(Y=2Ty-v@gr*szD!J2SGxH;S% z9zd7$7&^neKO_T{Mgysgo}t?4$~HvLR=On#2e=81tOvR@{jh=+&_G_qGjSEx#ck-D zuJF#JydqX6-vsTrJGxSX&@Gvb9?B)?*;tRPY&!Kj2`d)al?2cj-Q$*M!yC~K??spJ zNpuF2(Up4zGjC9IhVP;)u_E$cpey?wI?)|y`=9Z2@Bc9pc9eg25?M(!fM)34cSKj_ zJ}i$9qbo5T4QLU%#H-O2`3&8HAJBk~pc6cSo~^U@B=s6#LB>yAZUV1IXM779;r(bw z!_gI(hz7JE@}Hthx(Ds}IQkwaus0c?0%qQb=nt!wXn$SMetKit29J}dkI!Qj+=%Dl zUuYn;e@p^wiq5<>HpW}fm6?VY;44@Icj8%CXkYTfs3w}f2b<$4wEp^itbcV9d4EbG ztcQ8Xx5lz~EtbK1Fthhqf&652so%rO_!%1LQFNx+e@^nHFgN+C=*(-QE8H9_;dMW= z{#JO90+%q24m1Y61vAj+^CJHyx>d`t4t|PN@dUcmmG&nSsE-ENB)lr@jt0^n9p|w$ z3HM?GPQwM57q9#!`61B(&nDj)4J3{E@iBCOu~-0SV?kViS@;1~!SB&ClIz!`U1@aS z%9xq(c_gfGDHg)c=$Yt&9=ajuK$Fl0^Ux07M`!#gI`Eco9~#i_=uER6NcuektydxP zwUPGeRMU9SHXd}s)2Mi79+`4 zULFg2|Lc$_L_t%uVVleYewd&g-WvJ-;Uj4Mr?EOt!_#mL8qn8hKRd!-&_j0&4W!_q zq<$&P{Q18c312wpp-bHsJ)PaqB^-us(S&$DH~at{cmq1%b}WMX(E(3Jd6D0efy<)x ztE2VL$Fu{rBvB4~pnE?OPsiz480TXh{1Bb_LG*0=jV^u3!^r^k!e;0|Z7~;iiSq8@ zJ>j6ktbbi9JWhe9dug}=bCO?+HE})W!@tm#$Z;fjp`3{Z)({Qk4)p!;2)Ytapc9x9 z`MG!o`S;NG#OFuYe>>b86;7b9oW>ZC;t{&Z#5Rh&FD(~iWg#z-;+1!#n^!S z0Q5~c4{g5+UAawY{oUvrv10m<U@OCg()H89Km~VdwBpbcX%WYd18? zpNjHHcoF5Z!1Y)Xzl-wU&g{ZkyNaRo`Kq7BXnlX(XDBN4sZiH!0qS&_oDR%qX9h@ z&nKY$y?_q*DmvcM$bWu<{Vzqq4hpK_arCEFrISg6Hs}Cd&_j49mc@s$Hcr8c_z7N& zzhE=0{de-`gL|+(`MKzxe~koppNN87|0ESoLo1X!JZ)h#sbn z=t^`&`{{ws^gguxFm%9CXaJMYKwm)H?@W^@PhuZBlf3^XdsP!XgqMWv@eJ~}qQ3z> zfaP&Ax^nMEerK4SzkW23ieY{9475bI@J4Km>7FD?keG$eU@3ZESD}0LDY~aS&;Sl% zS=6!bSo;Mhp{=j#jVkaw8ykBo}1#qt>}xTH=c<@(IuRW z1~3C1@MW~!`{-7zKo8p{bVYtd2Re$b)IU+4KX(#fNwj{I+}V=*--rS`z83BHPCN_m zMmu^Ejd(nI7G|IwEJF|1=jh7(h@OcP=tK(SNdhQ`wy%K(+yK4CZSthEWqxYiMu9)Q z9!Hn(H7tYgVN?7jo)^oTY|;7XigZQ;?jHF&(1CiREAb%az!B(5Jb_MV0@lJAX%a@V z4sEa(JtRlaiYL$+<;s`TD~{fRI#>l;p)1iFJp)6+QRs?JiRTN@fLEaH*P`{)+ex@| zzoG+X%b!#%fF8o4;o0aw4bg^|p-X=~+P*g$_#@~ocmmymh3HvYh1TDOj`KURa_Q8+ zQINAh^58Ty(lgN|D<9=G(UoX`&froskQ>n@?}fG-fCf4^@}n_}{CKp#chG)TUxer~k!UdB^E2A^I5RLd!bVgUBXX6&kEIE1xMxg_YMbFT5Y>BU-0sn@jF>j%y zzetQdv5T~O7Zb47^ zaWufHMUt7<4$m*b{dZ|wL_yoILwIx8E9@T*2_Fx~h10^9!v*LIY$S4XG zN!T*HGVBm`3wwlp(T)d3{?YKMaC|(U9=?>APQ4xl?}Q(OtI<=t9zA56(Ix!@U7p!_1d6Y)Dbhk|92(fUfhLt@Br4tGuoAFrPpFJCg7P(H%X64@Q0@dI+Bn-$3v8 zGOUi@qAQcVcyfr#q3!EpX2$4yqYb(ex1bZa6J3dWG4uQX!z7G+9J&&d&?TN7<@3-E z7NQ+2LOb{n9cUf8BAd{e{fPE+5?#5xC6ebA(DzF{v|hUs+<)J6cT!-3htPNV2=q6h zF=)qcqA#G2(A)9_`oh_Rwm-9E{Cr1WJPptRuEQ$W6Px20bOK+XE48^K_unP`i2^&$ zab_}LNi?8p=t`W22G%6XTcJza4qcgEcsce#16_i)TZ6ue*P|2Jg|6Ju$Y)EJN|vx_ zSQd?}3VQe&paVA!TcTTaHCpd_^pM?#uEgDF{UPYqJb?!CEIRWkQ9cXZiuCIwvPi5) z58HvL@DJK?-qK0KB4~%DunAT|f0}heXE+cYXiStphpymozeU8d}}=4hX(RH`rB~6vPrutc!od! z>yvPx%h1!>37z?U=+B0M=+ccw_j)2agQ@6>yoN6MA~c{C=+=CO2D%Nc_ftGS66LA0 zXvg@ef+Vb1(gLg$){}7$wM`*|E(113FKcRsfL+j-&p9FY1TCWV+t_B+5`Dnnc(EvK2 z<8>*YPEPHu6j-rWJQ#$|WLV^%LC?l>=!<0mT7NY)HE0eyo8{0qAD$Itm; z=y(^R_0pG-Fv50G;pV7tKRV-~=u9VLcASgemeb`RGr}Md*^QN6*5K=pO%x_LH+x@*XLT zS>#)xf!~R~x*x()-v6;A9B>}ma1lDdx^NdZCVw2g9p{~$%WFS#SFC}z z#PiYU3XVr#Krf*yvJ#7W|2L2@vR&v*en(d%SLJM}0azLxU<}%DB3geo+VLW^{>SJR zZAE9e9kcLHG|)4vB)6q}SPj!vc~F;x4LhL?Z$y9m_Q%YCm_>dzdL~w*1AdQZ;}LW# z&a9gJzF!ZWX*cw23`SS(8T8D|3SY0v{rAD*sPHMe^xM&`_yZlVV727udSx`<5`Eqk zt=|tlY)_)^gK_9tn2OGP4!TnF(SVjm{>y6VWQMybu!FZ1Rg}k8=EF!$CJ^ec>(QUF526i1Ir{1bjuo{6S@e~7PKPa3S5Z>a7$FU51sKqbf973 zGw4jGq65!~^0&}HKaA&}#Pdz)jDJAK+l$rl*V^2F6D8{;4KGFqx+3ft<+q~0Z1#@w z$D@2adgz`HUkjIpYtjBTp%dGQPUvvtPt@W5`zkGPZW6#*=+ak3m%bUg$6V zzL@StXLcXjeh3=qQ|K9(iN0vwiRYi8E3gG^w;v5O{U-@4X0Ml62A$z~XoD7b3ARH6 znut~K74%SjhIX_Kt-lWq;21jN0`-&U#n67shvy{a{QJKojHngbpdGqoT_S%oy7WEK znT|j^8ixk{0(u+XMFZS~uGo)gAb+D(Lrkk>|6>JrTS=YKkra3;5-9rZ^87>f=# z5j}jf(7j%U?(J%{-Y4N_@%+okZ$|fcI~u@GcsAx~kgP~8Eav@hM8bjEq62h7m-1$G zW$umqV06Z#(EI%o`eXXT$p3&2bOJpir5Yv^E06YH8{MiVXke`{ZN+QiK?ihcyQ4Gf zgT5&Gqk#<$hoK!jiEi2Wa5_5B%b104MgA*vD}F$4+fj64xf^l+ooUfV$=+2&AJh+< zg;#_f!&}2XXdr{onT!o}YA(71l%pYlzOU z6&l#p=oWNA|DvHkdK;d_8n_hgZx0&KUugTBjg$I?&@)yG4YYNdgr~L(x|esOOZ7DR zB6<-o!gsL}9zz2tdqMICjs{qs{GDk1k>Lz9fW>J4E77g_5*=qpl&7;dNg_D|y%v?x zGtm@X+7@A3bO}2|{-&@;l;0N)3?Gf>Pey)xI1LSCHu5tkomxo3rCfua-aW~KRF0-e zo6mgTu9S^6yW`nJH#zyEh5 z2|MbE&R`JQU}EIwqo?_Q=t}KC_xxXU%gQ&)migD|8sa(R`=To|1D*M+=tNdT`S+N4 zRb$$U$4Jz~?9CHvqXTwE8{UfsHX7}44myM7=u9_9dFtZi_y04|30;bwrH<&HcSTpQ zSL7eOIPU+5D42lGXePRp@1h-ih7R-@LP6`fGMuxXUHLeIpt=ykjS zonZGC>13%Npuh;nppj3H3iHF&XvbU7f%l**@CRDI$R*h_Z@h|V;FqBFZa|m1Cwh1v zLi>3fJyYY-k$4HMxCCvu7LD*bbjc2)0sf8F%il8Dn$qa=Mrc5nq62ip%$Y(18iWow z2HnD0VfsB1M)oDTggdbf{)%>V{-w#xTA+vSRSI{_JpG_-6QS zM(+ReDEJsNhYg*{S5dwv%6~y;d^qwa(XGgSS+a6P(dTD{Rng~l(TQD*_In-rGvap4 z!}zI(OyDDEgD236lf${_-oJ;Q-nHn=zKHy{@%#rgfCK2YJ%+wfi(j6sWPP;V`Pdkn zVdkIzKSaX6Y8iqK^kP(a1O1`1FD%$PsdsMJ9-Ybk=oUVSZrwEW6+H(X@HKQoZ=v;8 zp@();Ywo`dc2nRR?-1HyzBWn3XQ5kC5v^AZU7_>PL)#Kv+V@RObBiN zMz}Ow(}w%+J9;Apc60#kINKG;Kt<31ve4&M!p31+bcWrq2Ht^J;#h2r+tJfsy=}53 zm!n&KJ9?XXr%4#;XmsFN=pMcqzK;&D23?``=&jg`2DU%^4Q=-)dPcHcnanspTCW6p zy~~DG(Je^VBVohl=u)*o_o^ehls(X;8;Du>7~0V*=vKUm2EGz~(R>m4z2WcZ1ae-L z)GrX0K_;F~)r^9R!)wt~+Z|o1G#b!IG>}Q?3}>SOydLErpn-jY2J{uWQoAr4?nAfY zXLKv`UF`(9e`QIy1+}pXwnTpj-Gwgsqv%h+saOvep#lDcS(xXVY?=Q|XEm%(zB~FV zo`4N-KHAS7bVdJ(e35IJfcL*T2?uD5&hR>P#y6ug?Ta=Xh|XvfI@7V}(oREHYF0Qe zd@Fn}{3!f1{1VeP+!6)5!u@E+M_CaSn7^~q(bc+_CEAuhB#NVOU`7pZ2r?pQ`c?EQ3>!4?&33}+; zwCDc&H=ozVgO2DSxdXi(BhW+kEH=Vfcrk9l3-PS$vhlCd@#{O*#wFMfe?;qdxjxyl zXVC#Cp#jW9w|HSX5-ZV&zYO=H4gNw`C`X6nm6{)2q0`XvV(4Kj6Zr<{iZw;Iwl#W& zu0^kBXY|$FC(6_PA~6^pa75&v2`8biJ`a8;VcV?pA|1(HrUO?y;v_vDk3SIK<=wZAUtv3V>V0<_Q-Rl?7EtwO} zM{mO-^z?6x^6$|=_F(3p{~aLVHToM3pm3MOQeh=DkaN(EnxY+Cjs|iq+OA{R9jlPP z3$Mg+=t}HB-<-dq{S~;8`)}l>Z%k%b5uL%gk#B_F`%BU5at(U8y2tar=u)TAm6?mK z+;a5reTlBXFX&d~?V9vc5M9x;x^n-Wc})tO*@b9it__eID*cSLQFY-yAn3^^2ktIx|he8B|9jx(;2DThNv074}63cn}R>EPAM>Mfr>9 z0869%6LjFu(0;x}``wNW@kg|ubh&QHOsbZ%_y7EOa1;9C8GtqzgC3g6=**^LX3rzPAo7cG z5KHwD`YLXATM~FD^oP`)n7Ov-3XDg$asg)k^FN=Es7=Aw=*)B8oih->1O6{scXQ-=Kej*^6~C zM~@`p2IzHdhSt9pJqz8?7t5XKKqJu8Jp-*b7d=}`&>!zR&~g9mkxn8h*fW{=>F8lA ziB_zNE@>-t=H1W^`=Phvk#IP=H6zibosJIh3TENkcs_oOm*Q!?l7E%+x-<#z;}ht> z%h9v20X@b4VihcZS2AEL^iZ}AuMDpZuMazgUBm9-?P1R_-J66n=^F+8!w18`;m~k+ z_;@%9Z9fLx^JgPJEu0a~3||W8B&JjINI3I1&{yIzbcsJl_i!7!r2FFeVYGgZyOROW zK+ix~wBFh18LA!6FGTCNLSM}t(0=d2Grj-!lkkVeGib$`cs9O?-uG|NhP%*#j-gwV z>YW6Tg_-LV`TFQtXd311(1314Z_{1qIQL=Z&;O5-Fn}k~>o*-eJhRXS3(yr=j5b`2 zzDT}C1NseJxxdgr^52sLRt!D7XN3*XvvYOW9y9m9BMD!LH)Ab)5Z%j{(4~3<9q8R~ z1$qrXK?B`_-j01}04LG*x%(vb3ZoOLfZnQV=!#y}hx>0wH&S2#_n-|QLpyo~-Ga&J z%wIz5y@THO^-;bb-I5dNQkS_msb2#P>;laEMuo0qcXXUS_j3OY;6Vx;@JV!l@o2=a zp&h=3uEa_-ko9N>+c5K@Lfhx)n*>}49jFxAt}42<_0Sj8`RD}NrAZj!y=WlA(LI`o z*>DQl@w6y^8C|-$XuA)?FXQ=-XuJL4ujtktL|?goqSy5#I$ru;5)OF!eaVc9qxo`S zMYMw|k*^)ri}Hr(id}@B`VQ#I+>Hi40BxU+{K$Ad76~MsnnJ>er=xp416|^IcmckL z{#5(}9q8PC$zMucjxO!p=u$s`&TIrafydDqkHU&L7VF{LcnSW9ncx3w_D}YrDZ1yK z(WU7g_CpWP2y`Zs&@=G@8t8n?Yz2C{zl`$3cnYPq8-UADA4{#^?%P zJ&^nFOuA4|10O;Mo{iqqC0H3ZqAPI>U5V_2k{Opm^VQHp)(oA%Eoi@E(3!u1wqG9p z4_%?J(j<)J2Xtn?#)G_rlYd2`IM$@R89L*;&_g;7eW6T7Px%b=y)YZ?_+4~s)}UMY z6?!dyK_~b-+CH7{;iSXD=;11X-s380$4$`=E=Fh23Eh%g(H}bZqt|UDI`C7Nxh3d; zFQ6;=D!TU{p<7mXNTz){Rfj}(3Yw$$d?q^JR&>ClXh;8`0r?-5HxGIXXL&@JnXuD~7P z1L#1Hqk+vpm--bW0vb`&*H&RbSYDhCcmW?MI*lq-P^Wk2iIZd z`l4s24>~{^9r($}KZj0aCb~lN(12Dx%Kdld8z``&UFhjPjCSxBy5zZsB@OeV9aTUB zse#t3hgGpzl;4T=(CZ0bCX3UC@>3iS{!f^26i#81zs+kDi@HX%a^MG5W$dh<03PL=tHhy0neL%h0Xr zh?nETXh&LbtbwsuOZhxoqCIed-`is_yaSC?}=my zi=q)%Km)6e*1rfdhZ4^w-xgi+zUYL8hEIpn&;aJ5{lA@&`?rRKr}kU4<6Y>0zn~o+ zMStDS@nq6L`LH^=*Y(jEH$%7PPIPHUwDaItN{`chCtg#mxO*83mir zz4;zpsy*o8JBaS}zvzmT9-RbM9sP}`3mV`+G_Yw{9$!IM;$yU*9caIY;`#B>+~isTI+g z_e8I4KeV6s(e0sd336>Vs{`Prz2V6Kzoa+2nV@Zs;Bkj{I=+@V$rz@G-iQ zo6w1+#wX8n1qMt3N(Oj=sW#>bOs~QrJjfeHYc7h zit>*m{~g-?XLRMVO-TkSg|@4X-hxKxgxX`;2X~NgX8q9tpF;z9869|W_(?q9g3j#c z@HqP7%0D$}UmoqZcI2C4ZSq&3{SHLiKQ)#6Z^fxm@m2KNEJ4dRM#UZR{18^5{9km2 zRi-8P{UUS)d!Z{Z1ha4gy7!CF0lz?J{sUU?=rr!X9Tk|K6jTZ?KpR{ec1O=hU-Sht z6D z=A*nbdfjeA-|2UuKSS<~=d;m(-oW$lBW!`k&3tndysIT`_LbskDyyH3Vp-PLOYxneuM_N1wDj+p(|JX&5*OkN=z!m&Gu(?V-9a?Kzrwt)BmL@BX#WG^`N(iQ zx&kl0!u_|wItp}CRM>$o<*#VuIp!qK3!|sL6js74^l-I|e0TKJkBIUq=!_SmEAc;c zoXzM;@1B!RB0orh5ue0!u*j=P`9)|4SD*piga*_fU7?}j6KIFy(5;z{uE=}ni)=00 zZc~)+L<2gQj)H&D4hzmr1}cue32UM=ycF&D7Hoz?u?{Xr_xcbTK(=|w1PX>1p!dE9 zT7MpPz%6(^rt7_yE%RTI`Z!)f!B+GPWWAm&Rkg4ldIp-J&##E`_UO#IqJi{8S8O2q z<{OP(%lT-4?}W>d_eDDODG8TqFWS)&bS3^pBhULrvgcQzznHYc+V~)P`d>i@{0I$T z6M86r#A^5t8c5aoNxRl){z1(A{GUR?y;z2J@EO|Sb~LcVSQr0A-*9yoBrDJs4fHy6 ztGc4?A3zV`mw>Of-K!rj5J}3HRtW^m_F|_qcEPQ20prL^w8_ z9KIO7imt>$^t!D?&(1n@rMF-$-2WE$-v?*DoeW$RZCD!(pjmhsy3|*rdwK&p(?`&~ zejTghDs;dDQGN_tlP~;EQoj?rr6bTS9`_FS-z9&Ef-HO&J%pR1;$HOr9*Od7i;@ls zp+A&Lqwn~}QGPSJlD*L-?uQ0G0v+&abiyy9E3qI=!U2|}4L(CF?m%BSN6;0?w>UXW zrO`v!6b-avl;4VO-H0e373GuA_Dj*N{uB*h54sZRqfsH-k|ffi=+c)#1F3|rP(yU- z+n`I`4-H^CdRSjYUrZlkea!Q2@?*UT+TTs+%G`kldN6Z{*~E@kcyl7bTG zQk6$n;%fAHcl3u)Upyb5MrZUf`l8v129kYQ55HS!>!X3UM}NcWh91J(mc{+= zM}a?$9!1|+-=dNKjYgXFVPbW3ruEQQ>m}$)-Hu+zhtQRrgwA+A`g_7k^ziLPSMnEh z0!KbfCx_*<<;hHIpx5F8wByS#3%j5Z503Ju&|5GAtKcW`{1AFp{>4kN(2C?&xAtft zcVSa}2HWAfGzn*1er0mXTcQyTMi0p_bWcZzlfqfy8{xZX{Z-*-;kV(=@R#t9FrE4+ zX_y}!xEN;cKe|MfB7YHj`dgt(dn39+eIh>$-KvRbKQqFY(ZF6uC$c!oS0Y=I=6{DP z>FD!#unP^~=kPFkc#dNh=3bQyP!+9L8y&bII#9E)b=W@a8r~W9&B*;56a^!~XTr&7 z$Fm~;TDT}&9{w-MIf+mc8ge z2hqLFw?0{_v(WrG=l~aoZPAtJh#tN>qP$l)0Ns+I=;3_~-O9=67QBd=|NQSl5=Qnu zy0>f4fYyhb&>3t;m+T*O;BucO?ao0vZiKdPhOR&>yd2x1TQL=@;$pPkcFg?!|6UTF z#%!M_dsqVP;2iYSHb(cX9lAodg+tIE*OSopYtf&M+rk6rb^bRjxFPAk6lPI=E@uAz z?^+TrZ8x-|Ug(U|Xdus{KUU|)^A+f?WSh{LpY}y^CQ6_ySquF+-w>TZ6Eu+P(8Jjs z-GV+}aQ~fIngW+}EIQx|QSr5KX}A^*a8u;>qwW4e_c-syWWX}$K z`Jj#5eyOu1wJ{lj~R=?WZMrXs<&j*aNe0VC1Kw z0l%J(g5~JUHev<*5k1xUzDky|5V}Q0(Ir0%eO?(otkuzW_0R#YLj$-Y9Ei4i8r`Ca zXyEA=NZ4>O8o+nxAv=KXVcxHkhK0~mTO5tNY?RkQm$(rc$R+4$Z;KAl1MN4Bo`vz) z9A8KJNv95wFw$(BlE{mr@ARsXZ-xeRExH1Cp)TD*IA(tTFZ4|kY1yzoI)gUo8Mp&Iy#vsteH86zd_13zmB=qc-;6uatvQAUauN-& z*tc;w(FvW0ng9IHRV3V#o6u9+1MTR3w1ZJt181Yx@^du6189Kxze`>$rO^Dv=z!Ot z19e1yo9-L=@#sX}z|5cjmy>8r!Dg(7#Wp81yezy0ee*qx4lq5+U&CtTKSl>Sge@@t zmSjb)M7OLjdNu~5ujCQoQ(L(IwI~=%fe|l5_i#0OC^w-iatxh$?yX56mC<^aqAS$_ z$Kl=R0RN&}mTOzG*G19#mC-}l5VPZz+v4~CYbbEQyU{?NMkAgOK98=;b=#p;3 zI+*%CS<-W{CfOEf!1thAI2x|=K=rwu@ z?eGQk$MF)(!mrUo_y-z5=^aVF75cmvI>D#V+w(el=F;zwaH&2-XTA}B2?XNOse*bSo!T>G~+lC#(Tf*Mx zKo5qGhNHrX;R|ShbHl~xnOKE);vw|?al>xzzkAxBgiAaUJ+;rEhvf}4@(t*~ThTY) zUOWf0?MY@*2c7Z7=)l*a6S@h#ZavYh7>cgo1oS=f>Yn)dzk~t<`5#utZRi=uvo~4N z0%%}G(1GfpXQLS!=nd%U9~jS{kMcM0Y|1yF6ZsttEZdLCZ7cX=I$P#?RH49Yb{QJs z_2`Q94Eu%;p#wgG1~3bKPrM(lMhEx|9q>DJMfODgFgngZ=!zCh?@KC{Kp#{@Px-lM z0FAH~HVf}YJDiNJ*vsgOyo(O}3HoCB3a$4y+Hd}!lIwRSdibh`=_Zl565ZQw=sg{X zcK8%}iYKBoel5yZqc5%v=o{@2xQD{I@(6jL>x?&5_nJz+4`-f;hyTij+m3-qE-M)|R@n-Ze9YVga&j8dJV5Y1L}ir?Sp8& z!Qmt5A%E;3_umJjDR2eGp^;8Q16hS0mS541kD-UK?4e}92Ix{=7+!@2*bUv|e(0GP zjZSn9*2eYW$wSJHr0qqv4qF`S3MtLj9%a z3jBetP`dJwB+(38QqT$g`TRV(ceBxV_#E_%e25;NZ=!q`dRva80Tnu$Y)Ki+B3}!A zKU|5v2l_>R4AO5pwTOgEx*qL#GrCuM(T)rJo@_}ubb#})Cbo$3d(g8o952GxBmWC} zc#Hp${8elNG(QMy;8e`~^S?DDTA(m_EqkP_%#RYqsf485M+&==Rk=oXE`bMaO5 zR%}MMa6cO0LG-qrKyO9rFYdpmx(o>esE9tOf!=~k(V29?^YC_b>8GG?z%}SVd(dAf z{y^IoJ)Yc-bI|M941L}n4YUt>=pQ@I{jW}94h43&5&gCLH*`;nok(VUA= zP>n&)$|AJGE$DmV?hEMp^P?SBLl5PZ=)j%P!`Bz< zVme%iF8MBWg^K-?1kxG}^e(K5BhlycBflFxgay<8CJ{G6uU!{(NxP#1-iHP<6g{M) z(LJAz4)7+rXq3vpM=c>4ct%^lc>U_}(ZOioUriThLqZU^o$dCBKdKw+5}Z1r6jkG|=KXl7Q-9=D+{{Y7#DCS9Gr* zjQlg6Y?F6{~Iig|M;f!=}cb$|2>O+)LiKv(2D%)+10K=S8e3%vhllQ;*@ z4R1pCXjJ%II5T`5o#7I657(o6|6TY4x`jWXhx>4NGR&PjDKCPV|NZaMBy3PQtQ|HA zn}@B#cIbdz(8GFbeTa0mZjqHJpw$a1A!b->@#$ zJe~Vri$vGcvuA!geG>iozXl!Xr^sh3nykRtSef$k(Ji^mI^DP9oLL}{jh0xX?RuGF}ykKnI>Te z_k{z)N5dz>ap9D3CVE!ph6~ZNvIL#+$LPv_iC)uGv1Fx6p<7!EJv-^vB;4cP=(QS! zF6~V8(9K70!$;^D`3xQ4OZ2DWcC_B#=xsQ?c=pVH8%{O!r{i#JjXUvStW_d=<~O0a z__+6fJBiDA(4%BBz(O>DMQA`Dp?myY_zQX%{|$?snbfb2Ze>ICjoJ)dp-a#eZi8oI zyU0I)nZN%_N5Ru*2NTf&W}qFt9py{H73lloe`ugv&=uK-uE0^WeSuPmS!f^)&=qWo zUdM~o`+qG7m$G}9MkAh%Hh2krCC|m0xCEQwZgeltE}iV<#pv_fu^Ns=uh~-cmHP|2 zqGie?x1%m*{`)^0k#Oc0V-~hSXMPtNX&-dPX|#he=zHR2^qS2q=d zC(qAE_x@t6gjb_`+7AtI9=bA%!ZqkbHih4Zd(ks@05gC8SE6zfSrhd7U5Xx(Ht3Sw zh6eI5I7hLTkZ*mS72x|8?H-_h zZ>+`h9@K4@m;L8QeCj8rv4Bdm__pKQnhG_jcmd!4(cyhOZ%dhf80%v&k{O5 zlZiY|o%c!i;dx=&{>XD~aH<#O5B;b9YSItcmhn?B(s1a19==QCoSqauhv{TCjlZMQ z|NFUuK!2gGpZwU0x_+J}J%DEq#LE6o+Xo}~{XBb?@^#d!PW^NqmZ&WSkCAzVN<;ac zM`J&=d6u8_Jkr-v&R>M5KBj}8=hlu~29O^|!5kWP;`=^9c4Ux}*qI<6ah7~LQnxGRg$eG|XCUQ%Hd8*3 z`e%`UjXtgkUNms$UpXt0|}hwwf1Io0j;v^hW~-7*^a%6yd| zrqLmPa7lfHh57!@cPHh2PxXLjQT7iV)FptU)O`jo=IiJ5IJlQnUY9_gr2oq(ABEFs z)1C4Hq&M;GWAA?zI=>(q*UEIkk4YZB9%Xa!Q5ro@iId&_g9|RC0~a+GfA(aY$EkeeNLyZTmA1}dM1|ZDlA6f(|9qR`T2?lmFeJh%9~U6 zJl+?Bo}}K;|8!{mLzKOU%P4Qaw=k=5lEJShU4_8?>?OaA?-1L1|9Q=)4#&d{JouFK zH4N6Dfu5sME1p-N{BhDp@E?NkQ-XT+DC^9i^Z1UT?9vFXB=ts;|Ae+rI1ry#Nk7K7 z9CiJCLppsm4Z4u1N8!k5e8R!_zRdU3=aLBURDL|2<|L4ZX?K8UTX8twmq}kjf2TeZ z>2m^^cPML5f3sa#+SVjJn!kVMf9;xIwJCTZqWmqEzBnB%BE2T^cG!dgI?>Sq%KTAV zg3hbZ?pFGkL@-xJknfTHnX*C#hr^=WKKyKm6?{1_C+8oVtUZsXw^D&Cbl6XV?!-x_nw1i=5h zCE{LBOfzWy4&P_(f_jA+cMr{1Mw^nuLCLtiqS!R@}&US?tCu*pK`t5uhD! zBfpro2MMAp1HQ+=TS))Gw*~dzjLAJnKJ)3#|L;Ph`aCGiHxJ)@@m_qNN;UY-rIT$D z{UhW%F#vyq_5XdEk!nEa*YLd~X6(bBe7_^O1=xc2^>VV~nSYGj+^39m9kqM%q&F>d z#54*r+NsZNl%M)!C#sdy9mTgT?VhLp*+f2sNb2Ex_&k;Wp!^J;zeT;rurz)AO!+g> z(e;ZW@h1<~Qu#^pQwe5KOsNOyyp#{YNBIupJDl$bzK`)8$#)iYU*UTtZExUv^Rs_X zDVe^L)aTJlHKx&>;d2v)pM$h2M3|>O-;%GycLUFhQ$Cw$2J=1j8AIEJJR3kixAOhg ze#y_noB2-U`HgtQ^5m18rBYOWlkf+|U@N23sg!SGz;*cFPv`#xwLYHJin4p?rvjDv ztL4n60(t*HvXOo=|8qQ~&!BEu#<Ecs{oz7WBE>Mtl&`CbtPHax+1Je4Q# zoyhk&zWhVe)MRW=y{Wi`@BjVGWst`yY)74~4B}@jWuNiwLJ(aDx)m1US!vR5WBOhm z`kBE1L-_Wg@DK9MNzdZDk+gqU`R`{1oh&DSM$B+N556T`9{bSgX_Pg>iS*MKulmo# zc2Ms|`fN%21JvV_PPL)H5C3#FRf`4#NpIs}bsA2lEH`&(0Oez7bn3H)XCL#O%hx{* z&r3Q>wG0PQe-wk2CBK6@50m%9Uy`M2MxCSdH^Tpc_^k{w$R&ygR;4GXk|3q8D4# z6fTZ74^YofXUhA30EGM{Yz3j)tD(ENzF9uNMd(pK^>$KVSY^k)L<8%t(O{!*2H z495+jtbGiSbjfeR(QZ+c_a{Fs`u{WnC`r4?G&q!w2X&+KuW9r%WwWp=f$b!HoDOnv z3w|YCk4C%bqz=!2B!B{xFONJ~f9m~BCpSmFDQ;#UKRFpFAKx?M*>pUVJW4gB@2BYJnW)QOn5I+1 zDO?i;l}LZW7Wg+|L#SASK|aJM_c$@45i@%-@;>wPBC~#)FaLH{>auv& zJnFv1^MZU|&B^??(D^7bh4BE{FY}gq-k`7%&8CmmR+hKds>y1*ha$~JX=7WyT~u3 zfuB=2kG23<$T{JW>A?RlkDcUgqrhG@^WGqze(~h17k7@?w;~jNdcRV==(lv^_|l{0(2`GoJjb zBr{`(l@CI)CqhfgK#QlqHTlMYuzr$uRBf#?3s z*`Ji{CVeh#4n`0*`qJ3kzFqj<$hRxsoA`F) z>*pxFoJYG4iSkWGo@QV2#L+j<)0J zuK{H<$hSE4%B>w8e#e8a70};_Em}stEOnkIKY@-OrK~33&E)-5 zVBmjaz|WJS%>Vz5c2nr5vVjq3%~QXG^`f&=pVlP4vKj&fF|J1i^ z77m&R^fB zT2c4m|CHyBpd8>=zI~|kF#WtsAmey8iMnHA75hfeOJa;x@yg8vcMlz(`aD454?3tr z2XjgPOD9#Llg4!N66Ie-{Q{)B@%?~7Uy3@X`q>xxraWIn`a}BJ$M<&fey+{Ml|L<_ z`jDu;h)zfIa4h*L@$7?e6+xX(`XdH=ndg_#>G#x~O@~>SqTEkw>dYjajqfrB^uxa+ zn3_U6-1KS;kuUsv*MS@hA7`d^TKkuk5Ld|1*=s=W(CdL+;0(xy#J zW>0vMy2nYsL;LbEmQ82U&d*;7sizqFU!J$5?g0NeNGlST@s07L8oyNL@Q;1Z9-5dZ z-Im9Go~G>_zL!(?AI8}geV=P1LhL{)Nuexy;4Sxjf5Z zp6C6^-_AIGrua9wzw)pr-w$JAx#(~pi=C72X{2AHVM8jP6@f0K-mBDqn{ORD{DIDX zXP}RGK87|e$oJq`8S+&!!|-Pu`goMGH_4wCL48C&Px4O?Qw@2zm%_<3e2+@SX*dzD zBfo}kPrm#czo}}J`}^!rzK`&IB|379t$erfEkZ#32%PczxmB?=Ko($v}+8GC0g-Rync!kDRmK1TweDZkk-|<^25&*u71<4${2rP@b z3H1i*_RQU4;oHnzMN2H7{u^LoNpQp-!yn@Z~SzT<`x?1_uC4WgwdC!u60oDpU*> zicnvz6W~^YZP8j}`h#ULmrd*i{wJ{~huOeR!#zM;3l_(LVoUIB*(0BSEqs8A^@h}x z!9b!|L-OkgbS9s~a0WxYWf0qpH>Q7wS6v3js58>L3AY|`p6Y%_-VN*zybV}eJdlTS zwkP>mCa{V4ReT(nAHtur=p&+7G~%m>Vf4cBW_WY_8kjH3f8mIo_csQ%#t0{%kUwH6f>Bki)*OJ zd<1JCEY_X*CGduUWl%@LsRK5UID(^E>r4^Y5Dwo+Oo1E4zDG`y0EQMqTuJ;0@D>A$ zsKvTM7MrKXN&XcgbBNy%!&v+i8guA3B|4a`#<7iceiGQPs_`LQGk7-92>%d0`Tl3< z$NIpr zL6`jV+`0}0iB$)FNBF9NSRN+z%7|ZZ7;z5MW zitjCnoDLqKq9JHJhM!J-O)(>N7A|%kZZMp3^fsYgom|W)zy2RX*sh`ic7-he zq@)z$LVA-S-=OZMPx1lWhvd@`6I%y=j4n#nxLA+yC)S781biwyk3~@5q!%P#AnVSe za7eXSBtN8mSV)+xT1-c@+@;NJp&oBSc%!??%JlAlF$qx}3IPcnno*9D^3IhJoiERuYS4t+vj zERB1Rqx$r7z&nz^PyCjCkuJPPyeLGqcc}yA0QvcM9t-<1 zG#uavb+szOHNd~1FMq0-pki&wzaxJWTn(!H0m~Ar1%c$55q;E&+=IJ4gRMSUSCq z)MAUlj)8TiK0)1uID`6gG<$J`*g6-N{XR5K;$aM}p^-x4JBVUyG)lfz^Bo8bhbtBW z_AdTC%fnUpIUeE){Z#Nua^JYOK+L6HqOikOG@N34)~7|SXU zyG-rHk`(eM$;Flu_v#|47w9psv8Xw7mAD`M5_k=WJDC^T%@KpCBV2sm{}jL%X(j+p zhipe61=6eJBZ#FORDjsCk-ACaRszvx*JS*p!quv56lcFO~xbq?U7>i9Fe zftiQ&rqYX6Jd%A+yK{Mde!i#Z452fP(TI96Sf+17`gwY-y+0W?omB-GBJv}klse-tI4nb-dtE67u&Bx>Wh&AS5kJUp zgFA>3_)l`Jnp2mwKKcfQ=IE_@cxSj>;6^j&Ad1D|@8EuDpN97woM`I()Scx0 z=TMvlY|VhbUYCV<3gV^oJhq78P)L-$jmq3@9E+B%!Sb3ptT=*E8$FlI|D3{ zd_M6IF>x23u`&)8OVIf* zSbPuVTO{~v%fkf9*`Av1`9HVBGU13N?g&|Mmy(nBT@H^Z4oj9|78 z{c-Sip;bxVjzuNZCFJ#4)RH`u+zfu0{3Eb8iDTre#RDnCKF8}rxPV`wxeehrwO5xq zl4aZIks6*OZjqrX_Ld&)uh-(P} zkL%(92LM*;K`S60W!bxUx?+j&ipcYMg1+ES!!c+tm0m1|bVWz3En4N&TfhT2Y!vuq zVwCbf*>Br!jIl6D#oXspZN1C~WFyvlvKp*>h5>f0*VLyp0Q>dYZx4KN%2 zyz09Me5Wqwm_;%t`wt@&NAZEH%Q3`22ni}Ql9-Ob^DG_%uTXKJe+F+jbzePVZ_fJQO?n(}tbJRHnv_?}`p?y*TU`fKg213wV2fi+V6B@Vp+c9|pJ z2W#LKGx(FY;V^G~8y?L%`e2WkIaB4Mc<965tmUX^FV|51jqMw~YlV)>v^&g6rVK~A z#g-D9b2`P?F8@SPW1kLTW?PcUo@`3CSj}OEFk5D7f;pW;2OQ>!4pWlZYDu*?TzJN$ z)C9XVEdO4~P456uYka!tb-T@+f8pSqmOkc02m1MGk5_r;)bch)7WDBp=6B2S>S?SO z5}$~ItO{#k3TpPDluS#KIm0DkNsUi2k4m)Lk}?w=_Vk?mQN~p@qas>G@}DWPL&tXQ z3M`|I4&QpAiDTk#*vuxg&5>?4xt@+yyoX5N*kp^1XXJv!F&5WD+U%(b>GC=}Po9}B z1bG=|Q$oDel5vfu`&F333IgrMP@jfLNfw8NtCPYq*(2}7G}xS)V2w{GXr5{Gj`odn zIC$Ba1rckEh1CNFnN!oO7T3$mxs-2wrJ(D2rmC;UA^?@(l9e2~32*+eobB%?A?G*mL$IYmgNXb7oPL>fja4Jl)h{t50C$OJnrxFx~}^g?`z!mImxfz^bL8Zt<9VM{`8!Wr}*T{mr9kv zD?6uBMGK}Ub8m#uC^c3*bnsgJZD)zJkSZ z2bRU(k@3>0Vylvl>Z2WW!rV9j^W#-`8jgs38i_S^KNi8qFb~d)@>eh~`8Ol~KIS67 zKFU8w`~Md6Gk$6Z2?zKY?f6e@k2ya~W_BJBNX zTRUut*6)htaR}yR{M2|7&g4O~+ir*qF@@@!Q&xrioaDKQjd?j2QzJ|GJ_XfK6E6^3(5anNC9`fIz zTe2rj!ivY@M)q|{2l>&8MbZ1E(2lC14I7|a))uYT9gAY`C?AH_8;zB596F%|=$0?T zT$o->!sq!Dw4+^^7Z0Enj-ef&hDpDq64%*+jm0)=^6P!Xy8MU z!=6r!BH?2(7M-W|+Qi8y$h{%CQ50RuGUyB|qA#MB=wA0mSL`Zu3r1l!yah8W73Jg6Et?e13SWu) z?{8rJZTJxdK6Y!+nS6{c*`_G}3O!Wcq5~d4&&Hw19}iDP`M;6R`)N|YAUe?^=t`f3 z2G;OX*1r&mP81mV#o+)fK>liUpwVc6ccB5_jdnN=Gh2bp$j?UKfM24Au+V3zRB5b$ z_SZ7(jP`eNnuIgzgU)<$Sf=lo;+=o7{$I-w}+nB6O33PyJ=*$|S{ho&f zu`9Z=eIq{z?I(SG+_)G0l6erF*|S&(Uk=|!2Uv%$)RxG9k9K?j-J+vWp5yam;KFGA zGU!TFK?84>l&4c&NZ9ekXyk*?4o9IC?}+@p=u94r@|kF$&!K_8f)2C_4SYl7x1#;* z4*!R?`#qCq|FdmM9=H5x2U+O1TMcZ1SE3!vK?8dc9dHR6_!@L;zCZ`wiAC@*7RJ;U z$;67FU)Pn;`)#na&;Lav{ONTamdE?hnJz#BdL3Q5mFS*rMF;)`PshK}!&YQ-GPASM zfa;=wx5hK@JoLSCX?PQ+9bgg(ofbYB&O-xPgwEt$H1Z8-0N-I1+>d8tkuA&)8>0jF zL*FA;poj5lG_c|57TmFg=ih>f6r6#Nqi?Dgu_!K%{3>+mKSl%DgvD?t+VSsbpnswR z=J_(IR|xIDELyJ?TCW~DfmUC#{ziH}1ukt*Y=zgLZ@&5H5`Tc*a0}MN3ST8N=pOb( z0~~@r#@C_!jzA}N8y3eY=)|5!SK#$@+;~6yDm)lw|2p|GS`yu&OVN(5LJ!*=;be5C zPoOh>0j<9f9dH?1e+{~VThJ9u?KQbkWoU=%(8Kv9 zxHlCOXg>^pt;&P4O#q zPfzI&#g>Y?>ppex!AoyY~~q3n$w(*9`wcZHMEk(d@f8O}qObP+nkmFPg5 z&_K4MhiDJFwEsg7*GY7M;yaT1<(SQ=kOS9C2J@DX&2PonM4*p>8G6NEQ_-0|fwq4ZU8zNAKOdlheTD|`I~w3=KPG`y$MTGyYDB^rUySbQ z_2?4ciLS^5wBs3QKnu|sE=3R5HniSBbl`u(g1eI$mqG)qjrP+5UD58C`Tidk1>?{q zosD+91bq*zLI?N;U5TIZOgxEpc>11XW@n@I+h9ZNjXn*Nu@Npt1KEQHdJNOfJoQuZ zi>DO2XT9(o9Dp@&CYHsIus!aIeC55VR9o^L(E9gcbzF%CxF7RiYG3jLCoi5wwlccX z?e?+$6-Zn}fioP5m2m!K1@KZduwj^mqp=D;j-HWs(RQ2Afw!YG{yFadg|1-H zgUOjFj~=?l=r|Xm_0w07u!B+PjK^U?d?b7Z3y^;qo#}G4o5=4$+aHVa9REw| z6+!zi7x~(eZ-Lb3_dkh(ROpY+Xc)SLBhd(_paDFM4zLid|2Eq3+9>}j%74N_lpjOe zWjmDAFNF42I`TC$vj5FU*q|d;$6k0E-h~GAAllIr;q&OBTZ9JkA)bbxqxF73UpPOb zOP%9zayZXKSMVHk3%lXzjGr280!O1AO+q`Gjz;_(I^b(jz7`#LGg^N~lpjW)f|FPd z%O6ShzBM}V#aI}JVqLr$)6V<_5+06a=+b|N4zNG`9UUmgFUhyu>FE8EVdby^)~CD; zdb)24Z^fMC(^wPl#eBH<7xv$!c$)%WFdNax{)Yxq_Gt3>HNzt0+oCh*5&6OB%8W$c z6BE(?o{IZR(G~s>eR?_^OIG4qwBDV^xO+N@X%zVCoQtjSZET2tU}LQHYw{g&1r{ZL z2fA`o(E3lJ6ZjT$;Bj<@C&OI7B`Z)EU72F&3Z9iF;f$)G4Vs}#)gB$_yvX-M&%}Vp zUyJVXjp)`qgm(B8x|Ivj7tcp%pr4{ExDAWrK`e&p?7t@+l|bLkP0)^dqK9c98rXRB zO*jRe!Q*HLvoRMgK_~Ji8qivF;IGh$?2i2JX#Y8nXH2JxCW%xzbcQw2$F6CVw~z7* zu{GtF#{F67!1K_+UP1?aE&Kq_Aiog}>_>FqW06n&;nuVNMM$_bmCyhhp)+oaHLy$M z$Asx{GJ19%jr^Qno+5Tkz9iT7?2PlI!tcq4_hz8Uu?sr2w z?1K(C2p#aI$WO#ld2EAw zumx8BD|svjqkH~18t_wSU@xM9FOB@WaesB>H=#4%8s+=`V*QQyR|-5#r~RF*L@~6Z z^5{&fqXV3S4%h(=;6gOeK4|-ySRS82C$bXVs$J+I{4>n|PjWa*r%Ct=s1DljB6R6S zM1E%Y78=O6;Q_Scljs(n@o(}IE(^~j-yc1UH=$c}E4r0a(5GTHmcjI55_a$@`kZb> zJ2)5>a-_0lDrTVrwnFdsMmrjgPT+356rV$v_#d>tg4wcVR-zo1Bi{~fKL`mdow|jD zOY$Jxn^)Vtv(bZLJ=XLJx<`eWhAFh};Jyg+zHcve^`tcf1>hFHMozcmS0pi8EJ zy~L{IhoCcg03CQHx`cDk02X29IY$G07oET=bVYWdE08lsl0Osery06(ZLm4xr+Sg_ zahQS*_&hq$5_DzWNB8P;^br0JJ)FOzGfCx40x5vLM~a{?o=RxFmS}*T&;Yuj3_N?M6HP2kp05u56ia#ZqWLP0@hc zp=Y66u59T{2iH;H;kpxDn#a(YFFY(tcPgRaCbWCH2bQ4&UyFMqP+CD4Wy(MYRD{v6CA-wy5Y3bdme(3KdARq%0i z#ok2&{Q{lP0W{#F=!E{lvwZ#w7lXK)0|Vva(| zN>xD18=xp?muXI`diR zOkY7~`YyV1>(MvoR&=F*L?^PZFweg?4pU$tf5eUKMUnyYp@*__0!hPW{;h$lS zqDesMf{`d5mP0$P8u_|mv#?#C`e3F5x?9 z#kFVvTcUhBx@Y^)E&3l??>KrUa-N>-b$+y;l4$$0u_o3+&rDzR1$G&_6=Sf7&;Qsc zco-dE2HNp+kzaszxD;*pHrnxr=$Fu8v|Y|KlJ~=D=pn2e`9|m=>>6H*KHk@1b-({7 zkZ@@hp{Mv0w1e+4Gh_5IJ&vwK;bKW3#n6=~iw05y4ZIDy5*^V)*dxmOqU{Hu6B&Y; z-~Yo&IM8kA-i${(d<^aAMRe(2kNcmYFPI7U%i*h4TmncCZ>V-|y&)XBRp^wlkA=`Xqp-Vml4d@1RYwkb~(fw$>>2ZHfl)r+u zdn@uEMgH?}8`{rL=!*S@_LI8|0r~tFF@dGfrL2f{SPu=PMdUl9f%HN<7#QW(paYDK z^6}_OO^Nbn(SaAo{SVMH@(E_1|7}rW9~!_3bf7$ClR(Zum#`fAgQGsWgcqWx_+m7m z{^()55=b(Ws$294-mG~$`)8JLF#wipfQL-Z-xf)029 zt@kS$;J9s8gYOZO*XN5j#9ZVo4-9nVH*G#?#c5!%s;@H6xc z`U5(F<7j{dDq?XC3}}2YmhID-aiMO zc{}t4)DvBi8_|`!3k_^4I+5ql6E&?SNU>13eQXG3|g4kT@IXpi8+LYvB** zObb>?W>_6vx|ZmfxhU)(g1^X%RxjceC zxBsF8=d708FNy|K5`D8(Kxb4L9k4apaVKaC0cI>8puI(px@Ae{zX@&VD%(l79F?-+P*nDv2&yRe6)VLF9{>R1|47o zx|DZD{(f|T>EZL?;&4T{9&P`1_+xlDJc$O9r$*A>>B!2ZQ{_qc>$fU)!VYL;_oI9C zB)Y_l(7k*UJzOi$0k@zlvIAYx{pex-C+=6OnG9SP?dKe{etXRP`F~du4mcoF!1IjG zcpSQf4@dda=(pbz^bBl7mvl4wlzfBE@HcepQnixDun5|&8oFhj&Gw!nKq8<mDROyRJ zc&P3`JGvij@HiU4Jaop(t?fu8bh=t>Ljya8*84lkb2Lu2=rnX%pdVqW+b+Wyn<8#J&V(Fqh*)63#;d_&80XK8ame9*Z?k8Z-*Kp#fZp4sav7HFu+DW=fPVLIZgpeJZ{{&%}Oo zWeA4(6l|G19py3efB#pTgiF^9t8e$GTE zPz|l$A@Y}@hxrzCrKVtcpZ}LhxMv&i9Q+Y$W4YGJ%5+0#ehE608>0LH%)F{2KM!ki ze^Iy%9WYOuq+MAwuyfGCv+jYl0(tDlk#^~151*&N1}iWNH=>arK`Z8JpUm(~^z>FiJ8F!c znKofhbS17r+l@iDU?RF=v(W$-qV?WPlWr)+)ssZ3e%L&07oLwc=n?h}2Zlq#>%-BQ zIc(@e?uqh8qI@Pg;b$^=p1&7KxEG7irCS*l)`wf-{`ct24xt@q>y&&)oQ}Srs)TjW z{+gimI)#1Ey}uegykju)_y5O6!Gx&r5E|i==-HTuzEW4AZ^#|!itIt3_k&Sh^1S4a zTFRmWwZ-Px9sSao6uyN1k<3O+n>b3sZ@c21lRd1C?p+J?YxX>Jz^>?wdZK$h1U=Pb z(E8)i$M9jazXfQ(@1k4s0a|Y@xf^Za{wex$&qJsRdZKN+ATdMImPW=3cS-NSz2 zRp=}FCbXX^XuoqXv$bddE93s^@SF2_{%!Cx1diUTa~9<(oZSOB3~KpC*6sJOVk66d@%Z=84>vj;bZ6wo=591 z4Btj)zCQ9h!XxORO?6LJsvH_n6?8&PkqM?#9Z1+=x43Z`8rjuoK%>y58i(0%61o+W z(XCs6&hQ;HkWaA+{)m1F<-Z_V@(P&w_QM90_r|jR{=bhz76mV0GhB-eF?C_`DsF_0 z$zFi&-M#35PhsY8p&hS8XSNlc=}+hu9!Kk^E=neHIy%7;n0fvylJGE959^1`!*=2M zVUMt1I5@l}yb0Z^+aiB=cwaa*oPlWvo)ZNN!o_F@%fpr7n()(bOSmoEg&yYp;bHVJ z{)Wytdyj0HzuZ;`-I^vnc>Z0Q?i9GR1JURBR&;M4Lr?d7bZK8l&%_7lY5yGk6VI(t z{vCQY4x;S}^h~y>6gDMa9oykxY=zJFziDAZ`pnPxT0NOYTNzHWLl#WwidX z$iIcP$$x-8C5O?cq4FikmrPsq{t)zs$26>lOOpHP)K(JC>~C~wPVbXg5}ipo%)+YZ zz@5>6x}#e#DDpRJRUw1zKGU)4ee(Y+Ws?4yHsD3u;F*%UaUg?7wnED z`zI?g6n&?ULOYy>nfC`e!v*LB-iZ7P^tt~8-Kww9v$Z$wAMeleUxR{NmnKV74_&%W z=;7;!uE0q2)IWrF^awiO^XSZ%pfmdr4QwNNroKm){8*UpvLvALX#EF%>#WV?TR7D49 z8#gXQ2fi5XXaL&rRoDctM?0E}&SVkV{v9-s_2`@N8}#|#79NiB90QUqPUj|J$FXKbS+wMEIRN6tcugnADeHX0USg3I@`d+qUbmk!s^IVl}^g3*j9sO(`tp z_y6NpBoQw{2U>w1nl0$e51?C=dq~njd8|XeCOYH(Xkd?_0lkb_xEAeaU*!Km11*1L zvclD{q|bkYDCmk-=N6^FgOx&M`&U{hae*@jJ599vV*oFK~ z%)(k%@%-OQqB{u({sLXHZRnTM-pFSgnw-``=)k9=dt4qpbhXi6#VxTu_CwFm1L))V zI9h)`I-%Fm_sEK&JpT@~jRH^eZ&5KdEICxCq2K3C(1ClSui`7vnGZt`+4X3>yU>-J zjn4dabl{KCr{U{xD;nT;!_rB|dnw4G;8$#h#jnnm>WCL$BYX^f>^?>ZOkIB>a9{W{I`c#5o9`cVX$xPQY+YG&Nvomv8=&<&pab?o_x>`p-j&GN zNvCdz3U{FmCZez4>FAkw3Ek5-(C>zgXuVx{HXcO}ZHeoWc9qb9nxR|M77bt!I`B1- zABDwz{_l(%kD#Y{Hu@O7gbuV6?Qj(uz(AJO_p&=on3w#zjoH<4z=ePA^1fG8lcFu12?FQrw@72JkA{ZVlSeMsy3lMQ6STt@j)HoEN$w zDX)ocNegtPFTH{1-v-xGU}U$WOZ*VJl+U6AEkXlajt;mU9bgL@@Ikc0W9Uj`zcC4@ z5ZX^Ew7e?1bq&z>PO}?%{*ACF1qLtz9q3+k3#MZ>oP`cNJIY@`S7ssFZe_SR?(aq0 z{T%)e-I~Mb3+y=hIR2F;;eh|50~Q^T%(yt3FBeusJE#)*I$?t-Z-TB!YxGO!5_IK; zqk)e>+ovNxDekAIkuZ{3Xv9yUd-)8yH80^g_zwDQ_d7aJy_=FhRO*Z_?QnFdZ$bN; zfKK2(bjA;2MVy8Wa2a;+`QJ;z$D-!QWGh;td)gmenZe;G^lVH(XEFob^Eqgsi!iel z=;7TQT_Vv*E9q=@t|6U~gp1%T}!B}+Q2ho*y8lCY%^jmHf+QAQT|1f%n zPND&p8l6}R4X6!Pz+Py-W8(fKW&G4E5>|XAZhU~wYzsQ@kLVtrM1P><8k4M888qP9 zX#Eyw0A0}M{c?2X*P;W@z^=G3{2kLaY=3hyqaJ93!Dv7aqa8jU_uoK&;jF!V&9?r9FO;)!4tvvrOT`LM|;HBum6Vc~$7FNb(=n8B_ zS70|9_{qrUzb!dj70?Nsi}pJbo%vL>{d3{V=nB1Y8_&Oc{2>L-Y-8LwfYr$#$C_B- z_GHH0(Ze|!eUaROp6+|l_rXN8<0sLrS%7Zg8|dTs89KqQ(e^*5N!Z~p=%M-pU81~q zBpsJSJE(-tpar@m9nq(zFZ!5WgARN>`gGim4mb{7$p_HApNDSQFKGL8(L1xH29v0W zKHvAE1HOk2_!ZjG4s@pbBYy}DKNlZrR1?3SWnQ*-gZ5KL5{< zu)#sJ;_v9v6&jm(7P{Bf(U~?wx2z>PgU(?;wEeYcVE3R){TTX!T7XXAHFW8hV@;p` z_ej{_Kveh}4In#b!ekPz3n2MSI z{@-j8p7O&=fSF zxtMn5OG((#YVU*z%Fjpp=@I$9kspNiGc3x- z-V?w7CsL5bjX7u_AE1xZ=jh?ugYM-?H1fjZk}WHX22c+zZ-uT*SG1o#ksliON1})F zZuIQT7{}5Y`HK|z!q|ka$YC_n?BkQAEfrQrx2idI#(`)@3&OX;^=RPRuq*z8u1KqU zla)IceG0mzNf`N6cn6L`XMPxsH0OjQpfXs8d|foq0qEm&CpN_=&@Y*d=!Aa3W>{)s z@{eRa(ZhN#8puQFP!-p>6ujmUU$D|~%0%-j#%p6KQn|vL#elK)F zSA-+Nv1kAfqWw=#Os5u*@YKGIcDx!L@H4c-uh6gOJ!l8n?n^9y?sai=#ud=5IUilx z8?heVhn}6c&^O_ySRMCbX`lb1laoL9tA#H8Aav=+V11l|F6~NefIHEEi`}0LR36>y zW@w-npfkJ{U5Pu-2WBbiqelH6RVLXVT1G0 z4*Q}V4Z_UIU@h`bp=V<~de}Ch9q&c={6yT(`Dn651<=D+5`VSD*(eiF+;FqHT-;7!KXxv|hF7@iT|0P=g zXp|Rt!in+xpGCsMQyUGS9Xdc?bOzU;D{w0s*!^*TMwGu8`FGIv8_<>e5e?uZ+OEKi zx@OkoA!uROY@fW%>rRF4G*L~18Vfs!I9=_FR0Q=At`3t*X!Do{NbOq-``3q>hH_#PXi`LtOzQDdh`b(z{lJKw{i3_|WIg}O97e+nw zTdfuPJK=Kl=@^R6_*S&zY3LHqN6*H}@F%o>q34qqS$WLo^WTMpr~hK~RXPOSf*a5` z+yu14Dd9Xcz!m5r+=i~)addzJbCa2uMOUZ}dX`$Fr@u>hIcEOve@2jSZ^oemzK_mu z9lCUz&;YlE2hf2}pn(>jm#k1Nw0?6mpblt2ed7K#;mufs^6{AY`@gS}u;KEkunJwu zjcDY1;{Gp~oBT=S-JQz*LUOpOp!p8ysUH^QccL?%iLS)U=s549E4}6go`3gt69q>6 zJ=VsfXnEHBq=VXMKyA^0E}X!4=pWi=`K4 z%lsEjuf+}&yoa8F>@Outl|L+oo`G`c{n}C97@b)gG?1?7l3#|t`EEoX%V}tUPlV5* zujceCBwVU>Xh&b7E3p%OV;w;Ey!Ok<50ge%hkSqZ5Kcx1oQDRm96gjDV>R4?29ocU zq+Lxk-ybC~Mh+>1GA2aC}TKR^T9g7tAH8u1ygCIQw#x2P%Ft_OPfu0RL4CCX=_ zXKNuE@O$VltgTqp=RdV5sZb5wi9G|;JPUP0?#MEAFbc; zwPY&?qFXy0-IDZcJpWlF9;Lv;w=62Yk3P4bM)@}Mp9A({70kUX>9BTq4tmPZLzlce z8u&nTz^l=fxC32@`_cYqE#vvO!GfsxHv0U3iZ11k=wbR5J$z@ro&;JSEpLUc;J_#! z8s#I=_K%^5bRHVOO7u{F7WcQMNf_xtbm@OXBmNs*q9Si3OMf=H)ZNjQx&=L~zhOSIoG|*0H`|jvC>3$?~kQg2}Mxc9nCpN{2n1%15OZNl%A~_uX ziLPL-<;mk!0u8Jo*2Ny^V|fp{BGb{8n2$^_oqB_W9jr%JVmsPk54uNxqFa*ptz_VG z=uE1k<@L~+bPD^S?T4dVb`SbE&qgQqI=Yf8@l2op{UmIVdOKP2;%L4)I#6qL$vTET z(5<>0ozYe3irkF0y9eEZ>1beY#r+NF1iwaCa))`}KSxNoR434tsQyk;p#}Qett&Re ztI-)fi@s>yMFZK62Cy4l`onR*(7Q?Cwb7qm&C#WA9d^gG-$Iv>@Qt+;jr?mg(m%r- zE0UQOL{EKL^l-L8AIo0o`(PwG10l66IH+dv_aF!RO=tdi1P(iyd(<`jf5p$|R7E*pmD;*b`qsCwyXMIyvR# z-cKUD1U)2|qf0t092wpf-WNWK)_*!&5H1bh4cCO9hg-wlX%a5YAv`y7*Dvz7pes2Ueb-Mz59iZp z057BOiPtgn_kY)uu;M1P!|%~OI)d)`@90+K`zYCh;#iY>8T8fN8GS6fp#$82p8i`R z|1i2mGthpYL(jwl%>4d;Eecj(18%HCUzsP-fs3t9@>%GiX^sxi9eqJvh0bUk`dB`J zb?`m3pZ}rtbFWG2l|%b&xQ6H77eN~ejO&97=~dMK8SvQzk+tO77gettc|~* zZ@%*Dk^!5b6FL|DH=l#h`_G^QzJb2F*I^CZmyX04A18m+vNgIi526FlK$mza`fax{ z@_W#&$i6>G68 zKhPQF*^qQx6m4G$U4bm@jJ43M7=u-D8d~oybPM0dVt)T`BjFw$K|9FvX>w}MK$of( zxC=gT6!}@3c>bN)%M?_=571Nn zBl?qRFM3)JqDy`}?*EG()*N3X?Fym;)ZM%_l1q5)lm2G|!3>~i$bfERv9(SWFQuW(p%etax;}Z0h zJTSZpYmvVWGynWQgM@qd40`o9HWeE4rllx5qCc zG~mwY77oMen8wQZBD!)L(Fy&ro#)>rEcsn>NE)DT!mj8F^g$n^tI!T_N576A!7N;a zF8SwJ6Mv0-*7wQ%bI}Q2g+4u#(D%T@=t|8@lW^uQpiA`%I^cWg%r>J-xd-jw4>Z8k z56O}jL{InWXg@X4$F4!-JE8q{N4ID|*1?dF@l%6Icxtaf56gXM z173p|5gV7ax5*yRgdj-QiPc`?j<|JNd6 zq)pHU=Z3wbd?*^wX!LN7M_23tbj7Bk0nSAGc`w|6RmpEf1I>OgIh<#s_3L2?pa0$@ zJUrKgw@aho1=T&9X%7n(3y_IIygW43JoOJ zVV-~YxZvSr@5-SAH$o3z8?@s2=t^9K*1tT;Z$tySIr3xC6_|kb^H4Z5oQrPJB6Leu z9On6VZ-1b`Q+WtIt+|dQ9TZ3NSz$f2gSO!X;bq~q;jQ6BY(f3U&=vR`U7>%&Qt4lk zzgW-^{eHd`-Mg`9K;zIK9y8H5+ma|>fj%u;(17-$hxa$k!rVub_d`|mJ3X$AE!Ui0Zuy>Ke5pA&gfYgfUR*-h#R4YuPfHae&GY?lCMBl=nxu6rN5Fu zJEAYN!RYDH7yX;(-^Z@;-^r4;KnLuGJ|6wi=YJTw=eM9M@gTb73(&*( zA^LoOg0}k;eTwq@le{@gqc5a}=$UAZ_S+>L1^v-C*HAQo8_`$lU1+4!qWpCqD4-NN(H`qyAxoPa(>ucH%6e?h{5_M(UCBpN_L{(;MU>98jH+_yxx ztYNt@mI!9W%fG=a6vEUPJftV|1q5Fb5t%1N;^3 z@NYDLLb(#lp<7rNt=9>C!(ABpOVF(whz2kmeOhkLl|7wV`gs)iirkDg{07_M4^dtr zclONlT?HMuGdf^D%)$}jH1s{NG~9wtA7 z>V-A&a`c5U8C{td;{Lng8Z>~<(Sg5?{4e1j;lJpL<}Q#-^mHV^bSjI4OIaU%ESiSx z(HVA+{9yDD4M&&ows2~c&qr5k89LAwbVYZd{TxEKB74Ea5?I*hzZMB+&=NiU9nkOp z-e|)sBY!LUPM?In*=C_z_a54A4La~QQN9~J0|%r0uP|?+WTlE>PR38wA(0ImqD$Qv z-OHY6#5bXDw24?3pGIf;8D`<3u<&WwGygKH9#*6LI;??@VRKxG_3;GO!kUG7{#%gf zOTzE}$IyY^L}$JcE8~yo(&sCZtiYL=MZP*(zYDsBSD-6!HM%mR(f7ff;e_y^@QETk z|5lh21uuq6!*{}u!cWnTzl!|#;ok5_cp}VRGzp+USPX4nHmqEf=ih?bQP4PS6?P1} zqi3Xdco}*|hM+SZi7x3_%sigxS@{Uv(y!4o^DDZwB~MSDrlx5UE^T*o$@`;E!42pe z@iugTvFNwq{b;=f=u_}6UW%L1Z^gQ2WY7H7t0{OF`LD4N_AZt^bsyf3o$-v~N&o4~ zNEpCi^!dI4jr`v53G@&y3|FG{x1d|M6MdB)Kv(Dxx}v|KU&nt(zT%n5iq$~xH%Hp@ z|NonW19U+<8kpQj4GD*%Z?ZAyz!T9Gc@$lNXVCU_As=FJ>OY@Go>F3zkrx zzZxWrs59E&BJ{=48*AbaY=aM@d$|$a%Y$*hNXg`JYl%KySD~-kC(spLgFYSG(KqWZ zbmb0Wme2ohB%Jw~rIJWXqcg67cF+QSKlDI5>VLW7dk5muxeNv zUD<}{mb3`lqff#4XYu^o!PQammZ*?MPx(Z21!kdJvKS5IJ#>XWM%!;i&&K|^|2w); z*~%mn%Y(KnidC@;cENMY@ci5H!xU7*r_c`9pb>wG-rtVS*7HM;lZ|XWA0|lIf1VatETP_!jhc z!Q@L(X-MB-OBE0|AW!9HVo+}ow|vHOM5H&rn(!Q$?NDLdmr7B4d_a2!|Zqv zeeMsVE0ME8GUJL^k9-w$pgw58gVFx3Mgts;jeY*_B2k%w*W$*v=$`MwN_Yg_%VHIi zz`CI;(kC2-PT-a>9Zo_I+r#La@J%$J?dW^vC(Qi!zkep-Qst_Y%%mK8I9j5S4nX&E z7&?>d(3y;k{Mg7(K;IL&sMLWGmf|Ybyo-(ad`^@{l4R-$bjiii2wIJP|w!5fvoa@xjN-~{k zIEGc|>$39sjz53kA1s+Em2bqAbXu2AHd0{&6+1=69AQTq@#`rynS3<{?Mm9u0qXjh z!!?V0|D%tVT+ecU27NE#epRl4QQx{NxqoMxPJXAs^+dLeihi1g1#w0Ue1L|7$k(I( z5$c{ty<4N++Dt3{sEq-pQU3)d;%8#`4sFlo>PG!oA>AN5IKZ^GD@hbUV z-1{s~s-pSK=NSKcaYWUS3a@eb>G$Y8kDQU7#+{4kYI20fk9qz9oM(a1M$*;i=;u7{ z*NM<4hcj^^bxYF6C)8;``UcwgSwp++F=~0*UO~SfQr|btU!>#X*EH|IsQ4Kj6sB@% z8t2AMgu06Ry=hR9d;7RHaqmI~nNFK?qND26eIW*ZHq3O)|D49Xa$KFc?zA0!9Om+~ z(0@#rOD7xYv?)GLh4#^D->788%zw=XcXGcq_g^91mp0E5U`aY2Oa69dcOzx1xE>%s zhPu~KcPDv2FLM8W`aE<>zy4!#>Tf#9$IbTmD6{&A247IVfJPPQd@5c~`Cig~uBPrU zbk6HD)s!}Vt_W*UZ(&mOfB*Xn_xQu+%%=$VU!iR)+UCT}`WGNkj_bcqBP#8V{ADzp zPC)r7`|op6%;QJ*Dvnw5v*;$4@D<-Zu>P zc(zBE%*y;bsAZJgM$6?~zmn#wB-Mu&XVZEl>3Up#hDI+>lYW|e&qv73L+h+yv=LnY zefY!K)HU>bA#Gn|st38jPtjC!(tgt4aHAvFM-=?Yjiyw7k2P5CU|dho*>~jcJMYpy6{pP{>NX+Y zB?7fgUdl^Q{v`c2vw+Vc+P@Wb9`;y2N5Rc_29>(gK`-*t$Pc7(Z?2up&QBA{zoYya z>UE^kz2yC5C;ysDjMF0E?cA$ITR)SyT5{Eoe1otYb<>Y><46qfCpU7?(V5Y4AM))8 zXb|R%virH;o%(gjUx)?iBww_@jCv1H{y2SZA<(zT|MzJ`aA!olHWa=`zq{RkKkspK z88@4Ay+w!fV;1Y^pfdMnP@bKKw*#FwBLF{bx%!iD5Ox1$z|4m>MJV@EKJMMaU@hbR z6_oK0?5V?C3;jFbA4i8r7|2g{XGkZ{Q{mB=K{f8(9O*4|-iXc~B0rV7d$3(}-UFYb z><0$@BX#=MnuS?Z=olK7s6J&AZ3H~bvp z#xlx|lfRq%QPSO`vG;p2_!RO#bAKX!MBDt-$%Bv6HYZjlh=~zoXUab1Dngxexaa3e z{9i8i|8_cPK%^_UIi4G($iK?X<#h1hXU!?;#s3xJIn*7(wK-;bHUZ5he+*kNpr8Gr z|FzxK^izYfUDWS{S$?_y8jah~=tM+p!!IfSjr;}9md5!BssnXCCD6BH7T;0tZ1QhX z{@>?Q>JR09_EUoPUcIPO9lxVa0rScEr&BVG>F7AuKpJ;q@Je*hhJhPWZ#1*=laGc? zsgolDu4%So(}vB!)DR>aOBUuGXIkEZ3fE2y~m>cl%#rU2>FwwJ2?NjG4S!&hMo*u zgGN_yeM<)ylfRw;chDdw=~F-R$b8Mc!d$=6&p0}sL;xkp|M%HSKY!8BGhBW?PvBpQ z@r&mF)}PG%Tu($L>uid^{-nc$T>a_j)Xz1PZDzoF3^tDIeCl6KfF+{c3M#)vf5o}_ zo)UN=+V!Ka_b`Xgf1jB7lM(g0SS|9s#9SMCZ1Cmg`OO576OF(Kyp9|5KMnTe;@b@O7>{)EiB` ziQMC_8)W{dXm$i)o2Ln+D)sN8ZUO2xB3%jR(dH7a`lR{vN==MNUZU~)6uwHsnX%Ma zH0nU*=ecT9ZyYV&C$QNO-0hh@c=O>7>b}X<+}~AaUO$?mU#T{ME=Naq2g2>#8^OK8 z-GUly>VPwEfhXO$bjC+RHI?k+`>v{8NwaTyRGEUQ+95xsTqmlYW=< z1X}&~8AgxiP<9&k{2a%b^fJ_mMZLA$UqX63SA9m!OPlNPzfYYQ^(^c_-6yEmh<+Z( z%Sm3#3XUhl`dp)FRF1}eZo{9k2JYut!hJtKQ|BIBNJoQ7cccAgIy{GKFxM!`Kd0a9zbfZzV;kRrFbcYc6Hgqh97oF2(?U#?r}+Twjo0 zK-t4MmjGR`71hU!dxHT;GwlBxu-JbyqWnPydYODBX69!gZO@|P2N|$?)VuwZ_AgQY{ZsNCse6nz10uk8 z{nMOR=xk{;w$s|=pQ6%cDqS1pUyzq@U#W4OE>;hdH=D z866M8MFemj&tlq-rroW08&_S*2XOyUt~>pM&r?5JsQ61X{IC2+26=&w ztI&80g-53V1$=jUz$8%{nC`M$LC^B1$dpZs?E_>pTd*G|S5N?Cds|8q6h zHC)$nUB|VN3Qh1Lt}HsMNe3q=yPo_FTsLx!;NmaXrbgl@uF+g$xNhe9j)D1mm8m+k z`R{W#1J0w&&mO#%iSqYk)2XkiG@b$ep|BXy|4j#eT65*5qcY?#r+hgLir{~rE9sEG zf}HuxrjPr%Hzo!=kMhrB6$?>gY^=m)9LHFnQ|}Gx@An_Y{d`7)Z@IoZ0qLVYjRn%P)1D;8`40Y^o7VY!I;FoZJBlr4YEABO867$G!qVH*xJz|3uB#z<- zF)+!@=SlJhqNB4(e?`6LxKoj9K0!>Pliig0X@LdloWF*a;;)+i-{%$5)v4Q`dwy<= z{!FhUkj(t=r}N#X4Bm|!rD;@`#*OK?c{KW-8TO#OGL7p||4;5;%GI9o|2`{d>!&8= zpHin61HVBZ6QaC#^wpj^pYpFGQ`b|m_9=reWq|)amAH2gMM8%2* z#oqN$z;0|&QLHC66pdhCjaz+dm$ezstUr8D@RiDOr5?c& zoB6ZYgd4tR^>%8T)6~bxyPCZ0KED7!mxEJA$rw+uIklSn( zyjW%`u-J_Q%21bQM$8S&A1~i&_BfT z_Z;U;e9i1|ZI;mok+L(roAh3S1u(ycTFhwqbu5wuJ)#KB^$<4_vn>?s%XvZsmzThU z>5Hu)R$y_mwKQx{+ykwNcp)@OvTy=XES04Z@N+m?>=asCO*Bt1cpIP;gk^wYx$(t% zWgdo#QdiR>8-sh1CkYXArhiO}JvWnQueil&FBa#-Uu-o7{z? zhI3pW@t zjhYO`TQWZT^{vbTi)Bek;v9T7cpyS~i60T~Pu>&!ck(o52Xp*Hdb6lMQqR_etfF3uG;R!5i!OUZ@wQze9(^%S% zW9_XTT(Ro-8}_)PQyjTd$P0==Tl)FPInw~aW21NPyssGH$GgI$xa|L3{%mRyJbEkZQH@k?A= zj40NCybW$-!7;@I-=a^Mi=NH0NY3JS(VC?X=0m?SN2hBo+@@$bx#{QMESmP_O>;d% z9t!@2SY`5p94WRRq2k1Y@D6iC9`fpXj5EE{%uXk6v|BiWyd8UvqH%(L3p6{(U*N7F z84Ng4kEl!@q)&N*-X?_eG0+~o7x`d379Wd`!^h(j@JzT9iDL50QC;8nGg;}n15wIGGi6zix1U6eRi>wMaOM17BiZxolAy7GdV@dR{J=!^O3%o?;- z<6n30Yby{kjrp_;r64~2CNTt4?LcH5sT_F z@2wi5<3#TR^R=1D0FNP7fOm%Z9Qn_2{(?{t52x9WXtQ$UF$}tLNPXfQ`g8PYJ;>W4 z;DyjZ@@a?;gVT!qJorfRdSGG!6-#Wy8;>RUAvq3vK>^{I`B z{sFd(SdaK8F$`~rxY#b@ed02F9i9lspV z>MI}Hn#3n)T-BomPSq!@Y=<3V z{*%tHB@bcGzi`u8hF9o7cYucs9bw^kNSkzEuL>>Dr5EiES<8Gn^KN(x<~s3C9EN|w zjx!bfEd94&qtF$rC`Zd*#cqW>jm5q+9umE1mIteVSHuG#4nd$BaW?L($C_DGL&c6D z{LLcEpNh=n2lqv*1i2qx62AymnphofHX0w`=g1EbKTv#B(Z>+}L%x~jLVbcv?G+Uq z(Fx#fSpJS<#GW#ffY;Syf{2CT8sR#^Sr1oi10KfgSn7`SpO8D5RQx3ZHXA}x1(Ei; zU>r~1$gVHE?TGZCzXtpcF$4Y<7LHWCD;lrSPtpTqE*RcVxPv~NshXfzv^7{>-?H!> zz7FArkZslhp;`#Gr1t}!$-;+vq^mBB0?R=BGjq4eZB|ElQU{|^iC%pd>z_Y{#enjc zQla=&mULs-8$!HZ9!Z^_JW)hh)B=7aF&WNymYvk)BHjS;t6(m~-gqWhZ|cU(`zvoc zd&I8GzyA-W=z(xF@f3n%7!sRLJ%jod!xb6a1l}K>QIGPqTUrp#UV5wPO|_02et|y_ zY!y%bj=np3*+j85%ofMn%E!Mrq%JBd&2-IgGEhj5xeF(nW5hlo=&pGZ_-@Vr06$DW zjybW>=Tp_veW7m2abow;36fvMI0;yt=3N>maSsN6=P7sS zhe61%5SWCguvqK`{4H=t5clFo=zT@-647QqXx@yOGO9HN&OQj9HWK?Sb`NqPnwt?5 zJI%moePXFo^y*J=#OlDy0rO(6ExgC%%ZbzRPhcB#c|UkzdUPC`PV{HOO(s4CH+hp> zrcuYLYZ%Ai4PBC5^<@2+7h(22{V#YN z2fc&0n?0Y2cy&tZ5L{y%EDVJKv0H$Hg~FHOA?K~IYSf5uZ6 zV#Y&=*b#Jmt*Pa;Dm*v(VgbxY!mC7V#-Nvc|DPMN_4suq3GteW4+AUDz;fyna8jg+ z`DtJBGV+4W)C0EB3*(4c#HIKi#bfjx3Pk5P&T50H6tDNSAtHTQxP*9)!GegC6&7|A zPAnb-_C+2UyN^gwJ-Rr(d{)@tsaQMu`@lotp971ezgBzCh!^DNf5{N?vgD>Nn#{GE z85H|UbXVMp@LdZB7#Qx3=yrM|nV*ZNGq+E;m2Vtz72qsNR=LB5%~U+gVbJqgB!!iW;Tqv9F%>W;jL63u;=6lRp&SA zuJmJwlZY!7&u}t?7(R&zevKmv@PQaj-ky9XaT3pBB#ISdun7k=1uI4!LEekpf%wQV zDf3{8Qv&~^*=k9b(@MD{1^xZpDXHqYX_b?Y8rL`_#5fzvI+qwTG^(F@p|f#!6URQ0 zy%Ji78Vj38g&J47nuFRI=jSt@i{O6-oY13}alL!ZN>!>>3JNSyrFNabnr5%w#$R%o zQ4h>zc8@mtxvXm$YpiYVu-&-FIiXmJv8Bs!t9V3;@j*NDPp%Hz+{~pt9kzOyua|OI QVN5u<(^w$E?C%iq5AfSDuK)l5 diff --git a/internat/fr/kicad.po b/internat/fr/kicad.po index 46fffa6354..c50d3ca0a5 100644 --- a/internat/fr/kicad.po +++ b/internat/fr/kicad.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: kicad\n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2007-12-30 19:07+0100\n" +"PO-Revision-Date: 2008-01-01 17:55+0100\n" "Last-Translator: \n" "Language-Team: kicad team \n" "MIME-Version: 1.0\n" @@ -560,8 +560,8 @@ msgstr "OK" #: pcbnew/muonde.cpp:352 #: pcbnew/modedit_onclick.cpp:203 #: pcbnew/modedit_onclick.cpp:235 -#: pcbnew/onrightclick.cpp:146 -#: pcbnew/onrightclick.cpp:160 +#: pcbnew/onrightclick.cpp:145 +#: pcbnew/onrightclick.cpp:159 #: pcbnew/block.cpp:157 #: pcbnew/globaleditpad.cpp:108 #: pcbnew/cotation.cpp:109 @@ -834,7 +834,7 @@ msgstr "Sauver pr #: pcbnew/dialog_setup_libs.cpp:97 #: eeschema/dialog_eeschema_config.cpp:105 -#: cvpcb/dialog_cvpcb_config.cpp:76 +#: cvpcb/dialog_cvpcb_config.cpp:77 #: gerbview/reglage.cpp:90 msgid "from " msgstr "De " @@ -1257,7 +1257,7 @@ msgstr "Echelle" #: pcbnew/dialog_display_options.cpp:221 #: pcbnew/dialog_display_options.cpp:229 #: pcbnew/dialog_display_options.cpp:266 -#: pcbnew/class_board_item.cpp:99 +#: pcbnew/class_board_item.cpp:98 #: pcbnew/dialog_zones_by_polygon.cpp:167 #: gerbview/options.cpp:321 msgid "Line" @@ -1331,7 +1331,7 @@ msgid "Ref." msgstr "Ref." #: pcbnew/class_text_mod.cpp:345 -#: pcbnew/class_board_item.cpp:80 +#: pcbnew/class_board_item.cpp:79 #: pcbnew/class_edge_mod.cpp:286 #: eeschema/component_class.cpp:55 #: eeschema/edit_component_in_schematic.cpp:784 @@ -1341,7 +1341,7 @@ msgstr "Valeur" #: pcbnew/class_text_mod.cpp:345 #: pcbnew/class_text_mod.cpp:353 -#: pcbnew/class_board_item.cpp:85 +#: pcbnew/class_board_item.cpp:84 msgid "Text" msgstr "Texte" @@ -1629,11 +1629,11 @@ msgstr "Hauteur Texte Module" msgid "Text Module Size H" msgstr "Largeur Texte Module" -#: pcbnew/zone_filling_algorithm.cpp:158 +#: pcbnew/zone_filling_algorithm.cpp:156 msgid "No pads or starting point found to fill this zone outline" msgstr "Pas de pads ou de points de départ pour remplir ce contour de zone" -#: pcbnew/zone_filling_algorithm.cpp:196 +#: pcbnew/zone_filling_algorithm.cpp:194 msgid "Ok" msgstr "Ok" @@ -1706,7 +1706,7 @@ msgid "Print Module" msgstr "Imprimer Module" #: pcbnew/tool_modedit.cpp:115 -#: pcbnew/tool_pcb.cpp:270 +#: pcbnew/tool_pcb.cpp:269 #: eeschema/tool_sch.cpp:108 #: eeschema/tool_lib.cpp:170 #: gerbview/tool_gerber.cpp:271 @@ -1714,7 +1714,7 @@ msgid "zoom +" msgstr "zoom +" #: pcbnew/tool_modedit.cpp:119 -#: pcbnew/tool_pcb.cpp:274 +#: pcbnew/tool_pcb.cpp:273 #: eeschema/tool_sch.cpp:112 #: eeschema/tool_lib.cpp:174 #: gerbview/tool_gerber.cpp:278 @@ -1722,7 +1722,7 @@ msgid "zoom -" msgstr "zoom -" #: pcbnew/tool_modedit.cpp:123 -#: pcbnew/tool_pcb.cpp:278 +#: pcbnew/tool_pcb.cpp:277 #: eeschema/tool_sch.cpp:116 #: eeschema/tool_lib.cpp:178 #: gerbview/tool_gerber.cpp:285 @@ -1730,7 +1730,7 @@ msgid "redraw" msgstr "Redessin" #: pcbnew/tool_modedit.cpp:128 -#: pcbnew/tool_pcb.cpp:283 +#: pcbnew/tool_pcb.cpp:282 #: eeschema/tool_sch.cpp:121 #: eeschema/tool_lib.cpp:184 #: gerbview/tool_gerber.cpp:296 @@ -1754,18 +1754,18 @@ msgid "Add Pads" msgstr "Addition de \"pins\"" #: pcbnew/tool_modedit.cpp:168 -#: pcbnew/tool_pcb.cpp:434 +#: pcbnew/tool_pcb.cpp:433 #: eeschema/tool_sch.cpp:226 msgid "Add graphic line or polygon" msgstr "Addition de lignes ou polygones graphiques" #: pcbnew/tool_modedit.cpp:172 -#: pcbnew/tool_pcb.cpp:438 +#: pcbnew/tool_pcb.cpp:437 msgid "Add graphic circle" msgstr "Addition de graphiques (Cercle)" #: pcbnew/tool_modedit.cpp:176 -#: pcbnew/tool_pcb.cpp:442 +#: pcbnew/tool_pcb.cpp:441 msgid "Add graphic arc" msgstr "Addition de graphiques (Arc de Cercle)" @@ -1783,7 +1783,7 @@ msgid "Place anchor" msgstr "Place Ancre" #: pcbnew/tool_modedit.cpp:190 -#: pcbnew/tool_pcb.cpp:460 +#: pcbnew/tool_pcb.cpp:459 #: eeschema/tool_sch.cpp:235 #: eeschema/tool_lib.cpp:93 #: gerbview/tool_gerber.cpp:393 @@ -1791,41 +1791,41 @@ msgid "Delete items" msgstr "Suppression d'éléments" #: pcbnew/tool_modedit.cpp:212 -#: pcbnew/tool_pcb.cpp:334 +#: pcbnew/tool_pcb.cpp:333 #: eeschema/tool_sch.cpp:257 #: gerbview/tool_gerber.cpp:417 msgid "Display Grid OFF" msgstr "Suppression de l'affichage de la grille" #: pcbnew/tool_modedit.cpp:216 -#: pcbnew/tool_pcb.cpp:337 +#: pcbnew/tool_pcb.cpp:336 #: gerbview/tool_gerber.cpp:423 msgid "Display Polar Coord ON" msgstr "Activer affichage coord Polaires" #: pcbnew/tool_modedit.cpp:220 -#: pcbnew/tool_pcb.cpp:339 +#: pcbnew/tool_pcb.cpp:338 #: eeschema/tool_sch.cpp:261 #: gerbview/tool_gerber.cpp:427 msgid "Units = Inch" msgstr "Unités = pouce" #: pcbnew/tool_modedit.cpp:224 -#: pcbnew/tool_pcb.cpp:341 +#: pcbnew/tool_pcb.cpp:340 #: eeschema/tool_sch.cpp:265 #: gerbview/tool_gerber.cpp:431 msgid "Units = mm" msgstr "Unités = mm" #: pcbnew/tool_modedit.cpp:230 -#: pcbnew/tool_pcb.cpp:344 +#: pcbnew/tool_pcb.cpp:343 #: eeschema/tool_sch.cpp:269 #: gerbview/tool_gerber.cpp:437 msgid "Change Cursor Shape" msgstr "Sélection de la forme du curseur" #: pcbnew/tool_modedit.cpp:238 -#: pcbnew/tool_pcb.cpp:366 +#: pcbnew/tool_pcb.cpp:365 msgid "Show Pads Sketch" msgstr "Afficher pastilles en contour" @@ -1838,7 +1838,7 @@ msgid "Show Edges Sketch" msgstr "Afficher Modules en contour" #: pcbnew/tool_modedit.cpp:285 -#: pcbnew/tool_pcb.cpp:567 +#: pcbnew/tool_pcb.cpp:566 #: eeschema/plotps.cpp:169 #: share/zoom.cpp:367 msgid "Auto" @@ -1860,7 +1860,7 @@ msgid "Grid %.3f" msgstr "Grille %.3f" #: pcbnew/tool_modedit.cpp:314 -#: pcbnew/tool_pcb.cpp:601 +#: pcbnew/tool_pcb.cpp:600 msgid "User Grid" msgstr "Grille perso" @@ -1888,7 +1888,7 @@ msgid "Error: Unexpected end of file !" msgstr "Erreur: Fin de fichier inattendue !" #: pcbnew/dialog_netlist.cpp:135 -#: pcbnew/class_board_item.cpp:76 +#: pcbnew/class_board_item.cpp:75 #: eeschema/onrightclick.cpp:320 #: eeschema/dialog_create_component.cpp:164 #: eeschema/edit_component_in_schematic.cpp:745 @@ -1910,9 +1910,9 @@ msgid "Keep" msgstr "Garder" #: pcbnew/dialog_netlist.cpp:143 -#: pcbnew/onrightclick.cpp:623 -#: pcbnew/onrightclick.cpp:733 -#: pcbnew/onrightclick.cpp:830 +#: pcbnew/onrightclick.cpp:589 +#: pcbnew/onrightclick.cpp:749 +#: pcbnew/onrightclick.cpp:846 #: eeschema/edit_component_in_lib.cpp:239 #: eeschema/edit_component_in_lib.cpp:320 msgid "Delete" @@ -2086,14 +2086,14 @@ msgid "Add Drawing" msgstr "Ajout d'éléments graphiques" #: pcbnew/modedit.cpp:424 -#: pcbnew/edit.cpp:526 +#: pcbnew/edit.cpp:536 #: eeschema/schedit.cpp:455 #: eeschema/libframe.cpp:579 msgid "Delete item" msgstr "Suppression d'éléments" #: pcbnew/modedit_onclick.cpp:207 -#: pcbnew/onrightclick.cpp:151 +#: pcbnew/onrightclick.cpp:150 #: eeschema/onrightclick.cpp:126 #: eeschema/libedit_onrightclick.cpp:53 #: gerbview/onrightclick.cpp:42 @@ -2101,7 +2101,7 @@ msgid "End Tool" msgstr "Fin Outil" #: pcbnew/modedit_onclick.cpp:217 -#: pcbnew/onrightclick.cpp:504 +#: pcbnew/onrightclick.cpp:469 #: eeschema/onrightclick.cpp:587 #: eeschema/libedit_onrightclick.cpp:237 #: gerbview/onrightclick.cpp:51 @@ -2109,13 +2109,13 @@ msgid "Cancel Block" msgstr "Annuler Bloc" #: pcbnew/modedit_onclick.cpp:219 -#: pcbnew/onrightclick.cpp:506 +#: pcbnew/onrightclick.cpp:471 #: gerbview/onrightclick.cpp:52 msgid "Zoom Block (Midd butt drag)" msgstr "Zoom Bloc (drag+bouton milieu)" #: pcbnew/modedit_onclick.cpp:222 -#: pcbnew/onrightclick.cpp:509 +#: pcbnew/onrightclick.cpp:474 #: eeschema/onrightclick.cpp:595 #: eeschema/libedit_onrightclick.cpp:245 #: gerbview/onrightclick.cpp:54 @@ -2123,7 +2123,7 @@ msgid "Place Block" msgstr "Place Bloc" #: pcbnew/modedit_onclick.cpp:224 -#: pcbnew/onrightclick.cpp:511 +#: pcbnew/onrightclick.cpp:476 #: eeschema/onrightclick.cpp:604 #: eeschema/libedit_onrightclick.cpp:251 msgid "Copy Block (shift + drag mouse)" @@ -2134,18 +2134,18 @@ msgid "Mirror Block (alt + drag mouse)" msgstr "Bloc Miroir (alt + drag mouse)" #: pcbnew/modedit_onclick.cpp:228 -#: pcbnew/onrightclick.cpp:515 +#: pcbnew/onrightclick.cpp:480 msgid "Rotate Block (ctrl + drag mouse)" msgstr "Rotation Bloc (ctrl + drag mouse)" #: pcbnew/modedit_onclick.cpp:230 -#: pcbnew/onrightclick.cpp:517 +#: pcbnew/onrightclick.cpp:482 msgid "Delete Block (shift+ctrl + drag mouse)" msgstr "Effacement Bloc (shift+ctrl + drag mouse)" #: pcbnew/modedit_onclick.cpp:252 -#: pcbnew/onrightclick.cpp:727 -#: pcbnew/onrightclick.cpp:824 +#: pcbnew/onrightclick.cpp:743 +#: pcbnew/onrightclick.cpp:840 msgid "Rotate" msgstr "Rotation" @@ -2170,17 +2170,17 @@ msgid "Move Pad" msgstr "Déplace Pad" #: pcbnew/modedit_onclick.cpp:274 -#: pcbnew/onrightclick.cpp:766 +#: pcbnew/onrightclick.cpp:782 msgid "Edit Pad" msgstr "Edit Pad" #: pcbnew/modedit_onclick.cpp:276 -#: pcbnew/onrightclick.cpp:770 +#: pcbnew/onrightclick.cpp:786 msgid "New Pad Settings" msgstr "Nouvelles Caract. Pads" #: pcbnew/modedit_onclick.cpp:278 -#: pcbnew/onrightclick.cpp:772 +#: pcbnew/onrightclick.cpp:788 msgid "Export Pad Settings" msgstr "Exporte Caract. Pads" @@ -2189,7 +2189,7 @@ msgid "delete Pad" msgstr "Supprimer Pad" #: pcbnew/modedit_onclick.cpp:285 -#: pcbnew/onrightclick.cpp:777 +#: pcbnew/onrightclick.cpp:793 msgid "Global Pad Settings" msgstr "Edition Globale des pads" @@ -2222,9 +2222,9 @@ msgid "Place edge" msgstr "Place contour" #: pcbnew/modedit_onclick.cpp:317 -#: pcbnew/onrightclick.cpp:695 -#: pcbnew/onrightclick.cpp:729 -#: pcbnew/onrightclick.cpp:826 +#: pcbnew/onrightclick.cpp:711 +#: pcbnew/onrightclick.cpp:745 +#: pcbnew/onrightclick.cpp:842 #: eeschema/onrightclick.cpp:313 msgid "Edit" msgstr "Editer" @@ -2263,7 +2263,7 @@ msgid "RefP" msgstr "RefP" #: pcbnew/class_pad.cpp:979 -#: pcbnew/class_board_item.cpp:36 +#: pcbnew/class_board_item.cpp:35 msgid "Net" msgstr "Net" @@ -2284,7 +2284,7 @@ msgid "Shape" msgstr "Forme" #: pcbnew/classpcb.cpp:199 -#: pcbnew/class_board_item.cpp:108 +#: pcbnew/class_board_item.cpp:107 #: pcbnew/class_track.cpp:776 #: pcbnew/dialog_pad_edit.cpp:176 #: pcbnew/dialog_pad_edit.cpp:196 @@ -2565,7 +2565,7 @@ msgid "Footprint name:" msgstr "Nom Module: " #: pcbnew/modules.cpp:281 -#: pcbnew/onrightclick.cpp:701 +#: pcbnew/onrightclick.cpp:717 msgid "Delete Module" msgstr "Supprimer Module" @@ -2874,385 +2874,394 @@ msgstr "&Divers" msgid "P&ostprocess" msgstr "P&ostprocesseurs" -#: pcbnew/onrightclick.cpp:83 +#: pcbnew/onrightclick.cpp:82 #, c-format msgid "Track %.1f" msgstr "Piste %.1f" -#: pcbnew/onrightclick.cpp:85 +#: pcbnew/onrightclick.cpp:84 #, c-format msgid "Track %.3f" msgstr "Piste %.3f" -#: pcbnew/onrightclick.cpp:101 +#: pcbnew/onrightclick.cpp:100 #, c-format msgid "Via %.1f" msgstr "Via %.1f" -#: pcbnew/onrightclick.cpp:103 +#: pcbnew/onrightclick.cpp:102 #, c-format msgid "Via %.3f" msgstr "Via %.3f" -#: pcbnew/onrightclick.cpp:219 +#: pcbnew/onrightclick.cpp:218 msgid "Lock Module" msgstr "Verrouiller Modules" -#: pcbnew/onrightclick.cpp:227 +#: pcbnew/onrightclick.cpp:226 msgid "Unlock Module" msgstr "Déverrouiller Modules" -#: pcbnew/onrightclick.cpp:235 +#: pcbnew/onrightclick.cpp:234 msgid "Auto place Module" msgstr "Auto place Module" -#: pcbnew/onrightclick.cpp:241 +#: pcbnew/onrightclick.cpp:240 msgid "Autoroute" msgstr "Autoroute" -#: pcbnew/onrightclick.cpp:257 +#: pcbnew/onrightclick.cpp:256 msgid "Move Drawing" msgstr "Déplace Tracé" -#: pcbnew/onrightclick.cpp:262 +#: pcbnew/onrightclick.cpp:261 msgid "End Drawing" msgstr "Fin tracé" -#: pcbnew/onrightclick.cpp:264 +#: pcbnew/onrightclick.cpp:263 msgid "Edit Drawing" msgstr "Edit Tracé" -#: pcbnew/onrightclick.cpp:265 +#: pcbnew/onrightclick.cpp:264 msgid "Delete Drawing" msgstr "Supprimer Tracé" -#: pcbnew/onrightclick.cpp:272 -msgid "End edge zone" -msgstr "Fin contour Zone" - -#: pcbnew/onrightclick.cpp:275 -msgid "Delete edge zone" -msgstr "Supprimer Contour Zone" - -#: pcbnew/onrightclick.cpp:284 -msgid "Place Corner" -msgstr "Place Sommet" - -#: pcbnew/onrightclick.cpp:294 -msgid "Move Corner" -msgstr "Déplace Sommet" - -#: pcbnew/onrightclick.cpp:296 -msgid "Delete Corner" -msgstr "Supprimer Sommet" - -#: pcbnew/onrightclick.cpp:302 -msgid "Create Corner" -msgstr "Créer Sommet" - -#: pcbnew/onrightclick.cpp:306 -msgid "Fill zone" -msgstr "Remplir zone" - -#: pcbnew/onrightclick.cpp:309 -msgid "Edit Zone Params" -msgstr "Editer Paramčtres de la Zone" - -#: pcbnew/onrightclick.cpp:311 -msgid "Delete Zone Outline" -msgstr "Supprimer Contour de Zone" - -#: pcbnew/onrightclick.cpp:328 +#: pcbnew/onrightclick.cpp:269 msgid "Delete Zone" msgstr "Supprimer Zone" -#: pcbnew/onrightclick.cpp:333 +#: pcbnew/onrightclick.cpp:276 +msgid "End edge zone" +msgstr "Fin contour Zone" + +#: pcbnew/onrightclick.cpp:279 +msgid "Delete edge zone" +msgstr "Supprimer Contour Zone" + +#: pcbnew/onrightclick.cpp:298 msgid "Delete Marker" msgstr "Effacer Marqueur" -#: pcbnew/onrightclick.cpp:340 +#: pcbnew/onrightclick.cpp:305 msgid "Edit Dimension" msgstr "Edit Cote" -#: pcbnew/onrightclick.cpp:343 +#: pcbnew/onrightclick.cpp:308 msgid "Delete Dimension" msgstr "Suppression Cote" -#: pcbnew/onrightclick.cpp:350 +#: pcbnew/onrightclick.cpp:315 msgid "Move Target" msgstr "Déplacer Mire" -#: pcbnew/onrightclick.cpp:353 +#: pcbnew/onrightclick.cpp:318 msgid "Edit Target" msgstr "Editer Mire" -#: pcbnew/onrightclick.cpp:355 +#: pcbnew/onrightclick.cpp:320 msgid "Delete Target" msgstr "Supprimer Mire" -#: pcbnew/onrightclick.cpp:382 +#: pcbnew/onrightclick.cpp:347 msgid "Get and Move Footprint" msgstr "Sel et Dépl.t module" -#: pcbnew/onrightclick.cpp:396 +#: pcbnew/onrightclick.cpp:361 msgid "Fill or Refill All Zones" msgstr "Remplir ou Re-remplir Toutes les Zones" -#: pcbnew/onrightclick.cpp:401 -#: pcbnew/onrightclick.cpp:412 -#: pcbnew/onrightclick.cpp:425 -#: pcbnew/onrightclick.cpp:486 +#: pcbnew/onrightclick.cpp:366 +#: pcbnew/onrightclick.cpp:377 +#: pcbnew/onrightclick.cpp:390 +#: pcbnew/onrightclick.cpp:451 msgid "Select Working Layer" msgstr "Sélection de la couche de travail" -#: pcbnew/onrightclick.cpp:410 -#: pcbnew/onrightclick.cpp:483 +#: pcbnew/onrightclick.cpp:375 +#: pcbnew/onrightclick.cpp:448 msgid "Select Track Width" msgstr "Sélection Epais. Piste" -#: pcbnew/onrightclick.cpp:414 +#: pcbnew/onrightclick.cpp:379 msgid "Select layer pair for vias" msgstr "Selection couple de couches pour Vias" -#: pcbnew/onrightclick.cpp:431 +#: pcbnew/onrightclick.cpp:396 msgid "Footprint documentation" msgstr "Documentation des modules" -#: pcbnew/onrightclick.cpp:441 +#: pcbnew/onrightclick.cpp:406 msgid "Glob Move and Place" msgstr "Move et Place Globaux" -#: pcbnew/onrightclick.cpp:443 +#: pcbnew/onrightclick.cpp:408 msgid "Unlock All Modules" msgstr "Déverrouiller tous les Modules" -#: pcbnew/onrightclick.cpp:445 +#: pcbnew/onrightclick.cpp:410 msgid "Lock All Modules" msgstr "Verrouiller tous les Modules" -#: pcbnew/onrightclick.cpp:448 +#: pcbnew/onrightclick.cpp:413 msgid "Move All Modules" msgstr "Déplace tous les Modules" -#: pcbnew/onrightclick.cpp:449 +#: pcbnew/onrightclick.cpp:414 msgid "Move New Modules" msgstr "Déplace nouveaux Modules" -#: pcbnew/onrightclick.cpp:451 +#: pcbnew/onrightclick.cpp:416 msgid "Autoplace All Modules" msgstr "Autoplace Tous Modules" -#: pcbnew/onrightclick.cpp:452 +#: pcbnew/onrightclick.cpp:417 msgid "Autoplace New Modules" msgstr "AutoPlace nouveaux Modules" -#: pcbnew/onrightclick.cpp:453 +#: pcbnew/onrightclick.cpp:418 msgid "Autoplace Next Module" msgstr "Autoplace Module suivant" -#: pcbnew/onrightclick.cpp:456 +#: pcbnew/onrightclick.cpp:421 msgid "Orient All Modules" msgstr "Oriente Tous Modules" -#: pcbnew/onrightclick.cpp:463 +#: pcbnew/onrightclick.cpp:428 msgid "Global Autoroute" msgstr "Autoroutage global" -#: pcbnew/onrightclick.cpp:465 +#: pcbnew/onrightclick.cpp:430 msgid "Select layer pair" msgstr "Selection couple de couches" -#: pcbnew/onrightclick.cpp:467 +#: pcbnew/onrightclick.cpp:432 msgid "Autoroute All Modules" msgstr "Autoroute Tous Modules" -#: pcbnew/onrightclick.cpp:469 +#: pcbnew/onrightclick.cpp:434 msgid "Reset Unrouted" msgstr "Réinit Non routés" -#: pcbnew/onrightclick.cpp:474 +#: pcbnew/onrightclick.cpp:439 msgid "Global AutoRouter" msgstr "Autorouteur Global" -#: pcbnew/onrightclick.cpp:476 +#: pcbnew/onrightclick.cpp:441 msgid "Read Global AutoRouter Data" msgstr "Lire Données de L'autorouteur global" -#: pcbnew/onrightclick.cpp:513 +#: pcbnew/onrightclick.cpp:478 msgid "Flip Block (alt + drag mouse)" msgstr "Inversion Bloc (alt + drag mouse)" -#: pcbnew/onrightclick.cpp:536 +#: pcbnew/onrightclick.cpp:501 msgid "Drag Via" msgstr "Drag Via" -#: pcbnew/onrightclick.cpp:540 -#: pcbnew/onrightclick.cpp:604 +#: pcbnew/onrightclick.cpp:505 +#: pcbnew/onrightclick.cpp:569 msgid "Edit Via" msgstr "Edit Via" -#: pcbnew/onrightclick.cpp:542 +#: pcbnew/onrightclick.cpp:507 msgid "Set via hole to Default" msgstr "Ajuste perçage via ŕ défaut" -#: pcbnew/onrightclick.cpp:544 +#: pcbnew/onrightclick.cpp:509 msgid "Set via hole to alt value" msgstr "Ajuste perçage via ŕ valeur alternative" -#: pcbnew/onrightclick.cpp:546 +#: pcbnew/onrightclick.cpp:511 msgid "Set the via hole alt value" msgstr "Ajuste la valeur alt. perçage via" -#: pcbnew/onrightclick.cpp:548 +#: pcbnew/onrightclick.cpp:513 msgid "Export Via hole to alt value" msgstr "Exporte perçage via ŕ valeur alt." -#: pcbnew/onrightclick.cpp:550 +#: pcbnew/onrightclick.cpp:515 msgid "Export via hole to others id vias" msgstr "Exporte perçage via aux autres semblables." -#: pcbnew/onrightclick.cpp:552 +#: pcbnew/onrightclick.cpp:517 msgid "Set ALL via holes to default" msgstr "Ajuste perçage TOUTES vias au défaut" -#: pcbnew/onrightclick.cpp:565 +#: pcbnew/onrightclick.cpp:530 msgid "Move Node" msgstr "Déplace Noeud" -#: pcbnew/onrightclick.cpp:570 +#: pcbnew/onrightclick.cpp:535 msgid "Drag Segments, keep slope" msgstr "Drag Segments, garder direction" -#: pcbnew/onrightclick.cpp:572 +#: pcbnew/onrightclick.cpp:537 msgid "Drag Segment" msgstr "Drag Segment" -#: pcbnew/onrightclick.cpp:575 +#: pcbnew/onrightclick.cpp:540 msgid "Move Segment" msgstr "Déplace Segment" -#: pcbnew/onrightclick.cpp:578 +#: pcbnew/onrightclick.cpp:543 msgid "Break Track" msgstr "Briser piste" -#: pcbnew/onrightclick.cpp:585 +#: pcbnew/onrightclick.cpp:550 msgid "Place Node" msgstr "Place noeud" -#: pcbnew/onrightclick.cpp:592 +#: pcbnew/onrightclick.cpp:557 msgid "End Track" msgstr "Terminer Piste" -#: pcbnew/onrightclick.cpp:595 +#: pcbnew/onrightclick.cpp:560 msgid "Place Via" msgstr "Place Via" -#: pcbnew/onrightclick.cpp:602 +#: pcbnew/onrightclick.cpp:567 msgid "Change Width" msgstr "Change Largeur" -#: pcbnew/onrightclick.cpp:604 +#: pcbnew/onrightclick.cpp:570 msgid "Edit Segment" msgstr "Edit Segment" -#: pcbnew/onrightclick.cpp:609 +#: pcbnew/onrightclick.cpp:575 msgid "Edit Track" msgstr "Editer Piste" -#: pcbnew/onrightclick.cpp:611 +#: pcbnew/onrightclick.cpp:577 msgid "Edit Net" msgstr "Edit Net" -#: pcbnew/onrightclick.cpp:613 +#: pcbnew/onrightclick.cpp:579 msgid "Edit ALL Tracks and Vias" msgstr "Editer TOUTES Pistes et Vias" -#: pcbnew/onrightclick.cpp:615 +#: pcbnew/onrightclick.cpp:581 msgid "Edit ALL Vias (no track)" msgstr "Editer TOUTES Vias (pas les pistes)" -#: pcbnew/onrightclick.cpp:617 +#: pcbnew/onrightclick.cpp:583 msgid "Edit ALL Tracks (no via)" msgstr "Editer TOUTES Pistes (pas les vias)" -#: pcbnew/onrightclick.cpp:625 +#: pcbnew/onrightclick.cpp:591 msgid "Delete Via" msgstr "Suppression Via" -#: pcbnew/onrightclick.cpp:625 +#: pcbnew/onrightclick.cpp:591 msgid "Delete Segment" msgstr "SupprimerSegment" -#: pcbnew/onrightclick.cpp:632 +#: pcbnew/onrightclick.cpp:598 msgid "Delete Track" msgstr "Effacer Piste" -#: pcbnew/onrightclick.cpp:636 +#: pcbnew/onrightclick.cpp:602 msgid "Delete Net" msgstr "Supprimer Net" -#: pcbnew/onrightclick.cpp:641 +#: pcbnew/onrightclick.cpp:607 msgid "Set Flags" msgstr "Ajust. Flags" -#: pcbnew/onrightclick.cpp:642 +#: pcbnew/onrightclick.cpp:608 msgid "Locked: Yes" msgstr "Verrou: Oui" -#: pcbnew/onrightclick.cpp:643 +#: pcbnew/onrightclick.cpp:609 msgid "Locked: No" msgstr "Verrou: Non" -#: pcbnew/onrightclick.cpp:653 +#: pcbnew/onrightclick.cpp:619 msgid "Track Locked: Yes" msgstr "Piste verrouillée: Oui" -#: pcbnew/onrightclick.cpp:654 +#: pcbnew/onrightclick.cpp:620 msgid "Track Locked: No" msgstr "Piste verrouillée: Non" -#: pcbnew/onrightclick.cpp:656 +#: pcbnew/onrightclick.cpp:622 msgid "Net Locked: Yes" msgstr "Net verrouillé: Oui" -#: pcbnew/onrightclick.cpp:657 +#: pcbnew/onrightclick.cpp:623 msgid "Net Locked: No" msgstr "Net verrouillé: Non" -#: pcbnew/onrightclick.cpp:679 -#: pcbnew/onrightclick.cpp:724 -#: pcbnew/onrightclick.cpp:762 -#: pcbnew/onrightclick.cpp:821 +#: pcbnew/onrightclick.cpp:638 +msgid "Place Corner" +msgstr "Place Sommet" + +#: pcbnew/onrightclick.cpp:648 +msgid "Move Corner" +msgstr "Déplace Sommet" + +#: pcbnew/onrightclick.cpp:650 +msgid "Delete Corner" +msgstr "Supprimer Sommet" + +#: pcbnew/onrightclick.cpp:656 +msgid "Create Corner" +msgstr "Créer Sommet" + +#: pcbnew/onrightclick.cpp:661 +msgid "Add Similar Zone" +msgstr "Addition d'une Zone Semblable" + +#: pcbnew/onrightclick.cpp:664 +#, fuzzy +msgid "Add Cutout Area" +msgstr "Addition d'une Zone Interdite" + +#: pcbnew/onrightclick.cpp:668 +msgid "Fill Zone" +msgstr "Remplir Zone" + +#: pcbnew/onrightclick.cpp:671 +msgid "Edit Zone Params" +msgstr "Editer Paramčtres de la Zone" + +#: pcbnew/onrightclick.cpp:673 +msgid "Delete Zone Outline" +msgstr "Supprimer Contour de Zone" + +#: pcbnew/onrightclick.cpp:695 +#: pcbnew/onrightclick.cpp:740 +#: pcbnew/onrightclick.cpp:778 +#: pcbnew/onrightclick.cpp:837 msgid "Move" msgstr "Move" -#: pcbnew/onrightclick.cpp:682 -#: pcbnew/onrightclick.cpp:764 +#: pcbnew/onrightclick.cpp:698 +#: pcbnew/onrightclick.cpp:780 msgid "Drag" msgstr "Drag" -#: pcbnew/onrightclick.cpp:686 +#: pcbnew/onrightclick.cpp:702 msgid "Rotate +" msgstr "Rotation +" -#: pcbnew/onrightclick.cpp:690 +#: pcbnew/onrightclick.cpp:706 #: eeschema/onrightclick.cpp:301 msgid "Rotate -" msgstr "Rotation -" -#: pcbnew/onrightclick.cpp:691 +#: pcbnew/onrightclick.cpp:707 msgid "Flip" msgstr "Change côté" -#: pcbnew/onrightclick.cpp:781 +#: pcbnew/onrightclick.cpp:797 msgid "delete" msgstr "Effacer" -#: pcbnew/onrightclick.cpp:788 +#: pcbnew/onrightclick.cpp:804 msgid "Autoroute Pad" msgstr "Autoroute Pad" -#: pcbnew/onrightclick.cpp:789 +#: pcbnew/onrightclick.cpp:805 msgid "Autoroute Net" msgstr "Autoroute Net" @@ -3565,131 +3574,131 @@ msgstr "Le texte est la REFERENCE!" msgid "Text is VALUE!" msgstr "Le texte est la VALEUR!" -#: pcbnew/class_board_item.cpp:41 +#: pcbnew/class_board_item.cpp:40 #: eeschema/dialog_build_BOM.cpp:300 #: eeschema/component_class.cpp:56 #: eeschema/edit_component_in_schematic.cpp:826 msgid "Footprint" msgstr "Module" -#: pcbnew/class_board_item.cpp:47 +#: pcbnew/class_board_item.cpp:46 msgid "Pad" msgstr "Pad" -#: pcbnew/class_board_item.cpp:50 +#: pcbnew/class_board_item.cpp:49 msgid "all copper layers" msgstr "Toutes Couches Cuivre" -#: pcbnew/class_board_item.cpp:52 +#: pcbnew/class_board_item.cpp:51 msgid "copper layer" msgstr "Couche Cuivre" -#: pcbnew/class_board_item.cpp:54 +#: pcbnew/class_board_item.cpp:53 msgid "cmp layer" msgstr "Couche Cmp" -#: pcbnew/class_board_item.cpp:55 +#: pcbnew/class_board_item.cpp:54 msgid "???" msgstr "???" -#: pcbnew/class_board_item.cpp:56 +#: pcbnew/class_board_item.cpp:55 msgid ") of " msgstr ") de " -#: pcbnew/class_board_item.cpp:60 +#: pcbnew/class_board_item.cpp:59 msgid "Pcb Graphic" msgstr "Pcb Graphic" -#: pcbnew/class_board_item.cpp:60 -#: pcbnew/class_board_item.cpp:69 -#: pcbnew/class_board_item.cpp:146 -#: pcbnew/class_board_item.cpp:165 -#: pcbnew/class_board_item.cpp:181 -#: pcbnew/class_board_item.cpp:208 -#: pcbnew/class_board_item.cpp:225 -#: pcbnew/class_board_item.cpp:231 +#: pcbnew/class_board_item.cpp:59 +#: pcbnew/class_board_item.cpp:68 +#: pcbnew/class_board_item.cpp:145 +#: pcbnew/class_board_item.cpp:164 +#: pcbnew/class_board_item.cpp:180 +#: pcbnew/class_board_item.cpp:207 +#: pcbnew/class_board_item.cpp:224 +#: pcbnew/class_board_item.cpp:230 msgid " on " msgstr " sur " -#: pcbnew/class_board_item.cpp:64 +#: pcbnew/class_board_item.cpp:63 msgid "Pcb Text" msgstr "Texte Pcb" -#: pcbnew/class_board_item.cpp:80 -#: pcbnew/class_board_item.cpp:86 -#: pcbnew/class_board_item.cpp:130 +#: pcbnew/class_board_item.cpp:79 +#: pcbnew/class_board_item.cpp:85 +#: pcbnew/class_board_item.cpp:129 msgid " of " msgstr " de " -#: pcbnew/class_board_item.cpp:93 +#: pcbnew/class_board_item.cpp:92 msgid "Graphic" msgstr "Graphique" -#: pcbnew/class_board_item.cpp:102 +#: pcbnew/class_board_item.cpp:101 #: pcbnew/dialog_pad_edit.cpp:198 msgid "Rect" msgstr "Rect" -#: pcbnew/class_board_item.cpp:105 +#: pcbnew/class_board_item.cpp:104 msgid "Arc" msgstr "Arc" -#: pcbnew/class_board_item.cpp:140 +#: pcbnew/class_board_item.cpp:139 #: pcbnew/pcbframe.cpp:447 #: pcbnew/class_track.cpp:739 msgid "Track" msgstr "Piste" -#: pcbnew/class_board_item.cpp:147 +#: pcbnew/class_board_item.cpp:146 #: pcbnew/dialog_zones_by_polygon.cpp:220 msgid "Net:" msgstr "Net:" -#: pcbnew/class_board_item.cpp:148 +#: pcbnew/class_board_item.cpp:147 msgid "Length:" msgstr "Long.:" -#: pcbnew/class_board_item.cpp:153 +#: pcbnew/class_board_item.cpp:152 #: pcbnew/class_zone.cpp:385 msgid "Zone Outline" msgstr "Contour de Zone" -#: pcbnew/class_board_item.cpp:169 +#: pcbnew/class_board_item.cpp:168 #: pcbnew/class_track.cpp:743 msgid "Zone" msgstr "Zone" -#: pcbnew/class_board_item.cpp:187 +#: pcbnew/class_board_item.cpp:186 #: pcbnew/pcbframe.cpp:479 msgid "Via" msgstr "Via" -#: pcbnew/class_board_item.cpp:191 +#: pcbnew/class_board_item.cpp:190 msgid "Blind" msgstr "Enterrée" -#: pcbnew/class_board_item.cpp:193 +#: pcbnew/class_board_item.cpp:192 msgid "Buried" msgstr "Borgne" -#: pcbnew/class_board_item.cpp:215 +#: pcbnew/class_board_item.cpp:214 #: pcbnew/class_marker.cpp:112 msgid "Marker" msgstr "Marqueur" -#: pcbnew/class_board_item.cpp:220 +#: pcbnew/class_board_item.cpp:219 msgid "Dimension" msgstr "Dimension" -#: pcbnew/class_board_item.cpp:225 +#: pcbnew/class_board_item.cpp:224 msgid "Target" msgstr "Mire" -#: pcbnew/class_board_item.cpp:226 +#: pcbnew/class_board_item.cpp:225 msgid "size" msgstr "dimension" -#: pcbnew/class_board_item.cpp:231 +#: pcbnew/class_board_item.cpp:230 msgid "Edge Zone" msgstr "Contour Zone" @@ -3780,7 +3789,7 @@ msgid "Do not Show Zones" msgstr "Ne pas monter Zones" #: pcbnew/pcbframe.cpp:416 -#: pcbnew/tool_pcb.cpp:361 +#: pcbnew/tool_pcb.cpp:360 #: pcbnew/set_color.h:423 msgid "Show Zones" msgstr "Monter Zones" @@ -3806,7 +3815,7 @@ msgid "Normal Contrast Mode Display" msgstr "Mode d'affichage Contraste normal" #: pcbnew/pcbframe.cpp:437 -#: pcbnew/tool_pcb.cpp:374 +#: pcbnew/tool_pcb.cpp:373 msgid "Hight Contrast Mode Display" msgstr "Mode d'affichage Haut Contraste" @@ -3865,7 +3874,7 @@ msgstr "Pads" #: pcbnew/class_track.cpp:765 #: pcbnew/zones.cpp:873 -#: pcbnew/zones_by_polygon.cpp:612 +#: pcbnew/zones_by_polygon.cpp:705 #: pcbnew/class_zone.cpp:398 msgid "NetName" msgstr "NetName" @@ -4424,22 +4433,74 @@ msgid "Delete Current Zone Edges" msgstr "Effacer contour zone courant" #: pcbnew/zones.cpp:871 -#: pcbnew/zones_by_polygon.cpp:610 +#: pcbnew/zones_by_polygon.cpp:703 msgid "No Net" msgstr "No Net" -#: pcbnew/dsn.cpp:455 +#: pcbnew/dsn.cpp:456 msgid "Line length exceeded" msgstr "Longueur de ligne dépassée" -#: pcbnew/dsn.cpp:530 -msgid "String delimiter char must be a single char" -msgstr "Le caractčre de délimitation de ligne doit ętre un seul caractčre" +#: pcbnew/dsn.cpp:518 +msgid "'quoted text delimiter'" +msgstr "'delimiteur de texte balisé'" -#: pcbnew/dsn.cpp:590 +#: pcbnew/dsn.cpp:524 +msgid "'symbol'" +msgstr "'symbole'" + +#: pcbnew/dsn.cpp:527 +msgid "'number'" +msgstr "'nombre'" + +#: pcbnew/dsn.cpp:536 +msgid "\"quoted string\"" +msgstr "\"chaîne entre quotes\"" + +#: pcbnew/dsn.cpp:539 +msgid "'end of file'" +msgstr "fin de fichier'" + +#: pcbnew/dsn.cpp:556 +msgid "in file" +msgstr "dans le fichier" + +#: pcbnew/dsn.cpp:557 +msgid "on line" +msgstr "en ligne" + +#: pcbnew/dsn.cpp:558 +msgid "at offset" +msgstr "a l'offset" + +#: pcbnew/dsn.cpp:597 +msgid "String delimiter must be a single character of ', \", or $" +msgstr "Le caractčre de délimitation de ligne doit ętre un seul caractčre ', \", or $" + +#: pcbnew/dsn.cpp:676 msgid "Un-terminated delimited string" msgstr "Ligne délimitée non terminée" +#: pcbnew/specctra.cpp:271 +#: pcbnew/specctra.cpp:280 +msgid "Expecting" +msgstr "Attendu" + +#: pcbnew/specctra.cpp:300 +#, c-format +msgid "Unable to open file \"%s\"" +msgstr "Ne peut pas ouvrirle fichier \"%s\"" + +#: pcbnew/specctra.cpp:401 +#: pcbnew/specctra.cpp:467 +#: pcbnew/specctra.cpp:474 +msgid "on or off" +msgstr "on ou off" + +#: pcbnew/specctra.cpp:452 +msgid "testpoint, guides, or image_conductor" +msgstr "testpoint, guides, ou image_conductor" + #: pcbnew/move_or_drag_track.cpp:714 msgid "Unable to drag this segment: too many segments connected" msgstr "Impossible de drag ce segment: trop de segments connectés" @@ -4856,7 +4917,7 @@ msgstr "Module %s trouv msgid "Delete module?" msgstr "Effacer Module?" -#: pcbnew/tool_pcb.cpp:51 +#: pcbnew/tool_pcb.cpp:50 msgid "" "Show active layer selections\n" "and select layer pair for route and place via" @@ -4864,101 +4925,101 @@ msgstr "" "Affiche selections couche active\n" "et selection paire de couches pour routage and placement via" -#: pcbnew/tool_pcb.cpp:239 +#: pcbnew/tool_pcb.cpp:238 msgid "New Board" msgstr "Nouveau Circuit Imprimé" -#: pcbnew/tool_pcb.cpp:241 +#: pcbnew/tool_pcb.cpp:240 msgid "Open existing Board" msgstr "Ouvrir C.I. existant" -#: pcbnew/tool_pcb.cpp:242 +#: pcbnew/tool_pcb.cpp:241 msgid "Save Board" msgstr "Sauver Circuit Imprimé" -#: pcbnew/tool_pcb.cpp:246 +#: pcbnew/tool_pcb.cpp:245 #: eeschema/tool_sch.cpp:65 #: gerbview/tool_gerber.cpp:232 msgid "page settings (size, texts)" msgstr "Ajustage de la feuille de dessin (dimensions, textes)" -#: pcbnew/tool_pcb.cpp:250 +#: pcbnew/tool_pcb.cpp:249 msgid "Open Module Editor" msgstr "Ouvrir Editeur de modules" -#: pcbnew/tool_pcb.cpp:253 +#: pcbnew/tool_pcb.cpp:252 #: eeschema/tool_sch.cpp:81 #: gerbview/tool_gerber.cpp:243 msgid "Cut selected item" msgstr "Suppression des éléments sélectionnés" -#: pcbnew/tool_pcb.cpp:257 +#: pcbnew/tool_pcb.cpp:256 #: eeschema/tool_sch.cpp:84 #: gerbview/tool_gerber.cpp:248 msgid "Copy selected item" msgstr "Copie des éléments sélectionnés" -#: pcbnew/tool_pcb.cpp:259 +#: pcbnew/tool_pcb.cpp:258 #: eeschema/tool_sch.cpp:87 #: gerbview/tool_gerber.cpp:254 msgid "Paste" msgstr "Copie des éléments sauvegardés" -#: pcbnew/tool_pcb.cpp:262 +#: pcbnew/tool_pcb.cpp:261 #: gerbview/tool_gerber.cpp:261 msgid "Undelete" msgstr "Annulation du dernier effacement" -#: pcbnew/tool_pcb.cpp:265 +#: pcbnew/tool_pcb.cpp:264 msgid "Print Board" msgstr "Imprimer C.I." -#: pcbnew/tool_pcb.cpp:267 +#: pcbnew/tool_pcb.cpp:266 msgid "Plot (HPGL, PostScript, or GERBER format)" msgstr "Tracer en format HPGL, POSTSCRIPT ou GERBER" -#: pcbnew/tool_pcb.cpp:286 +#: pcbnew/tool_pcb.cpp:285 #: eeschema/tool_sch.cpp:125 msgid "Find components and texts" msgstr "Recherche de composants et textes" -#: pcbnew/tool_pcb.cpp:292 +#: pcbnew/tool_pcb.cpp:291 msgid "Read Netlist" msgstr "Lire Netliste" -#: pcbnew/tool_pcb.cpp:294 +#: pcbnew/tool_pcb.cpp:293 msgid "Pcb Design Rules Check" msgstr "Controle des rčgles de conception" -#: pcbnew/tool_pcb.cpp:305 +#: pcbnew/tool_pcb.cpp:304 msgid "Mode Module: Manual and Automatic Move or Place for modules" msgstr "Mode Module: Déplacements ou Placement Manuel ou Automatique des modules" -#: pcbnew/tool_pcb.cpp:308 +#: pcbnew/tool_pcb.cpp:307 msgid "Mode Track and Autorouting" msgstr "Mode Pistes and Autoroutage" -#: pcbnew/tool_pcb.cpp:332 +#: pcbnew/tool_pcb.cpp:331 msgid "Drc OFF" msgstr "Drc DESACTIVEE" -#: pcbnew/tool_pcb.cpp:349 +#: pcbnew/tool_pcb.cpp:348 msgid "Show General Ratsnest" msgstr "Monter le chevelu général" -#: pcbnew/tool_pcb.cpp:352 +#: pcbnew/tool_pcb.cpp:351 msgid "Show Module Ratsnest when moving" msgstr "Monter le chevelu du module pendant déplacement" -#: pcbnew/tool_pcb.cpp:357 +#: pcbnew/tool_pcb.cpp:356 msgid "Enable Auto Del Track" msgstr "Autoriser l'effacement automatique des pistes" -#: pcbnew/tool_pcb.cpp:370 +#: pcbnew/tool_pcb.cpp:369 msgid "Show Tracks Sketch" msgstr "Afficher pistes en contour" -#: pcbnew/tool_pcb.cpp:383 +#: pcbnew/tool_pcb.cpp:382 msgid "" "Display auxiliary vertical toolbar (tools for micro wave applications)\n" " This is a very experimental feature (under development)" @@ -4966,68 +5027,68 @@ msgstr "" "Affiche toolbar vertical auxiliaire (outils pour applications micro-ondes)\n" "C'est un outil expérimental (en cours de développement)" -#: pcbnew/tool_pcb.cpp:412 +#: pcbnew/tool_pcb.cpp:411 msgid "Net highlight" msgstr "Surbrillance des équipotentielles" -#: pcbnew/tool_pcb.cpp:416 +#: pcbnew/tool_pcb.cpp:415 msgid "Display local ratsnest (pad or module)" msgstr "Afficher le chevelu local (pastilles ou modules)" -#: pcbnew/tool_pcb.cpp:421 +#: pcbnew/tool_pcb.cpp:420 msgid "Add modules" msgstr "Addition de Modules" -#: pcbnew/tool_pcb.cpp:425 +#: pcbnew/tool_pcb.cpp:424 msgid "Add tracks and vias" msgstr "Ajouter pistes et vias" -#: pcbnew/tool_pcb.cpp:429 +#: pcbnew/tool_pcb.cpp:428 msgid "Add zones" msgstr "Addition de Zones" -#: pcbnew/tool_pcb.cpp:446 +#: pcbnew/tool_pcb.cpp:445 msgid "Add text" msgstr "Ajout de Texte" -#: pcbnew/tool_pcb.cpp:451 +#: pcbnew/tool_pcb.cpp:450 msgid "Add dimension" msgstr "Ajout des cotes" -#: pcbnew/tool_pcb.cpp:455 +#: pcbnew/tool_pcb.cpp:454 #: gerbview/tool_gerber.cpp:378 msgid "Add layer alignment target" msgstr "Ajouter Mire de superposition" -#: pcbnew/tool_pcb.cpp:465 +#: pcbnew/tool_pcb.cpp:464 msgid "Offset adjust for drill and place files" msgstr "Ajuste offset pour fichier de perçage et placement" -#: pcbnew/tool_pcb.cpp:490 +#: pcbnew/tool_pcb.cpp:489 msgid "Create line of specified length for microwave applications" msgstr "Creation de lignes de longueur spécifiée (pour applications micro-ondes)" -#: pcbnew/tool_pcb.cpp:496 +#: pcbnew/tool_pcb.cpp:495 msgid "Create gap of specified length for microwave applications" msgstr "Creation de gaps de longueur spécifiée (pour applications micro-ondes)" -#: pcbnew/tool_pcb.cpp:504 +#: pcbnew/tool_pcb.cpp:503 msgid "Create stub of specified length for microwave applications" msgstr "Creation de stub de longueur spécifiée (pour applications micro-ondes)" -#: pcbnew/tool_pcb.cpp:510 +#: pcbnew/tool_pcb.cpp:509 msgid "Create stub (arc) of specified length for microwave applications" msgstr "Creation de stub (arc) de longueur spécifiée (pour applications micro-ondes)" -#: pcbnew/tool_pcb.cpp:517 +#: pcbnew/tool_pcb.cpp:516 msgid "Create a polynomial shape for microwave applications" msgstr "Creation de formes polynomiales (pour applications micro-ondes)" -#: pcbnew/tool_pcb.cpp:571 +#: pcbnew/tool_pcb.cpp:570 msgid "Zoom " msgstr "Zoom " -#: pcbnew/tool_pcb.cpp:585 +#: pcbnew/tool_pcb.cpp:584 #: eeschema/eelayer.cpp:223 #: pcbnew/set_color.h:414 #: eeschema/eelayer.h:210 @@ -5035,7 +5096,7 @@ msgstr "Zoom " msgid "Grid" msgstr "Grille" -#: pcbnew/tool_pcb.cpp:676 +#: pcbnew/tool_pcb.cpp:675 msgid "+/- to switch" msgstr "+/- pour commuter" @@ -9330,10 +9391,6 @@ msgstr "Contour Pcb" msgid "--- " msgstr "--- " -#: common/gestfich.cpp:621 -msgid "No default editor found, you must choose it" -msgstr "Pas d'éditeur par défaut trouvé, vous devez en choisir un" - #: common/basicframe.cpp:216 #, c-format msgid "Help file %s not found" @@ -9453,6 +9510,10 @@ msgstr "Inversion Bloc" msgid "Block Mirror" msgstr "Bloc Miroir" +#: common/gestfich.cpp:621 +msgid "No default editor found, you must choose it" +msgstr "Pas d'éditeur par défaut trouvé, vous devez en choisir un" + #: common/confirm.cpp:106 msgid "Infos:" msgstr "Infos:" @@ -10010,18 +10071,6 @@ msgstr "Options de nettoyage" msgid "General Options" msgstr "Options générales" -#: pcbnew/dsn.h:595 -msgid "in file" -msgstr "dans le fichier" - -#: pcbnew/dsn.h:596 -msgid "on line" -msgstr "en ligne" - -#: pcbnew/dsn.h:597 -msgid "at offset" -msgstr "a l'offset" - #: pcbnew/set_color.h:38 msgid "Pcbnew Layer Colors:" msgstr "Pcbnew: Couleur desCouches" diff --git a/pcbnew/class_board.h b/pcbnew/class_board.h index 3b0b5d729b..1acd983a91 100644 --- a/pcbnew/class_board.h +++ b/pcbnew/class_board.h @@ -224,6 +224,123 @@ public: void Show( int nestLevel, std::ostream& os ); #endif + + /* Functions used in test, merge and cut outlines */ + /** + * Function AddArea + * add empty copper area to net + * @return pointer to the new area + */ + ZONE_CONTAINER* AddArea( int netcode, int layer, int x, int y, int hatch ); + + /** + * remove copper area from net + * @param area = area to remove + * @return 0 + */ + int RemoveArea( ZONE_CONTAINER* area_to_remove ); + + /** + * Function InsertArea + * add empty copper area to net, inserting after m_ZoneDescriptorList[iarea] + * @return pointer to the new area + */ + ZONE_CONTAINER* InsertArea( int netcode, int iarea, int layer, int x, int y, int hatch ); + + /** + Function CompleteArea + * complete copper area contour by adding a line from last to first corner + * if there is only 1 or 2 corners, remove (delete) the area + * @param area_to_complete = area to complete or remove + * @param style = style of last corner + * @return 1 if Ok, 0 if area removed + */ + int CompleteArea( ZONE_CONTAINER* area_to_complete, int style ); + + /** + * Function TestAreaPolygon + * Test an area for self-intersection. + * + * @param CurrArea = copper area to test + * @return : + * -1 if arcs intersect other sides + * 0 if no intersecting sides + * 1 if intersecting sides, but no intersecting arcs + * Also sets utility2 flag of area with return value + */ + int TestAreaPolygon( ZONE_CONTAINER* CurrArea ); + + /** + * Function ClipAreaPolygon + * Process an area that has been modified, by clipping its polygon against itself. + * This may change the number and order of copper areas in the net. + * @param bMessageBoxInt == TRUE, shows message when clipping occurs. + * @param bMessageBoxArc == TRUE, shows message when clipping can't be done due to arcs. + * @return: + * -1 if arcs intersect other sides, so polygon can't be clipped + * 0 if no intersecting sides + * 1 if intersecting sides + * Also sets areas->utility1 flags if areas are modified + */ + int ClipAreaPolygon( ZONE_CONTAINER* CurrArea, + bool bMessageBoxArc, bool bMessageBoxInt, bool bRetainArcs = TRUE ); + + /** + * Process an area that has been modified, by clipping its polygon against + * itself and the polygons for any other areas on the same net. + * This may change the number and order of copper areas in the net. + * @param modified_area = area to test + * @param bMessageBox : if TRUE, shows message boxes when clipping occurs. + * @return : + * -1 if arcs intersect other sides, so polygon can't be clipped + * 0 if no intersecting sides + * 1 if intersecting sides, polygon clipped + */ + int AreaPolygonModified( ZONE_CONTAINER* modified_area, + bool bMessageBoxArc, + bool bMessageBoxInt ); + + /** + * Function CombineAllAreasInNet + * Checks all copper areas in net for intersections, combining them if found + * @param aNetCode = net to consider + * @param bMessageBox : if true display warning message box + * @param bUseUtility : if true, don't check areas if both utility flags are 0 + * Sets utility flag = 1 for any areas modified + * If an area has self-intersecting arcs, doesn't try to combine it + */ + int CombineAllAreasInNet( int aNetCode, bool bMessageBox, bool bUseUtility ); + + /** + * Function TestAreaIntersections + * Check for intersection of a given copper area with other areas in same net + * @param area_to_test = area to compare to all other areas in the same net + */ + bool TestAreaIntersections( ZONE_CONTAINER* area_to_test ); + + /** + * Function TestAreaIntersection + * Test for intersection of 2 copper areas + * area_to_test must be after area_ref in m_ZoneDescriptorList + * @param area_ref = area reference + * @param area_to_test = area to compare for intersection calculations + * @return : 0 if no intersection + * 1 if intersection + * 2 if arcs intersect + */ + int TestAreaIntersection( ZONE_CONTAINER* area_ref, ZONE_CONTAINER* area_to_test ); + + /** + * Function CombineAreas + * If possible, combine 2 copper areas + * area_ref must be BEFORE area_to_combine + * area_to_combine will be deleted, if areas are combined + * @return : 0 if no intersection + * 1 if intersection + * 2 if arcs intersect + */ + int CombineAreas( ZONE_CONTAINER* area_ref, ZONE_CONTAINER* area_to_combine ); + }; #endif // #ifndef CLASS_BOARD_H diff --git a/pcbnew/class_zone.cpp b/pcbnew/class_zone.cpp index e82ee1bf8f..38483e3ed2 100644 --- a/pcbnew/class_zone.cpp +++ b/pcbnew/class_zone.cpp @@ -8,30 +8,9 @@ #include "gr_basic.h" #include "common.h" +#include "PolyLine.h" #include "pcbnew.h" -/************************/ -/* class ZONE_CONTAINER */ -/************************/ - -ZONE_CONTAINER::ZONE_CONTAINER( BOARD* parent ) : - BOARD_ITEM( parent, TYPEZONE_CONTAINER ) - , CPolyLine( NULL ) - -{ - m_NetCode = -1; // Net number for fast comparisons - m_CornerSelection = -1; - m_ZoneClearance = 200; // a reasonnable clerance value - m_GridFillValue = 50; // a reasonnable grid used for filling - m_PadOption = THERMAL_PAD; -} - - -ZONE_CONTAINER::~ZONE_CONTAINER() -{ -} - - /**********************/ /* Class EDGE_ZONE */ /**********************/ @@ -49,7 +28,6 @@ EDGE_ZONE:: ~EDGE_ZONE() { } - /****************************************/ bool EDGE_ZONE::Save( FILE* aFile ) const /****************************************/ @@ -57,6 +35,51 @@ bool EDGE_ZONE::Save( FILE* aFile ) const return true; } + +/************************/ +/* class ZONE_CONTAINER */ +/************************/ + +ZONE_CONTAINER::ZONE_CONTAINER( BOARD* parent ) : + BOARD_ITEM( parent, TYPEZONE_CONTAINER ) + +{ + m_NetCode = -1; // Net number for fast comparisons + m_CornerSelection = -1; + m_ZoneClearance = 200; // a reasonnable clerance value + m_GridFillValue = 50; // a reasonnable grid used for filling + m_PadOption = THERMAL_PAD; + utility = 0; // flags used in polygon calculations + utility2 = 0; // flags used in polygon calculations + m_Poly = new CPolyLine( NULL ); // Outlines + +} + + +ZONE_CONTAINER::~ZONE_CONTAINER() +{ + delete m_Poly; + m_Poly = NULL; +} + + +/*******************************************/ +void ZONE_CONTAINER::SetNet( int anet_code ) +/*******************************************/ +{ + m_NetCode = anet_code; + if ( m_Parent ) + { + EQUIPOT* net = ((BOARD*) m_Parent)->FindNet( g_HightLigth_NetCode ); + if( net ) + m_Netname = net->m_Netname; + else m_Netname.Empty(); + } + else m_Netname.Empty(); +} + + + /********************************************/ bool ZONE_CONTAINER::Save( FILE* aFile ) const /********************************************/ @@ -66,7 +89,7 @@ bool ZONE_CONTAINER::Save( FILE* aFile ) const unsigned item_pos; int ret; - unsigned corners_count = corner.size(); + unsigned corners_count = m_Poly->corner.size(); int outline_hatch; fprintf( aFile, "$CZONE_OUTLINE\n"); @@ -79,16 +102,16 @@ bool ZONE_CONTAINER::Save( FILE* aFile ) const ret = fprintf( aFile, "ZLayer %d\n", m_Layer ); if ( ret < 1 ) return false; // Save the ouline aux info - switch ( m_HatchStyle ) + switch ( m_Poly->GetHatchStyle() ) { default: - case NO_HATCH: + case CPolyLine::NO_HATCH: outline_hatch = 'N'; break; - case DIAGONAL_EDGE: + case CPolyLine::DIAGONAL_EDGE: outline_hatch = 'E'; break; - case DIAGONAL_FULL: + case CPolyLine::DIAGONAL_FULL: outline_hatch = 'F'; break; } @@ -99,8 +122,8 @@ bool ZONE_CONTAINER::Save( FILE* aFile ) const for ( item_pos = 0; item_pos < corners_count; item_pos++ ) { ret = fprintf( aFile, "ZCorner %d %d %d \n", - corner[item_pos].x, corner[item_pos].y, - corner[item_pos].end_contour ); + m_Poly->corner[item_pos].x, m_Poly->corner[item_pos].y, + m_Poly->corner[item_pos].end_contour ); if ( ret < 3 ) return false; } fprintf( aFile, "$endCZONE_OUTLINE\n"); @@ -122,7 +145,7 @@ int ZONE_CONTAINER::ReadDescr( FILE* aFile, int* aLineNum ) char netname_buffer[1024]; int ret; int n_corner_item = 0; - int outline_hatch = NO_HATCH; + int outline_hatch = CPolyLine::NO_HATCH; bool error = false, has_corner = false; netname_buffer[0] = 0; @@ -137,13 +160,13 @@ int ZONE_CONTAINER::ReadDescr( FILE* aFile, int* aLineNum ) else { if ( ! has_corner ) - Start( m_Layer, 0, 0, + m_Poly->Start( m_Layer, 0, 0, x, y, outline_hatch ); else - AppendCorner( x, y ); + m_Poly->AppendCorner( x, y ); has_corner = true; - if ( flag ) Close(); + if ( flag ) m_Poly->Close(); } } if( strnicmp(Line, "ZInfo", 5 ) == 0 ) // general info found @@ -182,15 +205,15 @@ int ZONE_CONTAINER::ReadDescr( FILE* aFile, int* aLineNum ) { case 'n': case 'N': - outline_hatch = NO_HATCH; + outline_hatch = CPolyLine::NO_HATCH; break; case 'e': case 'E': - outline_hatch = DIAGONAL_EDGE; + outline_hatch = CPolyLine::DIAGONAL_EDGE; break; case 'f': case 'F': - outline_hatch = DIAGONAL_FULL; + outline_hatch = CPolyLine::DIAGONAL_FULL; break; } } @@ -245,32 +268,32 @@ void ZONE_CONTAINER::Draw( WinEDA_DrawPanel* panel, wxDC* DC, const wxPoint& off // draw the lines int i_start_contour = 0; - for( unsigned ic = 0; ic < corner.size(); ic++ ) + for( unsigned ic = 0; ic < m_Poly->corner.size(); ic++ ) { - int xi = corner[ic].x + offset.x; - int yi = corner[ic].y + offset.y; + int xi = m_Poly->corner[ic].x + offset.x; + int yi = m_Poly->corner[ic].y + offset.y; int xf, yf; - if( corner[ic].end_contour == FALSE && ic < corner.size() - 1 ) + if( m_Poly->corner[ic].end_contour == FALSE && ic < m_Poly->corner.size() - 1 ) { - xf = corner[ic + 1].x + offset.x; - yf = corner[ic + 1].y + offset.y; + xf = m_Poly->corner[ic + 1].x + offset.x; + yf = m_Poly->corner[ic + 1].y + offset.y; } else { - xf = corner[i_start_contour].x + offset.x; - yf = corner[i_start_contour].y + offset.y; + xf = m_Poly->corner[i_start_contour].x + offset.x; + yf = m_Poly->corner[i_start_contour].y + offset.y; i_start_contour = ic + 1; } GRLine( &panel->m_ClipBox, DC, xi, yi, xf, yf, 0, color ); } // draw hatches - for( unsigned ic = 0; ic < m_HatchLines.size(); ic++ ) + for( unsigned ic = 0; ic < m_Poly->m_HatchLines.size(); ic++ ) { - int xi = m_HatchLines[ic].xi + offset.x; - int yi = m_HatchLines[ic].yi + offset.y; - int xf = m_HatchLines[ic].xf + offset.x; - int yf =m_HatchLines[ic].yf + offset.y; + int xi = m_Poly->m_HatchLines[ic].xi + offset.x; + int yi = m_Poly->m_HatchLines[ic].yi + offset.y; + int xf = m_Poly->m_HatchLines[ic].xf + offset.x; + int yf =m_Poly->m_HatchLines[ic].yf + offset.y; GRLine( &panel->m_ClipBox, DC, xi, yi, xf, yf, 0, color ); } @@ -307,7 +330,7 @@ int ZONE_CONTAINER::HitTestForCorner( const wxPoint& refPos ) #define MIN_DIST_IN_PIXELS 5 int dist; unsigned item_pos, lim; - lim = corner.size(); + lim = m_Poly->corner.size(); // Min distance to hit = MIN_DIST_IN_PIXELS pixels : WinEDA_BasePcbFrame* frame = ((BOARD*)GetParent())->m_PcbFrame; @@ -315,7 +338,7 @@ int ZONE_CONTAINER::HitTestForCorner( const wxPoint& refPos ) for ( item_pos = 0; item_pos < lim; item_pos++ ) { - dist = abs( corner[item_pos].x - refPos.x ) + abs( corner[item_pos].y - refPos.y ); + dist = abs( m_Poly->corner[item_pos].x - refPos.x ) + abs( m_Poly->corner[item_pos].y - refPos.y ); if( dist <= min_dist ) return item_pos; } @@ -335,7 +358,7 @@ int ZONE_CONTAINER::HitTestForEdge( const wxPoint& refPos ) #define MIN_DIST_IN_PIXELS 5 int dist; unsigned item_pos, lim; - lim = corner.size(); + lim = m_Poly->corner.size(); // Min distance to hit = MIN_DIST_IN_PIXELS pixels : WinEDA_BasePcbFrame* frame = ((BOARD*)GetParent())->m_PcbFrame; @@ -351,7 +374,7 @@ int ZONE_CONTAINER::HitTestForEdge( const wxPoint& refPos ) * the last segment of the current outline starts at current corner, and ends * at the first corner of the outline */ - if( corner[item_pos].end_contour || end_segm >= lim) + if( m_Poly->corner[item_pos].end_contour || end_segm >= lim) { unsigned tmp = first_corner_pos; first_corner_pos = end_segm; // first_corner_pos is now the beginning of the next outline @@ -361,10 +384,10 @@ int ZONE_CONTAINER::HitTestForEdge( const wxPoint& refPos ) /* test the dist between segment and ref point */ dist = (int) GetPointToLineSegmentDistance( refPos.x, refPos.y, - corner[item_pos].x, - corner[item_pos].y, - corner[end_segm].x, - corner[end_segm].y ); + m_Poly->corner[item_pos].x, + m_Poly->corner[item_pos].y, + m_Poly->corner[end_segm].x, + m_Poly->corner[end_segm].y ); if( dist <= min_dist ) return item_pos; } @@ -407,10 +430,10 @@ void ZONE_CONTAINER::Display_Infos( WinEDA_DrawFrame* frame ) Affiche_1_Parametre( frame, text_pos, _( "Layer" ), msg, BROWN ); text_pos += 8; - msg.Printf( wxT( "%d" ), corner.size() ); + msg.Printf( wxT( "%d" ), m_Poly->corner.size() ); Affiche_1_Parametre( frame, text_pos, _( "Corners" ), msg, BLUE ); text_pos += 8; - msg.Printf( wxT( "%d" ), m_HatchLines.size() ); + msg.Printf( wxT( "%d" ), m_Poly->m_HatchLines.size() ); Affiche_1_Parametre( frame, text_pos, _( "Hatch lines" ), msg, BLUE ); } diff --git a/pcbnew/class_zone.h b/pcbnew/class_zone.h index d1682ea2a9..1e22dbfd97 100644 --- a/pcbnew/class_zone.h +++ b/pcbnew/class_zone.h @@ -15,7 +15,7 @@ * others polygons inside this main polygon are holes. */ -class ZONE_CONTAINER : public BOARD_ITEM, public CPolyLine +class ZONE_CONTAINER : public BOARD_ITEM { public: enum m_PadInZone { // How pads are covered by copper in zone @@ -24,10 +24,12 @@ public: PAD_IN_ZONE // pads are covered by copper }; wxString m_Netname; // Net Name + CPolyLine * m_Poly; // outlines int m_CornerSelection; // For corner moving, corner index to drag, or -1 if no selection int m_ZoneClearance; // clearance value int m_GridFillValue; // Grid used for filling m_PadInZone m_PadOption; // see m_PadInZone + int utility, utility2; // flags used in polygon calculations private: int m_NetCode; // Net number for fast comparisons @@ -55,7 +57,7 @@ public: const wxPoint& offset, int draw_mode ); int GetNet( void ) { return m_NetCode; } - void SetNet( int anet_code ) { m_NetCode = anet_code; } + void SetNet( int anet_code ); /** * Function HitTest * tests if the given wxPoint is within the bounds of this object. @@ -90,7 +92,6 @@ public: * @return error level (0 = no error) */ int Fill_Zone( WinEDA_PcbFrame* frame, wxDC* DC, bool verbose = TRUE); - }; /*******************/ diff --git a/pcbnew/dialog_zones_by_polygon.cpp b/pcbnew/dialog_zones_by_polygon.cpp index 41d2db44e5..41db468485 100644 --- a/pcbnew/dialog_zones_by_polygon.cpp +++ b/pcbnew/dialog_zones_by_polygon.cpp @@ -281,7 +281,7 @@ void WinEDA_ZoneFrame::CreateControls() } if ( m_Zone_Container ) - s_Zone_Hatching = m_Zone_Container->GetHatch(); + s_Zone_Hatching = m_Zone_Container->m_Poly->GetHatchStyle(); switch( s_Zone_Hatching ) { case CPolyLine::NO_HATCH: diff --git a/pcbnew/edit.cpp b/pcbnew/edit.cpp index d69e194900..677afea236 100644 --- a/pcbnew/edit.cpp +++ b/pcbnew/edit.cpp @@ -450,11 +450,13 @@ void WinEDA_PcbFrame::Process_Special_Functions( wxCommandEvent& event ) break; case ID_POPUP_PCB_ZONE_ADD_SIMILAR_ZONE: - wxMessageBox(wxT("ToDo")); + DrawPanel->MouseToCursorSchema(); + Add_Similar_Zone( &dc, (ZONE_CONTAINER*) GetCurItem() ); break; case ID_POPUP_PCB_ZONE_ADD_CUTOUT_ZONE: - wxMessageBox(wxT("ToDo")); + DrawPanel->MouseToCursorSchema(); + Add_Zone_Cutout( &dc, (ZONE_CONTAINER*) GetCurItem() ); break; case ID_POPUP_PCB_DELETE_ZONE_CONTAINER: @@ -469,23 +471,9 @@ void WinEDA_PcbFrame::Process_Special_Functions( wxCommandEvent& event ) } case ID_POPUP_PCB_DELETE_ZONE_CORNER: - { - DrawPanel->MouseToCursorSchema(); - ZONE_CONTAINER * zone_cont = (ZONE_CONTAINER*)GetCurItem(); - zone_cont->Draw(DrawPanel,&dc, wxPoint(0,0), GR_XOR); - if ( zone_cont->GetNumCorners() <= 3 ) - { - Delete_Zone( &dc, NULL, zone_cont->m_TimeStamp ); - m_Pcb->Delete( zone_cont ); - } - else - { - zone_cont->DeleteCorner(zone_cont->m_CornerSelection); - zone_cont->Draw(DrawPanel,&dc, wxPoint(0,0), GR_XOR); - } + Remove_Zone_Corner( &dc, (ZONE_CONTAINER*)GetCurItem() ); SetCurItem( NULL ); break; - } case ID_POPUP_PCB_MOVE_ZONE_CORNER: { @@ -505,7 +493,7 @@ void WinEDA_PcbFrame::Process_Special_Functions( wxCommandEvent& event ) * and start move the new corner */ zone_cont->Draw(DrawPanel, &dc, wxPoint(0,0), GR_XOR); - zone_cont->InsertCorner( zone_cont->m_CornerSelection, pos.x, pos.y ); + zone_cont->m_Poly->InsertCorner( zone_cont->m_CornerSelection, pos.x, pos.y ); zone_cont->m_CornerSelection++; zone_cont->Draw(DrawPanel, &dc, wxPoint(0,0), GR_XOR); Start_Move_Zone_Corner(&dc, zone_cont, zone_cont->m_CornerSelection, true); diff --git a/pcbnew/makefile.include b/pcbnew/makefile.include index 65994031bf..6c184f38d7 100644 --- a/pcbnew/makefile.include +++ b/pcbnew/makefile.include @@ -10,8 +10,10 @@ LIBVIEWER3D = ../3d-viewer/3d-viewer.a ZONE_FILES = zones_by_polygon.o #ZONE_FILES = zones.o + OBJECTS= $(TARGET).o classpcb.o\ $(ZONE_FILES)\ + zones_test_and_combine_areas.o\ zone_filling_algorithm.o\ lay2plot.o\ modedit_undo_redo.o\ diff --git a/pcbnew/onrightclick.cpp b/pcbnew/onrightclick.cpp index fd934948ab..e860974626 100644 --- a/pcbnew/onrightclick.cpp +++ b/pcbnew/onrightclick.cpp @@ -658,10 +658,10 @@ void WinEDA_PcbFrame::createPopUpMenuForZones( ZONE_CONTAINER* edge_zone, wxMenu aPopMenu->AppendSeparator(); ADD_MENUITEM( aPopMenu, ID_POPUP_PCB_ZONE_ADD_SIMILAR_ZONE, - _( "Add Similar Zone" ), fill_zone_xpm ); + _( "Add Similar Zone" ), add_zone_xpm ); ADD_MENUITEM( aPopMenu, ID_POPUP_PCB_ZONE_ADD_CUTOUT_ZONE, - _( "Add Cutout Zone" ), add_zone_cutout ); + _( "Add Cutout Area" ), add_zone_cutout ); aPopMenu->AppendSeparator(); ADD_MENUITEM( aPopMenu, ID_POPUP_PCB_FILL_ZONE, diff --git a/pcbnew/zone_filling_algorithm.cpp b/pcbnew/zone_filling_algorithm.cpp index 07f45b43cc..5fdf426a9e 100644 --- a/pcbnew/zone_filling_algorithm.cpp +++ b/pcbnew/zone_filling_algorithm.cpp @@ -112,20 +112,20 @@ int ZONE_CONTAINER::Fill_Zone( WinEDA_PcbFrame* frame, wxDC* DC, bool verbose ) // trace the zone edges into the routing matrix int i_start_contour = 0; - for( unsigned ic = 0; ic < corner.size(); ic++ ) + for( unsigned ic = 0; ic < m_Poly->corner.size(); ic++ ) { - int xi = corner[ic].x - Pcb->m_BoundaryBox.m_Pos.x; - int yi = corner[ic].y - Pcb->m_BoundaryBox.m_Pos.y; + int xi = m_Poly->corner[ic].x - Pcb->m_BoundaryBox.m_Pos.x; + int yi = m_Poly->corner[ic].y - Pcb->m_BoundaryBox.m_Pos.y; int xf, yf; - if( corner[ic].end_contour == FALSE && ic < corner.size() - 1 ) + if( m_Poly->corner[ic].end_contour == FALSE && ic < m_Poly->corner.size() - 1 ) { - xf = corner[ic + 1].x - Pcb->m_BoundaryBox.m_Pos.x; - yf = corner[ic + 1].y - Pcb->m_BoundaryBox.m_Pos.y; + xf = m_Poly->corner[ic + 1].x - Pcb->m_BoundaryBox.m_Pos.x; + yf = m_Poly->corner[ic + 1].y - Pcb->m_BoundaryBox.m_Pos.y; } else { - xf = corner[i_start_contour].x - Pcb->m_BoundaryBox.m_Pos.x; - yf = corner[i_start_contour].y - Pcb->m_BoundaryBox.m_Pos.y; + xf = m_Poly->corner[i_start_contour].x - Pcb->m_BoundaryBox.m_Pos.x; + yf = m_Poly->corner[i_start_contour].y - Pcb->m_BoundaryBox.m_Pos.y; i_start_contour = ic + 1; } TraceLignePcb( xi, yi, xf, yf, -1, HOLE | CELL_is_EDGE, WRITE_CELL ); @@ -136,9 +136,8 @@ int ZONE_CONTAINER::Fill_Zone( WinEDA_PcbFrame* frame, wxDC* DC, bool verbose ) int cells_count = 0; for( ii = 0, pad = frame->m_Pcb->m_Pads; ii < frame->m_Pcb->m_NbPads; ii++, pad++ ) { - int icont = 0; wxPoint pos; - if( TestPointInsideContour( icont, (*pad)->m_Pos.x, (*pad)->m_Pos.y ) ) + if( m_Poly->TestPointInside( (*pad)->m_Pos.x, (*pad)->m_Pos.y ) ) { ZoneStartFill.x = ( (*pad)->m_Pos.x - Pcb->m_BoundaryBox.m_Pos.x + (g_GridRoutingSize / 2) ) / g_GridRoutingSize; @@ -196,20 +195,20 @@ int ZONE_CONTAINER::Fill_Zone( WinEDA_PcbFrame* frame, wxDC* DC, bool verbose ) /* Recreate zone limits on the routing matrix * (could be deleted by PlaceCells()) : */ i_start_contour = 0; - for( unsigned ic = 0; ic < corner.size(); ic++ ) + for( unsigned ic = 0; ic < m_Poly->corner.size(); ic++ ) { - int xi = corner[ic].x - Pcb->m_BoundaryBox.m_Pos.x; - int yi = corner[ic].y - Pcb->m_BoundaryBox.m_Pos.y; + int xi = m_Poly->corner[ic].x - Pcb->m_BoundaryBox.m_Pos.x; + int yi = m_Poly->corner[ic].y - Pcb->m_BoundaryBox.m_Pos.y; int xf, yf; - if( corner[ic].end_contour == FALSE && ic < corner.size() - 1 ) + if( m_Poly->corner[ic].end_contour == FALSE && ic < m_Poly->corner.size() - 1 ) { - xf = corner[ic + 1].x - Pcb->m_BoundaryBox.m_Pos.x; - yf = corner[ic + 1].y - Pcb->m_BoundaryBox.m_Pos.y; + xf = m_Poly->corner[ic + 1].x - Pcb->m_BoundaryBox.m_Pos.x; + yf = m_Poly->corner[ic + 1].y - Pcb->m_BoundaryBox.m_Pos.y; } else { - xf = corner[i_start_contour].x - Pcb->m_BoundaryBox.m_Pos.x; - yf = corner[i_start_contour].y - Pcb->m_BoundaryBox.m_Pos.y; + xf = m_Poly->corner[i_start_contour].x - Pcb->m_BoundaryBox.m_Pos.x; + yf = m_Poly->corner[i_start_contour].y - Pcb->m_BoundaryBox.m_Pos.y; i_start_contour = ic + 1; } TraceLignePcb( xi, yi, xf, yf, -1, HOLE | CELL_is_EDGE, WRITE_CELL ); @@ -219,9 +218,8 @@ int ZONE_CONTAINER::Fill_Zone( WinEDA_PcbFrame* frame, wxDC* DC, bool verbose ) * (could be deleted by PlaceCells()) : */ for( ii = 0, pad = frame->m_Pcb->m_Pads; ii < frame->m_Pcb->m_NbPads; ii++, pad++ ) { - int icont = 0; wxPoint pos; - if( TestPointInsideContour( icont, (*pad)->m_Pos.x, (*pad)->m_Pos.y ) ) + if( m_Poly->TestPointInside( (*pad)->m_Pos.x, (*pad)->m_Pos.y ) ) { ZoneStartFill.x = ( (*pad)->m_Pos.x - Pcb->m_BoundaryBox.m_Pos.x + (g_GridRoutingSize / 2) ) / g_GridRoutingSize; diff --git a/pcbnew/zones_by_polygon.cpp b/pcbnew/zones_by_polygon.cpp index baff23a8b7..a17bf2d5ec 100644 --- a/pcbnew/zones_by_polygon.cpp +++ b/pcbnew/zones_by_polygon.cpp @@ -27,10 +27,9 @@ using namespace std; #include "common.h" #include "pcbnew.h" - #include "autorout.h" -#include "cell.h" -#include "trigo.h" + +#include "id.h" #include "protos.h" @@ -45,13 +44,15 @@ static void Abort_Zone_Move_Corner( WinEDA_DrawPanel* Panel, wxDC* DC ); static void Show_Zone_Corner_While_Move_Mouse( WinEDA_DrawPanel* panel, wxDC* DC, bool erase ); /* Local variables */ -static bool Zone_45_Only = FALSE; +static bool Zone_45_Only = FALSE; static ZONE_CONTAINER::m_PadInZone s_Zone_Pad_Options = ZONE_CONTAINER::THERMAL_PAD; -static int s_Zone_Layer; // Layer used to create the current zone -static int s_Zone_Hatching; // Option to show the zone area (outlines only, short hatches or full hatches -static int s_NetcodeSelection; // Net code selection for the current zone -static wxPoint s_CornerInitialPosition; // Used to abort a move corner command -static bool s_CornerIsNew; // Used to abort a move corner command (if it is a new corner, it must be deleted) +static int s_Zone_Layer; // Layer used to create the current zone +static int s_Zone_Hatching; // Option to show the zone area (outlines only, short hatches or full hatches +static int s_NetcodeSelection; // Net code selection for the current zone +static wxPoint s_CornerInitialPosition; // Used to abort a move corner command +static bool s_CornerIsNew; // Used to abort a move corner command (if it is a new corner, it must be deleted) +static bool s_AddCutoutToCurrentZone; // if true, the next outline will be addes to s_CurrentZone +static ZONE_CONTAINER* s_CurrentZone; // if != NULL, these ZONE_CONTAINER params will be used for the next zone // key used to store net sort option in config file : #define ZONE_NET_SORT_OPTION_KEY wxT( "Zone_NetSort_Opt" ) @@ -63,6 +64,44 @@ enum zone_cmd { #include "dialog_zones_by_polygon.cpp" +/**********************************************************************************/ +void WinEDA_PcbFrame::Add_Similar_Zone( wxDC* DC, ZONE_CONTAINER* zone_container ) +/**********************************************************************************/ + +/** + * Function Add_Similar_Zone + * Add a zone to a given zone outline. + * if the zones are overlappeing they will be merged + * @param DC = current Device Context + * @param zone_container = parent zone outline + */ +{ + s_AddCutoutToCurrentZone = false; + s_CurrentZone = zone_container; + wxCommandEvent evt; + evt.SetId( ID_PCB_ZONES_BUTT ); + Process_Special_Functions( evt ); +} + + +/**********************************************************************************/ +void WinEDA_PcbFrame::Add_Zone_Cutout( wxDC* DC, ZONE_CONTAINER* zone_container ) +/**********************************************************************************/ + +/** + * Function Add_Zone_Cutout + * Add a cutout zone to a given zone outline + * @param DC = current Device Context + * @param zone_container = parent zone outline + */ +{ + s_AddCutoutToCurrentZone = true; + s_CurrentZone = zone_container; + wxCommandEvent evt; + evt.SetId( ID_PCB_ZONES_BUTT ); + Process_Special_Functions( evt ); +} + /*****************************************************************************/ void WinEDA_PcbFrame::Delete_Zone( wxDC* DC, SEGZONE* aZone, long aTimestamp ) @@ -174,6 +213,8 @@ static void Abort_Zone_Create_Outline( WinEDA_DrawPanel* Panel, wxDC* DC ) Panel->ManageCurseur = NULL; Panel->ForceCloseManageCurseur = NULL; pcbframe->SetCurItem( NULL ); + s_AddCutoutToCurrentZone = false; + s_CurrentZone = NULL; } @@ -228,9 +269,11 @@ void WinEDA_PcbFrame::Start_Move_Zone_Corner( wxDC* DC, ZONE_CONTAINER* zone_con zone_container->m_Flags = IN_EDIT; DrawPanel->ManageCurseur = Show_Zone_Corner_While_Move_Mouse; DrawPanel->ForceCloseManageCurseur = Abort_Zone_Move_Corner; - s_CornerInitialPosition.x = zone_container->GetX( corner_id ); - s_CornerInitialPosition.y = zone_container->GetY( corner_id ); + s_CornerInitialPosition.x = zone_container->m_Poly->GetX( corner_id ); + s_CornerInitialPosition.y = zone_container->m_Poly->GetY( corner_id ); s_CornerIsNew = IsNewCorner; + s_AddCutoutToCurrentZone = false; + s_CurrentZone = NULL; } @@ -248,6 +291,72 @@ void WinEDA_PcbFrame::End_Move_Zone_Corner( wxDC* DC, ZONE_CONTAINER* zone_conta DrawPanel->ForceCloseManageCurseur = NULL; zone_container->Draw( DrawPanel, DC, wxPoint( 0, 0 ), GR_OR ); GetScreen()->SetModify(); + s_AddCutoutToCurrentZone = false; + s_CurrentZone = NULL; + + SetCurItem( NULL ); // This outine can be deleted when merging outlines + + /* Combine zones if possible */ + int layer = zone_container->GetLayer(); + + for( unsigned ii = 0; ii < m_Pcb->m_ZoneDescriptorList.size(); ii++ ) + { + ZONE_CONTAINER* edge_zone = m_Pcb->m_ZoneDescriptorList[ii]; + if( layer == edge_zone->GetLayer() ) + edge_zone->Draw( DrawPanel, DC, wxPoint( 0, 0 ), GR_XOR ); + } + + m_Pcb->AreaPolygonModified( zone_container, true, false ); + for( unsigned ii = 0; ii < m_Pcb->m_ZoneDescriptorList.size(); ii++ ) + { + ZONE_CONTAINER* edge_zone = m_Pcb->m_ZoneDescriptorList[ii]; + if( layer == edge_zone->GetLayer() ) + edge_zone->Draw( DrawPanel, DC, wxPoint( 0, 0 ), GR_OR ); + } +} + + +/*************************************************************************************/ +void WinEDA_PcbFrame::Remove_Zone_Corner( wxDC* DC, ZONE_CONTAINER * zone_container ) +/*************************************************************************************/ +/** + * Function End_Move_Zone_Corner + * Remove the currently selected corner in a zone outline + * the .m_CornerSelection is used as corner selection + */ +{ + if ( zone_container->m_Poly->GetNumCorners() <= 3 ) + { + Delete_Zone( DC, NULL, zone_container->m_TimeStamp ); + m_Pcb->Delete( zone_container ); + return; + } + + int layer = zone_container->GetLayer(); + + if ( DC ) + { + for( unsigned ii = 0; ii < m_Pcb->m_ZoneDescriptorList.size(); ii++ ) + { + ZONE_CONTAINER* edge_zone = m_Pcb->m_ZoneDescriptorList[ii]; + if( layer == edge_zone->GetLayer() ) + edge_zone->Draw( DrawPanel, DC, wxPoint( 0, 0 ), GR_XOR ); + } + } + + zone_container->m_Poly->DeleteCorner(zone_container->m_CornerSelection); + + // modify zones outlines accordiing to the new zone_container shape + m_Pcb->AreaPolygonModified( zone_container, true, false ); + if ( DC ) + { + for( unsigned ii = 0; ii < m_Pcb->m_ZoneDescriptorList.size(); ii++ ) + { + ZONE_CONTAINER* edge_zone = m_Pcb->m_ZoneDescriptorList[ii]; + if( layer == edge_zone->GetLayer() ) + edge_zone->Draw( DrawPanel, DC, wxPoint( 0, 0 ), GR_OR ); + } + } } @@ -267,19 +376,21 @@ void Abort_Zone_Move_Corner( WinEDA_DrawPanel* Panel, wxDC* DC ) if( s_CornerIsNew ) { - zone_container->DeleteCorner( zone_container->m_CornerSelection ); + zone_container->m_Poly->DeleteCorner( zone_container->m_CornerSelection ); } else { wxPoint pos = s_CornerInitialPosition; - zone_container->MoveCorner( zone_container->m_CornerSelection, pos.x, pos.y ); + zone_container->m_Poly->MoveCorner( zone_container->m_CornerSelection, pos.x, pos.y ); } zone_container->Draw( Panel, DC, wxPoint( 0, 0 ), GR_XOR ); Panel->ManageCurseur = NULL; Panel->ForceCloseManageCurseur = NULL; pcbframe->SetCurItem( NULL ); - zone_container->m_Flags = 0; + zone_container->m_Flags = 0; + s_AddCutoutToCurrentZone = false; + s_CurrentZone = NULL; } @@ -299,7 +410,7 @@ void Show_Zone_Corner_While_Move_Mouse( WinEDA_DrawPanel* Panel, wxDC* DC, bool } wxPoint pos = pcbframe->GetScreen()->m_Curseur; - zone_container->MoveCorner( zone_container->m_CornerSelection, pos.x, pos.y ); + zone_container->m_Poly->MoveCorner( zone_container->m_CornerSelection, pos.x, pos.y ); zone_container->Draw( Panel, DC, wxPoint( 0, 0 ), GR_XOR ); } @@ -317,36 +428,61 @@ EDGE_ZONE* WinEDA_PcbFrame::Begin_Zone( wxDC* DC ) EDGE_ZONE* oldedge; EDGE_ZONE* newedge = NULL; + // verify if s_CurrentZone exists: + unsigned ii; + + for( ii = 0; ii < m_Pcb->m_ZoneDescriptorList.size(); ii++ ) + { + if( s_CurrentZone == m_Pcb->m_ZoneDescriptorList[ii] ) + break; + } + + if( ii == m_Pcb->m_ZoneDescriptorList.size() ) // Not found: coul be deleted since last selection + { + s_AddCutoutToCurrentZone = false; + s_CurrentZone = NULL; + } + oldedge = m_Pcb->m_CurrentLimitZone; if( m_Pcb->m_CurrentLimitZone == NULL ) /* Start a new contour: init zone params (net and layer) */ { - DrawPanel->m_IgnoreMouseEvents = TRUE; - WinEDA_ZoneFrame* frame = new WinEDA_ZoneFrame( this ); + if( s_CurrentZone == NULL ) + { + DrawPanel->m_IgnoreMouseEvents = TRUE; + WinEDA_ZoneFrame* frame = new WinEDA_ZoneFrame( this ); - int diag = frame->ShowModal(); - frame->Destroy(); - DrawPanel->MouseToCursorSchema(); - DrawPanel->m_IgnoreMouseEvents = FALSE; - - if( diag == ZONE_ABORT ) - return NULL; - - GetScreen()->m_Active_Layer = s_Zone_Layer; + int diag = frame->ShowModal(); + frame->Destroy(); + DrawPanel->MouseToCursorSchema(); + DrawPanel->m_IgnoreMouseEvents = FALSE; + if( diag == ZONE_ABORT ) + return NULL; + } + else /* Start a new contour: init zone params (net and layer) from an existing zone */ + { + GetScreen()->m_Active_Layer = s_Zone_Layer = s_CurrentZone->GetLayer(); + s_Zone_Hatching = s_CurrentZone->m_Poly->GetHatchStyle(); + } /* Show the Net */ if( (g_HightLigth_NetCode > 0) && (g_HightLigth_NetCode != s_NetcodeSelection) ) { Hight_Light( DC ); // Remove old hightlight selection } + if( s_CurrentZone ) + s_NetcodeSelection = s_CurrentZone->GetNet(); g_HightLigth_NetCode = s_NetcodeSelection; if( !g_HightLigt_Status ) Hight_Light( DC ); + + if( !s_AddCutoutToCurrentZone ) + s_CurrentZone = NULL; // the zone is used only once } // if first segment - if( (m_Pcb->m_CurrentLimitZone == NULL ) /* Initial startt of a new outline */ + if( (m_Pcb->m_CurrentLimitZone == NULL ) /* Initial start of a new outline */ || (DrawPanel->ManageCurseur == NULL) ) /* reprise d'un trace complementaire */ { newedge = new EDGE_ZONE( m_Pcb ); @@ -400,6 +536,7 @@ void WinEDA_PcbFrame::End_Zone( wxDC* DC ) */ { EDGE_ZONE* edge; + int layer = GetScreen()->m_Active_Layer; if( m_Pcb->m_CurrentLimitZone ) { @@ -431,39 +568,74 @@ void WinEDA_PcbFrame::End_Zone( wxDC* DC ) DrawPanel->ManageCurseur = NULL; DrawPanel->ForceCloseManageCurseur = NULL; - /* Put edges in list */ - ZONE_CONTAINER* polygon = new ZONE_CONTAINER( m_Pcb ); - polygon->SetLayer( GetScreen()->m_Active_Layer ); - polygon->SetNet( g_HightLigth_NetCode ); - polygon->m_TimeStamp = GetTimeStamp(); - - EQUIPOT* net = m_Pcb->FindNet( g_HightLigth_NetCode ); - if( net ) - polygon->m_Netname = net->m_Netname; - edge = m_Pcb->m_CurrentLimitZone; - polygon->Start( GetScreen()->m_Active_Layer, 0, 0, - edge->m_Start.x, edge->m_Start.y, - s_Zone_Hatching ); - edge = edge->Next(); - while( edge ) + // Undraw old drawings, because they can have important changes + for( unsigned ii = 0; ii < m_Pcb->m_ZoneDescriptorList.size(); ii++ ) { - polygon->AppendCorner( edge->m_Start.x, edge->m_Start.y ); - edge = edge->Next(); + ZONE_CONTAINER* edge_zone = m_Pcb->m_ZoneDescriptorList[ii]; + if( layer == edge_zone->GetLayer() ) + edge_zone->Draw( DrawPanel, DC, wxPoint( 0, 0 ), GR_XOR ); } - polygon->Close(); // Close the current corner list - polygon->SetHatch( s_Zone_Hatching ); - polygon->m_PadOption = s_Zone_Pad_Options; - polygon->m_ZoneClearance = g_DesignSettings.m_ZoneClearence; - polygon->m_GridFillValue = g_GridRoutingSize; + /* Put edges in list */ + ZONE_CONTAINER* new_zone_container; + if( s_CurrentZone == NULL ) + { + new_zone_container = new ZONE_CONTAINER( m_Pcb ); + new_zone_container->SetLayer( layer ); + new_zone_container->SetNet( g_HightLigth_NetCode ); + new_zone_container->m_TimeStamp = GetTimeStamp(); - m_Pcb->m_ZoneDescriptorList.push_back( polygon ); + edge = m_Pcb->m_CurrentLimitZone; + new_zone_container->m_Poly->Start( layer, 0, 0, + edge->m_Start.x, edge->m_Start.y, + s_Zone_Hatching ); + edge = edge->Next(); + while( edge ) + { + new_zone_container->m_Poly->AppendCorner( edge->m_Start.x, edge->m_Start.y ); + edge = edge->Next(); + } + + new_zone_container->m_Poly->Close(); // Close the current corner list + new_zone_container->m_Poly->SetHatch( s_Zone_Hatching ); + new_zone_container->m_PadOption = s_Zone_Pad_Options; + new_zone_container->m_ZoneClearance = g_DesignSettings.m_ZoneClearence; + new_zone_container->m_GridFillValue = g_GridRoutingSize; + + m_Pcb->m_ZoneDescriptorList.push_back( new_zone_container ); + } + else // Append this outline as a cutout to an existing zone + { + new_zone_container = s_CurrentZone; + edge = m_Pcb->m_CurrentLimitZone; + while( edge ) + { + new_zone_container->m_Poly->AppendCorner( edge->m_Start.x, edge->m_Start.y ); + edge = edge->Next(); + } + + new_zone_container->m_Poly->Close(); // Close the current corner list + } + + s_AddCutoutToCurrentZone = false; + s_CurrentZone = NULL; /* Remove the current temporary list */ DelLimitesZone( DC, TRUE ); - /* Redraw the real edge zone */ - polygon->Draw( DrawPanel, DC, wxPoint( 0, 0 ), GR_OR ); + new_zone_container->m_Flags = 0; + SetCurItem( NULL ); // This outine can be deleted when merging outlines + + // Combine zones if possible : + m_Pcb->AreaPolygonModified( new_zone_container, true, false ); + + // Redraw the real edge zone : + for( unsigned ii = 0; ii < m_Pcb->m_ZoneDescriptorList.size(); ii++ ) + { + ZONE_CONTAINER* edge_zone = m_Pcb->m_ZoneDescriptorList[ii]; + if( layer == edge_zone->GetLayer() ) + edge_zone->Draw( DrawPanel, DC, wxPoint( 0, 0 ), GR_OR ); + } GetScreen()->SetModify(); } @@ -540,19 +712,32 @@ void WinEDA_PcbFrame::Edit_Zone_Params( wxDC* DC, ZONE_CONTAINER* zone_container if( diag == ZONE_ABORT ) return; - zone_container->Draw( DrawPanel, DC, wxPoint( 0, 0 ), GR_XOR ); + // Undraw old zone outlines + for( unsigned ii = 0; ii < m_Pcb->m_ZoneDescriptorList.size(); ii++ ) + { + ZONE_CONTAINER* edge_zone = m_Pcb->m_ZoneDescriptorList[ii]; + edge_zone->Draw( DrawPanel, DC, wxPoint( 0, 0 ), GR_XOR ); + } zone_container->SetLayer( s_Zone_Layer ); zone_container->SetNet( s_NetcodeSelection ); EQUIPOT* net = m_Pcb->FindNet( s_NetcodeSelection ); if( net ) zone_container->m_Netname = net->m_Netname; - zone_container->SetHatch( s_Zone_Hatching ); + zone_container->m_Poly->SetHatch( s_Zone_Hatching ); zone_container->m_PadOption = s_Zone_Pad_Options; zone_container->m_ZoneClearance = g_DesignSettings.m_ZoneClearence; zone_container->m_GridFillValue = g_GridRoutingSize; - zone_container->Draw( DrawPanel, DC, wxPoint( 0, 0 ), GR_OR ); + // Combine zones if possible : + m_Pcb->AreaPolygonModified( zone_container, true, false ); + + // Redraw the real new zone outlines: + for( unsigned ii = 0; ii < m_Pcb->m_ZoneDescriptorList.size(); ii++ ) + { + ZONE_CONTAINER* edge_zone = m_Pcb->m_ZoneDescriptorList[ii]; + edge_zone->Draw( DrawPanel, DC, wxPoint( 0, 0 ), GR_OR ); + } GetScreen()->SetModify(); } @@ -587,11 +772,11 @@ int WinEDA_PcbFrame::Fill_Zone( wxDC* DC, ZONE_CONTAINER* zone_container, bool v s_NetcodeSelection = zone_container->GetNet(); if( (g_HightLigth_NetCode > 0) && (g_HightLigth_NetCode != s_NetcodeSelection) && DC ) { - Hight_Light( DC ); // Remove old hightlight selection + Hight_Light( DC ); // Remove old hightlight selection } g_HightLigth_NetCode = s_NetcodeSelection; - if( !g_HightLigt_Status && DC) + if( !g_HightLigt_Status && DC ) Hight_Light( DC ); if( g_HightLigth_NetCode > 0 ) @@ -613,7 +798,7 @@ int WinEDA_PcbFrame::Fill_Zone( wxDC* DC, ZONE_CONTAINER* zone_container, bool v msg = _( "No Net" ); Affiche_1_Parametre( this, 22, _( "NetName" ), msg, RED ); - wxBusyCursor dummy; // Shows an hourglass cursor (removed by its destructor) + wxBusyCursor dummy; // Shows an hourglass cursor (removed by its destructor) zone_container->m_PadOption = s_Zone_Pad_Options; zone_container->m_ZoneClearance = g_DesignSettings.m_ZoneClearence; zone_container->m_GridFillValue = g_GridRoutingSize; @@ -641,22 +826,22 @@ int WinEDA_PcbFrame::Fill_All_Zones( wxDC* DC, bool verbose ) ZONE_CONTAINER* zone_container; int error_level = 0; - // Remove all zones : - if ( m_Pcb->m_Zone ) - { - m_Pcb->m_Zone->DeleteStructList(); - m_Pcb->m_Zone = NULL; - m_Pcb->m_NbSegmZone = 0; - } + // Remove all zones : + if( m_Pcb->m_Zone ) + { + m_Pcb->m_Zone->DeleteStructList(); + m_Pcb->m_Zone = NULL; + m_Pcb->m_NbSegmZone = 0; + } for( unsigned ii = 0; ii < m_Pcb->m_ZoneDescriptorList.size(); ii++ ) { zone_container = m_Pcb->m_ZoneDescriptorList[ii]; error_level = Fill_Zone( NULL, zone_container, verbose ); - if( error_level && ! verbose ) + if( error_level && !verbose ) break; } - DrawPanel->Refresh(true); + DrawPanel->Refresh( true ); return error_level; } diff --git a/pcbnew/zones_test_and_combine_areas.cpp b/pcbnew/zones_test_and_combine_areas.cpp new file mode 100644 index 0000000000..35e3bcef6d --- /dev/null +++ b/pcbnew/zones_test_and_combine_areas.cpp @@ -0,0 +1,975 @@ +/****************************************************************************/ +/* functions to test, merges and cut polygons used as copper areas outlines */ +/****************************************************************************/ + +#include + +#include "fctsys.h" + +#include "common.h" +#include "pcbnew.h" + +using namespace std; + +#undef ASSERT +#define ASSERT wxASSERT + +bool bDontShowSelfIntersectionArcsWarning; +bool bDontShowSelfIntersectionWarning; +bool bDontShowIntersectionArcsWarning; +bool bDontShowIntersectionWarning; + + +#define poly m_Poly + +// carea: describes a copper area +#define carea ZONE_CONTAINER + + +/** + * Function AddArea + * add empty copper area to net + * @return pointer to the new area + */ +ZONE_CONTAINER* BOARD::AddArea( int netcode, int layer, int x, int y, int hatch ) +{ + ZONE_CONTAINER* new_area = InsertArea( netcode, m_ZoneDescriptorList.size( + ) - 1, layer, x, y, hatch ); + + return new_area; +} + + +/** + * remove copper area from net + * @param area = area to remove + * @return 0 + */ +int BOARD::RemoveArea( ZONE_CONTAINER* area_to_remove ) +{ + Delete( area_to_remove ); + return 0; +} + + +/** + * Function InsertArea + * add empty copper area to net, inserting after m_ZoneDescriptorList[iarea] + * @return pointer to the new area + */ +ZONE_CONTAINER* BOARD::InsertArea( int netcode, int iarea, int layer, int x, int y, int hatch ) +{ + ZONE_CONTAINER* new_area = new ZONE_CONTAINER( this ); + + new_area->SetNet( netcode ); + new_area->SetLayer( layer ); + new_area->m_TimeStamp = GetTimeStamp(); + if( iarea < (int) ( m_ZoneDescriptorList.size() - 1) ) + m_ZoneDescriptorList.insert( m_ZoneDescriptorList.begin() + iarea + 1, new_area ); + else + m_ZoneDescriptorList.push_back( new_area ); + + new_area->poly->Start( layer, 1, 10 * NM_PER_MIL, x, y, + hatch ); + return new_area; +} + + +/** + * Function CompleteArea + * complete copper area contour by adding a line from last to first corner + * if there is only 1 or 2 corners, remove (delete) the area + * @param area_to_complete = area to complete or remove + * @param style = style of last corner + * @return 1 if Ok, 0 if area removed + */ +int BOARD::CompleteArea( ZONE_CONTAINER* area_to_complete, int style ) +{ + if( area_to_complete->poly->GetNumCorners() > 2 ) + { + area_to_complete->poly->Close( style ); + return 1; + } + else + { + RemoveArea( area_to_complete ); + } + return 0; +} + + +/** + * Function TestAreaPolygon + * Test an area for self-intersection. + * + * @param CurrArea = copper area to test + * @return : + * -1 if arcs intersect other sides + * 0 if no intersecting sides + * 1 if intersecting sides, but no intersecting arcs + * Also sets utility2 flag of area with return value + */ +int BOARD::TestAreaPolygon( ZONE_CONTAINER* CurrArea ) +{ + CPolyLine* p = CurrArea->poly; + + // first, check for sides intersecting other sides, especially arcs + bool bInt = false; + bool bArcInt = false; + int n_cont = p->GetNumContours(); + + // make bounding rect for each contour + std::vector cr; + cr.reserve( n_cont ); + for( int icont = 0; icontGetCornerBounds( icont ) ); + + for( int icont = 0; icontGetContourStart( icont ); + int is_end = p->GetContourEnd( icont ); + for( int is = is_start; is<=is_end; is++ ) + { + int is_prev = is - 1; + if( is_prev < is_start ) + is_prev = is_end; + int is_next = is + 1; + if( is_next > is_end ) + is_next = is_start; + int style = p->GetSideStyle( is ); + int x1i = p->GetX( is ); + int y1i = p->GetY( is ); + int x1f = p->GetX( is_next ); + int y1f = p->GetY( is_next ); + + // check for intersection with any other sides + for( int icont2 = icont; icont2 cr[icont2].right + || cr[icont].bottom > cr[icont2].top + || cr[icont2].left > cr[icont].right + || cr[icont2].bottom > cr[icont].top ) + { + // rectangles don't overlap, do nothing + } + else + { + int is2_start = p->GetContourStart( icont2 ); + int is2_end = p->GetContourEnd( icont2 ); + for( int is2 = is2_start; is2<=is2_end; is2++ ) + { + int is2_prev = is2 - 1; + if( is2_prev < is2_start ) + is2_prev = is2_end; + int is2_next = is2 + 1; + if( is2_next > is2_end ) + is2_next = is2_start; + if( icont != icont2 + || (is2 != is && is2 != is_prev && is2 != is_next && is != is2_prev + && is != + is2_next ) ) + { + int style2 = p->GetSideStyle( is2 ); + int x2i = p->GetX( is2 ); + int y2i = p->GetY( is2 ); + int x2f = p->GetX( is2_next ); + int y2f = p->GetY( is2_next ); + int ret = FindSegmentIntersections( x1i, + y1i, + x1f, + y1f, + style, + x2i, + y2i, + x2f, + y2f, + style2 ); + if( ret ) + { + // intersection between non-adjacent sides + bInt = TRUE; + if( style != CPolyLine::STRAIGHT || style2 != CPolyLine::STRAIGHT ) + { + bArcInt = TRUE; + break; + } + } + } + } + } + if( bArcInt ) + break; + } + + if( bArcInt ) + break; + } + + if( bArcInt ) + break; + } + + if( bArcInt ) + CurrArea->utility2 = -1; + else if( bInt ) + CurrArea->utility2 = 1; + else + CurrArea->utility2 = 0; + return CurrArea->utility2; +} + + +/** + * Function ClipAreaPolygon + * Process an area that has been modified, by clipping its polygon against itself. + * This may change the number and order of copper areas in the net. + * @param bMessageBoxInt == TRUE, shows message when clipping occurs. + * @param bMessageBoxArc == TRUE, shows message when clipping can't be done due to arcs. + * @return: + * -1 if arcs intersect other sides, so polygon can't be clipped + * 0 if no intersecting sides + * 1 if intersecting sides + * Also sets areas->utility1 flags if areas are modified + */ +int BOARD::ClipAreaPolygon( ZONE_CONTAINER* CurrArea, + bool bMessageBoxArc, bool bMessageBoxInt, bool bRetainArcs ) +{ + CPolyLine* p = CurrArea->poly; + int test = TestAreaPolygon( CurrArea ); // this sets utility2 flag + + if( test == -1 && !bRetainArcs ) + test = 1; + if( test == -1 ) + { + // arc intersections, don't clip unless bRetainArcs == false + if( bMessageBoxArc && bDontShowSelfIntersectionArcsWarning == false ) + { + wxString str; + str.Printf( wxT( "Area %X of net \"%s\" has arcs intersecting other sides.\n" ), + CurrArea->m_TimeStamp, CurrArea->m_Netname.GetData() ); + str += wxT( "This may cause problems with other editing operations,\n" ); + str += wxT( "such as adding cutouts. It can't be fixed automatically.\n" ); + str += wxT( "Manual correction is recommended." ); + wxMessageBox( str ); + +// bDontShowSelfIntersectionArcsWarning = dlg.bDontShowBoxState; + } + return -1; // arcs intersect with other sides, error + } + + // mark all areas as unmodified except this one + for( unsigned ia = 0; ia < m_ZoneDescriptorList.size(); ia++ ) + m_ZoneDescriptorList[ia]->utility = 0; + + CurrArea->utility = 1; + + if( test == 1 ) + { + // non-arc intersections, clip the polygon + if( bMessageBoxInt && bDontShowSelfIntersectionWarning == false ) + { + wxString str; + str.Printf( wxT( "Area %d of net \"%s\" is self-intersecting and will be clipped.\n" ), + CurrArea->m_TimeStamp, CurrArea->m_Netname.GetData() ); + str += wxT( "This may result in splitting the area.\n" ); + str += wxT( "If the area is complex, this may take a few seconds." ); + wxMessageBox( str ); + +// bDontShowSelfIntersectionWarning = dlg.bDontShowBoxState; + } + } + +//** TODO test for cutouts outside of area +//** if( test == 1 ) + { + std::vector * pa = new std::vector; + p->Undraw(); + int n_poly = CurrArea->poly->NormalizeWithGpc( pa, bRetainArcs ); + if( n_poly > 1 ) // i.e if clippinf has created some polygons, we must add these new copper areas + { + for( int ip = 1; ip < n_poly; ip++ ) + { + // create new copper area and copy poly into it + CPolyLine* new_p = (*pa)[ip - 1]; + CurrArea = AddArea( CurrArea->GetNet(), CurrArea->GetLayer(), 0, 0, 0 ); + + // remove the poly that was automatically created for the new area + // and replace it with a poly from NormalizeWithGpc + delete CurrArea->poly; + CurrArea->poly = new_p; + CurrArea->poly->Draw(); + CurrArea->utility = 1; + } + } + p->Draw(); + delete pa; + } + return test; +} + + +/** + * Process an area that has been modified, by clipping its polygon against + * itself and the polygons for any other areas on the same net. + * This may change the number and order of copper areas in the net. + * @param modified_area = area to test + * @param bMessageBox : if TRUE, shows message boxes when clipping occurs. + * @return : + * -1 if arcs intersect other sides, so polygon can't be clipped + * 0 if no intersecting sides + * 1 if intersecting sides, polygon clipped + */ +int BOARD::AreaPolygonModified( ZONE_CONTAINER* modified_area, + bool bMessageBoxArc, + bool bMessageBoxInt ) +{ + // clip polygon against itself + int test = ClipAreaPolygon( modified_area, bMessageBoxArc, bMessageBoxInt ); + + if( test == -1 ) + return test; + + // now see if we need to clip against other areas + bool bCheckAllAreas = false; + if( test == 1 ) + bCheckAllAreas = TRUE; + else + bCheckAllAreas = TestAreaIntersections( modified_area ); + if( bCheckAllAreas ) + CombineAllAreasInNet( modified_area->GetNet(), bMessageBoxInt, TRUE ); + + return test; +} + + +/** + * Function CombineAllAreasInNet + * Checks all copper areas in net for intersections, combining them if found + * @param aNetCode = net to consider + * @param bMessageBox : if true display warning message box + * @param bUseUtility : if true, don't check areas if both utility flags are 0 + * Sets utility flag = 1 for any areas modified + * If an area has self-intersecting arcs, doesn't try to combine it + */ +int BOARD::CombineAllAreasInNet( int aNetCode, bool bMessageBox, bool bUseUtility ) +{ + if( m_ZoneDescriptorList.size() > 1 ) + { + // start by testing all area polygons to set utility2 flags + for( unsigned ia = 0; ia < m_ZoneDescriptorList.size(); ia++ ) + if( m_ZoneDescriptorList[ia]->GetNet() == aNetCode ) + TestAreaPolygon( m_ZoneDescriptorList[ia] ); + + // now loop through all combinations + for( unsigned ia1 = 0; ia1 < m_ZoneDescriptorList.size() - 1; ia1++ ) + { + ZONE_CONTAINER* curr_area = m_ZoneDescriptorList[ia1]; + if( curr_area->GetNet() != aNetCode ) + continue; + + // legal polygon + CRect b1 = curr_area->poly->GetCornerBounds(); + bool mod_ia1 = false; + for( unsigned ia2 = m_ZoneDescriptorList.size() - 1; ia2 > ia1; ia2-- ) + { + ZONE_CONTAINER* area2 = m_ZoneDescriptorList[ia2]; + if( curr_area->poly->GetLayer() == area2->poly->GetLayer() + && curr_area->utility2 != -1 && area2->utility2 != -1 ) + { + CRect b2 = area2->poly->GetCornerBounds(); + if( !( b1.left > b2.right || b1.right < b2.left + || b1.bottom > b2.top || b1.top < b2.bottom ) ) + { + // check ia2 against 1a1 + if( curr_area->utility || area2->utility || bUseUtility == + false ) + { + int ret = TestAreaIntersection( curr_area, area2 ); + if( ret == 1 ) + ret = CombineAreas( curr_area, area2 ); + if( ret == 1 ) + { + if( bMessageBox && bDontShowIntersectionWarning == false ) + { + wxString str; + str.Printf( + wxT( + "Areas %d and %d of net \"%s\" intersect and will be combined.\n" ), + ia1 + 1, + ia2 + 1, + curr_area->m_Netname.GetData() ); + str += wxT( + "If they are complex, this may take a few seconds." ); + wxMessageBox( str ); + +// bDontShowIntersectionWarning = dlg.bDontShowBoxState; + } + mod_ia1 = TRUE; + } + else if( ret == 2 ) + { + if( bMessageBox && bDontShowIntersectionArcsWarning == false ) + { + wxString str; + str.Printf( + wxT( + "Areas %d and %d of net \"%s\" intersect, but some of the intersecting sides are arcs.\n" ), + ia1 + 1, + ia2 + 1, + curr_area->m_Netname.GetData() ); + str += wxT( "Therefore, these areas can't be combined." ); + wxMessageBox( str ); + +// bDontShowIntersectionArcsWarning = dlg.bDontShowBoxState; + } + } + } + } + } + } + + if( mod_ia1 ) + ia1--; // if modified, we need to check it again + } + } + return 0; +} + + +/** + * Function TestAreaIntersections + * Check for intersection of a given copper area with other areas in same net + * @param area_to_test = area to compare to all other areas in the same net + */ +bool BOARD::TestAreaIntersections( ZONE_CONTAINER* area_to_test ) +{ + CPolyLine* poly1 = area_to_test->poly; + + for( unsigned ia2 = 0; ia2 < m_ZoneDescriptorList.size(); ia2++ ) + { + ZONE_CONTAINER* area2 = m_ZoneDescriptorList[ia2]; + if( area_to_test->GetNet() != area_to_test->GetNet() ) + continue; + if( area_to_test != area2 ) + { + // see if areas are on same layer + if( area_to_test->GetLayer() != area2->GetLayer() ) + continue; + + CPolyLine* poly2 = area2->poly; + + // test bounding rects + CRect b1 = poly1->GetCornerBounds(); + CRect b2 = poly2->GetCornerBounds(); + if( b1.bottom > b2.top + || b1.top < b2.bottom + || b1.left > b2.right + || b1.right < b2.left ) + continue; + + // test for intersecting segments + for( int icont1 = 0; icont1GetNumContours(); icont1++ ) + { + int is1 = poly1->GetContourStart( icont1 ); + int ie1 = poly1->GetContourEnd( icont1 ); + for( int ic1 = is1; ic1<=ie1; ic1++ ) + { + int xi1 = poly1->GetX( ic1 ); + int yi1 = poly1->GetY( ic1 ); + int xf1, yf1, style1; + if( ic1 < ie1 ) + { + xf1 = poly1->GetX( ic1 + 1 ); + yf1 = poly1->GetY( ic1 + 1 ); + } + else + { + xf1 = poly1->GetX( is1 ); + yf1 = poly1->GetY( is1 ); + } + style1 = poly1->GetSideStyle( ic1 ); + for( int icont2 = 0; icont2GetNumContours(); icont2++ ) + { + int is2 = poly2->GetContourStart( icont2 ); + int ie2 = poly2->GetContourEnd( icont2 ); + for( int ic2 = is2; ic2<=ie2; ic2++ ) + { + int xi2 = poly2->GetX( ic2 ); + int yi2 = poly2->GetY( ic2 ); + int xf2, yf2, style2; + if( ic2 < ie2 ) + { + xf2 = poly2->GetX( ic2 + 1 ); + yf2 = poly2->GetY( ic2 + 1 ); + } + else + { + xf2 = poly2->GetX( is2 ); + yf2 = poly2->GetY( is2 ); + } + style2 = poly2->GetSideStyle( ic2 ); + int n_int = FindSegmentIntersections( xi1, yi1, xf1, yf1, style1, + xi2, yi2, xf2, yf2, style2 ); + if( n_int ) + return TRUE; + } + } + } + } + } + } + + return false; +} + + +/** + * Function TestAreaIntersection + * Test for intersection of 2 copper areas + * area_to_test must be after area_ref in m_ZoneDescriptorList + * @param area_ref = area reference + * @param area_to_test = area to compare for intersection calculations + * @return : 0 if no intersection + * 1 if intersection + * 2 if arcs intersect + */ +int BOARD::TestAreaIntersection( ZONE_CONTAINER* area_ref, ZONE_CONTAINER* area_to_test ) +{ + // see if areas are on same layer + if( area_ref->GetLayer() != area_to_test->GetLayer() ) + return 0; + + CPolyLine* poly1 = area_ref->poly; + CPolyLine* poly2 = area_to_test->poly; + + // test bounding rects + CRect b1 = poly1->GetCornerBounds(); + CRect b2 = poly2->GetCornerBounds(); + if( b1.bottom > b2.top + || b1.top < b2.bottom + || b1.left > b2.right + || b1.right < b2.left ) + return 0; + + // now test for intersecting segments + bool bInt = false; + bool bArcInt = false; + for( int icont1 = 0; icont1GetNumContours(); icont1++ ) + { + int is1 = poly1->GetContourStart( icont1 ); + int ie1 = poly1->GetContourEnd( icont1 ); + for( int ic1 = is1; ic1<=ie1; ic1++ ) + { + int xi1 = poly1->GetX( ic1 ); + int yi1 = poly1->GetY( ic1 ); + int xf1, yf1, style1; + if( ic1 < ie1 ) + { + xf1 = poly1->GetX( ic1 + 1 ); + yf1 = poly1->GetY( ic1 + 1 ); + } + else + { + xf1 = poly1->GetX( is1 ); + yf1 = poly1->GetY( is1 ); + } + style1 = poly1->GetSideStyle( ic1 ); + for( int icont2 = 0; icont2GetNumContours(); icont2++ ) + { + int is2 = poly2->GetContourStart( icont2 ); + int ie2 = poly2->GetContourEnd( icont2 ); + for( int ic2 = is2; ic2<=ie2; ic2++ ) + { + int xi2 = poly2->GetX( ic2 ); + int yi2 = poly2->GetY( ic2 ); + int xf2, yf2, style2; + if( ic2 < ie2 ) + { + xf2 = poly2->GetX( ic2 + 1 ); + yf2 = poly2->GetY( ic2 + 1 ); + } + else + { + xf2 = poly2->GetX( is2 ); + yf2 = poly2->GetY( is2 ); + } + style2 = poly2->GetSideStyle( ic2 ); + int n_int = FindSegmentIntersections( xi1, yi1, xf1, yf1, style1, + xi2, yi2, xf2, yf2, style2 ); + if( n_int ) + { + bInt = TRUE; + if( style1 != CPolyLine::STRAIGHT || style2 != CPolyLine::STRAIGHT ) + bArcInt = TRUE; + break; + } + } + + if( bArcInt ) + break; + } + + if( bArcInt ) + break; + } + + if( bArcInt ) + break; + } + + if( !bInt ) + return 0; + if( bArcInt ) + return 2; + return 1; +} + + +/** + * Function CombineAreas + * If possible, combine 2 copper areas + * area_ref must be BEFORE area_to_combine in m_ZoneDescriptorList + * area_to_combine will be deleted, if areas are combined + * @return : 0 if no intersection + * 1 if intersection + * 2 if arcs intersect + */ +int BOARD::CombineAreas( ZONE_CONTAINER* area_ref, ZONE_CONTAINER* area_to_combine ) +{ + if( area_ref == area_to_combine ) + ASSERT( 0 ); +#if 0 + + // test for intersection + int test = TestAreaIntersection( area_ref, area_to_combine ); + if( test != 1 ) + return test; // no intersection +#endif + + // polygons intersect, combine them + CPolyLine* poly1 = area_ref->poly; + CPolyLine* poly2 = area_to_combine->poly; + std::vector arc_array1; + std::vector arc_array2; + poly1->MakeGpcPoly( -1, &arc_array1 ); + poly2->MakeGpcPoly( -1, &arc_array2 ); + int n_ext_cont1 = 0; + for( int ic = 0; icGetGpcPoly()->num_contours; ic++ ) + if( !( (poly1->GetGpcPoly()->hole)[ic] ) ) + n_ext_cont1++; + + int n_ext_cont2 = 0; + for( int ic = 0; icGetGpcPoly()->num_contours; ic++ ) + if( !( (poly2->GetGpcPoly()->hole)[ic] ) ) + n_ext_cont2++; + + gpc_polygon* union_gpc = new gpc_polygon; + gpc_polygon_clip( GPC_UNION, poly1->GetGpcPoly(), poly2->GetGpcPoly(), union_gpc ); + + // get number of outside contours + int n_union_ext_cont = 0; + for( int ic = 0; icnum_contours; ic++ ) + if( !( (union_gpc->hole)[ic] ) ) + n_union_ext_cont++; + + // if no intersection, free new gpc and return + if( n_union_ext_cont == n_ext_cont1 + n_ext_cont2 ) + { + gpc_free_polygon( union_gpc ); + delete union_gpc; + return 0; + } + + // intersection, replace area_ref->m_Poly with combined areas and remove area_to_combine + RemoveArea( area_to_combine ); + area_ref->m_Poly->RemoveAllContours(); + + // create area with external contour + for( int ic = 0; icnum_contours; ic++ ) + { + if( !(union_gpc->hole)[ic] ) + { + // external contour, replace this poly + for( int i = 0; icontour[ic].num_vertices; i++ ) + { + int x = ( (union_gpc->contour)[ic].vertex )[i].x; + int y = ( (union_gpc->contour)[ic].vertex )[i].y; + if( i==0 ) + { + area_ref->m_Poly->Start( area_ref->GetLayer(), 0, 0, x, y, area_ref->m_Poly->GetHatchStyle() ); + } + else + area_ref->m_Poly->AppendCorner( x, y ); + } + + area_ref->m_Poly->Close(); + } + } + + // add holes + for( int ic = 0; icnum_contours; ic++ ) + { + if( (union_gpc->hole)[ic] ) + { + // hole + for( int i = 0; icontour[ic].num_vertices; i++ ) + { + int x = ( (union_gpc->contour)[ic].vertex )[i].x; + int y = ( (union_gpc->contour)[ic].vertex )[i].y; + area_ref->m_Poly->AppendCorner( x, y ); + } + + area_ref->m_Poly->Close(); + } + } + + area_ref->utility = 1; + area_ref->m_Poly->RestoreArcs( &arc_array1 ); + area_ref->m_Poly->RestoreArcs( &arc_array2 ); + area_ref->m_Poly->Draw(); + gpc_free_polygon( union_gpc ); + delete union_gpc; + return 1; +} + + +#if 0 +void dra_areas( CDlgLog* log, int copper_layers, + int units, BOOL check_unrouted, + CArray * board_outline, + DesignRules* dr, DRErrorList* drelist ) +{ + CString d_str, x_str, y_str; + CString str; + CString str2; + long nerrors = 0; + + // now iterate through all areas + for( int ia = 0; ianareas; ia++ ) + { + carea* a = &net->area[ia]; + + // iterate through all nets again + POSITION pos2 = pos; + void* ptr2; + CString name2; + while( pos2 != NULL ) + { + m_nlist->m_map.GetNextAssoc( pos2, name2, ptr2 ); + cnet* net2 = (cnet*) ptr2; + for( int ia2 = 0; ia2nareas; ia2++ ) + { + carea* a2 = &net2->area[ia2]; + + // test for same layer + if( a->poly->GetLayer() == a2->poly->GetLayer() ) + { + // test for points inside one another + for( int ic = 0; icpoly->GetNumCorners(); ic++ ) + { + int x = a->poly->GetX( ic ); + int y = a->poly->GetY( ic ); + if( a2->poly->TestPointInside( x, y ) ) + { + // COPPERAREA_COPPERAREA error + id id_a = net->id; + id_a.st = ID_AREA; + id_a.i = ia; + id_a.sst = ID_SEL_CORNER; + id_a.ii = ic; + str.Format( + "%ld: \"%s\" copper area inside \"%s\" inside copper area\r\n", + nerrors + 1, + net->name, + net2->name ); + DRError* dre = drelist->Add( nerrors, + DRError::COPPERAREA_INSIDE_COPPERAREA, + &str, + &net->name, + &net2->name, + id_a, + id_a, + x, + y, + x, + y, + 0, + 0 ); + if( dre ) + { + nerrors++; + if( log ) + log->AddLine( str ); + } + } + } + + for( int ic2 = 0; ic2poly->GetNumCorners(); ic2++ ) + { + int x = a2->poly->GetX( ic2 ); + int y = a2->poly->GetY( ic2 ); + if( a->poly->TestPointInside( x, y ) ) + { + // COPPERAREA_COPPERAREA error + id id_a = net2->id; + id_a.st = ID_AREA; + id_a.i = ia2; + id_a.sst = ID_SEL_CORNER; + id_a.ii = ic2; + str.Format( "%ld: \"%s\" copper area inside \"%s\" copper area\r\n", + nerrors + 1, net2->name, net->name ); + DRError* dre = drelist->Add( nerrors, + DRError::COPPERAREA_INSIDE_COPPERAREA, + &str, + &net2->name, + &net->name, + id_a, + id_a, + x, + y, + x, + y, + 0, + 0 ); + if( dre ) + { + nerrors++; + if( log ) + log->AddLine( str ); + } + } + } + + // now test spacing between areas + for( int icont = 0; icontpoly->GetNumContours(); icont++ ) + { + int ic_start = a->poly->GetContourStart( icont ); + int ic_end = a->poly->GetContourEnd( icont ); + for( int ic = ic_start; ic<=ic_end; ic++ ) + { + id id_a = net->id; + id_a.st = ID_AREA; + id_a.i = ia; + id_a.sst = ID_SIDE; + id_a.ii = ic; + int ax1 = a->poly->GetX( ic ); + int ay1 = a->poly->GetY( ic ); + int ax2, ay2; + if( ic == ic_end ) + { + ax2 = a->poly->GetX( ic_start ); + ay2 = a->poly->GetY( ic_start ); + } + else + { + ax2 = a->poly->GetX( ic + 1 ); + ay2 = a->poly->GetY( ic + 1 ); + } + int astyle = a->poly->GetSideStyle( ic ); + for( int icont2 = 0; icont2poly->GetNumContours(); icont2++ ) + { + int ic_start2 = a2->poly->GetContourStart( icont2 ); + int ic_end2 = a2->poly->GetContourEnd( icont2 ); + for( int ic2 = ic_start2; ic2<=ic_end2; ic2++ ) + { + id id_b = net2->id; + id_b.st = ID_AREA; + id_b.i = ia2; + id_b.sst = ID_SIDE; + id_b.ii = ic2; + int bx1 = a2->poly->GetX( ic2 ); + int by1 = a2->poly->GetY( ic2 ); + int bx2, by2; + if( ic2 == ic_end2 ) + { + bx2 = a2->poly->GetX( ic_start2 ); + by2 = a2->poly->GetY( ic_start2 ); + } + else + { + bx2 = a2->poly->GetX( ic2 + 1 ); + by2 = a2->poly->GetY( ic2 + 1 ); + } + int bstyle = a2->poly->GetSideStyle( ic2 ); + int x, y; + int d = ::GetClearanceBetweenSegments( bx1, + by1, + bx2, + by2, + bstyle, + 0, + ax1, + ay1, + ax2, + ay2, + astyle, + 0, + dr->copper_copper, + &x, + &y ); + if( d < dr->copper_copper ) + { + // COPPERAREA_COPPERAREA error + ::MakeCStringFromDimension( &d_str, + d, + units, + TRUE, + TRUE, + TRUE, + 1 ); + ::MakeCStringFromDimension( &x_str, + x, + units, + FALSE, + TRUE, + TRUE, + 1 ); + ::MakeCStringFromDimension( &y_str, + y, + units, + FALSE, + TRUE, + TRUE, + 1 ); + str.Format( + "%ld: \"%s\" copper area to \"%s\" copper area = %s, x=%s, y=%s\r\n", + nerrors + 1, + net->name, + net2->name, + d_str, + x_str, + y_str ); + DRError* dre = drelist->Add( + nerrors, + DRError:: + COPPERAREA_COPPERAREA, + &str, + &net->name, + &net2->name, + id_a, + id_b, + x, + y, + x, + y, + 0, + 0 ); + if( dre ) + { + nerrors++; + if( log ) + log->AddLine( str ); + } + } + } + } + } + } + } + } + } + } +} + + +#endif diff --git a/polygon/PolyLine.cpp b/polygon/PolyLine.cpp index 6e3d8000d4..1d3a4a8a74 100644 --- a/polygon/PolyLine.cpp +++ b/polygon/PolyLine.cpp @@ -748,6 +748,19 @@ void CPolyLine::RemoveContour( int icont ) Draw(); } + +void CPolyLine::RemoveAllContours( void ) +/** + * function RemoveAllContours + * removes all corners from the lists. + * Others params are not chnaged + */ +{ + corner.clear( ); + side_style.clear( ); +} + + /** Function InsertCorner * insert a new corner between two existing corners * @param ic = index for the insertion point: the corner is inserted AFTER ic diff --git a/polygon/PolyLine.h b/polygon/PolyLine.h index 63361fac02..ed29344910 100644 --- a/polygon/PolyLine.h +++ b/polygon/PolyLine.h @@ -81,6 +81,7 @@ public: void MoveCorner( int ic, int x, int y ); void Close( int style = STRAIGHT, BOOL bDraw=TRUE ); void RemoveContour( int icont ); + void RemoveAllContours( void ); // drawing functions void HighlightSide( int is ); @@ -107,6 +108,7 @@ public: // access functions + int GetLayer() { return m_layer;} int GetNumCorners(); int GetNumSides(); int GetClosed(); @@ -125,7 +127,7 @@ public: id GetId(); int GetSelBoxSize(); CDisplayList * GetDisplayList(){ return m_dlist; }; - int GetHatch(){ return m_HatchStyle; } + int GetHatchStyle(){ return m_HatchStyle; } void SetHatch( int hatch ){ Undraw(); m_HatchStyle = hatch; Draw(); }; void SetX( int ic, int x ); void SetY( int ic, int y ); @@ -159,14 +161,14 @@ private: int m_Width; // line width int m_sel_box; // corner selection box width/2 int utility; -protected: +public: std::vector corner; // array of points for corners std::vector side_style; // array of styles for sides private: std::vector dl_side; // graphic elements std::vector dl_side_sel; std::vector dl_corner_sel; -protected: +public: int m_HatchStyle; // hatch style, see enum above std::vector m_HatchLines; // hatch lines private: