From 43a3c670f8be54bff242be65d1b87d169671ed7e Mon Sep 17 00:00:00 2001 From: GERALD NICOLAS Date: Mon, 3 May 2021 17:39:16 +0200 Subject: [PATCH] neutral fiber macro --- src/PythonAddons/CMakeLists.txt | 8 +- src/PythonAddons/PythonAddons_msg_en.ts | 86 + src/PythonAddons/PythonAddons_msg_fr.ts | 90 + src/PythonAddons/addons_Features.py | 6 +- src/PythonAddons/addons_Features.xml.in | 1 + src/PythonAddons/doc/addons_Features.rst | 6 +- src/PythonAddons/doc/fibreNeutreFeature.rst | 70 + src/PythonAddons/doc/images/compound.png | Bin 213 -> 46 bytes src/PythonAddons/doc/images/fibreNeutre.png | 1 + .../doc/images/fibreNeutrePanel.png | Bin 0 -> 4881 bytes .../doc/images/fibreNeutre_solide.png | Bin 0 -> 39751 bytes .../images/fibreNeutre_solide_surfaces.png | Bin 0 -> 47536 bytes .../doc/images/fibreNeutre_surfaces.png | Bin 0 -> 22356 bytes .../doc/images/importParameters.png | Bin 191 -> 50 bytes src/PythonAddons/doc/images/rectangle.png | Bin 304 -> 42 bytes .../macros/compoundVertices/__init__.py | 0 .../macros/compoundVertices/feature.py | 82 +- .../macros/compoundVertices/widget.xml | 4 +- .../macros/fibreNeutre/__init__.py | 19 + .../macros/fibreNeutre/feature.py | 106 + .../macros/fibreNeutre/icons/fibreNeutre.png | Bin 0 -> 325 bytes .../macros/fibreNeutre/icons/fibreNeutre.xcf | Bin 0 -> 1081 bytes .../macros/fibreNeutre/surfaceMediane.py | 1923 +++++++++++++++++ .../macros/fibreNeutre/widget.xml | 14 + .../macros/importParameters/__init__.py | 0 .../macros/importParameters/feature.py | 46 +- .../macros/importParameters/widget.xml | 4 +- src/PythonAddons/macros/rectangle/__init__.py | 0 src/PythonAddons/macros/rectangle/feature.py | 23 +- 29 files changed, 2410 insertions(+), 79 deletions(-) create mode 100644 src/PythonAddons/PythonAddons_msg_fr.ts create mode 100644 src/PythonAddons/doc/fibreNeutreFeature.rst mode change 100644 => 120000 src/PythonAddons/doc/images/compound.png create mode 120000 src/PythonAddons/doc/images/fibreNeutre.png create mode 100644 src/PythonAddons/doc/images/fibreNeutrePanel.png create mode 100644 src/PythonAddons/doc/images/fibreNeutre_solide.png create mode 100644 src/PythonAddons/doc/images/fibreNeutre_solide_surfaces.png create mode 100644 src/PythonAddons/doc/images/fibreNeutre_surfaces.png mode change 100644 => 120000 src/PythonAddons/doc/images/importParameters.png mode change 100644 => 120000 src/PythonAddons/doc/images/rectangle.png mode change 100644 => 100755 src/PythonAddons/macros/compoundVertices/__init__.py mode change 100644 => 100755 src/PythonAddons/macros/compoundVertices/feature.py create mode 100755 src/PythonAddons/macros/fibreNeutre/__init__.py create mode 100755 src/PythonAddons/macros/fibreNeutre/feature.py create mode 100644 src/PythonAddons/macros/fibreNeutre/icons/fibreNeutre.png create mode 100644 src/PythonAddons/macros/fibreNeutre/icons/fibreNeutre.xcf create mode 100755 src/PythonAddons/macros/fibreNeutre/surfaceMediane.py create mode 100644 src/PythonAddons/macros/fibreNeutre/widget.xml mode change 100644 => 100755 src/PythonAddons/macros/importParameters/__init__.py mode change 100644 => 100755 src/PythonAddons/macros/importParameters/feature.py mode change 100644 => 100755 src/PythonAddons/macros/rectangle/__init__.py mode change 100644 => 100755 src/PythonAddons/macros/rectangle/feature.py diff --git a/src/PythonAddons/CMakeLists.txt b/src/PythonAddons/CMakeLists.txt index 289f365e7..5fd04ff0a 100644 --- a/src/PythonAddons/CMakeLists.txt +++ b/src/PythonAddons/CMakeLists.txt @@ -19,6 +19,7 @@ SET(TEXT_RESOURCES PythonAddons_msg_en.ts + PythonAddons_msg_fr.ts ) # configuration @@ -42,6 +43,7 @@ INSTALL(DIRECTORY macros DESTINATION ${SHAPER_INSTALL_ADDONS}) INSTALL(DIRECTORY macros/rectangle/icons/ DESTINATION ${SHAPER_INSTALL_XML_RESOURCES}/icons/Addons) INSTALL(DIRECTORY macros/compoundVertices/icons/ DESTINATION ${SHAPER_INSTALL_XML_RESOURCES}/icons/Addons) INSTALL(DIRECTORY macros/importParameters/icons/ DESTINATION ${SHAPER_INSTALL_XML_RESOURCES}/icons/Addons) +INSTALL(DIRECTORY macros/fibreNeutre/icons/ DESTINATION ${SHAPER_INSTALL_XML_RESOURCES}/icons/Addons) INSTALL(FILES ${TEXT_RESOURCES} DESTINATION ${SHAPER_INSTALL_XML_RESOURCES}) INCLUDE(UnitTest) @@ -53,16 +55,16 @@ ADD_UNIT_TESTS(${TEST_NAMES}) if(${HAVE_SALOME}) enable_testing() set(TEST_INSTALL_DIRECTORY "${SALOME_SHAPER_INSTALL_TESTS}/PythonAddons") - + install(FILES CTestTestfileInstall.cmake DESTINATION ${TEST_INSTALL_DIRECTORY} RENAME CTestTestfile.cmake) install(FILES tests.set DESTINATION ${TEST_INSTALL_DIRECTORY}) - + set(TMP_TESTS_NAMES) foreach(tfile ${TEST_NAMES}) list(APPEND TMP_TESTS_NAMES "Test/${tfile}") endforeach(tfile ${TEST_NAMES}) - + install(FILES ${TMP_TESTS_NAMES} DESTINATION ${TEST_INSTALL_DIRECTORY}) endif(${HAVE_SALOME}) diff --git a/src/PythonAddons/PythonAddons_msg_en.ts b/src/PythonAddons/PythonAddons_msg_en.ts index 305ed4131..9f397afa9 100644 --- a/src/PythonAddons/PythonAddons_msg_en.ts +++ b/src/PythonAddons/PythonAddons_msg_en.ts @@ -1,4 +1,90 @@ + + + + compoundVertices + + Points set + Import points + + + Import a set of construction points + Import a set of construction points + + + + compoundVertices:file_path + + Import file + Import txt file (X Y Z) + + + Select file + Select the file of the points, + defined by their coordinates X Y Z + + + + compoundVertices:separator + + Separator (optional): + Separator (optional): + + + "Select separator" + Select a separator; the default value is white spaces. + + + + + + importParameters + + Import Parameters + Import parameters + + + Import a set of parameters + Import a set of parameters + + + + importParameters:file_path + + Import file + Import file + + + Select file + Select the file of the parameters, + defined by couples: name, value + + + + + + fibreNeutre + + Fibre neutre + Create midsurfaces + + + Create + Create midsurfaces + + + + fibreNeutre:file_path + + Import file + CAD file of the object + + + Select file + Select the CAD file of the object + + + diff --git a/src/PythonAddons/PythonAddons_msg_fr.ts b/src/PythonAddons/PythonAddons_msg_fr.ts new file mode 100644 index 000000000..fd5a27a8c --- /dev/null +++ b/src/PythonAddons/PythonAddons_msg_fr.ts @@ -0,0 +1,90 @@ + + + + + + + compoundVertices + + Points set + Importer des points + + + Import a set of construction points + Importer un ensemble de points de construction + + + + compoundVertices:file_path + + Import file + Fichier des points à importer (X Y Z) + + + Select file + Choisir le fichier contenant les points à importer, + définis par leurs coordonnées X Y Z + + + + compoundVertices:separator + + Separator (optional): + Séparateur (optionnel) : + + + "Select separator" + Choisir éventuellement un séparateur ; par défaut ce sont des blancs. + + + + + + importParameters + + Import Parameters + Importer des paramètres + + + Import a set of parameters + Importer un ensemble de paramètres + + + + importParameters:file_path + + Import file + Fichier des paramètres à importer + + + Select file + Choisir le fichier contenant les paramètres à importer, + définis par les paires : nom, valeur + + + + + + fibreNeutre + + Fibre neutre + Créer des fibres neutres + + + Create + Créer des fibres neutres + + + + fibreNeutre:file_path + + Import file + Fichier CAO de l'objet à traiter + + + Select file + Choisir le fichier de type CAO contenant l'objet à traiter + + + + diff --git a/src/PythonAddons/addons_Features.py b/src/PythonAddons/addons_Features.py index 64fbca848..7c173acd0 100644 --- a/src/PythonAddons/addons_Features.py +++ b/src/PythonAddons/addons_Features.py @@ -17,13 +17,13 @@ # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com # -"""Registration of all user-defined Python features -""" +"""Registration of all user-defined Python features""" import ModelAPI from macros.rectangle.feature import SketchPlugin_Rectangle from macros.compoundVertices.feature import compoundVertices from macros.importParameters.feature import importParameters +from macros.fibreNeutre.feature import fibreNeutre class PythonFeaturesPlugin(ModelAPI.ModelAPI_Plugin): @@ -49,6 +49,8 @@ class PythonFeaturesPlugin(ModelAPI.ModelAPI_Plugin): aFeature = compoundVertices().__disown__() elif theFeatureID == importParameters.ID(): aFeature = importParameters().__disown__() + elif theFeatureID == fibreNeutre.ID(): + aFeature = fibreNeutre().__disown__() else: raise Exception("No such feature %s" % theFeatureID) diff --git a/src/PythonAddons/addons_Features.xml.in b/src/PythonAddons/addons_Features.xml.in index 3f3b7666d..efb23c7b6 100644 --- a/src/PythonAddons/addons_Features.xml.in +++ b/src/PythonAddons/addons_Features.xml.in @@ -2,4 +2,5 @@ + diff --git a/src/PythonAddons/doc/addons_Features.rst b/src/PythonAddons/doc/addons_Features.rst index 1db6329d6..4c268e76c 100644 --- a/src/PythonAddons/doc/addons_Features.rst +++ b/src/PythonAddons/doc/addons_Features.rst @@ -1,4 +1,3 @@ - Python addons ============= @@ -10,7 +9,7 @@ A feature description includes 4 files: - widget.xml with a description of the property panel, - __init__.py, -- feature.py with python commands, +- feature.py with python commands, - icon.png with image of button in the toolbar (the file is located at sub-folder /icons). Some examples of already created custom features are: @@ -19,6 +18,7 @@ Some examples of already created custom features are: :titlesonly: :maxdepth: 1 - rectangleFeature.rst compoundVerticesFeature.rst importParametersFeature.rst + fibreNeutreFeature.rst + rectangleFeature.rst diff --git a/src/PythonAddons/doc/fibreNeutreFeature.rst b/src/PythonAddons/doc/fibreNeutreFeature.rst new file mode 100644 index 000000000..e9413dc1b --- /dev/null +++ b/src/PythonAddons/doc/fibreNeutreFeature.rst @@ -0,0 +1,70 @@ +.. _create_fibreNeutre: +.. |fibreNeutre.icon| image:: images/fibreNeutre.png + +Fibre neutre +============ + +FIbre neutre est une macro fonction qui ne peut pas être éditée après usage. +Elle permet de créer les surfaces médianes à des solides minces, encore appelées fibres neutres. + +Pour créer les fibres neutres d'un objet : + +#. Choisir dans le menu principal *Macros - > Fibre neutre* item ou +#. cliquer le bouton |fibreNeutre.icon| **Fibre neutre** dans la barre des macros. + +Le menu suivant apparaît : + +.. figure:: images/fibreNeutrePanel.png + :align: center + + Fibre neutre + +On doit fournir le fichier de type **XAO** qui contient l'objet. On retrouve dans l'arbre d'étude du module GEOM cet objet de départ et un nouvel objet formé des fibres neutres. Son nom est celui de l'objet de départ, suffixé par **_M**. + +.. note:: + Les surfaces ainsi créées ne sont pas reliées entre elles. Il reste ensuite un travail de jonction à effectuer. + +Plus : +"""""" + +Le programme crée les surfaces sous réserve que pour le solide envisagé, il a réussi à trouver deux faces \ +de taille identique et supérieure aux autres faces du solide pour des polyèdres ou \ +s'il a reconnu des formes canoniques. +Il crée alors une surface au milieu de ces deux grandes faces. Cette face est coloriée en vert. + +Si les 2 faces les plus grandes sont planes mais que leurs tailles ne sont pas identiques, le programme \ +crée néanmoins une face basée sur la plus grande de ces faces. Un message est émis et cette face médiane \ +est coloriée en bleu. Le volume correspondant n'est pas détruit et est colorié en rouge. + +On sait traiter les faces : + . planes + . cylindriques + . sphériques + . toriques + . coniques + +Exemple : +""""""""" + +A partir d'un ensemble de 4 solides de forme torique : + +.. figure:: images/fibreNeutre_solide.png + :align: center + + Solides à traiter + +on obtient 4 surfaces indépendantes : + +.. figure:: images/fibreNeutre_surfaces.png + :align: center + + Surfaces + + +.. figure:: images/fibreNeutre_solide_surfaces.png + :align: center + + Surfaces dans les solides + + + diff --git a/src/PythonAddons/doc/images/compound.png b/src/PythonAddons/doc/images/compound.png deleted file mode 100644 index 5e119b39a983359f202624c1e9c2a1878ca5df56..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 213 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Y)RhkE)4%caKYZ?lYt_f1s;*b z3=DinK$vl=HlH+5kiEpy*OmP-ha9hT(^NX`VSDXolC=I}d&xCk(m*RSQ?^`fj@(W2VVEPL#txr9hT29m{oxj=ja@ziiH|~WD35-jwbUU82Ny!D;#^CAd=d#Wzp$P!& C$VWZ^ diff --git a/src/PythonAddons/doc/images/compound.png b/src/PythonAddons/doc/images/compound.png new file mode 120000 index 000000000..9f17b4516 --- /dev/null +++ b/src/PythonAddons/doc/images/compound.png @@ -0,0 +1 @@ +../../macros/compoundVertices/icons/import.png \ No newline at end of file diff --git a/src/PythonAddons/doc/images/fibreNeutre.png b/src/PythonAddons/doc/images/fibreNeutre.png new file mode 120000 index 000000000..92b07a5a7 --- /dev/null +++ b/src/PythonAddons/doc/images/fibreNeutre.png @@ -0,0 +1 @@ +../../macros/fibreNeutre/icons/fibreNeutre.png \ No newline at end of file diff --git a/src/PythonAddons/doc/images/fibreNeutrePanel.png b/src/PythonAddons/doc/images/fibreNeutrePanel.png new file mode 100644 index 0000000000000000000000000000000000000000..91e15d2c0d1426cf1e981675f53ef2d95af21aa7 GIT binary patch literal 4881 zcmaKwXEa>xyT(VfQ6?sds4+~um}nt-lwk-F!H5W=MvpRj9|WVqe1bS(c4$Km{$+c6mCC1`!HS31Ma_x8ia#>O}hK#Kf=0;~0Hbs+SV zg^n7ENyLPK5nao13F&=y#U&*{m3N>QpYeo#9UWE{A0r4CdpA?6;zrfcRGydApo28l zOsNEi8>enn21bPL$wXgl<9&VZ1&qR0XZ?MndbV_Qmu6(<*L~b{C!BO09g71MBaVGo zCPOiMWg`(04Ou?E0UYcZ8T~}LDm(Gr{zl{Mx`NrGWBV=W`60Y&e@vwR%TbI|oo6e_ zXJRwD%bMOL5IkMu!pqMeSyTjjR&Ji~-D*hWY}~|E+oweZ4$lnE9*nSbfs@$Vf|P0X$T@PyRp3t>4pxkIp=qA=}8rdXA=**#;ac8e`u$4 zablfzP*EYaMmpPV85l1!p<`kakd;kO;FS5|G=bBZew~@w`>WEL{hkd_7k(~TUte$T zGQidBPz#oTqr*_h5}F@g52y$JPHakM5Wue!-j{Sm=V{9^1KiE`1pD=Tb<;FkEaQX>@=6$+NPh^8h5 zNC?S2X>->xP`^;emYkK*i3$CuPu0-qCe-=hAd;S*z6qxRbnVNKiX)d!=18V-)y(tV ze(J-}RAslO`%1oPx}xS+(iH=xJy&~M9lv^9o)fAZ$BK2*LKb5L#Ml@W{tT)zv$Edc z;_7Sg-c-P~lx%;>&)@5n7)T~ZcWqBiy1B z1J^A4@I398?|hVG`Z@L;)KX<^zQ10;-otC^rnG6 zac@^%oc*zIVjxC^zXejRKO!kS&QCh0@yCnQB63P|-w4!@m{URk^LT&h5!Cy*?~Xau zO_|w2r?eLW+n#g57wpY9(C;Qd*K=C}1%xtUlRZe3BqQvxg)^SO3UOI;(-CcipMbI1 z@T9Utfh~FHwy1BxGUo;1t4)|N%OZp%v)Y@rt$o<2gm$PlA`VQ{N^D1NC|vdm_O`0n zKxPIm!fAmZI_UnSREMd2OkoYGYie}az#6l@D>@q7Q~6$14U}XvTA??pzd7Xd-dXy% z=}-xK`Jr3OION4zl0{Ba?oZqLkq3OF)0IBwKDi%}OOv;VW3FT|{3&MxW5fUxr1P#N zjA2d0^0KvMzcq>*EaM|vg#)dPjOv~&x*E?^?TMDcY*vF;{#AW*@#fno7De^<^y#4* zjX7ELu{v+UD|#vi4y?!J&UMDZewM?K@}^E9e+{vmAq?VOH)ft^7nL$>3nLx<5Er#* z?&T(sGDiQ*ziwL846a)bR3PDr&PK=Jv*sTF9v@TTdVvAIF*fLFReTtHQRebTVlj`PiU{amKq2M8Wfzpf_=nbhW2UnHNY@FWJ88lGfKb;@C%#nY+2<+Rx_2DMN!)rj;U{;Ome-Qfya^?!HI7#vP1l1= ztPR@2tvmDSdebFaR}MwE(YsYae z>z^m6#$(Ym+d0yvU1whfErJUqnfkomMZGJ@-E#ty?q0DfC+)0h)jrV$9F#PNpYri* zx4+^AFV?~L{d3#9{LHxh{IU=S2~L7X)`LS4R`mV)3rtR+t0#hZaH7V-f~U*Z-4GOLCx4?OFfEiwn={h zW7)DFFVMxdVrk7k9Sl?3`#Od=mw%Vw_Fr<6D6cq3zDJq_jpxHg z&xqpA>&Wc!v2En9pmpG7!yf9Xf$jA4wEt1JM!LL9tS%>?n#Dnzi;3)8e*l0w;$@Zn z-eUHLf}wznYU>t$KT}|E`rsg}SFU?WrhLmPZq~D*2s7W*lwo*~XxTBRimW8CNpqin zX&-s_;kOSA9aMv$-GO!77xE+uWe;E zrBB)zEsWKy!@jAX9%_eq{|8>%B#P}#BJ<2||NVr=-P-lQI7?uF z<#0o&yt4AhIFe4^xY|c5ZXCDz9YP<8vRJ7I*r1f0bOun-FdjEhApWo(3J5P^DZghb zTBvpGxv7J=7KG(%;87wBAv;wKjkLLml-h-?44=2tro?ay2VpcI==1`9tl>L`A#QwyCBxcP zR?iC$>ai)lpNBn09!q&jWxO!4WT%~a>_nIDa{XpuBUM;9FWZN#ds%6?me^E+d2HDt&;&*(d&26@l7Y~UZvs(F|8bmuAW#FL0?gqh+tc9d|I3*E z-^VBgnU&7ABs!D0lO~;g?l|pAKrtmcsyTPJAMRAId`dH4Owm=!X=s?*_Qrq%D2of- zc4p+r+_sqMiwOs}1(B<3(wYCxotWropp~_?rmn64A72ES`uMfqcU+vGdH0~EYZB7a z*>ZDpjqm|dEOFnB=YIWqh(KJatgP(l?0l1)tZZ$ahdQsF3y6!kA#nZr^+i&r47QIe z_zc@;=PZr&%;--w_}{!ZHyaWGrhHx-K)(y>G2c7-+@q>qqfn*eU{pQW0aNtscjI8@2RUl!NC(ii*-VH{UTm{uW9}{?03Iiyd?j^q$I>sw#@;xVWXfBqfj3 zwY9Y>uZ<`6^^?x4WVVZEmnfL6sT-L)p4#<;2c3Ea6MHP~1(W;${n_w=CjUd(fImfz zmoiYA{L#_T9Yw9-Aua-e;G5w(drk{vV)AWHijMwRT|Fvi@$6ZFP*QyS=sU`Ih+>1h z_GapvH`nd@GwEIxymWXUxww)N5Wxn!uYeu|FjJRh5zPAXV9YmJ<<|ySZi;)1!q!M+ zRFpG$x||8uH!2d+&@-(mXJc$29v9%Imi^#%TSiyy?LBjH!(x9v5-ce$Dk|ObIJ?)q zy!rX=@5(Bsn3$Ni@80P>d!}w>bz3V{*gaLmyeS=np?ajHbw@;m4+;$>1DS6F{=Z=m zJzS%~9rTurYGg93FcMx~S@|cI+0G`>7r35w+CFysM{#|dpJtn`V>NGT)*i27?^|Mqw@>Xur{ zxZ#Bw^z^Dd4EC{zBi4%hmjobE={n;n(%~uv!_FHqSNSkBl4Qi zWfZ1J#T@^t(tr2KI;Ss&+By9NNEd@5moF`@6`=;yU;WW4F6QIdsv8JKuSe4ptNT|pco?5ZUWpeQ zExK0vl2HQjQBPI;I9O~Qk<(g$v^Ib_Ng@r=SAILuIT!u)(RYf!2i(NLTHEBFU;CX3M0ZQWq~jJhgvX8l)=YLw+eG1UZ)_I3^ZpdCgF zuD%s+DFeuCVxP104QA$!I`<_7REj7wxsZGF-Cue!TD(K|8Me%8eVmEVjE3m3g6TtB zO{MGTD3MNwko39}yibRHhAc_?4vg)REWvIck5$5BB(ws;oaFU=l#2NL`OZ zdtbBIG{JK+pNq^&H3>L<~O~8HfKP`af106LS!ZPf?04er+xBvhE literal 0 HcmV?d00001 diff --git a/src/PythonAddons/doc/images/fibreNeutre_solide.png b/src/PythonAddons/doc/images/fibreNeutre_solide.png new file mode 100644 index 0000000000000000000000000000000000000000..be6756436fee6a9605d50f7903e4d31bd59655f5 GIT binary patch literal 39751 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

vU_-7KG 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 z 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 diff --git a/src/PythonAddons/doc/images/importParameters.png b/src/PythonAddons/doc/images/importParameters.png new file mode 120000 index 000000000..c5167fbcc --- /dev/null +++ b/src/PythonAddons/doc/images/importParameters.png @@ -0,0 +1 @@ +../../macros/importParameters/icons/parameters.png \ No newline at end of file diff --git a/src/PythonAddons/doc/images/rectangle.png b/src/PythonAddons/doc/images/rectangle.png deleted file mode 100644 index b98a99162ce70129bafcc89b78cd5db47b8b64c7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 304 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Y)RhkE)4%caKYZ?lYt_f1s;*b zKpodXn9)gNb_Gz7y~NYkmHhz|3#X8-?1>~BpwM1V7sn8b(?=(t - + - + diff --git a/src/PythonAddons/macros/fibreNeutre/__init__.py b/src/PythonAddons/macros/fibreNeutre/__init__.py new file mode 100755 index 000000000..6ccc82085 --- /dev/null +++ b/src/PythonAddons/macros/fibreNeutre/__init__.py @@ -0,0 +1,19 @@ +# Copyright (C) 2016-2021 CEA/DEN, EDF R&D +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + diff --git a/src/PythonAddons/macros/fibreNeutre/feature.py b/src/PythonAddons/macros/fibreNeutre/feature.py new file mode 100755 index 000000000..afe62ae2b --- /dev/null +++ b/src/PythonAddons/macros/fibreNeutre/feature.py @@ -0,0 +1,106 @@ +# -*- coding: utf-8 -*- +# Copyright (C) 2016-2021 CEA/DEN, EDF R&D +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +"""Obtention des surfaces médianes à partir d'une CAO contenue dans un fichier + +On sait traiter les faces : + . planes + . cylindriques + . sphériques + . toriques + . coniques + +Author: Gérald NICOLAS +""" +__revision__ = "V02.01" + +import os + +from salome.shaper import model + +import ModelAPI + +from macros.fibreNeutre.surfaceMediane import SurfaceMediane + +class fibreNeutre(model.Feature): + """Création des fibres neutres""" + +# Feature initializations + + def __init__(self): + """x.__init__(...) initializes x; see x.__class__.__doc__ for signature""" + model.Feature.__init__(self) + + @staticmethod + def ID(): + """Return Id of the Feature.""" + return "fibreNeutre" + + @staticmethod + def FILE_ID(): + """Returns ID of the file.""" + return "file_path" + + def getKind(self): + """Override Feature.getKind()""" + return fibreNeutre.ID() + + +# Initialization of the dialog panel + + def initAttributes(self): + """Override Feature.initAttributes()""" + # Creating the input argument of the feature + self.data().addAttribute(self.FILE_ID(), ModelAPI.ModelAPI_AttributeString_typeId()) + + +# Execution + + def execute(self): + """F.execute() -- execute the Feature""" + apath = self.string(self.FILE_ID()) + filepath = apath.value() + #print("filepath : '{}'".format(filepath)) + if filepath != "" : + if os.path.isfile(filepath): + # Lancement du script de création des fibres neutres + l_options = list() + #l_options.append("-v") + #l_options.append("-vmax") + l_options.append("-retour_shaper") + #print("l_options : '{}'".format(l_options)) + s_med = SurfaceMediane(l_options) + erreur, message = s_med.surf_fic_cao (filepath) + del s_med + if erreur: + self.setError(message) + else: + self.setError("The file '{}' does not exist".format(filepath)) + + return + + def isMacro(self): + """Override Feature.initAttributes(). + F.isMacro() -> True + + fibreNeutre feature is macro: removes itself on the creation transaction + finish. + """ + return False diff --git a/src/PythonAddons/macros/fibreNeutre/icons/fibreNeutre.png b/src/PythonAddons/macros/fibreNeutre/icons/fibreNeutre.png new file mode 100644 index 0000000000000000000000000000000000000000..bb8452e024997f32666d2d18e45e6a0ba2865d06 GIT binary patch literal 325 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Y)RhkE)4%caKYZ?lYt_f1s;*b z3=DjSL74G){)!Z!AbW|YuPgggRu*1P9W~h+f1uDMPZ!4!i_=Rl@AYDK6gcqlek+Th zPE9|@q6HmOOMls%FVdgd?y*p8<7eJQOPj9Vdeipt#N94F9_!-IU(?I_=WlYEcY%G5 z_}qt^xQ~Wc9AS-{5bP!UrFQwZyPnr-Pp{~C>Har-(renfd;T91Ik-IXzsT RxDDt#22WQ%mvv4FO#t+5gl+%; literal 0 HcmV?d00001 diff --git a/src/PythonAddons/macros/fibreNeutre/icons/fibreNeutre.xcf b/src/PythonAddons/macros/fibreNeutre/icons/fibreNeutre.xcf new file mode 100644 index 0000000000000000000000000000000000000000..ccc9063b0502d58ed066c3bf3725305003da8bd3 GIT binary patch literal 1081 zcmd5)Jxc>Y5S=|QF@B%;)mWTh5ed;mP=b|cZzWhK@$OuRNw`Zut1J9r_BL8r`VahS zj3}tvlqKwcQLjjpxjk1$gcX$Z5_sBbs9)oT%m~tTm#tD)56TMHzZ#LIs7zrd}^A z*x!dYL@(;*`SR*Q@hsSXQuc`2u&>9rw46NqtC3%lPLOo^U;dNHr_5LPq#c6m_c*L) YRB^`_(_ZDFlJagv23}UZZ`$~hPnDwZ1poj5 literal 0 HcmV?d00001 diff --git a/src/PythonAddons/macros/fibreNeutre/surfaceMediane.py b/src/PythonAddons/macros/fibreNeutre/surfaceMediane.py new file mode 100755 index 000000000..a2aae3805 --- /dev/null +++ b/src/PythonAddons/macros/fibreNeutre/surfaceMediane.py @@ -0,0 +1,1923 @@ +# -*- coding: utf-8 -*- +# Copyright (C) 2016-2021 CEA/DEN, EDF R&D +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# +"""Obtention des surfaces médianes à partir d'un objet GEOM ou SHAPER + +On sait traiter les faces : + . planes + . cylindriques + . sphériques + . toriques + . coniques + +Version initiale par : +alexandre.prunie@blastsolutions.io +guillaume.schweitzer@blastsolutions.io + +Gérald NICOLAS ++33.1.78.19.43.52 +""" + +__revision__ = "V10.09" + +#========================= Les imports - Début =================================== + +import os +import sys +import tempfile + +import salome +import SALOMEDS +from salome.shaper import model +from salome.geom import geomBuilder +from salome.geom import geomtools +from salome.kernel.studyedit import getStudyEditor + +import numpy as np + +#========================== Les imports - Fin ==================================== + +D_FMT = dict() +D_FMT["stp"] = ["stp", "step"] +D_FMT["igs"] = ["igs", "iges"] +for CLE in ("brep", "xao"): + D_FMT[CLE] = [CLE] + +#========================= Début de la fonction ================================== + +def decode_cao (fmt_cao): + """Décode le format de la cao + +Entrées : + :fmt_cao: format du fichier, step, iges, etc. +Sorties : + :fmt_cao_0: format décodé + """ + + fmt_cao_0 = "" + + fmt_cao_low = fmt_cao.lower() + + for cle, l_aux in D_FMT.items(): + if ( fmt_cao_low in l_aux ): + fmt_cao_0 = cle + break + + return fmt_cao_0 + +#========================= Fin de la fonction =================================== + +#========================= Début de la fonction ================================== + +def import_cao (part_doc, ficcao, verbose=False): + """Importation d'une cao + +Entrées : + :part_doc: part + :ficcao: le fichier de la CAO +Sorties : + :objet: l'objet importé dans SHAPER + """ + + + erreur = 0 + message = "Fichier '{}'\n".format(ficcao) + if verbose: + print (message) + + objet = None + + laux = ficcao.split(".") + fmt_cao_0 = decode_cao (laux[-1]) + + if ( fmt_cao_0 not in ("stp", "brep", "igs", "xao") ): + message += "Le format de CAO est inconnu" + erreur = 1 + + elif not ficcao: + message += "Le fichier de CAO n'a pas été décodé correctement." + erreur = 2 + + elif not os.path.isfile(ficcao): + message += "Le fichier de CAO est inconnu." + erreur = 3 + + else: + + message = "" + objet = model.addImport(part_doc, ficcao) + objet.execute(True) + model.do() + + if verbose: + texte = "Objet : '{}'\n".format(objet.result().name()) + texte += "De type : '{}'".format(objet.result().shapeType()) + print (texte) + + + return erreur, message, objet + +#========================= Fin de la fonction =================================== + +#=================================== La classe =================================== + +class SurfaceMediane (object): + + """Calcul des surfaces médianes de solides minces + +L'objectif de ce programme est de créer les surfaces médianes, encore appelées fibres neutres, pour \ +une structure qui est un solide ou un assemblage de solides (compound). +Pour réaliser l'opération, deux façons de faire : + +1. On sélectionne la structure dans l'arbre d'étude ou dans la fenêtre graphique de GEOM, puis on lance le script. + +2. On écrit un script python dans lequel on réalise la création ou l'importation d'une CAO. \ +On insère cette classe dans le script, puis on lance surf_fic_cao, surf_objet_shaper ou surf_objet_geom selon le point de départ. + +Le programme crée les surfaces sous réserve que pour le solide envisagé, il a réussi à trouver deux faces \ +de taille identique et supérieure aux autres faces du solide pour des polyèdres ou \ +s'il a reconnu des formes canoniques. +Il crée alors une surface au milieu de ces deux grandes faces. Cette face est coloriée en vert. + +Si les 2 faces les plus grandes sont planes mais que leurs tailles ne sont pas identiques, le programme \ +crée néanmoins une face basée sur la plus grande de ces faces. Un message est émis et cette face médiane \ +est coloriée en bleu. Le volume correspondant n'est pas détruit et est colorié en rouge. + +On sait traiter les faces : + . planes + . cylindriques + . sphériques + . toriques + . coniques + +Options obligatoires +******************** +Aucune + +Options facultatives +******************** +. Suppression des solides et faces créés par l'explosion des objets. Par défaut, la suppression est faite. +-menage/-no_menage + +. Retour dans Shaper. Par défaut, les faces restent dans GEOM. +-retour_shaper/-no_retour_shaper + + """ + +# A. La base + + message_info = "" + _verbose = 0 + _verbose_max = 0 + affiche_aide_globale = 0 + _menage = True + +# B. Les variables + + _choix_objet = 0 + _retour_shaper = False + nom_solide = None + epsilon = 5.e-3 + part_doc = None + + ficcao = None + rep_trav = None + objet_geom = None + + l_faces_trans = list() + + faces_pb_nb = 0 + faces_pb_msg = "" + +#=========================== Début de la méthode ================================= + + def __init__ ( self, liste_option ): + + """Le constructeur de la classe SurfaceMediane + +Décodage des arguments +On cherche ici les arguments généraux : aide, verbeux + """ + + for option in liste_option : + + #print (option) + if isinstance(option,str): + saux = option.upper() + #print (saux) + if saux in ( "-H", "-HELP" ): + self.affiche_aide_globale = 1 + elif saux == "-V" : + self._verbose = 1 + elif saux == "-VMAX" : + self._verbose = 1 + self._verbose_max = 1 + elif saux == "-MENAGE" : + self._menage = True + elif saux == "-NO_MENAGE" : + self._menage = False + elif saux == "-RETOUR_SHAPER": + self._retour_shaper = True + elif saux == "-NO_RETOUR_SHAPER": + self._retour_shaper = False + +#=========================== Fin de la méthode ================================== + +#=========================== Début de la méthode ================================= + + def __del__(self): + """A la suppression de l'instance de classe""" + if self._verbose_max: + print ("Suppression de l'instance de la classe.") + +#=========================== Fin de la méthode ================================== + +#=========================== Début de la méthode ================================= + + def _selection_objet_graphique ( self, geompy ): + """Sélectionne l'objet dans la fenêtre graphique + +Entrées : + :geompy: environnement de GEOM + +Sorties : + :objet: objet à traiter + """ + + nom_fonction = __name__ + "/_selection_objet_graphique" + blabla = "\nDans {} :\n".format(nom_fonction) + + erreur = 0 + message = "" + objet = None + + while ( not erreur ): + +# 1. Contrôle du nombre d'objets sélectionnés graphiquement + nb_objet = salome.sg.SelectedCount() + if self._verbose_max: + print (blabla+"Nombre d'objets sélectionnés : {}.".format(nb_objet)) + + if ( nb_objet != 1 ): + message = "Nombre d'objets sélectionnés : {}.\nIl en faut un et un seul.".format(nb_objet) + erreur = 1 + break + +# 2. Récupération de l'ID de l'objet en cours + entry = salome.sg.getSelected(0) +# Récupération de l'objet + objet = salome.myStudy.FindObjectID( entry ).GetObject() + if self._verbose_max: + print (geompy.WhatIs(objet)) + + break + + return erreur, message, objet + +#=========================== Fin de la méthode ================================== + +#=========================== Début de la méthode ================================= + + def _les_solides ( self, geompy, objet ): + """Les solides de l'objet à traiter + +Entrées : + :geompy: environnement de GEOM + :objet: l'objet à traiter + +Sorties : + :l_solides: liste des solides de la sélection + """ + + nom_fonction = __name__ + "/_les_solides" + blabla = "\nDans {} :\n".format(nom_fonction) + if self._verbose_max: + print (blabla) + + erreur = 0 + message = "" + l_solides = list() + + while ( not erreur ): + +# 1. Nombre de solides composant l'objet à traiter + d_shape_info = geompy.ShapeInfo(objet) + n_solides = d_shape_info["SOLID"] + if self._verbose_max: + print ("Nombre de solides : {}".format(n_solides)) + + nom_objet = objet.GetName() + if self._verbose: + print (". Traitement de l'objet '{}'".format(nom_objet)) + +# 2. Liste des solides qui composent l'objet + if ( n_solides == 0 ): + message = "Aucun solide dans l'objet sélectionné." + erreur = 1 + break + elif ( n_solides == 1 ): + l_solides.append(objet) + else: + l_solides = geompy.ExtractShapes(objet, geompy.ShapeType["SOLID"], True) + for iaux, solide in enumerate(l_solides): + geompy.addToStudyInFather( objet, solide, "{}_{:03d}".format(nom_objet,iaux+1) ) + if self._verbose_max: + print ("l_solides : {}.".format(l_solides)) + for iaux, solide in enumerate(l_solides): + print (geompy.WhatIs(solide)) + + break + + return erreur, message, l_solides + +#=========================== Fin de la méthode ================================== + +#=========================== Début de la méthode ================================= + + def _faces_du_solide ( self, geompy, solide ): + """Détermine les faces d'un solide + +Entrées : + :geompy: environnement de GEOM + :solide: le solide à traiter + +Sorties : + :l_faces: liste des faces du solide + """ + + nom_fonction = __name__ + "/_faces_du_solide" + blabla = "\nDans {} :\n".format(nom_fonction) + if self._verbose_max: + print (blabla) + + erreur = 0 + message = "" + l_faces = list() + + while ( not erreur ): + + self.nom_solide = solide.GetName() + if self._verbose: + print (".. Traitement du solide '{}'".format(self.nom_solide)) + +# 1. Le solide est-il un solide unique ? + if self._verbose_max: + print (geompy.WhatIs(solide)) + longueur, aire, volume = geompy.BasicProperties(solide) + if self._verbose_max: + print (". longueur, aire, volume : {}, {}, {}".format(longueur,aire,volume)) +# Contrôle du solide + d_shape_info = geompy.ShapeInfo(solide) + n_solides = d_shape_info["SOLID"] + if self._verbose_max: + print ("Nombre de solides : {}".format(n_solides)) + if ( n_solides != 1 ): + message = "Nombre de solides : {}.\nIl en faut un et un seul.".format(n_solides) + erreur = 1 + break + +# 2. Liste des faces qui composent le solide + l_faces = geompy.ExtractShapes(solide, geompy.ShapeType["FACE"], True) + for iaux, face in enumerate(l_faces): + geompy.addToStudyInFather( solide, face, "Face_{}".format(iaux+1) ) + if self._verbose_max: + print ("l_faces : {}".format(l_faces)) + for iaux, face in enumerate(l_faces): + print (geompy.WhatIs(face)) + + break + + return erreur, message, l_faces + +#=========================== Fin de la méthode ================================== + +#=========================== Début de la méthode ================================= + + def _calcul_caract_faces ( self, geompy, l_faces ): + """Calcule les caractéristiques géométriques des faces + +Entrées : + :geompy: environnement de GEOM + :l_faces: liste des faces du solide + +Sorties : + :tb_caract: tableau des caractéristiques géométriques des faces + """ + + nom_fonction = __name__ + "/_calcul_caract_faces" + blabla = "\nDans {} :\n".format(nom_fonction) + + nb_faces = len(l_faces) + if self._verbose_max: + print (blabla+"Nombre de faces : {}.".format(nb_faces)) + + tb_caract = np.zeros((nb_faces,3), dtype = 'object') + for iaux, face in enumerate(l_faces): + _, aire, _ = geompy.BasicProperties(face) + #longueur, aire, volume = geompy.BasicProperties(face) + if self._verbose_max: + texte = "\t. Face numéro {}".format(iaux) + #texte += "\n\t. longueur, aire, volume : {}, {}, {}".format(longueur,aire,volume) + print (texte) + + tb_caract [iaux][0] = face + tb_caract [iaux][1] = aire + tb_caract [iaux][2] = geompy.KindOfShape(face) + if self._verbose_max: + print ("\t. tb_caract : {} {}".format(aire,tb_caract[iaux][2])) + + return tb_caract + +#=========================== Fin de la méthode ================================== + +#=========================== Début de la méthode ================================= + + def _tri_faces ( self, tb_caract ): + """Trie les faces en fonction de leurs surfaces + +Entrées : + :geompy: environnement de GEOM + +Sorties : + :tb_caract_1[-1], tb_caract_1[-2]: les caractéristiques des 2 faces les plus grandes + """ + + erreur = 0 + message = "" + + nom_fonction = __name__ + "/_tri_faces" + blabla = "\nDans {} :\n".format(nom_fonction) + +# Tri du tableau en fonction des surfaces + if self._verbose_max: + print (blabla+"tb_caract brut : {}".format(tb_caract)) + tb_caract_1 = sorted(tb_caract, key=lambda colonnes: colonnes[1]) + if self._verbose_max: + print ("tb_caract trié : {}".format(tb_caract_1)) + + if self._verbose: + texte = "\tSurface de la plus grande face : {}, de caractéristiques {}\n".format(tb_caract_1[-1][1],tb_caract_1[-1][2]) + texte += "\tSurface de la face suivante : {}, de caractéristiques {}".format(tb_caract_1[-2][1],tb_caract_1[-2][2]) + print (texte) + +# La surface suivante doit être différente, sinon ce n'est pas un solide mince + if ( np.abs((tb_caract_1[-1][1]-tb_caract_1[-3][1])/tb_caract_1[-1][1]) < self.epsilon ): + message += ". Surface de la plus grande face : {}\n".format(tb_caract_1[-1][1]) + message += ". Surface de la face suivante : {}\n".format(tb_caract_1[-2][1]) + message += ". Surface de la 3ème face suivante : {}\n".format(tb_caract_1[-3][1]) + message += "==> L'écart est trop faible.\n" + message += "Impossible de créer la face médiane pour le solide '{}' ".format(self.nom_solide) + message += "car le solide n'est pas assez mince." + erreur = -1 + + return erreur, message, tb_caract_1[-1], tb_caract_1[-2] + +#=========================== Fin de la méthode ================================== + +#=========================== Début de la méthode ================================= + + def _calcul_caract_aretes_face ( self, geompy, caract_face ): + """Détermine les caractéristiques des arêtes d'une face + +Entrées : + :geompy: environnement de GEOM + :caract_face: les caractéristiques de la face + +Sorties : + :caract_arete_face: les caractéristiques des arêtes de la face + """ + + nom_fonction = __name__ + "/_calcul_caract_aretes_face" + blabla = "\nDans {} :\n".format(nom_fonction) + + if self._verbose_max: + texte = blabla + texte += "face : {}\n".format(caract_face) + print (texte) + +# Détermination des arêtes pour chaque face + face = caract_face[0] + l_aretes = geompy.ExtractShapes(face, geompy.ShapeType["EDGE"], True) + caract_arete_face = list() + for arete in l_aretes: + caract_arete_face.append(geompy.KindOfShape(arete)) + + if self._verbose_max: + print ("Aretes de la face : {}".format(caract_arete_face)) + + return caract_arete_face + +#=========================== Fin de la méthode ================================== + +#=========================== Début de la méthode ================================= + + def _cree_face_mediane ( self, geompy, solide, caract_face_1, caract_face_2 ): + """Crée la face médiane entre deux autres + +Entrées : + :geompy: environnement de GEOM + :solide: l'objet solide à traiter + :caract_face_1, caract_face_2: les caractéristiques des 2 faces les plus grandes + +Sorties : + :face: la face médiane + """ + erreur = 0 + message = "" + face = None + + nom_fonction = __name__ + "/_cree_face_mediane" + blabla = "\nDans {} :\n".format(nom_fonction) + + if self._verbose_max: + texte = blabla + texte += "face_1 : {}\n".format(caract_face_1) + texte += "face_2 : {}".format(caract_face_2) + print (texte) + + while not erreur: + +# 1. Forme de la face + forme = caract_face_1[2][0] + if self._verbose_max: + print ("forme = {}".format(forme) ) + +# 2. Traitement selon la forme de la face +# 2.1. Face plane + if forme in ( geompy.kind.DISK_CIRCLE, geompy.kind.DISK_ELLIPSE, geompy.kind.POLYGON, geompy.kind.PLANE, geompy.kind.PLANAR): + erreur, message, face = self._cree_face_mediane_polygone ( geompy, caract_face_1, caract_face_2 ) + +# 2.2. Face cylindrique + elif forme == geompy.kind.CYLINDER2D: + face = self._cree_face_mediane_cylindre ( geompy, solide, caract_face_1, caract_face_2 ) + +# 2.3. Face sphérique + elif forme == geompy.kind.SPHERE2D: + face = self._cree_face_mediane_sphere ( geompy, solide, caract_face_1, caract_face_2 ) + +# 2.4. Face torique + elif forme == geompy.kind.TORUS2D: + face = self._cree_face_mediane_tore ( geompy, solide, caract_face_1, caract_face_2 ) + +# 2.5. Face conique + elif forme == geompy.kind.CONE2D: + face = self._cree_face_mediane_cone ( geompy, solide, caract_face_1, caract_face_2 ) + +# 2.N. Face de forme inconnue + else: + self.faces_pb_msg += "Impossible de créer la face médiane pour le solide '{}' ".format(self.nom_solide) + self.faces_pb_msg += "car sa face la plus grande est de forme : {}\n".format(forme) + self.faces_pb_nb += 1 + +# 3. Gestion de la face produite + + if face is not None: + erreur, message = self._cree_face_mediane_0 ( geompy, face ) + + break + + return erreur, message, face + +#=========================== Fin de la méthode ================================== + +#=========================== Début de la méthode ================================= + + def _cree_face_mediane_0 ( self, geompy, face ): + """Gestion de la face médiane créée entre deux autres + +Entrées : + :geompy: environnement de GEOM + :face: la face médiane créée + """ + erreur = 0 + message = "" + + nom_fonction = __name__ + "/_cree_face_mediane_0" + blabla = "\nDans {} :\n".format(nom_fonction) + + if self._verbose_max: + texte = blabla + print (texte) + + while not erreur: + +# 3.1. Insertion dans l'étude + nom_face = self.nom_solide+"_M" + geompy.addToStudy (face,nom_face) + +# 3.2. Transfert éventuel de GEOM vers SHAPER + if self._retour_shaper: + +# 3.2.1. Le fichier doit être différent à chaque fois + #print ("l_faces_trans = {}".format(self.l_faces_trans)) + nom_fic = nom_face + iaux = 0 + while True: + if nom_fic in self.l_faces_trans: + nom_fic = "{}_{}".format(nom_face,iaux) + iaux += 1 + else: + break + self.l_faces_trans.append(nom_fic) + fichier = os.path.join(self.rep_trav, "{}.stp".format(nom_fic)) + +# 3.2.2. Exportation depuis GEOM + if self._verbose_max: + texte = "Exportation depuis GEOM de la face médiane '{}' dans le fichier {}".format(nom_face,fichier) + print (texte) + try: + geompy.ExportSTEP (face, fichier) + except OSError as err: + print (err) + message += "Impossible d'exporter la face médiane '{}' dans le fichier {}".format(nom_face,fichier) + erreur = 1 + break + +# 3.2.3. Importation dans SHAPER + if self._verbose_max: + texte = "Importation dans SHAPER de la face médiane '{}' depuis le fichier {}".format(nom_face,fichier) + print (texte) + face_mediane = model.addImportSTEP(self.part_doc, fichier, False, False, False) + face_mediane.execute(True) + model.do() + +# Le nom + face_mediane.setName(nom_face) + face_mediane.result().setName(nom_face) + +# La couleur. Attention aux conventions différents entr GEOM et SHAPER + while True: + tbaux = np.array(face.GetColor()._tuple()) + np_aux = (tbaux<0.).nonzero() + if np.any(np_aux): + break + np_aux = (tbaux>1.).nonzero() + if np.any(np_aux): + break + tbaux *= 255. + face_mediane.result().setColor(int(tbaux[0]), int(tbaux[1]), int(tbaux[2])) + break + + break + + return erreur, message + +#=========================== Fin de la méthode ================================== + +#=========================== Début de la méthode ================================= + + def _cree_face_mediane_polygone ( self, geompy, caract_face_1, caract_face_2 ): + """Crée la face médiane entre deux autres - cas des polygones + +Entrées : + :geompy: environnement de GEOM + :caract_face_1, caract_face_2: les caractéristiques des 2 faces les plus grandes + +Sorties : + :face: la face médiane + """ + erreur = 0 + message = "" + face = None + + nom_fonction = __name__ + "/_cree_face_mediane_polygone" + blabla = "\nDans {} :\n".format(nom_fonction) + + while not erreur: + +# Les deux faces + face_1 = caract_face_1[0] + face_2 = caract_face_2[0] + if self._verbose_max: + texte = blabla + texte += "face_1 : {}\n".format(caract_face_1) + texte += "face_2 : {}".format(caract_face_2) + print (texte) + +# Les 2 surfaces doivent être les mêmes, sinon c'est qu'elles ne sont pas similaires + ecart = np.abs((caract_face_1[1]-caract_face_2[1])/caract_face_1[1]) + if ( ecart > self.epsilon ): + if self._verbose: + message += ". Surface de la plus grande face : {}\n".format(caract_face_1[1]) + message += ". Surface de la face suivante : {}\n".format(caract_face_2[1]) + +# Distance entre les deux faces + d_face_1_2 = geompy.MinDistance(face_1, face_2) + if self._verbose: + print ("\tDistance entre les deux faces = {}".format(d_face_1_2)) + +# Copie de la plus grande face + face_1_copie= geompy.MakeCopy(face_1) + if self._verbose_max: + geompy.addToStudy(face_1_copie, face_1.GetName()+"_copie" ) + +# On la translate d'une demi épaisseur +# Attention : les normales des faces issues de l'explosion du solide sont dirigées vers l'extérieur. +# Comme il faut translater la face vers l'intérieur, on le fait avec une distance négative. + vnorm_face_1_copie = geompy.GetNormal(face_1_copie) + face = geompy.TranslateVectorDistance (face_1_copie, vnorm_face_1_copie, -0.5*d_face_1_2) + +# Si les 2 surfaces ne sont pas similaires, on a quand même tenté la création mais on le signale + if ( ecart > self.epsilon ): + face.SetColor(SALOMEDS.Color(0,0,1)) + message += "Problème pour créer la face médiane pour le solide '{}' : ".format(self.nom_solide) + message += "ce n'est pas un véritable polyèdre." + if self._verbose: + message += "\nL'écart de surface entre les 2 plus grandes faces est trop grand : {:5.2f}%.\n".format(ecart*100.) + message += "Tentative de création à partir de la plus grande des faces du solide." + erreur = -2 + else: + face.SetColor(SALOMEDS.Color(0,1,0)) + + break + + return erreur, message, face + +#=========================== Fin de la méthode ================================== + +#=========================== Début de la méthode ================================= + + def _cree_face_mediane_cylindre ( self, geompy, solide, caract_face_1, caract_face_2 ): + """Crée la face médiane entre deux autres - cas des cylindres + +Entrées : + :geompy: environnement de GEOM + :solide: l'objet solide à traiter + :caract_face_1, caract_face_2: les caractéristiques des 2 faces les plus grandes + +Sorties : + :face: la face médiane + """ + face = None + + nom_fonction = __name__ + "/_cree_face_mediane_cylindre" + blabla = "\nDans {} :\n".format(nom_fonction) + +# Les deux faces + if self._verbose_max: + texte = blabla + texte += "face_1 : {}\n".format(caract_face_1) + texte += "face_2 : {}".format(caract_face_2) + print (texte) + +# Caractéristiques des cylindres + coo_x, coo_y, coo_z, axe_x, axe_y, axe_z, rayon, hauteur = self._cree_face_mediane_cylindre_0 ( geompy, solide, caract_face_1, caract_face_2 ) + +# Création de la face + centre, axe, cylindre = self._cree_face_mediane_cylindre_1 ( geompy, coo_x, coo_y, coo_z, axe_x, axe_y, axe_z, rayon, hauteur ) + +# Gestion de l'intersection avec le solide initial + face = self._cree_face_mediane_cylindre_2 ( geompy, solide, centre, axe, cylindre ) + +# Couleur verte + face.SetColor(SALOMEDS.Color(0,1,0)) + + return face + +#=========================== Fin de la méthode ================================== + +#=========================== Début de la méthode ================================= + + def _cree_face_mediane_cylindre_0 ( self, geompy, solide, caract_face_1, caract_face_2 ): + """Crée la face médiane entre deux autres - cas des cylindres + +Décodage des caractéristiques + +Entrées : + :geompy: environnement de GEOM + :solide: l'objet solide à traiter + :caract_face_1, caract_face_2: les caractéristiques des 2 faces les plus grandes + +Sorties : + :coo_x, coo_y, coo_z: coordonnées du centre de la base + :axe_x, axe_y, axe_z: coordonnées de l'axe + :rayon: rayon moyen entre les deux faces + :hauteur: hauteur du cylindre + """ + + nom_fonction = __name__ + "/_cree_face_mediane_cylindre_0" + blabla = "\nDans {} :\n".format(nom_fonction) + +# Les deux faces + if self._verbose_max: + texte = blabla + texte += "face_1 : {}\n".format(caract_face_1) + texte += "face_2 : {}".format(caract_face_2) + print (texte) + +# Coordonnées du centre de la base + coo_x = caract_face_1[2][1] + coo_y = caract_face_1[2][2] + coo_z = caract_face_1[2][3] +# Coordonnées de l'axe + axe_x = caract_face_1[2][4] + axe_y = caract_face_1[2][5] + axe_z = caract_face_1[2][6] +# Rayons + rayon = (caract_face_2[2][7]+caract_face_1[2][7])/2. +# Hauteur : la diagonale de la boîte englobante permet d'être certain de tout prendre + hauteur = self._calcul_hauteur_englobante ( geompy, solide ) + + return coo_x, coo_y, coo_z, axe_x, axe_y, axe_z, rayon, hauteur + +#=========================== Fin de la méthode ================================== + +#=========================== Début de la méthode ================================= + + def _cree_face_mediane_cylindre_1 ( self, geompy, coo_x, coo_y, coo_z, axe_x, axe_y, axe_z, rayon, hauteur ): + """Crée la face médiane entre deux autres - cas des cylindres + +Création des objets temporaires et de la face externe du cylindre support + +Entrées : + :geompy: environnement de GEOM + :coo_x, coo_y, coo_z: coordonnées du centre de la base + :axe_x, axe_y, axe_z: coordonnées de l'axe + :rayon: rayon moyen entre les deux faces + :hauteur: hauteur du cylindre + +Sorties : + :centre: le centre de la base du cylindre médian + :axe: l'axe des cylindres + :cylindre: le cylindre support + """ + nom_fonction = __name__ + "/_cree_face_mediane_cylindre_1" + blabla = "\nDans {} :\n".format(nom_fonction) + +# Les deux faces + if self._verbose_max: + texte = blabla + texte += "Centre : ({}, {}, {})\n".format(coo_x, coo_y, coo_z) + texte += "Axe : ({}, {}, {})\n".format(axe_x, axe_y, axe_z) + texte += "Rayon : {}\n".format(rayon) + texte += "Hauteur : {}".format(hauteur) + print (texte) + +# Création du point central + centre = geompy.MakeVertex(coo_x, coo_y, coo_z) + #geompy.addToStudy( centre, "centre" ) + +# Création de l'axe + axe = geompy.MakeVectorDXDYDZ(axe_x, axe_y, axe_z) + #geompy.addToStudy( axe, "axe" ) + +# Création d'un cylindre + cylindre = geompy.MakeCylinder(centre, axe, rayon, hauteur) + if self._verbose_max: + geompy.addToStudy( cylindre, "cylindre médian" ) + + return centre, axe, cylindre + +#=========================== Fin de la méthode ================================== + +#=========================== Début de la méthode ================================= + + def _cree_face_mediane_cylindre_2 ( self, geompy, solide, centre, axe, cylindre ): + """Crée la face médiane entre deux autres - cas des cylindres + +Intersection de la face cylindrique avec le solide initial + +Entrées : + :geompy: environnement de GEOM + :solide: l'objet solide à traiter + :centre: le centre de la base du cylindre médian + :axe: l'axe des cylindres + :cylindre: le cylindre support + +Sorties : + :face: la face médiane + """ + face = None + + nom_fonction = __name__ + "/_cree_face_mediane_cylindre_2" + blabla = "\nDans {} :\n".format(nom_fonction) + + if self._verbose_max: + print (blabla) + +# Récupération de la bonne face après intersection du cylindre avec le solide initial + face = self._creation_face_inter ( geompy, solide, cylindre, 1 ) + +# Pour des raisons inconnues de moi, il arrive que l'axe donné par les caractéristiques soit dans le mauvais sens. +# Dans ce cas l'intersection est vide, et il faut retourner la face créée précédemment et recalculer l'intersection. + tb_caract = geompy.KindOfShape(face) + if ( tb_caract[1] == 0 ): + if self._verbose_max: + print ("On opère un retournement du cylindre.") + plan_de_base = geompy.MakePlane(centre, axe, 100) + #geompy.addToStudy( plan_de_base, "plan_de_base" ) + geompy.MirrorByPlane(cylindre, plan_de_base) +# Récupération de la bonne face après intersection du cylindre retourné avec le solide initial + face = self._creation_face_inter ( geompy, solide, cylindre, 1 ) + + return face + +#=========================== Fin de la méthode ================================== + +#=========================== Début de la méthode ================================= + + def _cree_face_mediane_sphere ( self, geompy, solide, caract_face_1, caract_face_2 ): + """Crée la face médiane entre deux autres - cas des sphères + +Entrées : + :geompy: environnement de GEOM + :solide: l'objet solide à traiter + :caract_face_1, caract_face_2: les caractéristiques des 2 faces les plus grandes + +Sorties : + :face: la face médiane + """ + face = None + + nom_fonction = __name__ + "/_cree_face_mediane_sphere" + blabla = "\nDans {} :\n".format(nom_fonction) + +# Les deux faces + if self._verbose_max: + texte = blabla + texte += "face_1 : {}\n".format(caract_face_1) + texte += "face_2 : {}".format(caract_face_2) + print (texte) + +# Caractéristiques des sphères + coo_x, coo_y, coo_z, rayon = self._cree_face_mediane_sphere_0 ( caract_face_1, caract_face_2 ) + +# Création de la face + face = self._cree_face_mediane_sphere_1 ( geompy, solide, coo_x, coo_y, coo_z, rayon ) + +# Couleur verte + face.SetColor(SALOMEDS.Color(0,1,0)) + + return face + +#=========================== Fin de la méthode ================================== + +#=========================== Début de la méthode ================================= + + def _cree_face_mediane_sphere_0 ( self, caract_face_1, caract_face_2 ): + """Crée la face médiane entre deux autres - cas des sphères + +Décodage des caractéristiques + +Entrées : + :caract_face_1, caract_face_2: les caractéristiques des 2 faces les plus grandes + +Sorties : + :coo_x, coo_y, coo_z: coordonnées du centre de la sphère + :rayon: rayon moyen entre les deux faces + """ + + nom_fonction = __name__ + "/_cree_face_mediane_sphere_0" + blabla = "\nDans {} :\n".format(nom_fonction) + +# Les deux faces + if self._verbose_max: + texte = blabla + texte += "face_1 : {}\n".format(caract_face_1) + texte += "face_2 : {}".format(caract_face_2) + print (texte) + +# Coordonnées du centre de la sphère + coo_x = caract_face_1[2][1] + coo_y = caract_face_1[2][2] + coo_z = caract_face_1[2][3] +# Rayons + rayon = (caract_face_2[2][4]+caract_face_1[2][4])/2. + + return coo_x, coo_y, coo_z, rayon + +#=========================== Fin de la méthode ================================== + +#=========================== Début de la méthode ================================= + + def _cree_face_mediane_sphere_1 ( self, geompy, solide, coo_x, coo_y, coo_z, rayon ): + """Crée la face médiane entre deux autres - cas des sphères + +Création des objets temporaires et de la face externe de la sphère support + +Entrées : + :geompy: environnement de GEOM + :solide: l'objet solide à traiter + :coo_x, coo_y, coo_z: coordonnées du centre de la sphère + :rayon: rayon moyen entre les deux faces + +Sorties : + :face: la face externe de la sphère support + """ + face = None + + nom_fonction = __name__ + "/_cree_face_mediane_sphere_1" + blabla = "\nDans {} :\n".format(nom_fonction) + +# Les deux faces + if self._verbose_max: + texte = blabla + texte += "Centre : ({}, {}, {})\n".format(coo_x, coo_y, coo_z) + texte += "Rayon : {}".format(rayon) + print (texte) + +# Création du point central + centre = geompy.MakeVertex(coo_x, coo_y, coo_z) + #geompy.addToStudy( centre, "centre" ) + +# Création d'une sphère médiane + sphere = geompy.MakeSpherePntR(centre, rayon) + if self._verbose_max: + geompy.addToStudy( sphere, "sphère médiane" ) + +# Récupération de la bonne face après intersection avec le solide initial + face = self._creation_face_inter ( geompy, solide, sphere, 0 ) + + return face + +#=========================== Fin de la méthode ================================== + +#=========================== Début de la méthode ================================= + + def _cree_face_mediane_tore ( self, geompy, solide, caract_face_1, caract_face_2 ): + """Crée la face médiane entre deux autres - cas des tores + +Entrées : + :geompy: environnement de GEOM + :solide: l'objet solide à traiter + :caract_face_1, caract_face_2: les caractéristiques des 2 faces les plus grandes + +Sorties : + :face: la face médiane + """ + face = None + + nom_fonction = __name__ + "/_cree_face_mediane_tore" + blabla = "\nDans {} :\n".format(nom_fonction) + +# Les deux faces + if self._verbose_max: + texte = blabla + texte += "face_1 : {}\n".format(caract_face_1) + texte += "face_2 : {}".format(caract_face_2) + print (texte) + +# Caractéristiques des tores + coo_x, coo_y, coo_z, axe_x, axe_y, axe_z, rayon_1, rayon_2 = self._cree_face_mediane_tore_0 ( caract_face_1, caract_face_2 ) + +# Création de la face + face = self._cree_face_mediane_tore_1 ( geompy, solide, coo_x, coo_y, coo_z, axe_x, axe_y, axe_z, rayon_1, rayon_2 ) + +# Couleur verte + face.SetColor(SALOMEDS.Color(0,1,0)) + + return face + +#=========================== Fin de la méthode ================================== + +#=========================== Début de la méthode ================================= + + def _cree_face_mediane_tore_0 ( self, caract_face_1, caract_face_2 ): + """Crée la face médiane entre deux autres - cas des tores + +Décodage des caractéristiques + +Entrées : + :caract_face_1, caract_face_2: les caractéristiques des 2 faces les plus grandes + +Sorties : + :coo_x, coo_y, coo_z: coordonnées du centre du tore + :axe_x, axe_y, axe_z: coordonnées de l'axe + :rayon_1 : rayon principal + :rayon_2 : rayon secondaire + """ + + nom_fonction = __name__ + "/_cree_face_mediane_tore_0" + blabla = "\nDans {} :\n".format(nom_fonction) + +# Les deux faces + if self._verbose_max: + texte = blabla + texte += "face_1 : {}\n".format(caract_face_1) + texte += "face_2 : {}".format(caract_face_2) + print (texte) + +# Coordonnées du centre du tore + coo_x = caract_face_1[2][1] + coo_y = caract_face_1[2][2] + coo_z = caract_face_1[2][3] +# Coordonnées de l'axe + axe_x = caract_face_1[2][4] + axe_y = caract_face_1[2][5] + axe_z = caract_face_1[2][6] +# Rayons + rayon_1 = caract_face_2[2][7] + rayon_2 = (caract_face_2[2][8]+caract_face_1[2][8])/2. + + return coo_x, coo_y, coo_z, axe_x, axe_y, axe_z, rayon_1, rayon_2 + +#=========================== Fin de la méthode ================================== + +#=========================== Début de la méthode ================================= + + def _cree_face_mediane_tore_1 ( self, geompy, solide, coo_x, coo_y, coo_z, axe_x, axe_y, axe_z, rayon_1, rayon_2 ): + """Crée la face médiane entre deux autres - cas des tores + +Création des objets temporaires et de la face externe du tore support + +Entrées : + :geompy: environnement de GEOM + :solide: l'objet solide à traiter + :coo_x, coo_y, coo_z: coordonnées du centre du tore + :axe_x, axe_y, axe_z: coordonnées de l'axe + :rayon_1 : rayon principal + :rayon_2 : rayon secondaire + +Sorties : + :face: la face externe du tore support + """ + face = None + + nom_fonction = __name__ + "/_cree_face_mediane_tore_1" + blabla = "\nDans {} :\n".format(nom_fonction) + +# Les deux faces + if self._verbose_max: + texte = blabla + texte += "Centre : ({}, {}, {})\n".format(coo_x, coo_y, coo_z) + texte += "Axe : ({}, {}, {})\n".format(axe_x, axe_y, axe_z) + texte += "Rayon principal : {}\n".format(rayon_1) + texte += "Rayon secondaire : {}".format(rayon_2) + print (texte) + +# Création du point central + centre = geompy.MakeVertex(coo_x, coo_y, coo_z) + #geompy.addToStudy( centre, "centre" ) + +# Création de l'axe + axe = geompy.MakeVectorDXDYDZ(axe_x, axe_y, axe_z) + #geompy.addToStudy( axe, "axe" ) + +# Création d'un tore médian + tore = geompy.MakeTorus(centre, axe, rayon_1, rayon_2) + if self._verbose_max: + geompy.addToStudy( tore, "tore médian" ) + +# Récupération de la bonne face après intersection avec le solide initial + face = self._creation_face_inter ( geompy, solide, tore, 0 ) + + return face + +#=========================== Fin de la méthode ================================== + +#=========================== Début de la méthode ================================= + + def _cree_face_mediane_cone ( self, geompy, solide, caract_face_1, caract_face_2 ): + """Crée la face médiane entre deux autres - cas des cones + +Entrées : + :geompy: environnement de GEOM + :solide: l'objet solide à traiter + :caract_face_1, caract_face_2: les caractéristiques des 2 faces les plus grandes + +Sorties : + :face: la face médiane + """ + face = None + + nom_fonction = __name__ + "/_cree_face_mediane_cone" + blabla = "\nDans {} :\n".format(nom_fonction) + +# Les deux faces + if self._verbose_max: + texte = blabla + texte += "face_1 : {}\n".format(caract_face_1) + texte += "face_2 : {}".format(caract_face_2) + print (texte) + +# Caractéristiques des cones + coo_x, coo_y, coo_z, axe_x, axe_y, axe_z, rayon_1, rayon_2, hauteur = self._cree_face_mediane_cone_0 ( geompy, caract_face_1, caract_face_2 ) + +# Création de la face + centre, axe, cone = self._cree_face_mediane_cone_1 ( geompy, coo_x, coo_y, coo_z, axe_x, axe_y, axe_z, rayon_1, rayon_2, hauteur ) + +# Gestion de l'intersection avec le solide initial + face = self._cree_face_mediane_cone_2 ( geompy, solide, centre, axe, cone ) + +# Couleur verte + face.SetColor(SALOMEDS.Color(0,1,0)) + + return face + +#=========================== Fin de la méthode ================================== + +#=========================== Début de la méthode ================================= + + def _cree_face_mediane_cone_0 ( self, geompy, caract_face_1, caract_face_2 ): + """Crée la face médiane entre deux autres - cas des cones + +Décodage des caractéristiques + +Entrées : + :geompy: environnement de GEOM + :caract_face_1, caract_face_2: les caractéristiques des 2 faces les plus grandes + +Sorties : + :coo_x, coo_y, coo_z: coordonnées du centre de la base + :axe_x, axe_y, axe_z: coordonnées de l'axe + :rayon_1, rayon_2: rayons moyens du côté de la base et à l'opposé + :hauteur: hauteur du cone + """ + + nom_fonction = __name__ + "/_cree_face_mediane_cone_0" + blabla = "\nDans {} :\n".format(nom_fonction) + +# Les deux faces + if self._verbose_max: + texte = blabla + texte += "face_1 : {}\n".format(caract_face_1) + texte += "face_2 : {}".format(caract_face_2) + print (texte) + +# Coordonnées du centre de la base + coo_x = caract_face_1[2][1] + coo_y = caract_face_1[2][2] + coo_z = caract_face_1[2][3] +# Coordonnées de l'axe + axe_x = caract_face_1[2][4] + axe_y = caract_face_1[2][5] + axe_z = caract_face_1[2][6] +# Rayons +# Pour un cone complet, les caractéristiques forunies par GEOM sont correctes +# Mais s'il est découpé, malheureusement,bug dans GEOM et caract_face_2[2][8] est toujours nul ! +# Alors on passe par le décodage des arêtes + #rayon_1 = (caract_face_2[2][7]+caract_face_1[2][7])/2. + #rayon_2 = (caract_face_2[2][8]+caract_face_1[2][8])/2. + caract_arete_face_1 = self._calcul_caract_aretes_face ( geompy, caract_face_1 ) + caract_arete_face_2 = self._calcul_caract_aretes_face ( geompy, caract_face_2 ) + rayon_1 = 0. + rayon_2 = 0. + for caract_aretes_face in [caract_arete_face_1,caract_arete_face_2]: + prem = True + for l_aux in caract_aretes_face: + if ( l_aux[0] in ( geompy.kind.CIRCLE, geompy.kind.ARC_CIRCLE ) ): + #print ("R =",l_aux[7]) + if prem: + rayon_1 += l_aux[7] + prem = False + else: + rayon_2 += l_aux[7] + rayon_1 *= 0.5 + rayon_2 *= 0.5 +# Hauteur + hauteur = caract_face_1[2][9] + + return coo_x, coo_y, coo_z, axe_x, axe_y, axe_z, rayon_1, rayon_2, hauteur + +#=========================== Fin de la méthode ================================== + +#=========================== Début de la méthode ================================= + + def _cree_face_mediane_cone_1 ( self, geompy, coo_x, coo_y, coo_z, axe_x, axe_y, axe_z, rayon_1, rayon_2, hauteur ): + """Crée la face médiane entre deux autres - cas des cones + +Création des objets temporaires et de la face externe du cone support + +Entrées : + :geompy: environnement de GEOM + :coo_x, coo_y, coo_z: coordonnées du centre de la base + :axe_x, axe_y, axe_z: coordonnées de l'axe + :rayon_1, rayon_2: rayons moyens du côté de la base et à l'opposé + :hauteur: hauteur du cone + +Sorties : + :centre: le centre de la base du cone médian + :axe: l'axe des cones + :cone: le cone support + """ + nom_fonction = __name__ + "/_cree_face_mediane_cone_1" + blabla = "\nDans {} :\n".format(nom_fonction) + +# Les deux faces + if self._verbose_max: + texte = blabla + texte += "Centre : ({}, {}, {})\n".format(coo_x, coo_y, coo_z) + texte += "Axe : ({}, {}, {})\n".format(axe_x, axe_y, axe_z) + texte += "Rayons : {}, {}\n".format(rayon_1, rayon_2) + texte += "Hauteur : {}".format(hauteur) + print (texte) + +# Création du point central + centre = geompy.MakeVertex(coo_x, coo_y, coo_z) + #geompy.addToStudy( centre, "centre" ) + +# Création de l'axe + axe = geompy.MakeVectorDXDYDZ(axe_x, axe_y, axe_z) + #geompy.addToStudy( axe, "axe" ) + +# Création d'un cone + cone = geompy.MakeCone(centre, axe, rayon_1, rayon_2, hauteur) + if self._verbose_max: + geompy.addToStudy( cone, "cone médian" ) + + return centre, axe, cone + +#=========================== Fin de la méthode ================================== + +#=========================== Début de la méthode ================================= + + def _cree_face_mediane_cone_2 ( self, geompy, solide, centre, axe, cone ): + """Crée la face médiane entre deux autres - cas des cones + +Intersection de la face cylindrique avec le solide initial + +Entrées : + :geompy: environnement de GEOM + :solide: l'objet solide à traiter + :centre: le centre de la base du cone médian + :axe: l'axe des cones + :cone: le cone support + +Sorties : + :face: la face médiane + """ + face = None + + nom_fonction = __name__ + "/_cree_face_mediane_cone_2" + blabla = "\nDans {} :\n".format(nom_fonction) + + if self._verbose_max: + print (blabla) + +# Récupération de la bonne face après intersection du cone avec le solide initial + face = self._creation_face_inter ( geompy, solide, cone, 1 ) + +# Pour des raisons inconnues de moi, il arrive que l'axe donné par les caractéristiques soit dans le mauvais sens. +# Dans ce cas l'intersection est vide, et il faut retourner la face créée précédemment et recalculer l'intersection. + tb_caract = geompy.KindOfShape(face) + if ( tb_caract[1] == 0 ): + if self._verbose_max: + print ("On opère un retournement du cone.") + plan_de_base = geompy.MakePlane(centre, axe, 100) + #geompy.addToStudy( plan_de_base, "plan_de_base" ) + geompy.MirrorByPlane(cone, plan_de_base) +# Récupération de la bonne face après intersection du cone retourné avec le solide initial + face = self._creation_face_inter ( geompy, solide, cone, 1 ) + + return face + +#=========================== Fin de la méthode ================================== + +#=========================== Début de la méthode ================================= + + def _calcul_hauteur_englobante ( self, geompy, solide ): + """Crée la hauteur englobant à coup sûr le solide + +Décodage des caractéristiques + +Entrées : + :geompy: environnement de GEOM + :solide: l'objet solide à traiter + +Sorties : + :hauteur: hauteur englobante + """ + + nom_fonction = __name__ + "/_calcul_hauteur_englobante" + blabla = "\nDans {} :\n".format(nom_fonction) + +# Les deux faces + if self._verbose_max: + print (blabla[:-1]) + +# Hauteur : la diagonale de la boîte englobante permet d'être certain de tout prendre + bounding_box = geompy.BoundingBox(solide) + if self._verbose_max: + texte = "Boîte englobante du solide '{}'\n".format(self.nom_solide) + texte += "\tXmin = {}, Xmax = {}\n".format(bounding_box[0],bounding_box[1]) + texte += "\tYmin = {}, Ymax = {}\n".format(bounding_box[2],bounding_box[3]) + texte += "\tZmin = {}, Zmax = {}".format(bounding_box[4],bounding_box[5]) + print(texte) + + coo_1 = np.array([bounding_box[0],bounding_box[2],bounding_box[4]]) + coo_2 = np.array([bounding_box[1],bounding_box[3],bounding_box[5]]) + longueur = np.linalg.norm(coo_2-coo_1) + if self._verbose_max: + print ("Longueur de la diagonale {}".format(longueur)) + hauteur = 1.2*longueur + + return hauteur + +#=========================== Fin de la méthode ================================== + +#=========================== Début de la méthode ================================= + + def _creation_face_inter ( self, geompy, solide, objet, numero ): + """Crée la face + +. Repère la face principale de l'objet support +. Réalise l'intersection avec le solide initial + +Entrées : + :geompy: environnement de GEOM + :solide: l'objet solide à traiter + :objet: l'objet support de la face + :numero: numero de la face dans l'explosion de l'objet support + +Sorties : + :face: la face externe de l'objet support intersecté avec le solide initial + """ + + nom_fonction = __name__ + "/_creation_face_inter" + blabla = "\nDans {} :\n".format(nom_fonction) + +# Les deux faces + if self._verbose_max: + print (blabla[:-1]) + +# Récupération de la bonne face + l_aux = geompy.ExtractShapes(objet, geompy.ShapeType["FACE"], True) + face_1 = geompy.MakeShell([l_aux[numero]]) + #geompy.addToStudy( face_1, "face externe" ) + +# Intersection entre la face externe du solide médian et le solide initial + face = geompy.MakeCommonList([solide, face_1], True) + #geompy.addToStudy( face, "face" ) + + return face + +#=========================== Fin de la méthode ================================== + +#=========================== Début de la méthode ================================= + + def _menage_faces ( self, gst, l_faces ): + """Fait le ménage des faces dans l'étude + +Entrées : + :gst: environnement de GeomStudyTools + :l_faces: liste des faces du solide + """ + + nom_fonction = __name__ + "/_menage_faces" + blabla = "\nDans {} :\n".format(nom_fonction) + + if self._verbose_max: + texte = blabla + texte += "Nombre de faces à supprimer : {}\n".format(len(l_faces)) + print (texte) + +# Suppression des faces incluses dans l'étude + if self._menage: + for face in l_faces: + if self._verbose_max: + print ("\tSuppression de {}".format(face.GetName())) + gst.deleteShape(face.GetStudyEntry()) + +# Rafraichissement de l'affichage + salome.sg.updateObjBrowser() + + return + +#=========================== Fin de la méthode ================================== + +#=========================== Début de la méthode ================================= + + def face_mediane_solide (self, geompy, gst, solide): + + """Calcul de la face médiane pour un solide + +Entrées : + :geompy: environnement de GEOM + :gst: environnement de GeomStudyTools + :solide: l'objet solide à traiter + +Sorties : + :erreur: code d'erreur + :message: message d'erreur + """ + + nom_fonction = __name__ + "/face_mediane_solide" + blabla = "\nDans {} :\n".format(nom_fonction) + + if self._verbose_max: + print (blabla) + if self._verbose: + print ("Traitement du solide '{}'".format(solide.GetName())) + +# 1. Préalables + + erreur = 0 + message = "" + + while not erreur : + +# 2. Explosion du solide en faces + + erreur, message, l_faces = self._faces_du_solide ( geompy, solide ) + if erreur: + break + +# 3. Calcul des caractéristiques géométriques des faces + + tb_caract = self._calcul_caract_faces ( geompy, l_faces ) + +# 4. Tri des faces en fonction de leurs caractéristiques géométriques + + erreur, message, caract_face_1, caract_face_2 = self._tri_faces ( tb_caract ) + if erreur: + break + +# 5. Création de la face médiane + + erreur, message, face = self._cree_face_mediane ( geompy, solide, caract_face_1, caract_face_2 ) + if erreur: + break + +# 6. Ménage des faces + + if salome.sg.hasDesktop(): + if self._retour_shaper: + l_faces.append(face) + self._menage_faces ( gst, l_faces ) + + break + +# 7. La fin + + if ( erreur and self._verbose_max ): + print (blabla, message) + + return erreur, message + +#=========================== Fin de la méthode ================================== + +#=========================== Début de la méthode ================================= + + def _menage_solides ( self, gst, l_solides, l_solides_m, type_selection, objet ): + """Fait le ménage des solides dans l'étude + +Entrées : + :gst: environnement de GeomStudyTools + :l_solides: liste des solides de l'objet + :l_solides_m: liste des solides de l'objet dont on veut le ménage + :type_selection: type de sélection de l'objet à traiter (0: graphique, 1: GEOM, 2;SHAPER) + :objet: l'objet à traiter + """ + + nom_fonction = __name__ + "/_menage_solides" + blabla = "\nDans {} :\n".format(nom_fonction) + + if self._verbose_max: + texte = blabla + texte += "Nombre de solides de l'objet : {}\n".format(len(l_solides)) + texte += "Nombre de solides à supprimer : {}".format(len(l_solides_m)) + print (texte) + + if self._menage: + +# Suppression des solides inclus dans l'étude dans le cas d'un assemblage explosé + if ( len(l_solides) > 1 ): + for solide in l_solides_m: + if self._verbose_max: + print ("\tSuppression de {}".format(solide.GetName())) + gst.deleteShape(solide.GetStudyEntry()) + +# Suppression de l'objet initial quand il vient d'une exportation depuis SHAPER si ça s'est mal passé + if ( type_selection == 2 ): + if ( len(l_solides) != len(l_solides_m) ): + pass + else: + if self._verbose_max: + print ("\tSuppression de {}".format(objet.GetName())) + gst.deleteShape(objet.GetStudyEntry()) + +# Mise en évidence des solides non détruits + for solide in l_solides: + if solide not in l_solides_m: + solide.SetColor(SALOMEDS.Color(1,0,0)) + +# Rafraichissement de l'affichage + salome.sg.updateObjBrowser() + + return + +#=========================== Fin de la méthode ================================== + +#=========================== Début de la méthode ================================= + + def _traitement_objet (self, type_selection=0, objet=None ): + """Traitement d'un objet + +Entrées : + :type_selection: type de sélection de l'objet à traiter (0: graphique, 1: GEOM, 2;SHAPER) + :objet: l'objet à traiter quand il passe par argument + +Sorties : + :erreur: code d'erreur + :message: message d'erreur + """ + + nom_fonction = __name__ + "/_traitement_objet" + blabla = "\nDans {} :\n".format(nom_fonction) + + if self._verbose_max: + texte = blabla + texte += "type_selection = {}".format(type_selection) + print (texte) + +# 1. Préalables + + erreur = 0 + message = "" + + while not erreur : + +# 2. L'aide + + if self.affiche_aide_globale : + break + +# 3. Les imports pour salomé + geompy = geomBuilder.New() + gst = geomtools.GeomStudyTools(getStudyEditor()) + +# 4. Sélection de l'objet + if ( type_selection == 0 ): + erreur, message, objet = self._selection_objet_graphique ( geompy ) + elif ( type_selection in (1,2) ): + pass + else: + message = "Le type d'objet {} est inconnu.".format(type_selection) + erreur = 4 + if erreur: + break + +# 5. En cas de retour vers shaper, répertoire de travail associé à l'éventuel fichier de départ + if self._retour_shaper: + if self.ficcao is None: + self.rep_trav = tempfile.mkdtemp(prefix="{}_".format(objet.GetName())) + else: + self.rep_trav = os.path.join(os.path.dirname(self.ficcao),"{}_M".format(objet.GetName())) + if not os.path.isdir(self.rep_trav): + os.mkdir(self.rep_trav) + if self._verbose_max: + print ("Les fichiers CAO des surfaces seront dans le répertoire {}".format(self.rep_trav)) + +# 6. Liste des solides qui composent l'objet + erreur, message, l_solides = self._les_solides ( geompy, objet ) + if erreur: + break + +# 7. Calcul des surfaces médianes pour chaque solide + l_solides_m = list() + for solide in l_solides: + erreur, message = self.face_mediane_solide (geompy, gst, solide) + if erreur: + break + l_solides_m.append(solide) + if erreur: + break + +# 8. Ménage des solides + + if salome.sg.hasDesktop(): + self._menage_solides ( gst, l_solides, l_solides_m, type_selection, objet ) + +# 9. Informations sur les faces à problème + if self.faces_pb_nb: + if ( self.faces_pb_nb == 1 ): + texte = "1 face pose" + else: + texte = "{} faces posent".format(self.faces_pb_nb) + print ("{} problème.\n{}".format(texte,self.faces_pb_msg)) + +# 10. Final + print ("Les fichiers CAO des surfaces sont dans le répertoire {}".format(self.rep_trav)) + + break + + return erreur, message + +#=========================== Fin de la méthode ================================== + +#=========================== Début de la méthode ================================= + + def surf_fic_cao (self, ficcao): + """Calcule la surface médiane pour un objet dans un fichier passé en argument + +Entrées : + :ficcao: fichier de l'objet à traiter + +Sorties : + :erreur: code d'erreur + :message: message d'erreur + """ + + nom_fonction = __name__ + "/surf_fic_cao" + blabla = "\nDans {} :\n".format(nom_fonction) + + if self._verbose_max: + print (blabla) + + erreur = 0 + message = "" + + while not erreur : + +# 1. Définition de la pièce + + self.part_doc = model.activeDocument() + +# 2. Import de la CAO + + self.ficcao = ficcao + print ("Traitement du fichier {}".format(self.ficcao)) + + erreur, message, objet = import_cao (self.part_doc, self.ficcao, self._verbose_max) + if erreur: + break + +# 3. Calcul des surfaces + + erreur, message = self.surf_objet_shaper ( objet.result().name(), objet.result().shapeType() ) + + if ( erreur and self._verbose_max ): + print (blabla, message) + + break + + return erreur, message + +#=========================== Fin de la méthode ================================== + +#=========================== Début de la méthode ================================= + + def surf_objet_shaper (self, nom_objet, type_objet): + """Calcule la surface médiane pour un objet SHAPER passé en argument + +Entrées : + :nom_objet: nom de l'objet à traiter + :type_objet: type de l'objet à traiter "SOLID"/"COMPOUND" + +Sorties : + :erreur: code d'erreur + :message: message d'erreur + """ + + nom_fonction = __name__ + "/surf_objet_shaper" + blabla = "\nDans {} :\n".format(nom_fonction) + + if self._verbose_max: + print (blabla) + + erreur = 0 + message = "" + + while not erreur : + +# 1. Transfert vers GEOM +# 1.1. Le départ est-il un fichier au format step ? + deja_step = False + if self.ficcao is not None: + laux = self.ficcao.split(".") + fmt_cao_0 = decode_cao (laux[-1]) + if ( fmt_cao_0 == "stp" ): + deja_step = True + if self._verbose_max: + print ("deja_step = {}".format(deja_step)) + +# 1.1. Exportation si le fichier de départ n'est pas au format step + if deja_step: + fichier = self.ficcao + else: + fichier = tempfile.mkstemp(suffix=".stp")[1] + if self._verbose_max: + print ('fichier = {}'.format(fichier)) + print ('nom_objet = {}'.format(nom_objet)) + print ('type_objet = {}'.format(type_objet)) + export = model.exportToFile(self.part_doc, fichier, [model.selection(type_objet, nom_objet)]) + export.execute(True) + model.do() + taille = os.path.getsize(fichier) + if ( taille <= 0 ): + message = "Export de SHAPER vers GEOM impossible pour l'objet '{}' de type '{}'\n".format(nom_objet, type_objet) + message += "Le fichier {} est de taille {}".format(fichier,taille) + erreur = 2 + break + +# 1.2. Importation + geompy = geomBuilder.New() + objet = geompy.ImportSTEP(fichier, False, True) + geompy.addToStudy( objet, nom_objet ) + if not deja_step: + os.remove(fichier) + +# 2. Traitement de l'objet GEOM correspondant + erreur, message = self._traitement_objet ( 2, objet ) + + if ( erreur and self._verbose_max ): + print (blabla, message) + + break + + return erreur, message + +#=========================== Fin de la méthode ================================== + +#=========================== Début de la méthode ================================= + + def surf_objet_geom (self, objet): + """Calcule la surface médiane pour un objet GEOM passé en argument + +Entrées : + :objet: l'objet à traiter + +Sorties : + :erreur: code d'erreur + :message: message d'erreur + """ + + nom_fonction = __name__ + "/surf_objet_geom" + blabla = "\nDans {} :\n".format(nom_fonction) + + if self._verbose_max: + print (blabla) + + erreur, message = self._traitement_objet ( 1, objet ) + + if ( erreur and self._verbose_max ): + print (blabla, message) + + return erreur, message + +#=========================== Fin de la méthode ================================== + +#=========================== Début de la méthode ================================= + + def lancement (self): + + """Lancement + +Sorties : + :erreur: code d'erreur + :message: message d'erreur + """ + + nom_fonction = __name__ + "/lancement" + blabla = "\nDans {} :\n".format(nom_fonction) + + if self._verbose_max: + print (blabla) + + erreur, message = self._traitement_objet ( ) + + if ( erreur and self._verbose_max ): + print (blabla, message) + + return erreur, message + +#=========================== Fin de la méthode ================================== + +#========================== Fin de la classe ==================================== + +#================================================================================== +# Lancement +#================================================================================== + +if __name__ == "__main__" : + +# 1. Options + + L_OPTIONS = list() + #L_OPTIONS.append("-h") + #L_OPTIONS.append("-v") + #L_OPTIONS.append("-vmax") + #L_OPTIONS.append("-no_menage") + #L_OPTIONS.append("-retour_shaper") + +# 2. Lancement de la classe + + #print ("L_OPTIONS :", L_OPTIONS) + SURFACE_MEDIANE = SurfaceMediane(L_OPTIONS) + if SURFACE_MEDIANE.affiche_aide_globale: + sys.stdout.write(SURFACE_MEDIANE.__doc__+"\n") + else: + ERREUR, MESSAGE_ERREUR = SURFACE_MEDIANE.lancement() + if ERREUR: + MESSAGE_ERREUR += "\n Code d'erreur : %d\n" % ERREUR + sys.stderr.write(MESSAGE_ERREUR) + + del SURFACE_MEDIANE + + #sys.exit(0) diff --git a/src/PythonAddons/macros/fibreNeutre/widget.xml b/src/PythonAddons/macros/fibreNeutre/widget.xml new file mode 100644 index 000000000..9322e5d1b --- /dev/null +++ b/src/PythonAddons/macros/fibreNeutre/widget.xml @@ -0,0 +1,14 @@ + + + + + + + + + + diff --git a/src/PythonAddons/macros/importParameters/__init__.py b/src/PythonAddons/macros/importParameters/__init__.py old mode 100644 new mode 100755 diff --git a/src/PythonAddons/macros/importParameters/feature.py b/src/PythonAddons/macros/importParameters/feature.py old mode 100644 new mode 100755 index bfe49e196..c744cb112 --- a/src/PythonAddons/macros/importParameters/feature.py +++ b/src/PythonAddons/macros/importParameters/feature.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- # Copyright (C) 2016-2021 CEA/DEN, EDF R&D # # This library is free software; you can redistribute it and/or @@ -20,9 +21,10 @@ """importParameters Author: Nathalie Gore """ +import os from salome.shaper import model -from salome.shaper import geom + import ModelAPI import ParametersAPI @@ -43,7 +45,7 @@ class importParameters(model.Feature): @staticmethod def FILE_ID(): - """Returns ID of the file select parameter.""" + """Returns ID of the file.""" return "file_path" def getKind(self): @@ -64,10 +66,10 @@ class importParameters(model.Feature): def existingParameters(self): """ Returns list of already existing parameters names""" aDoc = model.activeDocument() - aNbFeatures = aDoc.numInternalFeatures(); - aNames = [] + aNbFeatures = aDoc.numInternalFeatures() + aNames = list() for i in range(aNbFeatures): - aParamFeature = aDoc.internalFeature(i); + aParamFeature = aDoc.internalFeature(i) if aParamFeature is not None: if aParamFeature.getKind() == ParametersAPI.ParametersAPI_Parameter.ID(): aNames.append(aParamFeature.name()) @@ -81,24 +83,24 @@ class importParameters(model.Feature): # Retrieving the user input apath = self.string(self.FILE_ID()) filepath = apath.value() - #print("filepath : ", filepath) + #print("filepath : '{}'".format(filepath)) if filepath != "" : - - # Creating the parameters in the current document - part = model.activeDocument() - aNames = self.existingParameters() - - with open(filepath) as file: - for line in file: - defParameters = line.replace("\n","").split(' ') - if len(defParameters) == 2 : - if defParameters[0] not in aNames: - model.addParameter(part, defParameters[0], defParameters[1]) - aNames.append(defParameters[0]) - file.close() - return - - setError("The file does not exist") + if os.path.isfile(filepath): + # Creating the parameters in the current document + part = model.activeDocument() + aNames = self.existingParameters() + with open(filepath) as fic: + for line in fic: + defParameters = line.replace("\n","").split(' ') + if len(defParameters) == 2 : + if defParameters[0] not in aNames: + model.addParameter(part, defParameters[0], defParameters[1]) + aNames.append(defParameters[0]) + fic.close() + else: + self.setError("The file '{}' does not exist".format(filepath)) + + return def isMacro(self): """Override Feature.initAttributes(). diff --git a/src/PythonAddons/macros/importParameters/widget.xml b/src/PythonAddons/macros/importParameters/widget.xml index 37e0208d7..6d4954165 100644 --- a/src/PythonAddons/macros/importParameters/widget.xml +++ b/src/PythonAddons/macros/importParameters/widget.xml @@ -2,11 +2,11 @@ - + diff --git a/src/PythonAddons/macros/rectangle/__init__.py b/src/PythonAddons/macros/rectangle/__init__.py old mode 100644 new mode 100755 diff --git a/src/PythonAddons/macros/rectangle/feature.py b/src/PythonAddons/macros/rectangle/feature.py old mode 100644 new mode 100755 index 7ad629f89..304785c3e --- a/src/PythonAddons/macros/rectangle/feature.py +++ b/src/PythonAddons/macros/rectangle/feature.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- # Copyright (C) 2014-2021 CEA/DEN, EDF R&D # # This library is free software; you can redistribute it and/or @@ -35,6 +36,9 @@ class SketchPlugin_Rectangle(model.Feature): # Initializations + __sketch = None + __isHV = list() + def __init__(self): """x.__init__(...) initializes x; see x.__class__.__doc__ for signature""" model.Feature.__init__(self) @@ -131,6 +135,7 @@ class SketchPlugin_Rectangle(model.Feature): # Edition of the rectangle def execute(self): + """F.execute() -- execute the Feature""" # Retrieving list of already created lines aLinesList = self.reflist(self.LINES_LIST_ID()) aNbLines = aLinesList.size() @@ -156,7 +161,7 @@ class SketchPlugin_Rectangle(model.Feature): aRefAttrA.setAttr(aPrevLine.attribute("EndPoint")) aRefAttrB.setAttr(aLine.attribute("StartPoint")) aStartPoints.append(aLine.attribute("StartPoint")) - # Flags which show horizontal or vertical constraint is build for correponding line + # Flags which show horizontal or vertical constraint is build for corresponding line self.__isHV = [False, False, False, False] # Update coordinates of created lines self.updateLines() @@ -203,12 +208,12 @@ class SketchPlugin_Rectangle(model.Feature): self.__isHV[i] = True def attributeChanged(self, theID): + """attributeChanged""" if theID == self.START_ID() or theID == self.END_ID() or theID == self.CENTER_ID() or theID == self.CENTER_REF_ID() or theID == self.CORNER_ID(): # Search the sketch containing this rectangle - self.__sketch = None - aRefs = self.data().refsToMe(); - for iter in aRefs: - aFeature = ModelAPI.objectToFeature(iter.owner()) + aRefs = self.data().refsToMe() + for itera in aRefs: + aFeature = ModelAPI.objectToFeature(itera.owner()) if aFeature.getKind() == "Sketch": self.__sketch = ModelAPI.featureToCompositeFeature(aFeature) break @@ -226,9 +231,9 @@ class SketchPlugin_Rectangle(model.Feature): aCenter = self.getPointByRef(self.attribute(self.CENTER_ID()), self.refattr(self.CENTER_REF_ID())) aCorner = GeomDataAPI.geomDataAPI_Point2D(self.attribute(self.CORNER_ID())) if (aStartPoint.isInitialized() and aEndPoint.isInitialized()) or (aCenter is not None and aCorner.isInitialized()): - self.updateLines() + self.updateLines() else: - self.updateStartPoint() + self.updateStartPoint() if theID == self.AUXILIARY_ID(): anAuxiliary = self.data().boolean(self.AUXILIARY_ID()).value() aLinesList = self.reflist(self.LINES_LIST_ID()) @@ -239,6 +244,7 @@ class SketchPlugin_Rectangle(model.Feature): aLine.data().boolean("Auxiliary").setValue(anAuxiliary) def getReferencePoint(self, theRef): + """getReferencePoint""" if theRef.isObject() and theRef.object() is not None: feature = ModelAPI.ModelAPI_Feature.feature(theRef.object()) if feature.getKind() == "SketchPoint": @@ -248,6 +254,7 @@ class SketchPlugin_Rectangle(model.Feature): return None def getPointByRef(self, thePoint, theRef): + """getPointByRef""" attr = thePoint if theRef.isInitialized(): refPnt = self.getReferencePoint(theRef) @@ -258,6 +265,7 @@ class SketchPlugin_Rectangle(model.Feature): return GeomDataAPI.geomDataAPI_Point2D(attr).pnt() def updateLines(self): + """updateLines""" # Retrieving list of already created lines aLinesList = self.reflist(self.LINES_LIST_ID()) aNbLines = min(aLinesList.size(), 4) @@ -304,6 +312,7 @@ class SketchPlugin_Rectangle(model.Feature): aLinesList.object(i).data().blockSendAttributeUpdated(wasBlocked[i], True) def updateStartPoint(self): + """updateStartPoint""" # Retrieving list of already created lines aLinesList = self.reflist(self.LINES_LIST_ID()) aNbLines = aLinesList.size() -- 2.39.2