From d5c7c1ea45f68ffd96758d81a317ec4d5b4605c3 Mon Sep 17 00:00:00 2001 From: jrheinlaender Date: Fri, 8 Jun 2012 19:51:53 +0430 Subject: [PATCH] Pad feature: Midplane, two-sided dimensions, up to first/last/face options --- data/tests/PadTest.fcstd | Bin 0 -> 14782 bytes src/Mod/Part/App/PartFeature.cpp | 74 +++++- src/Mod/Part/App/PartFeature.h | 32 +++ src/Mod/PartDesign/App/FeaturePad.cpp | 231 +++++++++++++++---- src/Mod/PartDesign/App/FeaturePad.h | 12 +- src/Mod/PartDesign/Gui/TaskPadParameters.cpp | 156 +++++++++++-- src/Mod/PartDesign/Gui/TaskPadParameters.h | 14 +- src/Mod/PartDesign/Gui/TaskPadParameters.ui | 57 ++++- 8 files changed, 499 insertions(+), 77 deletions(-) create mode 100644 data/tests/PadTest.fcstd diff --git a/data/tests/PadTest.fcstd b/data/tests/PadTest.fcstd new file mode 100644 index 0000000000000000000000000000000000000000..8a7223083d43f88af19d30fa4f4f7e9512152815 GIT binary patch literal 14782 zcmbW8V~`-*)8^Z@ZQHiHr)}G|ZBN_wv~AnAIo&;NyL;!}ci;WrI~%*Pv8O&%L`D57 zPMpefG9&Xz`ES4=C;$Ke5CC!+{Q{3a%P<7M0RZOs0RUirKNYbva*bSg2M$7`9s*WN~nL)OIRA#mIOd~MJM8O;M|cIcP> z07;1F^Et0}ZJM~BIRCVmeUe0DJrU4yLtB6S?nTrQOw=kwJwra~u;&;;IY}~c zn@-Z#YE8k?f;S4~C*yw)*0o|*Q^LHXg`CSpB9OX0T#Vl3u$tp)9UrB3Sm1VACB(xk z(qh%>)1fOzHrBAg`CvdhXH-*i1N$0~iv6r77XhZUss}1uQ`cc*VxFrnb?$Zn3n#7D zha%JWC1ZV$XcxaNzV2RtiL4^rUVd5zXRtDz;2qd9@2q&#r-gWg?J6wk=!+C4Mg)pf zyqabhlHdPe@to6_wA@TTYn{ypf{3? zdLxBt4gljZVm$KNl4*U_UgCg zLyRW#z*i4m$*OSo;wIE*`J5=}jmkg&&01)4S-38C#Ahss`Fw#IiQ|bb4H5r-Dk=p7JTO5~+q&vo!%WbJR!;k61<}ZL@_avBmIm^`LY+;6vTPy#JUFHhJEdL`{h|bG@O{CVn0N;b(x*1Nd2_EwR<+Renufmx>AN(^kg zpffXh%JDinuVk2CgVwUg+wQZ5p7TgMQAh{S>}r!fn~huh$&y%SQPf%h)Kx8@GH(zR z{BRjDjr|IhblS5;8UVq5GjOz{yi;^ZD!D)&5Cu5P*ttDP%&NvhfKuwe!C2XG^WtcrtZIgF!6`<|tfV=q{{=4cP!=XL zLD{$WQ-HIMoIDprtBzCjo!XIM%Kisyc&oE z7zY*zoRboGELre6{EdM^g1fLN2{6lITu@`j^wX#LtsOn^nk zK^r1{_rRODls7v47eU;5p|3~I z-LON?47;0lJ>kkQ6Rc%MguG+dgZ=q5{!hPp5XQ43ghOmh5Sf_-+)Df-MX5x|Rj8BE ztWEJ3^Avl1%&-_#vL20BjhF^+2PvW_j0`1!XLu5UXq`-~hj*>XB9V(P)Qz1E*HeyJ zxIz?Vw2Y`Ar@UnXk11p zAvCOC!i0(^NfYt{J*6WA`uT(U-2z_<5<)-P%+E#fCHh$&$_D_7bOn@Z8f)dRGLm9Q z;du3)G^4jozgZ(1XxJ=gf&f>-*Z? z`!x=xLlt(+N7M((ACBp{XK=y3xKcwM@34;RQe*9Cm3oM(0{r$xxO{3dTc)~m76-I8!@MsOKWyfcS=c&|Y> zroqZDVAp1+0!+)W-iO!HJ%6e<@Ln$FxR%kdx=kNgGb<7f!f#y!PVfNxb)1MpxN;QIFu;Ufc|+l@xI>Ao)h`&KKQ$W+AUTf+e(RzUKmeDW&$r`GXx@-| z^zW4c8bBiTMS4l39)F4?d(g=Myv-kV2fuCYN zH^;+g^SK`jmyH$h*KOO+%w1VYpdhH;3^-KCu`VoRUMK!&yPXt@QEYCMSVr|yMtB~W ziUmf47@hspxkFSTQiV*loh)+6K0FUKlrZQD z@+UjF3JgxncSBnyDM{@3G>!!rPW{k28O#O4N5Nn+JUBTyKUA-BTOJ5$DdD!>RtDPF zUIrfPuax!mT`YXxWQO{%R`qFti0e4q%K)ftpicTBf`J&!<9r#QFQQ(EW@K^_5V9Ck z*a`{{M!YWZ1tXNkA;@DJ`xK6&1dp@!K_gtosce`%yFnG|OM+eVrmpm zqM)LPNtmcq+j`Cj?W`(1wB zKX!axh0)J|KiEGzK3{wsKgr>D^ze4^diUYydht59pP|!t;XDpFRz@=N=|T0P-}8xC zH9~IxGQij@oX?L_tWhjepewA2lWMo#lx^#>t&n8uaikgs>q9z{%C zTw1LB7OWlJmmW-OVWv~R8hxtvI0_!4q`o89G-`g@O1SD_BxZ%61qL4GymwC2EVghp zWuEl}XNw!eCfmE|f3#L;p4FhM6mRWdw|U~t0NDO~f`j=>qfAS@!C?+b5XaV_B2~t# zIn?pg_%)P`o;`Tuh}~MC3Zw7HriDk7)%iY#!Ex?1v93>(m+LGM4-uYDy`Oj4W^~kM zueo)WBP3NzXuy(v+)iC+^UU12Rx^{Ogb)Oznp-SLKC`doI~X=PYcXVSsyHz3x!_xU z>M8bm=O&nK>P{?}XE+}Sf?5q?toY#u`mx*6Y@M{T2-PJX>}8#;3DjjQO}+yZeM_(y z%PK`rpOI?#HmEItt(z3I*_dFEhwqzxt;1Ya1ra{n90;$bmG^8AB(b|rqF~L9hQX5A z7+!3p>EZDqM+ za3OUW?&{%$%IpNQKiE)WD9{rypw*2dIdNGIjN2eiKXh;fd8NEd*5Xnth&ia)L!KZJ z)=Qag7MDn>T8&5@`0bvfJ?EE)a7#y@wHg|Kf$s}+G3quWlKxGx!Xo^yCGtXEWF8$* zzq_#{H1eeD#X_9+6}{XqFZU?*nk~!9 z+`wpeO&bG>s~>j@_3x*|vJj;7S(b)q-3byL%~KyGrseU6ZeG=t*zp>4nQ~3AEA2om zGeMQyQ5no4_S+m}gFq9!%?URWKdo7o4}ml4sAw;g8s~xp^5%trU>BPut-$ZXX3v_> zc~}Y8oX6iW2Y=FO6t;8n?pQLlkRFe*+TM<;YME$lcHh9T6(4i^Z%dHEz9Pp`-VI-D zrPN;qTu(*33?rKlzQcmKGViN2pKV`0Q*m>jooAifiWTY!ake?vGxgZ+4wE2CVS;+jOrsPV`Z<>q zroMtk0gH_I`>2mC1aW{3;20UiB7=B;=@OVc&N8o-Vi6}@-=)(SeeZrd0|fUJVOoKE zm`6gP>|hHdN~{JBY2?P5P0JT}WZ6Z@EUN_-t;++Wx}#x}B2fqhWnX4tL8il?bCnG* z3r^cYqjd95gn^ECZe57;|4CGYAek1I!pamaY3yxCVr*Cz7hqwcFP4$e5tUR(s#p9N zsON^B?u^S+v^Cb`0|tsqe7X@xmLOh6;kxKARt=l2kGS?Nc7R1NNDh4#fdVQ}EiZli zQ1T~4dQm$JtaN-Gr7;s#k!i?OFqF7iu&h4vFcdb1dZ_RSyjO%Vxv68INXT=iev#oo~pCbdG`CxNoH4pOt>L;hME|^Y+?l3_@32PD%5xHiWh`b^Yh5J_gB{TZrrN&RwP1Vh` zeB)^sLWD75Udd4m^0VJ&|0FY3cEHA7X7@z?l7XXks>gv$O zB*+j}$Sbsbh&Ld4%A`C(8EStJtY_XXFCd8cVxVxUGGq;L8Y;l`tfC@rFH!+=QyH(| zV)}97v_@Ms5ecM5+Pc!;-!>cy;)%}AI^f8W6xkDmf!#{40VKI`L4vYE3T2KlLsNhv zHJ4a`A_xfe>o1We@{cQ`_O~a%6xgML_AfH&s$xpuR0DD*f^?3ny$|_D_;Jf?C_^l; zXs%@_SC!xrn+<~y%}f7Xo&e%I1roGyVH$9A$aHYhH$8PFU4noDR%nvYP?joyjJ&G0^~dw$>D|Ie=~GWMe;I#_pZn9uja>)*4EIg#Tm9S1 zz(iQ7+<;#0_C@z@YO2DTAnd`p_!PZ3XAjyED_<^jFZv=INMZ8hGzDd`56ZZjq9$!J zW)qf6fO5U)_d=`?tfQ-oKGl8YgXP^|_TY6-Ohb8vinwJf$at+mfwBm+gR?{TMu^n9mPSg-5Lm|#g|(khW^JN-mRK;;$lO?rDIee_6^_3G$@-AV}-v+G+bnOrj&F@sqd_+*6~Es ztJvTK4T{_Z=k0pXL|@ptyLm;cl*`XnnN)CjGE=-_RUOYyx&wTw5mqC>J3!@%{L=(_ zf|$M!pN{K__vU5L%*p7?E>sppTiq`*{Aw)7rNnC2J)ZYDsfd!QNqGu?4i1!+qejbE z*UM+NSikY-`>EwdMx9K@YB*Am*TPkfGE1e~;}sugl&jG`4)@nhC?Tv%zL zT_*dl_Ec%+mOa60wX4VVyIGKrC2m|`OResKa8HvZ}UZj?+y^+?nrd zKs((_b8c$Lz2%qzL7>0iwt0#IJTY_`Au!*L|0{H)4$gF2%>z@gG@k)n*I((Jb4DFy zZX1HCdp-?LET!%9xQL;c?&Yn&*G?{9JI39(1Z&Wc_Z9efM_>0n&sm-d0$NtKyYJ{* zc(K8L?zoaho=Eb0mUMidUcXI0%xVE0XBIy|jCiS^QB|q?v@)!kD((c&C1s=kIA==kNpKi|o9;iVK-y z)4w;~<>Q|7=d@^HYa7oF7E=rAF(s?*xI`tM8TVzduQ4w3_DPV+(F_cZBzJ_ACB0v-~ttH$2=fSs=`>9rU$lP>mcL&o+A_J)K;w|5`K8vwPtzcCU5NR)WM6wbj zy)Wpw1$_KnA4d;Mkw~LWDir#8ZF+Trk=8uJOO<8KAODcV3#wjAROPC8TLGK>={yqGYF>l=VkgMy6|Jz+sq@?OdUp>9-r zu}^ZKs9IE3MT_#BCDMlP6tH+Vkl3B`E$vR+S#x7A(|b`@5!_kc-MeNmE3tsE(^AZZ#WgGf^r>#!0tRi%pyNPUZuX_C+IWtOrB|^h;87VTD5PRPPDFB-zjLqH0%I)IzU_ zvW!9x8tD{!D(H&8D@ef8iK9?lyFo*b4MimhACgP(nxcb!O$MtFG03N}q3w;IXEZ>L zP}EJ*O-62=k8{Kq(`sWBsrs?s*t(U+GGQ9z2XZIY@r!DFXjp2$VTnoOK?M{809 ziKH~E%TU}ml<1u zZ$wko)%mLg({5irBrq;lbD<-; zw}>sV?a5@PFdCECa=HiXPXtSDwuHnxgV zABH*a%;z?LAbuxN90xQx0&8WaL2;c%&`O6(LlYjuayU^pB6q6V#X z`^lo$KJ*joNpEDZ&>OcM?VR<48=JY6`AkpeD@BL1<*{|!hq}5SgFH~dZ>xO5$EyQ< z<+2rE5OPr?z$E8uwNoX~M!N$f${q)%g9-qnJE292mMrVJPJcx9m>pS6wE)FtZy%=N z5Vcqmx`Te=lopM-6S2!L_5MTU& zics_pYKkAE3pBSGuo{LHf~X4w@5{Ft7xLnOkv74q;qieUnLNpfS?ok`a%#Ca@%sIKs z8@&T}4=ah=1U_mX*PhZKZ4HDLU4{t+M79R62mGQ3mt{3~#{%1x;13!N07afN{lx!w zsL4rV8Y2h@0ATSu>-?{LA@g6MX0k$`Z9fA{*BiC>rv8ufV7AkE1=~zE*uhvOFw6?& zrZP~nPhVN^M1SNNg+mID8G6^7XEZi^(KEkyGgQ+ZUt|EXgEeDqX@_m=jB*Wp`#yO0 zmd+8g9-A(z_vNdJYHLe(%M@Q~$uKMoj=E*@Wev-;a4|uL(Br(j!u^H@L!s6X|6hvN zin|3sMEU!J#wk@3GCA`SXI8mH&{*+Dv`Esf7knowZc^OFZ7RbgNt!lHFIMnDp-4o{ zDR;<4x-cnm;~$afGL^2x&4YnFj(bf%;Lb|eLXtRt(m!<4`gCopjL;!Zx?ZH}g`OP! zg8TUaz|B$%(JL4qva0A(U#w6XF*jW|k?k+o35XB{YlzY747z&v2@@1e-cCA+bOF<` z7{@{<=k#2P2m?E8JIdz&ghXID_HIxX!U2FGR;Bmv#m099xNQLj05JTW+yB>Mv-};` ztIF76vmyXZVkbN<&F$W$$bdfkc{Y`QN#icFd1`;e){a#lWM#Xs>99VNnt-; zCg60l-0b&!P4xG*p!QzTl!S|Fjo&2lWqHDYaU=tKd}xvYs7ksPGp_Luv9 zm9LhZaG2^#4JpudWyN}ft<>R5QkAD+zWdxu2S_Py8iYRmAdzEz+Ci!c^sL2mv=q^V z8k5}gOdPz#ndHt*trB6`B1n3zkYnas+)Z@JM@`)uPhgY}d0#XyBeM+sX7MDx1g?+K zClp6sTRxcIlw}auDw*!7-)CK$@zH^AP#s zBXb^G7xS@L@oi>L$B>^v8Se!nWmdv^tabq#>cxNvxUrg^?2sE?wrN7#H!Qr+ zgB~suP2L*n#ZPxyUSnWy;g6jJQqi4=_~d2Aw{;b87Q4tv&*cW#1YWld*%yRbf`aay zUm`hadzD1>MpaS!0mfADgzxu>En(e*lT}sAYW^!NQs1w+l)5E zlUG@uoHj?z|UbRUA*`P1G>-HC$OnZK@SPM(L2Zcm0@9GNl9fHmmvy{#_u#};S(Yl~lKZzN#1Ao?7uT{AK=E4Aw3 z;f{HXR}rOtq^+-FYp76FeXGyD-8pte=4zdA+=Rd)vAkIZC|e);&McjNEu z!PedWuzy;}gtx=nzW98e%aBLwW>;Yu{WAElK;C5!?`)k@f}VoA?;)P{9#)txT}C# z#!us&$?@!KxT3!Zw(7f0C&0I%#2cdO{?lLYYBq~wrF4y#XnMXd?WWb2SdG7=>)FV5 zqqm-mAZ6fayC?aysf$%buaGOJxhS5|zH9C9Pqo>1+(FF989Zfcc9f}|n4J)lRB@TL{5H{%Muw*e98%z59^omyXYr4b zbKzR94dcLvv9mWqGOTgTssuL$uR;b?6BY59JFRKWnjqP}pK%Kx2sE&4$O2{_RP0vv zApJc2^G^#uGpb7q3k(Fst*Ef}%aYy5H1UIk&g-5(D`{XX6Q<`#ONHb)xivjUd?6<0 zhU0kLBbMYR^gZmQ4p$~CDQKDT z>T?nU`L9|*9+Snp?SY_&;hN1`J1?i)iqA$ul|D$nMhmtyZ=MZYLyCDTf>c-SQ!;uG z6YJo0pl2NPn|E*Gz{pZt7r=5R$|;jvTwo-~s&?%5b}Pps^}8<0zDdjA<~mN&756j>$QZr#(N1cW z9MptK!RP_a5WQBa&llM3>!X-&c_yF36Uc_hD(rwP4e$+lzp>8Ol8|2JtVz6_SJ}>0 znGfqM3ZDG%GaVfn_qtGwHPD}d@ip^il!mi^S7d}8X9~r63Ih%yfrHUQu z1tj$qcn2<`6@_*s6d%>=S%E%#)!kZ2tnSVJgrfv@8D`zKg8;#RB9T`!NQ)ti8dbza zz$4x^=Udn!0*8tqQuX%->tblnj zBCJ)f&};O(}FfFwOwNb$2Wqi379GLqEfv@ zI2$_{8;1}FyLKu+?IaeOy2_uj6mF}Lw}hKQqJ-^n+^vV)D%g2==4>#$^ZGoQdmLpt z&%G9K-g!Ad>j&6PW!YM};rF%3+SWLLn)u(4obkD`?PGZ-6q7XoHkxhA`3#I?`H49QVyq7?KvoKP1)dodzGf}i=8{Ez zvMmSLoVD@VqFe|$M&nmWo}8GR%K(NYpMiSkGx+(rzuldMxjmA~!Y1{6Jzh>c*(tPY2~CO?EwVs4fi7qft`f#-EtMPcHws3T7M4bH5^8dCD~fcIy#8XDUSNuNp4iDqtBY;y8yClpe(nWoyWT_QGD;6gXc z@uf|_quc5Oyq4PQCCnQsSa0vVmsJI^HPh|MPf_Zy5Hhb)bCmAcswT5ZlP6OA6mX|G z->0PyxS8_SLNuh$wK+fTEaru0wZSFzzoy$j_Fy;8s>S7HLJTmaS zi9P-{5bo3jMaUCbivc$b6rQZ@{8SG|u?Mw} zr=c*J<{6i@Y1N~VJGmF#zDhDufrhdMu2e=@!0T9EHaBzpTYdNBN^1T6&z6=f7HM=` z*xTLdH43!u_3}9!=xun@(hsyHgKP2>H0qT+r9&a7Sxjp%8I;F)QA;OcRgfpyQ^P$S z(*o^W@Fu4aENBsn4HE-pwTDRWB#kP}Sq$Zyb1>*}g{zlpg4g})Ql;I_ zOC|);0Rm;nM?-h1Q>=_IRS_J#7)Sa-eb_x8jGJKIn#F=N$;1w9qA4YWzAOfRpgI#e zI3k(Jv0U`UacJ#o%1@6`)ou}1P^^HF5nSxmBLy_E7}LbOzh{|WpQ9E)d_sj|T9;?Z zM_1!ED&;jGg_vL{UWV7tC3;Cp^VFI5v1>vi6cwVz8%WeT7bi~z}xi1wl3IT}}YBUEn1Sb3gialA+!kk0#5jN0L{d zA4QOf)P{IMhgBORHoD-6g$Nl6z(^g#lP*VKku^7uIEBna`kF5jsx+NLB?5v0#AlyW z2%jp)n&|I72X~Vq8C&eLD71qehUjsk#na^JFE58GBA^vFmyM%VT}LTL5^ijhr$~Y! zbk?RL*!&VD&}=@Ki_@ZQlp|EF854dyZxA+a(9Sx?H)bS{<5PHhzbej zJrn_Yx|9IaQ+&?dX4p17w`*%Y?ysGxY+biYa)5_Hl#d_sNyy*`ra4H+fUqCsa6f+K z>ASMf(Gg_EP+X8VB+0|xCwYZQ?)8le$x1;sYf;Tvr`J?>3;11Bt)U$hYD5jje|PtY zgg~8jS(Y6WA67j7o?&#bw87${WX7`2!*~1#BUzS0qvJ16VD8W`VytrDgO7#%%J@mt zkLB-C@HX%7DAfq`qXNMDs6DT=;7pEQul2ljGRGTF_9*dfe6`D8G~zoc@M`n*X+aQM zi&g#v&m;)7E|Q}xKiqkaeaU@7b;F7+Hwl2IU5IJpsltr1*OK58zMJ_{f?^^;5Ym=W zhHX^R4A3AG;)a;$b(U9(rm33H%YWjip$d|E|6I^xZmQECy>bUt3Uu!cNOw;&p~@Nb znc`vtSC%_XSj<2U-d9#;aiqKKhR*AqE4th${UkBZANnnYe^KF{)?dI&Dy+FErvw>N zE)z`>Ue($N5}6{=HmB2(QlC>w{URo4A-Czg~qA&_TjuqMYB5udY5C4Y4VqMaJy({44lKn;D9y&9dn{EL> z*&Ropfdpt$zQp2nT7G%Z2^JYke?TZWIjEz!Ln6c`nM_{Fv7<2vWKcZfVj3hw{ty7D zGYkD>;<*8$BD2!GJQ*VM7IS|(bMFZy`#~x74s$Vl;{~QkY?Mh05*G9NBK%_Tx1$hm&=F+7+(C%<(sUA1E6Kt61$YfEaBWF z*vX;W1lVq@NCBdoNWtDuk%BEA&%9)dGre`P`ES+iffNN`@=l!vBSJw$qh_+YE^4(w z?AYP48wfIlo#sH8b-Xs_GbS8ApDZ_ikcC89$3O?EixPcTQ+4O=Ai+*^<^p zCyA2W?HjGj!)RsP}

PRq*>42O03P1^v|#P$@HIIK6?4UliZ_|#7K$qdn3G;9~A0F zD0_!zIH6~4Re1-^I;CZ1GsZcllr}Kcl_TzeT(SF%Vu*h8Vbk0>7EiB5l=Ou#d|f-& z+1#vc#Qv9S%$1&ic2K!A@XGVzSV~P4>;^Ry3sZIM1fMhl=C)u6Z$hEmJlojxtDiaU z`GGf0moI(K`>U^K4&Hkqd_0)3U!neG8<5sJfGFw=*Ia~fI`CEJ`HFqB7y5;jF>(5+=o2VBRSIc*Acae{@BZevMCN<_eIS%iwfbKgh zfuWJFAzL~pK<6|}9GeB??})YDq95HEF2BWY&KjDv1-@>ig{bT4VReDxqXHCG2a&J5 zE*X-dAF7L2u7-wtN*6n=Z9CoLD{Z}8{O$mpJwU=}_46-oagd?2GeV-?RQ5=7_9`Fb zLgsMkgOKQPhe;&Yl)vEpUQL|8HuC)5Zk+IcA=CYsUKfEKVe_dt;Iuge<7yy>09w42 z*|Bh;LGL~kGHWoQ%z;px;2G7mY2t$GY_XZSyKn`l!R zO&V>Q?7iJ!^9~}zK4OEo+w85+$2k+>c+h|re*Fp# # include # include +// includes for findAllFacesCutBy() +# include +# include +# include // for Precision::Confusion() #endif @@ -139,22 +143,25 @@ ShapeHistory Feature::buildHistory(BRepBuilderAPI_MakeShape& mkShape, TopAbs_Sha history.type = type; TopTools_IndexedMapOfShape newM, oldM; - TopExp::MapShapes(newS, type, newM); - TopExp::MapShapes(oldS, type, oldM); + TopExp::MapShapes(newS, type, newM); // map containing all old objects of type "type" + TopExp::MapShapes(oldS, type, oldM); // map containing all new objects of type "type" + // Look at all objects in the old shape and try to find the modified object in the new shape for (int i=1; i<=oldM.Extent(); i++) { bool found = false; TopTools_ListIteratorOfListOfShape it; + // Find all new objects that are a modification of the old object (e.g. a face was resized) for (it.Initialize(mkShape.Modified(oldM(i))); it.More(); it.Next()) { found = true; - for (int j=1; j<=newM.Extent(); j++) { + for (int j=1; j<=newM.Extent(); j++) { // one old object might create several new ones! if (newM(j).IsPartner(it.Value())) { - history.shapeMap[i-1].push_back(j-1); + history.shapeMap[i-1].push_back(j-1); // adjust indices to start at zero break; } } } + // Find all new objects that were generated from an old object (e.g. a face generated from an edge) for (it.Initialize(mkShape.Generated(oldM(i))); it.More(); it.Next()) { found = true; for (int j=1; j<=newM.Extent(); j++) { @@ -166,10 +173,12 @@ ShapeHistory Feature::buildHistory(BRepBuilderAPI_MakeShape& mkShape, TopAbs_Sha } if (!found) { + // Find all old objects that don't exist any more (e.g. a face was completely cut away) if (mkShape.IsDeleted(oldM(i))) { history.shapeMap[i-1] = std::vector(); } else { + // Mop up the rest (will this ever be reached?) for (int j=1; j<=newM.Extent(); j++) { if (newM(j).IsPartner(oldM(i))) { history.shapeMap[i-1].push_back(j-1); @@ -204,6 +213,15 @@ ShapeHistory Feature::joinHistory(const ShapeHistory& oldH, const ShapeHistory& return join; } +const TopoDS_Shape Feature::findOriginOf(const TopoDS_Shape& reference) { +/* Base::Console().Error("Looking for origin of face in %s\n", this->getName()); + if (reference.ShapeType() == TopAbs_FACE) { + // Find index of reference in the history + } +*/ + return TopoDS_Shape(); +} + /// returns the type name of the ViewProvider const char* Feature::getViewProviderName(void) const { return "PartGui::ViewProviderPart"; @@ -253,3 +271,51 @@ template<> PyObject* Part::FeaturePython::getPyObject(void) { template class PartExport FeaturePythonT; } +// ---------------------------------------------------------------- +#include +#include +#include +#include +#include +#include + +std::vector Part::findAllFacesCutBy( + const TopoDS_Shape& shape, const TopoDS_Shape& face, const gp_Dir& dir) +{ + // Find the centre of gravity of the face + GProp_GProps props; + BRepGProp::SurfaceProperties(face,props); + gp_Pnt cog = props.CentreOfMass(); + + // create a line through the centre of gravity + gp_Lin line = gce_MakeLin(cog, dir); + + // Find intersection of line with all faces of the shape + std::vector result; + BRepIntCurveSurface_Inter mkSection; + // TODO: Less precision than Confusion() should be OK? + + for (mkSection.Init(shape, line, Precision::Confusion()); mkSection.More(); mkSection.Next()) { + gp_Pnt iPnt = mkSection.Pnt(); + double dsq = cog.SquareDistance(iPnt); + + if (dsq < Precision::Confusion()) + continue; // intersection with original face + + // Find out which side of the original face the intersection is on + gce_MakeDir mkDir(cog, iPnt); + if (!mkDir.IsDone()) + continue; // some error (appears highly unlikely to happen, though...) + + if (mkDir.Value().IsOpposite(dir, Precision::Confusion())) + continue; // wrong side of face (opposite to extrusion direction) + + cutFaces newF; + newF.face = mkSection.Face(); + newF.distsq = dsq; + result.push_back(newF); + } + + return result; +} +// -------------------------------------------------------------------- diff --git a/src/Mod/Part/App/PartFeature.h b/src/Mod/Part/App/PartFeature.h index 689736a42..ed3de3737 100644 --- a/src/Mod/Part/App/PartFeature.h +++ b/src/Mod/Part/App/PartFeature.h @@ -29,9 +29,16 @@ #include #include #include +// includes for findAllFacesCutBy() +#include +class gp_Dir; class BRepBuilderAPI_MakeShape; +// includes for findAllFacesCutBy() +#include +class gp_Dir; + namespace Part { @@ -63,9 +70,22 @@ public: virtual PyObject* getPyObject(void); virtual std::vector getPySubObjects(const std::vector&) const; + /** + /* Find the origin of a reference, e.g. the vertex or edge in a sketch that + /* produced a face + */ + const TopoDS_Shape findOriginOf(const TopoDS_Shape& reference); + protected: void onChanged(const App::Property* prop); TopLoc_Location getLocation() const; + /** + /* Build a history of changes + /* MakeShape: The operation that created the changes, e.g. BRepAlgoAPI_Common + /* type: The type of object we are interested in, e.g. TopAbs_FACE + /* newS: The new shape that was created by the operation + /* oldS: The original shape prior to the operation + */ ShapeHistory buildHistory(BRepBuilderAPI_MakeShape&, TopAbs_ShapeEnum type, const TopoDS_Shape& newS, const TopoDS_Shape& oldS); ShapeHistory joinHistory(const ShapeHistory&, const ShapeHistory&); @@ -99,6 +119,18 @@ public: } }; +// Utility methods +/** +/* Find all faces cut by a line through the centre of gravity of a given face +/* Useful for the "up to face" options to pocket or pad +*/ +struct cutFaces { + TopoDS_Face face; + double distsq; +}; +std::vector findAllFacesCutBy(const TopoDS_Shape& shape, + const TopoDS_Shape& face, const gp_Dir& dir); + } //namespace Part diff --git a/src/Mod/PartDesign/App/FeaturePad.cpp b/src/Mod/PartDesign/App/FeaturePad.cpp index 1a12c4556..c7742c1f4 100644 --- a/src/Mod/PartDesign/App/FeaturePad.cpp +++ b/src/Mod/PartDesign/App/FeaturePad.cpp @@ -39,23 +39,32 @@ # include # include # include +# include +# include #endif #include #include +#include #include "FeaturePad.h" using namespace PartDesign; +const char* Pad::TypeEnums[]= {"Length","UpToLast","UpToFirst","UpToFace","TwoLengths",NULL}; + PROPERTY_SOURCE(PartDesign::Pad, PartDesign::Additive) Pad::Pad() { + ADD_PROPERTY(Type,((long)0)); + Type.setEnums(TypeEnums); ADD_PROPERTY(Length,(100.0)); ADD_PROPERTY(Reversed,(0)); - ADD_PROPERTY(MirroredExtent,(0)); + ADD_PROPERTY(Midplane,(0)); + ADD_PROPERTY(Length2,(100.0)); + ADD_PROPERTY(FaceName,("")); } short Pad::mustExecute() const @@ -63,8 +72,10 @@ short Pad::mustExecute() const if (Placement.isTouched() || Sketch.isTouched() || Length.isTouched() || - MirroredExtent.isTouched() || - Reversed.isTouched()) + Midplane.isTouched() || + Reversed.isTouched() || + Length2.isTouched() || + FaceName.isTouched()) return 1; return 0; } @@ -74,6 +85,10 @@ App::DocumentObjectExecReturn *Pad::execute(void) double L = Length.getValue(); if (L < Precision::Confusion()) return new App::DocumentObjectExecReturn("Length of pad too small"); + double L2 = Length2.getValue(); + if ((std::string(Type.getValueAsString()) == "TwoLengths") && (L < Precision::Confusion())) + return new App::DocumentObjectExecReturn("Second length of pad too small"); + App::DocumentObject* link = Sketch.getValue(); if (!link) return new App::DocumentObjectExecReturn("No sketch linked"); @@ -103,10 +118,8 @@ App::DocumentObjectExecReturn *Pad::execute(void) // get the Sketch plane Base::Placement SketchPos = static_cast(link)->Placement.getValue(); Base::Rotation SketchOrientation = SketchPos.getRotation(); - Base::Vector3d SketchOrientationVector(0,0,1); - if (Reversed.getValue()) // negative direction - SketchOrientationVector *= -1; - SketchOrientation.multVec(SketchOrientationVector,SketchOrientationVector); + Base::Vector3d SketchVector(0,0,1); + SketchOrientation.multVec(SketchVector,SketchVector); // get the support of the Sketch if any App::DocumentObject* SupportLink = static_cast(link)->Support.getValue(); @@ -118,27 +131,159 @@ App::DocumentObjectExecReturn *Pad::execute(void) if (aFace.IsNull()) return new App::DocumentObjectExecReturn("Creating a face from sketch failed"); - // lengthen the vector - SketchOrientationVector *= L; - this->positionBySketch(); TopLoc_Location invObjLoc = this->getLocation().Inverted(); try { // extrude the face to a solid - gp_Vec vec(SketchOrientationVector.x,SketchOrientationVector.y,SketchOrientationVector.z); - vec.Transform(invObjLoc.Transformation()); - BRepPrimAPI_MakePrism PrismMaker(aFace.Moved(invObjLoc),vec,0,1); - if (PrismMaker.IsDone()) { - // if the sketch has a support fuse them to get one result object (PAD!) - if (SupportObject) { - // At this point the prism can be a compound - TopoDS_Shape result = PrismMaker.Shape(); - // set the additive shape property for later usage in e.g. pattern - this->AddShape.setValue(result); + TopoDS_Shape prism; + bool isSolid = false; // support is a solid? + bool isSolidChecked = false; // not checked yet + + if ((std::string(Type.getValueAsString()) == "UpToLast") || + (std::string(Type.getValueAsString()) == "UpToFirst") || + (std::string(Type.getValueAsString()) == "UpToFace")) + { + TopoDS_Face upToFace; + gp_Dir dir(SketchVector.x,SketchVector.y,SketchVector.z); + + if ((std::string(Type.getValueAsString()) == "UpToLast") || + (std::string(Type.getValueAsString()) == "UpToFirst")) + { + // Check for valid support object + if (!SupportObject) + return new App::DocumentObjectExecReturn("Cannot extrude up to face: No support in Sketch!"); const TopoDS_Shape& support = SupportObject->Shape.getValue(); - bool isSolid = false; + if (support.IsNull()) + return new App::DocumentObjectExecReturn("Cannot extrude up to face: Support shape is invalid"); + TopExp_Explorer xp (support, TopAbs_SOLID); + if (!xp.More()) + return new App::DocumentObjectExecReturn("Cannot extrude up to face: Support shape is not a solid"); + isSolid = true; + isSolidChecked = true; + + TopoDS_Shape origFace = makeFace(wires); // original sketch face before moving one unit + std::vector cfaces = Part::findAllFacesCutBy(support, origFace, dir); + if (cfaces.empty()) + return new App::DocumentObjectExecReturn("No faces found in this direction"); + + // Find nearest/furthest face + std::vector::const_iterator it, it_near, it_far; + it_near = it_far = cfaces.begin(); + for (it = cfaces.begin(); it != cfaces.end(); it++) + if (it->distsq > it_far->distsq) + it_far = it; + else if (it->distsq < it_near->distsq) + it_near = it; + upToFace = (std::string(Type.getValueAsString()) == "UpToLast" ? it_far->face : it_near->face); + } else { + if (FaceName.getValue() == "") + return new App::DocumentObjectExecReturn("Cannot extrude up to face: No face selected"); + + // Get active object, this is the object that the user referenced when he clicked on the face! + App::DocumentObject* baseLink = this->getDocument()->getActiveObject(); + + if (!baseLink) + return new App::DocumentObjectExecReturn("Cannot extrude up to face: No object linked"); + if (!baseLink->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) + return new App::DocumentObjectExecReturn("Cannot extrude up to face: Linked object is not a Part object"); + Part::Feature *base = static_cast(baseLink); + const Part::TopoShape& baseShape = base->Shape.getShape(); + if (baseShape._Shape.IsNull()) + return new App::DocumentObjectExecReturn("Cannot extrude up to face: Cannot work on invalid shape"); + + TopoDS_Shape sub = baseShape.getSubShape(FaceName.getValue()); + if (!sub.IsNull() && sub.ShapeType() == TopAbs_FACE) + upToFace = TopoDS::Face(sub); + else + return new App::DocumentObjectExecReturn("Cannot extrude up to face: Selection is not a face"); + + // Validate face + // TODO: This would also exclude faces that are valid but not cut by the line + // So for now we trust to the intelligence of the user when picking the face + /*std::vector cfaces = findAllFacesCutBy(upToFace, origFace, dir); + if (cfaces.empty()) + return new App::DocumentObjectExecReturn("No faces found in this direction");*/ + } + + // Create semi-infinite prism from sketch in direction dir + // Hack, because the two lines commented out below do NOT work!!! + SketchVector *= 1E6; + gp_Vec vec(SketchVector.x,SketchVector.y,SketchVector.z); + vec.Transform(invObjLoc.Transformation()); + BRepPrimAPI_MakePrism PrismMaker(aFace.Moved(invObjLoc),vec,0,1); // very long, but finite prism + //dir.Transform(invObjLoc.Transformation()); + //BRepPrimAPI_MakePrism PrismMaker(aFace.Moved(invObjLoc),dir,0,0,1); + if (!PrismMaker.IsDone()) + return new App::DocumentObjectExecReturn("Cannot extrude up to face: Could not extrude the sketch!"); + + // Cut off the prism at the face we found + // Grab any point from the sketch + TopExp_Explorer exp; + exp.Init(aFace, TopAbs_VERTEX); + if (!exp.More()) + return new App::DocumentObjectExecReturn("Cannot extrude up to face: Sketch without points?"); + gp_Pnt aPnt = BRep_Tool::Pnt(TopoDS::Vertex(exp.Current())); + + // Create a halfspace from the face, extending in direction of sketch plane + BRepPrimAPI_MakeHalfSpace mkHalfSpace(upToFace, aPnt); + if (!mkHalfSpace.IsDone()) + return new App::DocumentObjectExecReturn("Cannot extrude up to face: HalfSpace creation failed"); + + // Find common material between halfspace and prism + BRepAlgoAPI_Common mkCommon(PrismMaker.Shape(), mkHalfSpace.Solid().Moved(invObjLoc)); + if (!mkCommon.IsDone()) + return new App::DocumentObjectExecReturn("Cannot extrude up to face: Common creation failed"); + + prism = this->getSolid(mkCommon.Shape()); + if (prism.IsNull()) + return new App::DocumentObjectExecReturn("Cannot extrude up to face: Resulting shape is not a solid"); + } else if ((std::string(Type.getValueAsString()) == "Length") || + (std::string(Type.getValueAsString()) == "TwoLengths")) { + if (std::string(Type.getValueAsString()) == "Length") { + if (Midplane.getValue()) { + // Move face by half the extrusion distance to get pad symmetric to sketch plane + gp_Trsf mov; + mov.SetTranslation(gp_Vec(SketchVector.x,SketchVector.y,SketchVector.z) * (-1.0) * L/2.0); + TopLoc_Location loc(mov); + aFace.Move(loc); + } else if (Reversed.getValue()) { // negative direction + SketchVector *= -1.0; + } + + // lengthen the vector + SketchVector *= L; + } else { + // Move face by the second length to get pad extending to both sides of sketch plane + gp_Trsf mov; + mov.SetTranslation(gp_Vec(SketchVector.x,SketchVector.y,SketchVector.z) * (-1.0) * L2); + TopLoc_Location loc(mov); + aFace.Move(loc); + + // lengthen the vector + SketchVector *= (L + L2); + } + + // create the extrusion + gp_Vec vec(SketchVector.x,SketchVector.y,SketchVector.z); + vec.Transform(invObjLoc.Transformation()); + BRepPrimAPI_MakePrism PrismMaker(aFace.Moved(invObjLoc),vec,0,1); // finite prism + if (!PrismMaker.IsDone()) + return new App::DocumentObjectExecReturn("Could not extrude the sketch!"); + prism = PrismMaker.Shape(); + } else { + return new App::DocumentObjectExecReturn("Internal error: Unknown type for Pad feature"); + } + + // if the sketch has a support fuse them to get one result object (PAD!) + if (SupportObject) { + // set the additive shape property for later usage in e.g. pattern + this->AddShape.setValue(prism); + + const TopoDS_Shape& support = SupportObject->Shape.getValue(); + + if (!isSolidChecked) { // we haven't checked for solid, yet if (!support.IsNull()) { TopExp_Explorer xp; xp.Init(support,TopAbs_SOLID); @@ -147,32 +292,30 @@ App::DocumentObjectExecReturn *Pad::execute(void) break; } } - if (isSolid) { - // Let's call algorithm computing a fuse operation: - BRepAlgoAPI_Fuse mkFuse(support.Moved(invObjLoc), result); - // Let's check if the fusion has been successful - if (!mkFuse.IsDone()) - return new App::DocumentObjectExecReturn("Fusion with support failed"); - result = mkFuse.Shape(); - // we have to get the solids (fuse create seldomly compounds) - TopoDS_Shape solRes = this->getSolid(result); - // lets check if the result is a solid - if (solRes.IsNull()) - return new App::DocumentObjectExecReturn("Resulting shape is not a solid"); - this->Shape.setValue(solRes); - } - else + + if (!isSolid) return new App::DocumentObjectExecReturn("Support is not a solid"); } - else { - TopoDS_Shape result = this->getSolid(PrismMaker.Shape()); - // set the additive shape property for later usage in e.g. pattern - this->AddShape.setValue(result); - this->Shape.setValue(result); - } + + // Let's call algorithm computing a fuse operation: + BRepAlgoAPI_Fuse mkFuse(support.Moved(invObjLoc), prism); + // Let's check if the fusion has been successful + if (!mkFuse.IsDone()) + return new App::DocumentObjectExecReturn("Fusion with support failed"); + TopoDS_Shape result = mkFuse.Shape(); + // we have to get the solids (fuse create seldomly compounds) + TopoDS_Shape solRes = this->getSolid(result); + // lets check if the result is a solid + if (solRes.IsNull()) + return new App::DocumentObjectExecReturn("Resulting shape is not a solid"); + this->Shape.setValue(solRes); + } + else { + TopoDS_Shape result = this->getSolid(prism); + // set the additive shape property for later usage in e.g. pattern + this->AddShape.setValue(result); + this->Shape.setValue(result); } - else - return new App::DocumentObjectExecReturn("Could not extrude the sketch!"); return App::DocumentObject::StdReturn; } diff --git a/src/Mod/PartDesign/App/FeaturePad.h b/src/Mod/PartDesign/App/FeaturePad.h index c758c94f7..91bdeff59 100644 --- a/src/Mod/PartDesign/App/FeaturePad.h +++ b/src/Mod/PartDesign/App/FeaturePad.h @@ -38,10 +38,13 @@ class Pad : public Additive public: Pad(); - App::PropertyLength Length; + App::PropertyEnumeration Type; + App::PropertyLength Length; //App::PropertyEnumeration Side; - App::PropertyBool Reversed; - App::PropertyBool MirroredExtent; + App::PropertyBool Reversed; + App::PropertyBool Midplane; + App::PropertyLength Length2; + App::PropertyString FaceName; /** @name methods override feature */ //@{ @@ -54,7 +57,8 @@ public: } //@} private: - static const char* SideEnums[]; + static const char* TypeEnums[]; + //static const char* SideEnums[]; }; } //namespace PartDesign diff --git a/src/Mod/PartDesign/Gui/TaskPadParameters.cpp b/src/Mod/PartDesign/Gui/TaskPadParameters.cpp index 8a902b2b9..d7c37b7b3 100644 --- a/src/Mod/PartDesign/Gui/TaskPadParameters.cpp +++ b/src/Mod/PartDesign/Gui/TaskPadParameters.cpp @@ -59,30 +59,106 @@ TaskPadParameters::TaskPadParameters(ViewProviderPad *PadView,QWidget *parent) connect(ui->doubleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(onLengthChanged(double))); - connect(ui->checkBoxMirrored, SIGNAL(toggled(bool)), - this, SLOT(onMirrored(bool))); + connect(ui->checkBoxMidplane, SIGNAL(toggled(bool)), + this, SLOT(onMidplane(bool))); connect(ui->checkBoxReversed, SIGNAL(toggled(bool)), this, SLOT(onReversed(bool))); + connect(ui->doubleSpinBox2, SIGNAL(valueChanged(double)), + this, SLOT(onLength2Changed(double))); + connect(ui->changeMode, SIGNAL(currentIndexChanged(int)), + this, SLOT(onModeChanged(int))); + connect(ui->lineFaceName, SIGNAL(textEdited(QString)), + this, SLOT(onFaceName(QString))); this->groupLayout()->addWidget(proxy); + // Get the feature data PartDesign::Pad* pcPad = static_cast(PadView->getObject()); double l = pcPad->Length.getValue(); - bool mirrored = pcPad->MirroredExtent.getValue(); + bool midplane = pcPad->Midplane.getValue(); bool reversed = pcPad->Reversed.getValue(); + double l2 = pcPad->Length2.getValue(); + int index = pcPad->Type.getValue(); // must extract value here, clear() kills it! + const char* upToFace = pcPad->FaceName.getValue(); + // Fill data into dialog elements ui->doubleSpinBox->setMinimum(0); + ui->doubleSpinBox->setMaximum(INT_MAX); ui->doubleSpinBox->setValue(l); - ui->doubleSpinBox->selectAll(); - ui->checkBoxMirrored->setChecked(mirrored); + ui->doubleSpinBox2->setMinimum(0); + ui->doubleSpinBox2->setMaximum(INT_MAX); + ui->doubleSpinBox2->setValue(l2); + ui->checkBoxMidplane->setChecked(midplane); // According to bug #0000521 the reversed option // shouldn't be de-activated if the pad has a support face ui->checkBoxReversed->setChecked(reversed); + ui->lineFaceName->setText(upToFace == "" ? tr("No face selected") : tr(upToFace)); + ui->changeMode->clear(); + ui->changeMode->insertItem(0, tr("Dimension")); + ui->changeMode->insertItem(1, tr("To last")); + ui->changeMode->insertItem(2, tr("To first")); + ui->changeMode->insertItem(3, tr("Up to face")); + ui->changeMode->insertItem(4, tr("Two dimensions")); + ui->changeMode->setCurrentIndex(index); - // Make sure that the spin box has the focus to get key events - // Calling setFocus() directly doesn't work because the spin box is not - // yet visible. - QMetaObject::invokeMethod(ui->doubleSpinBox, "setFocus", Qt::QueuedConnection); + // activate and de-activate dialog elements as appropriate + updateUI(index); +} + +void TaskPadParameters::updateUI(int index) +{ + if (index == 0) { // dimension + ui->doubleSpinBox->setEnabled(true); + ui->doubleSpinBox->selectAll(); + // Make sure that the spin box has the focus to get key events + // Calling setFocus() directly doesn't work because the spin box is not + // yet visible. + QMetaObject::invokeMethod(ui->doubleSpinBox, "setFocus", Qt::QueuedConnection); + ui->checkBoxMidplane->setEnabled(true); + ui->checkBoxReversed->setEnabled(true); + ui->doubleSpinBox2->setEnabled(false); + ui->lineFaceName->setEnabled(false); + } else if ((index == 1) || (index == 2)) { // up to first/last + ui->doubleSpinBox->setEnabled(false); + ui->checkBoxMidplane->setEnabled(false); + ui->checkBoxReversed->setEnabled(false); + ui->doubleSpinBox2->setEnabled(false); + ui->lineFaceName->setEnabled(false); + } else if (index == 3) { // up to face + ui->doubleSpinBox->setEnabled(false); + ui->checkBoxMidplane->setEnabled(false); + ui->checkBoxReversed->setEnabled(false); + ui->doubleSpinBox2->setEnabled(false); + ui->lineFaceName->setEnabled(true); + QMetaObject::invokeMethod(ui->lineFaceName, "setFocus", Qt::QueuedConnection); + } else { // two dimensions + ui->doubleSpinBox->setEnabled(true); + ui->doubleSpinBox->selectAll(); + QMetaObject::invokeMethod(ui->doubleSpinBox, "setFocus", Qt::QueuedConnection); + ui->checkBoxMidplane->setEnabled(false); + ui->checkBoxReversed->setEnabled(false); + ui->doubleSpinBox2->setEnabled(true); + ui->lineFaceName->setEnabled(false); + } +} + +void TaskPadParameters::onSelectionChanged(const Gui::SelectionChanges& msg) +{ + PartDesign::Pad* pcPad = static_cast(PadView->getObject()); + if (pcPad->Type.getValue() != 3) // ignore user selections if mode is not upToFace + return; + + if (!msg.pSubName || msg.pSubName[0] == '\0') + return; + std::string element(msg.pSubName); + if (element.substr(0,4) != "Face") + return; + + if (msg.Type == Gui::SelectionChanges::AddSelection) { + pcPad->FaceName.setValue(element); + pcPad->getDocument()->recomputeFeature(pcPad); + ui->lineFaceName->setText(tr(element.c_str())); + } } void TaskPadParameters::onLengthChanged(double len) @@ -92,10 +168,10 @@ void TaskPadParameters::onLengthChanged(double len) pcPad->getDocument()->recomputeFeature(pcPad); } -void TaskPadParameters::onMirrored(bool on) +void TaskPadParameters::onMidplane(bool on) { PartDesign::Pad* pcPad = static_cast(PadView->getObject()); - pcPad->MirroredExtent.setValue(on); + pcPad->Midplane.setValue(on); pcPad->getDocument()->recomputeFeature(pcPad); } @@ -106,6 +182,40 @@ void TaskPadParameters::onReversed(bool on) pcPad->getDocument()->recomputeFeature(pcPad); } +void TaskPadParameters::onLength2Changed(double len) +{ + PartDesign::Pad* pcPad = static_cast(PadView->getObject()); + pcPad->Length2.setValue((float)len); + pcPad->getDocument()->recomputeFeature(pcPad); +} + +void TaskPadParameters::onModeChanged(int index) +{ + PartDesign::Pad* pcPad = static_cast(PadView->getObject()); + + switch (index) { + case 0: pcPad->Type.setValue("Length"); break; + case 1: pcPad->Type.setValue("UpToLast"); break; + case 2: pcPad->Type.setValue("UpToFirst"); break; + case 3: pcPad->Type.setValue("UpToFace"); break; + default: pcPad->Type.setValue("TwoLengths"); + } + + updateUI(index); + + pcPad->getDocument()->recomputeFeature(pcPad); +} + +void TaskPadParameters::onFaceName(const QString& text) +{ + if (text.left(4) != tr("Face")) + return; + + PartDesign::Pad* pcPad = static_cast(PadView->getObject()); + pcPad->FaceName.setValue(text.toUtf8()); + pcPad->getDocument()->recomputeFeature(pcPad); +} + double TaskPadParameters::getLength(void) const { return ui->doubleSpinBox->value(); @@ -116,9 +226,24 @@ bool TaskPadParameters::getReversed(void) const return ui->checkBoxReversed->isChecked(); } -bool TaskPadParameters::getMirroredExtent(void) const +bool TaskPadParameters::getMidplane(void) const { - return ui->checkBoxMirrored->isChecked(); + return ui->checkBoxMidplane->isChecked(); +} + +double TaskPadParameters::getLength2(void) const +{ + return ui->doubleSpinBox2->value(); +} + +int TaskPadParameters::getMode(void) const +{ + return ui->changeMode->currentIndex(); +} + +const QString TaskPadParameters::getFaceName(void) const +{ + return ui->lineFaceName->text(); } TaskPadParameters::~TaskPadParameters() @@ -174,7 +299,10 @@ bool TaskDlgPadParameters::accept() //Gui::Command::openCommand("Pad changed"); Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Length = %f",name.c_str(),parameter->getLength()); Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Reversed = %i",name.c_str(),parameter->getReversed()?1:0); - Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.MirroredExtent = %i",name.c_str(),parameter->getMirroredExtent()?1:0); + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Midplane = %i",name.c_str(),parameter->getMidplane()?1:0); + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Length2 = %f",name.c_str(),parameter->getLength2()); + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.Type = %u",name.c_str(),parameter->getMode()); + Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.%s.FaceName = \"%s\"",name.c_str(),parameter->getFaceName().toAscii().data()); Gui::Command::doCommand(Gui::Command::Doc,"App.ActiveDocument.recompute()"); if (!PadView->getObject()->isValid()) throw Base::Exception(PadView->getObject()->getStatusString()); diff --git a/src/Mod/PartDesign/Gui/TaskPadParameters.h b/src/Mod/PartDesign/Gui/TaskPadParameters.h index c16493cad..53afdacd0 100644 --- a/src/Mod/PartDesign/Gui/TaskPadParameters.h +++ b/src/Mod/PartDesign/Gui/TaskPadParameters.h @@ -44,7 +44,7 @@ namespace PartDesignGui { -class TaskPadParameters : public Gui::TaskView::TaskBox +class TaskPadParameters : public Gui::TaskView::TaskBox, public Gui::SelectionObserver { Q_OBJECT @@ -52,19 +52,27 @@ public: TaskPadParameters(ViewProviderPad *PadView,QWidget *parent = 0); ~TaskPadParameters(); + int getMode(void) const; double getLength(void) const; + double getLength2(void) const; bool getReversed(void) const; - bool getMirroredExtent(void) const; + bool getMidplane(void) const; + const QString getFaceName(void) const; private Q_SLOTS: void onLengthChanged(double); - void onMirrored(bool); + void onMidplane(bool); void onReversed(bool); + void onLength2Changed(double); + void onModeChanged(int); + void onFaceName(const QString& text); protected: void changeEvent(QEvent *e); private: + void onSelectionChanged(const Gui::SelectionChanges& msg); + void updateUI(int index); private: QWidget* proxy; diff --git a/src/Mod/PartDesign/Gui/TaskPadParameters.ui b/src/Mod/PartDesign/Gui/TaskPadParameters.ui index d407bbf31..d1f2601cb 100644 --- a/src/Mod/PartDesign/Gui/TaskPadParameters.ui +++ b/src/Mod/PartDesign/Gui/TaskPadParameters.ui @@ -6,8 +6,8 @@ 0 0 - 158 - 116 + 272 + 238 @@ -19,7 +19,7 @@ - Type: + Type @@ -39,7 +39,7 @@ - Length: + Length @@ -55,19 +55,19 @@ 5.000000000000000 - 20.000000000000000 + 10.000000000000000 - + - false + true - Mirrored extent + Symmetric to plane @@ -78,6 +78,47 @@ + + + + + + 2nd length + + + + + + + -999999999.000000000000000 + + + 999999999.000000000000000 + + + 5.000000000000000 + + + 0.000000000000000 + + + + + + + + + + + Face + + + + + + + +