1 # -*- coding: utf-8 -*-
2 # Copyright (C) 2016-2022 CEA/DEN, EDF R&D
4 # This library is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU Lesser General Public
6 # License as published by the Free Software Foundation; either
7 # version 2.1 of the License, or (at your option) any later version.
9 # This library is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 # Lesser General Public License for more details.
14 # You should have received a copy of the GNU Lesser General Public
15 # License along with this library; if not, write to the Free Software
16 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
20 """Obtention des surfaces médianes à partir d'un objet GEOM ou SHAPER
22 On sait traiter les faces :
29 Pour un objet complexe, on crée l'objet final comme étant la partition de toutes
30 les surfaces médianes.
32 Version initiale par :
33 alexandre.prunie@blastsolutions.io
34 guillaume.schweitzer@blastsolutions.io
39 __revision__ = "V10.55"
41 #========================= Les imports - Début ===================================
53 from SketchAPI import *
54 from salome.shaper import model
56 from GeomAlgoAPI import *
58 from salome.geom import geomBuilder
62 #========================== Les imports - Fin ====================================
65 D_FMT["stp"] = ["stp", "step"]
66 D_FMT["igs"] = ["igs", "iges"]
67 for CLE in ("brep", "xao"):
70 # statut = 0 si pas encore traité, 1 si traité avec succès, 2 si trop mince, -1 si pas assez mince, -2 si impossible.
89 # Transparence des solides traités correctement
92 # Limite basse de l'épaisseur pour pouvoir faire les intersections
95 #========================= Début de la fonction ==================================
97 def decode_cao (fmt_cao):
98 """Décode le format de la cao
101 :fmt_cao: format du fichier, step, iges, etc.
103 :fmt_cao_0: format décodé
108 fmt_cao_low = fmt_cao.lower()
110 for cle, l_aux in D_FMT.items():
111 if ( fmt_cao_low in l_aux ):
117 #========================= Fin de la fonction ===================================
119 #========================= Début de la fonction ==================================
121 def import_cao (part_doc, ficcao, nom_objet=None, verbose=False):
122 """Importation d'une cao
126 :ficcao: le fichier de la CAO
127 :nom_objet: nom à donner à l'objet lu, éventuellement
129 :objet: l'objet importé dans SHAPER
132 nom_fonction = __name__ + "/import_cao"
133 blabla = "\nDans {} :\n".format(nom_fonction)
134 message_0 = "Fichier : {}\n".format(ficcao)
136 message = blabla + message_0
137 message += "nom_objet : {}".format(nom_objet)
145 laux = ficcao.split(".")
146 fmt_cao_0 = decode_cao (laux[-1])
148 if ( fmt_cao_0 not in ("stp", "brep", "igs", "xao") ):
149 message += "Le format de CAO est inconnu"
153 message += "Le fichier de CAO n'a pas été décodé correctement."
156 elif not os.path.isfile(ficcao):
157 message += "Le fichier de CAO est inconnu."
163 objet = model.addImport(part_doc, ficcao)
167 if nom_objet is not None:
168 objet.result().setName(nom_objet)
171 texte = "Objet : '{}'\n".format(objet.result().name())
172 texte += "De type : '{}'".format(objet.result().shapeType())
175 return erreur, message, objet
177 #========================= Fin de la fonction ===================================
179 #========================= Début de la fonction ==================================
181 def print_tab (nb_tab, message, argu=None, saut_av=False, saut_ap=False):
182 """Imprime avec des tabulations
185 :nb_tab: nombre de tabulations à appliquer
186 :message: message principal
187 :argu: argument du format
188 :saut_av: saut de ligne avant le texte
189 :saut_ap: saut de ligne après le texte
197 for _ in range(nb_tab):
201 if ( argu is not None ):
202 texte += "{}".format(argu)
208 #========================= Fin de la fonction ===================================
211 #=================================== La classe ===================================
213 class SurfaceMediane (object):
215 """Calcul des surfaces médianes de solides minces
217 L'objectif de ce programme est de créer les surfaces médianes, encore appelées fibres neutres, pour \
218 une structure qui est un solide ou un assemblage de solides (compound).
219 Pour réaliser l'opération, trois façons de faire :
221 1. On lance le script en précisant le fichier à analyser dans la zone d'auto-test.
223 2. Si on part d'un script qui manipule un fichier au format CAO, on crée une instance de la classe SurfaceMediane \
224 puis on appelle la méthode surf_fic_cao avec ce fichier en argument.
226 3. Si on part d'un script qui crée un objet SHAPER, on crée une instance de la classe SurfaceMediane \
227 puis on appelle la méthode surf_objet_shaper avec cet objet en argument.
230 Le programme crée les surfaces sous réserve que pour le solide envisagé, il a réussi à trouver deux faces \
231 de taille identique et supérieure aux tailles des autres faces du solide. \
232 Cela fonctionne pour des surfaces planes ou de forme canonique.
233 Il crée alors une surface au milieu de ces deux grandes faces. \
234 Cette face est coloriée en vert, le solide est en vert et transparent.
236 On sait traiter les faces :
243 Si la création n'a pas eu lieu, un message est émis et les solides sont mis en couleur :
244 . Rouge : le solide n'est pas assez mince.
245 . Bleu : le solide est trop mince, vis-à-vis de la précision de SHAPER.
246 . Orange : la forme de la face n'est pas reconnue.
254 . Exportation finale dans un fichier step. Par défaut, pas d'export.
255 -export_step/-no_export_step
258 surf_fic_cao --> import_cao
259 --> surf_objet_shaper (récursif) --> _nom_sous_objets
260 --> _surf_objet_shaper_0
261 --> surf_solide_shaper --> _isole_solide
262 --> _traitement_objet --> face_mediane_solide --> _faces_du_solide
264 --> _cree_face_mediane
266 _cree_face_mediane --> _cree_face_mediane_plane
267 --> _cree_face_mediane_cylindre
268 --> _cree_face_mediane_sphere
269 --> _cree_face_mediane_tore
270 --> _cree_face_mediane_cone
271 --> _cree_face_mediane_0
280 affiche_aide_globale = 0
287 nom_solide_aux = None
293 objet_principal = None
295 # Pour chaque sous-objet dans l'ordre de l'arborescence : nom
297 # Statut de chaque sous-objet connu par son nom :
298 # 0 si pas encore traité, 1 si traité avec succès, 2 si trop mince, -1 si pas assez mince, -2 si impossible.
300 # Liste des faces médianes créées et des fonctions initiales
302 # La fonction initiale
308 #=========================== Début de la méthode =================================
310 def __init__ ( self, liste_option ):
312 """Le constructeur de la classe SurfaceMediane
314 Décodage des arguments
315 On cherche ici les arguments généraux : aide, verbeux
318 for option in liste_option :
321 if isinstance(option,str):
322 saux = option.upper()
324 if saux in ( "-H", "-HELP" ):
325 self.affiche_aide_globale = 1
328 elif saux == "-VMAX" :
330 self._verbose_max = 1
331 elif saux == "-EXPORT_STEP":
332 self._export_step = True
333 elif saux == "-NO_EXPORT_STEP":
334 self._export_step = False
336 #=========================== Fin de la méthode ==================================
338 #=========================== Début de la méthode =================================
341 """A la suppression de l'instance de classe"""
342 if self._verbose_max:
343 print ("Suppression de l'instance de la classe.")
345 #=========================== Fin de la méthode ==================================
347 #=========================== Début de la méthode =================================
349 def _nom_sous_objets (self, objet, lecture, n_recur=0, rang=0):
350 """Gère les noms des sous_objets solides
353 :objet: objet à traiter
354 :lecture: vrai pour lire les noms, faux pour les attribuer
355 :n_recur: niveau de récursivité
356 :rang: rang du sous-objet
359 :rang: rang du sous-objet
362 nom_fonction = __name__ + "/_nom_sous_objets"
363 blabla = "Dans {} :\n".format(nom_fonction)
365 if self._verbose_max:
367 for _ in range(n_recur):
369 texte = "\n{}{}".format(prefixe,blabla)
370 texte += "{}n_recur = {}".format(prefixe,n_recur)
371 texte += "\n{}lecture = {}".format(prefixe,lecture)
374 # 1. Au premier passage, il faut garder la référence au résultat principal
377 objet_0 = objet.result()
378 if self._verbose_max:
379 print ("d_statut_so = {}".format(self.d_statut_so))
383 # 2. On descend dans l'arborescence des sous-objets jusqu'à en trouver un qui n'en n'a pas
385 nb_sub_results = objet_0.numberOfSubs()
387 if self._verbose_max:
388 texte = "{}Examen de l'objet '{}' ".format(prefixe,objet_0.name())
389 texte += "de type '{}'".format(objet_0.shapeType())
390 texte += "\n{}objet.result().numberOfSubs() : {}".format(prefixe,nb_sub_results)
393 for n_sobj in range(nb_sub_results):
395 # 2.1. Exploration récursive de l'arborescence
397 rang = self._nom_sous_objets ( objet_0.subResult(n_sobj), lecture, n_recur+1, rang )
399 # 2.2. Cet objet n'a pas de sous-objets. Si c'est un solide, on le traite
401 if ( objet_0.shapeType() == "SOLID" ):
402 # A la lecture, on enregistre le nom
405 self.l_noms_so.append(nom)
406 self.d_statut_so[nom] = 0
407 # A la récupération, on redonne le nom et on affecte une couleur dépendant de l'état
409 nom = self.l_noms_so[rang]
411 etat = self.d_statut_so[nom]
412 objet_0.setColor (D_COLOR_R[etat],D_COLOR_G[etat],D_COLOR_B[etat])
414 objet_0.setTransparency (TRANSPARENCE)
419 #=========================== Fin de la méthode ==================================
421 #=========================== Début de la méthode =================================
423 def _couleur_objet (self, objet, n_recur=0, coul_r=1, coul_g=0, coul_b=0):
424 """Appliquer une couleur à un objet et à ses sous_objets
427 :objet: objet à traiter
428 :n_recur: niveau de récursivité
429 :coul_r,coul_g,coul_b: code RGB de la couleur à appliquer
432 :rang: rang du sous-objet
435 nom_fonction = __name__ + "/_couleur_objet"
436 blabla = "Dans {} :".format(nom_fonction)
438 if self._verbose_max:
440 print_tab(n_recur, "objet : ", objet.name())
441 print_tab(n_recur, "RGB = ({},{},{})".format(coul_r,coul_g,coul_b))
443 # 1. Au premier passage, il faut garder la référence au résultat principal
446 objet_0 = objet.result()
450 # 2. On descend dans l'arborescence des sous-objets jusqu'à en trouver un qui n'en n'a pas
452 nb_sub_results = objet_0.numberOfSubs()
454 if self._verbose_max:
455 print_tab(n_recur, "Examen de l'objet ",objet_0.name())
456 texte = "de type '{}' ".format(objet_0.shapeType())
457 texte += "et de {} sous-objets".format(nb_sub_results)
458 print_tab(n_recur, texte)
460 for n_sobj in range(nb_sub_results):
462 # 2.1. Exploration récursive de l'arborescence
464 self._couleur_objet ( objet_0.subResult(n_sobj), n_recur+1, coul_r, coul_g, coul_b )
466 # 2.2. Cet objet n'a pas de sous-objets : on le colore
467 if self._verbose_max:
468 print_tab(n_recur, "Couleur affectée à l'objet ",objet_0.name())
469 objet_0.setColor (int(coul_r),int(coul_g),int(coul_b))
471 #print ("sortie de {}".format(nom_fonction))
475 #=========================== Fin de la méthode ==================================
477 #=========================== Début de la méthode =================================
479 def _isole_solide ( self, solide, n_recur ):
480 """Isole le solide de son arboresence
483 :solide: le solide à traiter
484 :n_recur: numéro de la récurrence
487 :objet: le solide isolé
488 :recover: la fonction de récupération
491 nom_fonction = __name__ + "/_isole_solide"
492 blabla = "\nDans {} :".format(nom_fonction)
493 if self._verbose_max:
495 texte = "Pour le solide '{}' ".format(solide.name())
496 texte += "de l'objet principal '{}'".format(self.objet_principal.name())
497 print_tab (n_recur, texte)
499 if ( solide.name() != self.objet_principal.name() ):
500 objet, recover = self._isole_solide_a ( solide, n_recur )
503 objet, recover = self._isole_solide_b ( solide, n_recur )
505 if self._verbose_max:
506 print_tab (n_recur, "objet final : ", objet.name())
507 print_tab (n_recur, "fonction_0 : ", self.fonction_0)
508 print_tab (n_recur, "recover : ", recover)
510 return objet, recover
512 #=========================== Fin de la méthode ==================================
514 #=========================== Début de la méthode =================================
516 def _isole_solide_a ( self, solide, n_recur ):
517 """Isole le solide de son arboresence
520 :solide: le solide à traiter
521 :n_recur: numéro de la récurrence
524 :objet: le solide isolé
525 :recover: la fonction de récupération
528 nom_fonction = __name__ + "/_isole_solide_a"
529 blabla = "\nDans {} :".format(nom_fonction)
530 if self._verbose_max:
532 texte = "Pour le solide '{}' ".format(solide.name())
533 texte += "de l'objet principal '{}'".format(self.objet_principal.name())
534 print_tab (n_recur, texte)
536 if self._verbose_max:
537 print_tab (n_recur, ". Extraction du solide '{}'".format(self.objet_principal.name()))
539 # 1. Extraction du solide
540 remove_subshapes = model.addRemoveSubShapes(self.part_doc, model.selection("COMPOUND", self.objet_principal.name()))
541 remove_subshapes.setSubShapesToKeep([model.selection("SOLID", solide.name())])
543 self.nom_solide_aux = "{}_S".format(solide.name())
544 if self._verbose_max:
545 print_tab (n_recur, "\tAttribution à remove_subshapes.result() du nom '{}'".format(self.nom_solide_aux))
546 remove_subshapes.result().setName(self.nom_solide_aux)
548 self.fonction_0 = remove_subshapes
550 # 2. Récupération de l'objet principal
551 recover = model.addRecover(self.part_doc, remove_subshapes, [self.objet_principal])
552 if self._verbose_max:
553 print_tab (n_recur, "\tAttribution à recover du nom '{}'".format(self.objet_principal.name()))
554 recover.result().setName(self.objet_principal.name())
556 return remove_subshapes.result(), recover
558 #=========================== Fin de la méthode ==================================
560 #=========================== Début de la méthode =================================
562 def _isole_solide_b ( self, solide, n_recur ):
563 """Isole le solide de son arboresence
566 :solide: le solide à traiter
567 :n_recur: numéro de la récurrence
570 :objet: le solide isolé
571 :recover: la fonction de récupération
574 nom_fonction = __name__ + "/_isole_solide_b"
575 blabla = "\nDans {} :".format(nom_fonction)
576 if self._verbose_max:
578 texte = "Pour le solide '{}' ".format(solide.name())
579 texte += "de l'objet principal '{}'".format(self.objet_principal.name())
580 print_tab (n_recur, texte)
582 if self._verbose_max:
583 print_tab (n_recur, ". Mise en place du solide")
585 self.nom_solide_aux = self.objet_principal.name()
586 self.fonction_0 = None
590 #=========================== Fin de la méthode ==================================
592 #=========================== Début de la méthode =================================
594 def _faces_du_solide ( self, geompy, objet_geom, solide, n_recur=0 ):
595 """Détermine les faces d'un solide
598 :geompy: environnement de GEOM
599 :objet_geom: l'objet solide à traiter au format GEOM
600 :solide: solide SHAPER à traiter
601 :n_recur: niveau de récursivité
604 :l_faces_geom: liste des faces du solide au format GEOM
605 :l_faces: liste des faces du solide
608 nom_fonction = __name__ + "/_faces_du_solide"
609 blabla = "\nDans {} :\n".format(nom_fonction)
610 if self._verbose_max:
615 l_faces_geom = list()
618 while ( not erreur ):
620 if self._verbose_max:
621 print_tab (n_recur, ".. Traitement du solide ", self.nom_solide)
622 longueur, aire, volume = geompy.BasicProperties(objet_geom)
623 texte = "{}".format(geompy.WhatIs(objet_geom))
624 texte += ". longueur, aire, volume : {}, {}, {}".format(longueur,aire,volume)
627 # Liste des faces qui composent le solide
628 l_faces_geom = geompy.ExtractShapes(objet_geom, geompy.ShapeType["FACE"], True)
629 #if self._verbose_max:
630 #print ("Liste des {} faces qui composent le solide :".format(len(l_faces_geom)))
631 #for iaux, face in enumerate(l_faces_geom):
632 #print ("Face n° {} :\n {}".format(iaux,geompy.WhatIs(face)))
634 print_tab (n_recur, "Type python : ", type(solide))
635 print_tab (n_recur, "Type ", solide.shapeType())
636 #print ("Type {}".format(solide.shapeTypeStr()))
637 #print ("volume = {}".format(GeomAlgoAPI_ShapeTools.volume(solide)))
639 #exp = GeomAPI_ShapeExplorer(solide, GeomAPI_Shape.FACE)
641 #l_faces.append(exp.current().face())
646 return erreur, message, l_faces_geom, l_faces
648 #=========================== Fin de la méthode ==================================
650 #=========================== Début de la méthode =================================
652 def _calcul_caract_faces ( self, geompy, l_faces ):
653 """Calcule les caractéristiques géométriques des faces
656 :geompy: environnement de GEOM
657 :l_faces: liste des faces du solide
660 :tb_caract: tableau des caractéristiques géométriques des faces
663 nom_fonction = __name__ + "/_calcul_caract_faces"
664 blabla = "\nDans {} :\n".format(nom_fonction)
666 nb_faces = len(l_faces)
667 if self._verbose_max:
668 print (blabla+"Nombre de faces : {}.".format(nb_faces))
670 tb_caract = np.zeros((nb_faces,3), dtype = 'object')
671 for iaux, face in enumerate(l_faces):
672 _, aire, _ = geompy.BasicProperties(face)
673 #longueur, aire, volume = geompy.BasicProperties(face)
674 if self._verbose_max:
675 texte = "\t. Face numéro {}".format(iaux)
676 #texte += "\n\t. longueur, aire, volume : {}, {}, {}".format(longueur,aire,volume)
677 texte += ", surface : {}".format(aire)
680 tb_caract [iaux][0] = face
681 tb_caract [iaux][1] = aire
682 tb_caract [iaux][2] = geompy.KindOfShape(face)
683 if self._verbose_max:
684 print ("\t. tb_caract : {} {}".format(aire,tb_caract[iaux][2]))
688 #=========================== Fin de la méthode ==================================
690 #=========================== Début de la méthode =================================
692 def _tri_faces ( self, tb_caract ):
693 """Trie les faces en fonction de leurs surfaces
696 :tb_caract: tableau des caractéristiques géométriques des faces
699 :tb_caract_1[-1], tb_caract_1[-2]: les caractéristiques des 2 faces les plus grandes
705 nom_fonction = __name__ + "/_tri_faces"
706 blabla = "\nDans {} :\n".format(nom_fonction)
708 # Tri du tableau en fonction des surfaces
709 if self._verbose_max:
710 print (blabla+"tb_caract brut : {}".format(tb_caract))
711 tb_caract_1 = sorted(tb_caract, key=lambda colonnes: colonnes[1])
712 if self._verbose_max:
713 print ("tb_caract trié : {}".format(tb_caract_1))
715 if self._verbose_max:
716 texte = "\tSurface de la plus grande face : {}, de caractéristiques {}\n".format(tb_caract_1[-1][1],tb_caract_1[-1][2])
717 texte += "\tSurface de la face suivante : {}, de caractéristiques {}".format(tb_caract_1[-2][1],tb_caract_1[-2][2])
718 if self._verbose_max:
719 texte += "\n\tSurface de la 3ème face suivante : {}, de caractéristiques {}".format(tb_caract_1[-3][1],tb_caract_1[-3][2])
722 # La surface suivante doit être différente, sinon ce n'est pas un solide mince
723 ecart = np.abs((tb_caract_1[-1][1]-tb_caract_1[-3][1])/tb_caract_1[-1][1])
724 if ( ecart < self._epsilon ):
725 message = "\nSolide '{}'\n".format(self.nom_solide)
726 message += ". Surface de la plus grande face : {}\n".format(tb_caract_1[-1][1])
727 message += ". Surface de la 1ère face suivante : {}\n".format(tb_caract_1[-2][1])
728 message += ". Surface de la 2ème face suivante : {}\n".format(tb_caract_1[-3][1])
729 if self._verbose_max:
730 message += ". Ecart relatif :{:4.1f}%\n".format(ecart*100.)
731 message += "L'écart est trop faible par rapport à la limite de {}%.\n".format(self._epsilon*100.)
732 message += "==> Impossible de créer la face médiane car le solide n'est pas assez mince.\n"
734 self.d_statut_so[self.nom_solide] = -1
735 self.faces_pb_nb += 1
736 self.faces_pb_msg += message
738 return erreur, message, tb_caract_1[-1], tb_caract_1[-2]
740 #=========================== Fin de la méthode ==================================
742 #=========================== Début de la méthode =================================
744 def _calcul_caract_aretes_face ( self, geompy, caract_face ):
745 """Détermine les caractéristiques des arêtes d'une face
748 :geompy: environnement de GEOM
749 :caract_face: les caractéristiques de la face
752 :caract_arete_face: les caractéristiques des arêtes de la face
755 nom_fonction = __name__ + "/_calcul_caract_aretes_face"
756 blabla = "\nDans {} :\n".format(nom_fonction)
758 if self._verbose_max:
760 texte += "face : {}\n".format(caract_face)
763 # Détermination des arêtes pour chaque face
764 face = caract_face[0]
765 l_aretes = geompy.ExtractShapes(face, geompy.ShapeType["EDGE"], True)
766 caract_arete_face = list()
767 for arete in l_aretes:
768 caract_arete_face.append(geompy.KindOfShape(arete))
770 if self._verbose_max:
771 print ("Aretes de la face : {}".format(caract_arete_face))
773 return caract_arete_face
775 #=========================== Fin de la méthode ==================================
777 #=========================== Début de la méthode =================================
779 def _verif_epaisseur ( self, epaisseur ):
780 """Contrôle de la validité de l'épaisseur
783 :epaisseur: épaisseur du solide
786 nom_fonction = __name__ + "/_verif_epaisseur"
787 blabla = "\nDans {} :\n".format(nom_fonction)
789 if self._verbose_max:
791 texte += ". Epaisseur du solide : {}\n".format(epaisseur)
792 texte += ". EP_MIN : {}".format(EP_MIN)
795 if ( epaisseur <= EP_MIN ):
796 message = "\nSolide '{}'\n".format(self.nom_solide)
797 message += ". Epaisseur : {}\n".format(epaisseur)
798 message += "L'épaisseur est trop faible par rapport à la limite de {}.\n".format(EP_MIN)
799 message += "==> Impossible de créer la face médiane car le solide est trop mince.\n"
801 self.d_statut_so[self.nom_solide] = 2
802 self.faces_pb_nb += 1
803 self.faces_pb_msg += message
810 #=========================== Fin de la méthode ==================================
812 #=========================== Début de la méthode =================================
814 def _cree_face_mediane ( self, solide, geompy, caract_face_1, caract_face_2, n_recur ):
815 """Crée la face médiane entre deux autres
818 :solide: solide SHAPER à traiter
819 :geompy: environnement de GEOM
820 :caract_face_1, caract_face_2: les caractéristiques des 2 faces les plus grandes
821 :n_recur: niveau de récursivité
824 :face: la face médiane créée
827 nom_fonction = __name__ + "/_cree_face_mediane"
828 blabla = "\nDans {} :\n".format(nom_fonction)
830 if self._verbose_max:
832 print_tab (n_recur, "face_1 : " ,caract_face_1)
833 print_tab (n_recur, "face_2 : " ,caract_face_2)
838 # 1. Forme de la face
839 forme = caract_face_1[2][0]
840 if self._verbose_max:
841 print ("forme = {}".format(forme) )
843 # 2. Traitement selon la forme de la face
845 if forme in ( geompy.kind.DISK_CIRCLE, geompy.kind.DISK_ELLIPSE, geompy.kind.POLYGON, geompy.kind.PLANE, geompy.kind.PLANAR ):
846 erreur, face = self._cree_face_mediane_plane ( geompy, solide, caract_face_1, caract_face_2, n_recur )
848 # 2.2. Face cylindrique
849 elif forme == geompy.kind.CYLINDER2D:
850 erreur, face = self._cree_face_mediane_cylindre ( solide, caract_face_1, caract_face_2, n_recur )
852 # 2.3. Face sphérique
853 elif forme == geompy.kind.SPHERE2D:
854 erreur, face = self._cree_face_mediane_sphere ( caract_face_1, caract_face_2, n_recur )
857 elif forme == geompy.kind.TORUS2D:
858 erreur, face = self._cree_face_mediane_tore ( caract_face_1, caract_face_2, n_recur )
861 elif forme == geompy.kind.CONE2D:
862 erreur, face = self._cree_face_mediane_cone ( geompy, caract_face_1, caract_face_2, n_recur )
864 # 2.N. Face de forme inconnue
866 message = "\nSolide '{}'\n".format(self.nom_solide)
867 message += "sa face la plus grande est de forme : {}\n".format(forme)
868 message += "==> Impossible de créer la face médiane.\n"
870 self.d_statut_so[self.nom_solide] = -2
871 self.faces_pb_nb += 1
872 self.faces_pb_msg += message
874 # 3. Gestion de la face produite
877 self._cree_face_mediane_0 ( face, n_recur )
881 #=========================== Fin de la méthode ==================================
883 #=========================== Début de la méthode =================================
885 def _cree_face_mediane_0 ( self, face, n_recur ):
886 """Gestion de la face médiane créée entre deux autres
889 :face: la face médiane créée
890 :n_recur: niveau de récursivité
893 nom_fonction = __name__ + "/_cree_face_mediane_0"
894 blabla = "\nDans {} :".format(nom_fonction)
896 if self._verbose_max:
900 nom_face = self.nom_solide+"_M"
901 if self._verbose_max:
902 print_tab (n_recur,"Nom de la face créée : ", nom_face)
903 #if ( self.nom_solide_aux != self.objet_principal.name() ):
905 face.setName(nom_face)
906 face.result().setName(nom_face)
908 # 2. Mémorisation de la face et de la fonction initiale
909 self.l_faces_m.append((face, self.fonction_0))
911 # 3. Couleur verte pour la face
912 self._couleur_objet (face, coul_r=0, coul_g=170, coul_b=0)
914 # 4. Changement de statut pour le solide
915 self.d_statut_so[self.nom_solide] = 1
919 #=========================== Fin de la méthode ==================================
921 #=========================== Début de la méthode =================================
923 def _cree_face_mediane_plane ( self, geompy, solide, caract_face_1, caract_face_2, n_recur ):
924 """Crée la face médiane entre deux autres - cas des surfaces planes
927 :geompy: environnement de GEOM
928 :solide: l'objet solide à traiter
929 :caract_face_1, caract_face_2: les caractéristiques des 2 faces les plus grandes
930 :n_recur: niveau de récursivité
933 :face: la face médiane
936 nom_fonction = __name__ + "/_cree_face_mediane_plane"
937 blabla = "\nDans {} :\n".format(nom_fonction)
938 if self._verbose_max:
941 # Caractéristiques des surfaces
942 coo_x, coo_y, coo_z, vnor_x, vnor_y, vnor_z, taille, d_face_1_2 = self._cree_face_mediane_plane_0 ( geompy, solide, caract_face_1, caract_face_2, n_recur )
944 # Contrôle de la validité de l'épaisseur
945 erreur = self._verif_epaisseur ( d_face_1_2 )
947 # Création de la face
949 face = self._cree_face_mediane_plane_1 ( solide, (coo_x, coo_y, coo_z),(vnor_x, vnor_y, vnor_z), taille, d_face_1_2, n_recur )
955 #=========================== Fin de la méthode ==================================
957 #=========================== Début de la méthode =================================
959 def _cree_face_mediane_plane_0 ( self, geompy, solide, caract_face_1, caract_face_2, n_recur ):
960 """Crée la face médiane entre deux autres - cas des surfaces planes
962 Décodage des caractéristiques
965 :geompy: environnement de GEOM
966 :solide: l'objet solide à traiter
967 :caract_face_1, caract_face_2: les caractéristiques des 2 faces les plus grandes
968 :n_recur: niveau de récursivité
971 :coo_x, coo_y, coo_z: coordonnées du centre de la base
972 :vnor_x, vnor_y, vnor_z: coordonnées du vecteur normal
973 :taille: estimation de la taille de la future face
974 :d_face_1_2: la distance entre les deux faces
977 nom_fonction = __name__ + "/_cree_face_mediane_plane_0"
978 blabla = "\nDans {} :".format(nom_fonction)
980 if self._verbose_max:
982 print_tab (n_recur, "face_1 : ", caract_face_1)
983 print_tab (n_recur, "face_2 : ", caract_face_2)
985 # 1. Caractéristiques de la base
986 # Coordonnées du centre de la base
987 coo_x = caract_face_1[2][1]
988 coo_y = caract_face_1[2][2]
989 coo_z = caract_face_1[2][3]
990 # Coordonnées du vecteur normal
991 vnor_x = caract_face_1[2][4]
992 vnor_y = caract_face_1[2][5]
993 vnor_z = caract_face_1[2][6]
994 # taille : la diagonale de la boîte englobante permet d'être certain de tout prendre
995 l_diag = self._calcul_boite_englobante ( solide, n_recur )
997 if self._verbose_max:
998 print_tab (n_recur, "Taille englobante : ",taille)
1000 # 2. Distance entre les deux faces
1001 face_1 = caract_face_1[0]
1002 face_2 = caract_face_2[0]
1003 d_face_1_2 = geompy.MinDistance(face_1, face_2)
1004 if self._verbose_max:
1005 print_tab (n_recur, "Distance entre les deux faces = ", d_face_1_2)
1007 return coo_x, coo_y, coo_z, vnor_x, vnor_y, vnor_z, taille, d_face_1_2
1009 #=========================== Fin de la méthode ==================================
1011 #=========================== Début de la méthode =================================
1013 def _cree_face_mediane_plane_1 ( self, solide, coo_c, vnor, taille, d_face_1_2, n_recur ):
1014 """Crée la face médiane entre deux autres - cas des surfaces planes
1016 Création des objets temporaires et de la face médiane
1019 :solide: l'objet solide à traiter
1020 :coo_c: coordonnées du centre de la base
1021 :vnor: coordonnées du vecteur normal
1022 :taille: estimation de la taille de la future face
1023 :d_face_1_2: la distance entre les deux faces
1024 :n_recur: niveau de récursivité
1027 :face: la face médiane
1030 nom_fonction = __name__ + "/_cree_face_mediane_plane_1"
1031 blabla = "\nDans {} :".format(nom_fonction)
1032 if self._verbose_max:
1034 print_tab (n_recur, "Centre : ({}, {}, {})".format(coo_c[0], coo_c[1], coo_c[2]))
1035 print_tab (n_recur, "Normale : ({}, {}, {})".format(vnor[0], vnor[1], vnor[2]))
1036 print_tab (n_recur, "Taille : ", taille)
1037 print_tab (n_recur, "Distance entre les deux faces : ", d_face_1_2)
1039 # Création de paramètres
1040 nom_par_1 = "{}_taille".format(self.nom_solide)
1041 model.addParameter(self.part_doc, "{}".format(nom_par_1), "{}".format(taille))
1043 # Création du point central
1044 centre = model.addPoint(self.part_doc, coo_c[0], coo_c[1], coo_c[2])
1045 nom_centre = "{}_centre".format(self.nom_solide)
1046 centre.result().setName(nom_centre)
1048 # Création du vecteur normal
1049 v_norm = model.addAxis(self.part_doc, vnor[0], vnor[1], vnor[2])
1050 nom_normal = "{}_normale".format(self.nom_solide)
1051 v_norm.result().setName(nom_normal)
1053 # Création du plan perpendiculaire au vecteur normal
1054 plan = model.addPlane(self.part_doc, model.selection("EDGE", nom_normal), model.selection("VERTEX", nom_centre), True)
1055 nom_plan = "{}_plan".format(self.nom_solide)
1056 plan.result().setName(nom_plan)
1058 # Création de l'esquisse
1059 sketch = self._cree_face_mediane_plane_1a ( nom_plan, nom_centre, nom_par_1, taille, n_recur )
1061 ### Create LinearCopy
1062 LinearCopy_1 = model.addMultiTranslation(self.part_doc, [model.selection("SOLID", self.nom_solide_aux)], model.selection("EDGE", "PartSet/OX"), 0, 1, keepSubResults = True)
1063 LinearCopy_1.result().subResult(0).setName("{}_0".format(self.nom_solide_aux))
1066 Recover_1 = model.addRecover(self.part_doc, LinearCopy_1, [solide])
1067 Recover_1.result().setName("{}_1".format(self.nom_solide_aux))
1069 # Création d'une face ; on la translate d'une demi-épaisseur.
1070 for iaux in range(2):
1072 distance = -0.5*d_face_1_2*float(2*iaux-1)
1073 nom_solide = "{}_{}".format(self.nom_solide_aux,iaux)
1074 face = self._cree_face_mediane_plane_2 ( sketch.name(), nom_normal, nom_solide, distance, iaux )
1077 face = self._cree_face_mediane_plane_11 ( face, Recover_1, n_recur )
1079 # Si l'intersection est vide, on la translate dans l'autre sens
1081 if self._verbose_max:
1082 print_tab (n_recur, "L'intersection est vide.")
1087 #=========================== Fin de la méthode ==================================
1089 #=========================== Début de la méthode =================================
1091 def _cree_face_mediane_plane_1a ( self, nom_plan, nom_centre, nom_par_1, taille, n_recur ):
1092 """Crée la face médiane entre deux autres - cas des surfaces planes - l'esquisse
1095 :nom_plan: nom du plan
1096 :nom_centre: nom du centre
1097 :nom_par_1: nom du paramètre
1098 :taille: estimation de la taille de la future face
1099 :n_recur: niveau de récursivité
1105 nom_fonction = __name__ + "/_cree_face_mediane_plane_1a"
1106 blabla = "\nDans {} :".format(nom_fonction)
1107 if self._verbose_max:
1109 print_tab (n_recur, "Plan : {}".format(nom_plan))
1110 print_tab (n_recur, "Centre : {}".format(nom_centre))
1111 print_tab (n_recur, "Paramètre : {}".format(nom_par_1))
1113 sketch = model.addSketch(self.part_doc, model.selection("FACE", nom_plan))
1115 SketchProjection_1 = sketch.addProjection(model.selection("VERTEX", nom_centre), False)
1116 SketchPoint_1 = SketchProjection_1.createdFeature()
1118 ### Create SketchLine
1119 SketchLine_1 = sketch.addLine(-taille/2., taille/2., taille/2., taille/2.)
1121 ### Create SketchLine
1122 SketchLine_2 = sketch.addLine(taille/2., taille/2., taille/2., -taille/2.)
1124 ### Create SketchLine
1125 SketchLine_3 = sketch.addLine(taille/2., -taille/2., -taille/2., -taille/2.)
1127 ### Create SketchLine
1128 SketchLine_4 = sketch.addLine(-taille/2., -taille/2., -taille/2., taille/2.)
1129 sketch.setCoincident(SketchLine_4.endPoint(), SketchLine_1.startPoint())
1130 sketch.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
1131 sketch.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
1132 sketch.setCoincident(SketchLine_3.endPoint(), SketchLine_4.startPoint())
1134 ### Create SketchLine
1135 SketchLine_5 = sketch.addLine(-taille/2., taille/2., taille/2., -taille/2.)
1136 SketchLine_5.setAuxiliary(True)
1138 ### Create SketchLine
1139 SketchLine_6 = sketch.addLine(taille/2., taille/2., -taille/2., -taille/2.)
1140 SketchLine_6.setAuxiliary(True)
1141 sketch.setCoincident(SketchLine_1.startPoint(), SketchLine_5.startPoint())
1142 sketch.setCoincident(SketchLine_2.startPoint(), SketchLine_6.startPoint())
1143 sketch.setCoincident(SketchLine_3.startPoint(), SketchLine_5.endPoint())
1144 sketch.setCoincident(SketchLine_4.startPoint(), SketchLine_6.endPoint())
1145 sketch.setCoincident(SketchAPI_Point(SketchPoint_1).coordinates(), SketchLine_5.result())
1146 sketch.setCoincident(SketchAPI_Point(SketchPoint_1).coordinates(), SketchLine_6.result())
1147 sketch.setHorizontal(SketchLine_1.result())
1148 sketch.setVertical(SketchLine_2.result())
1149 sketch.setHorizontal(SketchLine_3.result())
1150 sketch.setVertical(SketchLine_4.result())
1151 sketch.setLength(SketchLine_3.result(), nom_par_1)
1152 sketch.setEqual(SketchLine_3.result(), SketchLine_4.result())
1156 nom_sketch = "{}_esquisse".format(self.nom_solide)
1157 sketch.setName(nom_sketch)
1158 sketch.result().setName(nom_sketch)
1162 #=========================== Fin de la méthode ==================================
1164 #=========================== Début de la méthode =================================
1166 def _cree_face_mediane_plane_11 ( self, face, Recover_1, n_recur ):
1167 """Crée la face médiane entre deux autres - cas des surfaces planes
1169 Création des objets temporaires et de la face médiane
1172 :face: la face médiane
1173 :Recover_1: la récupératiuon du solide
1174 :n_recur: niveau de récursivité
1177 :face: la face médiane
1180 nom_fonction = __name__ + "/_cree_face_mediane_plane_11"
1181 blabla = "\nDans {} :".format(nom_fonction)
1182 if self._verbose_max:
1184 print_tab (n_recur, "face : ", face.name())
1186 # Si on traite un objet solide unique, on le récupère
1187 if ( self.nom_solide_aux == self.objet_principal.name() ):
1188 if self._verbose_max:
1189 print_tab (n_recur, "On traite un objet solide unique ==> on le récupère.")
1190 Recover_2 = model.addRecover(self.part_doc, face, [Recover_1.result()])
1191 Recover_2.result().setName("{}_S".format(self.nom_solide_aux))
1193 nb_inter = face.result().numberOfSubs()
1194 if self._verbose_max:
1195 print_tab (n_recur, "Nombre d'intersections : ", nb_inter)
1198 face = self._cree_face_mediane_plane_3 ( face )
1202 #=========================== Fin de la méthode ==================================
1204 #=========================== Début de la méthode =================================
1206 def _cree_face_mediane_plane_2 ( self, nom_sketch, nom_normal, nom_solide, distance, icpt=0 ):
1207 """Crée la face médiane entre deux autres - cas des surfaces planes
1209 Intersection de la face avec le solide
1212 :nom_sketch: nom de l'esquisse
1213 :nom_normal: nom du vecteur normal
1214 :nom_solide: nom du solide à intersecter
1215 :distance: la distance de translation
1216 :icpt: numéro de la tentative
1219 :face: la face médiane
1222 nom_fonction = __name__ + "/_cree_face_mediane_plane_2"
1223 blabla = "\nDans {} :\n".format(nom_fonction)
1224 if self._verbose_max:
1226 texte += "nom_sketch : {}\n".format(nom_sketch)
1227 texte += "nom_normal : {}\n".format(nom_normal)
1228 texte += "nom_solide : {}\n".format(nom_solide)
1229 texte += "distance : {}".format(distance)
1232 # Création d'une face
1233 Face_1 = model.addFace(self.part_doc, [model.selection("COMPOUND", "all-in-{}".format(nom_sketch))])
1234 nom_face_1 = "{}_face_1_{}".format(self.nom_solide_aux,icpt)
1235 Face_1.result().setName(nom_face_1)
1238 Translation_1 = model.addTranslation(self.part_doc, [model.selection("FACE", nom_face_1)], axis = model.selection("EDGE", nom_normal), distance = distance, keepSubResults = True)
1239 nom_trans = "{}_trans_{}".format(self.nom_solide_aux,icpt)
1240 Translation_1.setName(nom_trans)
1241 Translation_1.result().setName(nom_trans)
1242 Translation_1.result().setColor(85, 0, 255)
1244 # Intersection de cette face avec le solide initial
1245 face = model.addCommon(self.part_doc, [model.selection("SOLID", nom_solide), model.selection("FACE", nom_trans)], keepSubResults = True)
1249 #=========================== Fin de la méthode ==================================
1251 #=========================== Début de la méthode =================================
1253 def _cree_face_mediane_plane_3 ( self, face ):
1254 """Crée la face médiane entre deux autres - cas des surfaces planes
1256 Fusion des 2 intersections
1259 :face: la face médiane composée de plusieurs intersections
1262 :face_m: la face médiane
1265 nom_fonction = __name__ + "/_cree_face_mediane_plane_3"
1266 blabla = "\nDans {} :\n".format(nom_fonction)
1267 if self._verbose_max:
1271 # Nommage des sous-objets
1273 for iaux in range(face.result().numberOfSubs()):
1274 nom = "{}_common_{}".format(self.nom_solide_aux,iaux)
1275 face.result().subResult(iaux).setName(nom)
1276 l_fuse.append(model.selection("FACE", '{}'.format(nom)))
1279 if self._verbose_max:
1280 print ("Fusion de {} faces.".format(len(l_fuse)))
1281 face_m = model.addFuse(self.part_doc, l_fuse, keepSubResults = True)
1285 #=========================== Fin de la méthode ==================================
1287 #=========================== Début de la méthode =================================
1289 def _cree_face_mediane_cylindre ( self, solide, caract_face_1, caract_face_2, n_recur ):
1290 """Crée la face médiane entre deux autres - cas des cylindres
1293 :solide: solide SHAPER à traiter
1294 :caract_face_1, caract_face_2: les caractéristiques des 2 faces les plus grandes
1295 :n_recur: niveau de récursivité
1298 :face: la face médiane
1301 nom_fonction = __name__ + "/_cree_face_mediane_cylindre"
1302 blabla = "\nDans {} :\n".format(nom_fonction)
1305 if self._verbose_max:
1307 print_tab (n_recur, "face_1 : ", caract_face_1)
1308 print_tab (n_recur, "face_2 : ", caract_face_2)
1310 # Caractéristiques des cylindres
1311 coo_x, coo_y, coo_z, axe_x, axe_y, axe_z, rayon, hauteur, epaisseur = self._cree_face_mediane_cylindre_0 ( solide, caract_face_1, caract_face_2, n_recur )
1313 # Contrôle de la validité de l'épaisseur
1314 erreur = self._verif_epaisseur ( epaisseur )
1316 # Création de la face
1318 face = self._cree_face_mediane_cylindre_1 ( coo_x, coo_y, coo_z, axe_x, axe_y, axe_z, rayon, hauteur )
1320 self._couleur_objet (solide, n_recur, coul_r=0, coul_g=0, coul_b=255)
1325 #=========================== Fin de la méthode ==================================
1327 #=========================== Début de la méthode =================================
1329 def _cree_face_mediane_cylindre_0 ( self, solide, caract_face_1, caract_face_2, n_recur ):
1330 """Crée la face médiane entre deux autres - cas des cylindres
1332 Décodage des caractéristiques
1335 :solide: l'objet solide à traiter
1336 :caract_face_1, caract_face_2: les caractéristiques des 2 faces les plus grandes
1337 :n_recur: niveau de récursivité
1340 :coo_x, coo_y, coo_z: coordonnées du centre de la base
1341 :axe_x, axe_y, axe_z: coordonnées de l'axe
1342 :rayon: rayon moyen entre les deux faces
1343 :hauteur: hauteur du cylindre
1344 :epaisseur: épaisseur de l'interface entre les deux faces
1347 nom_fonction = __name__ + "/_cree_face_mediane_cylindre_0"
1348 blabla = "\nDans {} :\n".format(nom_fonction)
1350 if self._verbose_max:
1352 print_tab (n_recur, "face_1 : ", caract_face_1)
1353 print_tab (n_recur, "face_2 : ", caract_face_2)
1355 # Coordonnées du centre de la base
1356 coo_x = caract_face_1[2][1]
1357 coo_y = caract_face_1[2][2]
1358 coo_z = caract_face_1[2][3]
1359 # Coordonnées de l'axe
1360 axe_x = caract_face_1[2][4]
1361 axe_y = caract_face_1[2][5]
1362 axe_z = caract_face_1[2][6]
1364 rayon = (caract_face_2[2][7]+caract_face_1[2][7])/2.
1365 # Hauteur : la diagonale de la boîte englobante permet d'être certain de tout prendre
1366 l_diag = self._calcul_boite_englobante ( solide, n_recur )
1367 hauteur = 10.*l_diag
1368 if self._verbose_max:
1369 print_tab (n_recur, "Hauteur englobante : ", hauteur)
1371 epaisseur = np.abs(caract_face_2[2][7]-caract_face_1[2][7])
1373 return coo_x, coo_y, coo_z, axe_x, axe_y, axe_z, rayon, hauteur, epaisseur
1375 #=========================== Fin de la méthode ==================================
1377 #=========================== Début de la méthode =================================
1379 def _cree_face_mediane_cylindre_1 ( self, coo_x, coo_y, coo_z, axe_x, axe_y, axe_z, rayon, hauteur ):
1380 """Crée la face médiane entre deux autres - cas des cylindres
1382 Création des objets temporaires et de la face externe du cylindre support
1385 :coo_x, coo_y, coo_z: coordonnées du centre de la base
1386 :axe_x, axe_y, axe_z: coordonnées de l'axe
1387 :rayon: rayon moyen entre les deux faces
1388 :hauteur: hauteur du cylindre
1391 :face: la face médiane
1393 nom_fonction = __name__ + "/_cree_face_mediane_cylindre_1"
1394 blabla = "\nDans {} :\n".format(nom_fonction)
1396 # Les caractéristiques du cylindre à créer
1397 if self._verbose_max:
1399 texte += "Centre : ({}, {}, {})\n".format(coo_x, coo_y, coo_z)
1400 texte += "Axe : ({}, {}, {})\n".format(axe_x, axe_y, axe_z)
1401 texte += "Rayon : {}\n".format(rayon)
1402 texte += "Hauteur : {}".format(hauteur)
1405 # Création du point central
1406 centre = model.addPoint(self.part_doc, coo_x, coo_y, coo_z)
1407 nom_centre = "{}_centre".format(self.nom_solide)
1408 centre.result().setName(nom_centre)
1411 axe = model.addAxis(self.part_doc, axe_x, axe_y, axe_z)
1412 nom_axe = "{}_axe".format(self.nom_solide)
1413 axe.result().setName(nom_axe)
1415 # Création du plan perpendiculaire à l'axe
1416 plan = model.addPlane(self.part_doc, model.selection("EDGE", nom_axe), model.selection("VERTEX", nom_centre), True)
1417 nom_plan = "{}_plan".format(self.nom_solide)
1418 plan.result().setName(nom_plan)
1420 # Création de l'esquisse
1421 nom_par_1 = "{}_R".format(self.nom_solide)
1422 model.addParameter(self.part_doc, "{}".format(nom_par_1), "{}".format(rayon))
1423 nom_par_2 = "{}_H".format(self.nom_solide)
1424 model.addParameter(self.part_doc, "{}".format(nom_par_2), "{}".format(hauteur))
1426 sketch = model.addSketch(self.part_doc, model.selection("FACE", nom_plan))
1428 SketchProjection_1 = sketch.addProjection(model.selection("VERTEX", nom_centre), False)
1429 SketchPoint_1 = SketchProjection_1.createdFeature()
1431 SketchCircle_1 = sketch.addCircle(0., 0., rayon)
1432 sketch.setCoincident(SketchPoint_1.result(), SketchCircle_1.center())
1433 sketch.setRadius(SketchCircle_1.results()[1], nom_par_1)
1435 nom_sketch = "{}_esquisse".format(self.nom_solide)
1436 sketch.setName(nom_sketch)
1437 sketch.result().setName(nom_sketch)
1439 # Création du cylindre complet
1440 cylindre = model.addExtrusion(self.part_doc, [model.selection("COMPOUND", "all-in-{}".format(nom_sketch))], model.selection(), nom_par_2, nom_par_2, "Edges")
1441 nom_cylindre = "{}_cylindre".format(self.nom_solide)
1442 cylindre.setName(nom_cylindre)
1443 cylindre.result().setName(nom_cylindre)
1444 cylindre.result().setColor(85, 0, 255)
1446 # Intersection de la face cylindrique avec le solide initial
1447 face = self._creation_face_inter ( nom_cylindre )
1451 #=========================== Fin de la méthode ==================================
1453 #=========================== Début de la méthode =================================
1455 def _cree_face_mediane_sphere ( self, caract_face_1, caract_face_2, n_recur ):
1456 """Crée la face médiane entre deux autres - cas des sphères
1459 :caract_face_1, caract_face_2: les caractéristiques des 2 faces les plus grandes
1460 :n_recur: niveau de récursivité
1463 :face: la face médiane
1466 nom_fonction = __name__ + "/_cree_face_mediane_sphere"
1467 blabla = "\nDans {} :".format(nom_fonction)
1470 if self._verbose_max:
1472 print_tab (n_recur, "face_1 : ", caract_face_1)
1473 print_tab (n_recur, "face_2 : ", caract_face_2)
1475 # Caractéristiques des sphères
1476 coo_x, coo_y, coo_z, rayon, epaisseur = self._cree_face_mediane_sphere_0 ( caract_face_1, caract_face_2, n_recur )
1478 # Contrôle de la validité de l'épaisseur
1479 erreur = self._verif_epaisseur ( epaisseur )
1481 # Création de la face
1483 face = self._cree_face_mediane_sphere_1 ( coo_x, coo_y, coo_z, rayon )
1489 #=========================== Fin de la méthode ==================================
1491 #=========================== Début de la méthode =================================
1493 def _cree_face_mediane_sphere_0 ( self, caract_face_1, caract_face_2, n_recur ):
1494 """Crée la face médiane entre deux autres - cas des sphères
1496 Décodage des caractéristiques
1499 :caract_face_1, caract_face_2: les caractéristiques des 2 faces les plus grandes
1500 :n_recur: niveau de récursivité
1503 :coo_x, coo_y, coo_z: coordonnées du centre de la sphère
1504 :rayon: rayon moyen entre les deux faces
1505 :epaisseur: épaisseur de l'interface entre les deux faces
1508 nom_fonction = __name__ + "/_cree_face_mediane_sphere_0"
1509 blabla = "\nDans {} :".format(nom_fonction)
1512 if self._verbose_max:
1514 print_tab (n_recur, "face_1 : ", caract_face_1)
1515 print_tab (n_recur, "face_2 : ", caract_face_2)
1517 # Coordonnées du centre de la sphère
1518 coo_x = caract_face_1[2][1]
1519 coo_y = caract_face_1[2][2]
1520 coo_z = caract_face_1[2][3]
1522 rayon = (caract_face_2[2][4]+caract_face_1[2][4])/2.
1524 epaisseur = np.abs(caract_face_2[2][4]-caract_face_1[2][4])
1526 return coo_x, coo_y, coo_z, rayon, epaisseur
1528 #=========================== Fin de la méthode ==================================
1530 #=========================== Début de la méthode =================================
1532 def _cree_face_mediane_sphere_1 ( self, coo_x, coo_y, coo_z, rayon ):
1533 """Crée la face médiane entre deux autres - cas des sphères
1535 Création des objets temporaires et de la face externe de la sphère support
1538 :coo_x, coo_y, coo_z: coordonnées du centre de la sphère
1539 :rayon: rayon moyen entre les deux faces
1542 :face: la face externe de la sphère support
1545 nom_fonction = __name__ + "/_cree_face_mediane_sphere_1"
1546 blabla = "\nDans {} :\n".format(nom_fonction)
1548 # Les caractéristiques de la sphère à créer
1549 if self._verbose_max:
1551 texte += "Centre : ({}, {}, {})\n".format(coo_x, coo_y, coo_z)
1552 texte += "Rayon : {}".format(rayon)
1555 # Création du point central
1556 centre = model.addPoint(self.part_doc, coo_x, coo_y, coo_z)
1557 nom_centre = "{}_centre".format(self.nom_solide)
1558 centre.result().setName(nom_centre)
1560 # Création d'un plan passant par ce centre et cet axe
1561 plan = model.addPlane(self.part_doc, model.selection("EDGE", "PartSet/OX"), model.selection("VERTEX", nom_centre), False)
1562 nom_plan = "{}_plan".format(self.nom_solide)
1563 plan.result().setName(nom_plan)
1565 # Création de l'esquisse
1566 nom_par_1 = "{}_R".format(self.nom_solide)
1567 model.addParameter(self.part_doc, "{}".format(nom_par_1), "{}".format(rayon))
1569 sketch = model.addSketch(self.part_doc, model.selection("FACE", nom_plan))
1571 SketchProjection_1 = sketch.addProjection(model.selection("VERTEX", nom_centre), False)
1572 SketchPoint_1 = SketchProjection_1.createdFeature()
1574 ### Create SketchArc
1575 SketchArc_1 = sketch.addArc(coo_x, coo_y, coo_x-rayon, coo_y, coo_x+rayon, coo_y, False)
1576 sketch.setRadius(SketchArc_1.results()[1], nom_par_1)
1577 sketch.setCoincident(SketchPoint_1.result(), SketchArc_1.center())
1579 ### Create SketchLine
1580 SketchLine_1 = sketch.addLine(coo_x-rayon, coo_y, coo_x+rayon, coo_y)
1581 nom_ligne = "{}_ligne".format(self.nom_solide)
1582 SketchLine_1.setName(nom_ligne)
1583 SketchLine_1.result().setName(nom_ligne)
1584 SketchLine_1.setAuxiliary(True)
1585 sketch.setHorizontal(SketchLine_1.result())
1586 sketch.setCoincident(SketchArc_1.startPoint(), SketchLine_1.startPoint())
1587 sketch.setCoincident(SketchArc_1.endPoint(), SketchLine_1.endPoint())
1588 sketch.setCoincident(SketchAPI_Point(SketchPoint_1).coordinates(), SketchLine_1.result())
1591 nom_sketch = "{}_esquisse".format(self.nom_solide)
1592 sketch.setName(nom_sketch)
1593 sketch.result().setName(nom_sketch)
1595 # Création de la sphère complète
1596 sphere = model.addRevolution(self.part_doc, [model.selection("COMPOUND", nom_sketch)], model.selection("EDGE", "{}/{}".format(nom_sketch,nom_ligne)), 360, 0, "Edges")
1597 nom_sphere = "{}_sphere".format(self.nom_solide)
1598 sphere.setName(nom_sphere)
1599 sphere.result().setName(nom_sphere)
1600 sphere.result().setColor(85, 0, 255)
1602 # Intersection de la face sphérique avec le solide initial
1603 face = self._creation_face_inter ( nom_sphere )
1607 #=========================== Fin de la méthode ==================================
1609 #=========================== Début de la méthode =================================
1611 def _cree_face_mediane_tore ( self, caract_face_1, caract_face_2, n_recur ):
1612 """Crée la face médiane entre deux autres - cas des tores
1615 :caract_face_1, caract_face_2: les caractéristiques des 2 faces les plus grandes
1616 :n_recur: niveau de récursivité
1619 :face: la face médiane
1622 nom_fonction = __name__ + "/_cree_face_mediane_tore"
1623 blabla = "\nDans {} :".format(nom_fonction)
1626 if self._verbose_max:
1628 print_tab (n_recur, "face_1 : ", caract_face_1)
1629 print_tab (n_recur, "face_2 : ", caract_face_2)
1631 # Caractéristiques des tores
1632 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, n_recur )
1634 # Contrôle de la validité de l'épaisseur (bidon)
1635 erreur = self._verif_epaisseur ( EP_MIN*10. )
1637 # Création de la face
1639 face = self._cree_face_mediane_tore_1 ( coo_x, coo_y, coo_z, axe_x, axe_y, axe_z, rayon_1, rayon_2 )
1645 #=========================== Fin de la méthode ==================================
1647 #=========================== Début de la méthode =================================
1649 def _cree_face_mediane_tore_0 ( self, caract_face_1, caract_face_2, n_recur ):
1650 """Crée la face médiane entre deux autres - cas des tores
1652 Décodage des caractéristiques
1655 :caract_face_1, caract_face_2: les caractéristiques des 2 faces les plus grandes
1656 :n_recur: niveau de récursivité
1659 :coo_x, coo_y, coo_z: coordonnées du centre du tore
1660 :axe_x, axe_y, axe_z: coordonnées de l'axe
1661 :rayon_1 : rayon principal
1662 :rayon_2 : rayon secondaire
1665 nom_fonction = __name__ + "/_cree_face_mediane_tore_0"
1666 blabla = "\nDans {} :".format(nom_fonction)
1669 if self._verbose_max:
1671 print_tab (n_recur, "face_1 : ", caract_face_1)
1672 print_tab (n_recur, "face_2 : ", caract_face_2)
1674 # Coordonnées du centre du tore
1675 coo_x = caract_face_1[2][1]
1676 coo_y = caract_face_1[2][2]
1677 coo_z = caract_face_1[2][3]
1678 # Coordonnées de l'axe
1679 axe_x = caract_face_1[2][4]
1680 axe_y = caract_face_1[2][5]
1681 axe_z = caract_face_1[2][6]
1683 rayon_1 = caract_face_2[2][7]
1684 rayon_2 = (caract_face_2[2][8]+caract_face_1[2][8])/2.
1686 return coo_x, coo_y, coo_z, axe_x, axe_y, axe_z, rayon_1, rayon_2
1688 #=========================== Fin de la méthode ==================================
1690 #=========================== Début de la méthode =================================
1692 def _cree_face_mediane_tore_1 ( self, coo_x, coo_y, coo_z, axe_x, axe_y, axe_z, rayon_1, rayon_2 ):
1693 """Crée la face médiane entre deux autres - cas des tores
1695 Création des objets temporaires et de la face externe du tore support
1698 :coo_x, coo_y, coo_z: coordonnées du centre du tore
1699 :axe_x, axe_y, axe_z: coordonnées de l'axe
1700 :rayon_1 : rayon principal
1701 :rayon_2 : rayon secondaire
1704 :face: la face externe du tore support
1707 nom_fonction = __name__ + "/_cree_face_mediane_tore_1"
1708 blabla = "\nDans {} :\n".format(nom_fonction)
1711 if self._verbose_max:
1713 texte += "Centre : ({}, {}, {})\n".format(coo_x, coo_y, coo_z)
1714 texte += "Axe : ({}, {}, {})\n".format(axe_x, axe_y, axe_z)
1715 texte += "Rayon principal : {}\n".format(rayon_1)
1716 texte += "Rayon secondaire : {}".format(rayon_2)
1719 # Création du point central
1720 centre = model.addPoint(self.part_doc, coo_x, coo_y, coo_z)
1721 nom_centre = "{}_centre".format(self.nom_solide)
1722 centre.result().setName(nom_centre)
1725 axe = model.addAxis(self.part_doc, axe_x, axe_y, axe_z)
1726 nom_axe = "{}_axe".format(self.nom_solide)
1727 axe.result().setName(nom_axe)
1729 # Création d'un plan passant par ce centre et cet axe
1730 plan = model.addPlane(self.part_doc, model.selection("EDGE", nom_axe), model.selection("VERTEX", nom_centre), False)
1731 nom_plan = "{}_plan".format(self.nom_solide)
1732 plan.result().setName(nom_plan)
1734 # Création de l'esquisse
1735 nom_par_1 = "{}_R_1".format(self.nom_solide)
1736 model.addParameter(self.part_doc, "{}".format(nom_par_1), "{}".format(rayon_1))
1737 nom_par_2 = "{}_R_2".format(self.nom_solide)
1738 model.addParameter(self.part_doc, "{}".format(nom_par_2), "{}".format(rayon_2))
1740 sketch = model.addSketch(self.part_doc, model.selection("FACE", nom_plan))
1742 SketchProjection_1 = sketch.addProjection(model.selection("VERTEX", nom_centre), False)
1743 SketchPoint_1 = SketchProjection_1.createdFeature()
1745 SketchProjection_2 = sketch.addProjection(model.selection("EDGE", nom_axe), False)
1746 SketchLine_1 = SketchProjection_2.createdFeature()
1748 SketchPoint_2 = sketch.addPoint(rayon_1, 0.)
1749 sketch.setDistance(SketchPoint_1.result(), SketchPoint_2.coordinates(), nom_par_1, True)
1751 SketchLine_2 = sketch.addLine(0., 0., rayon_1, 0.)
1752 SketchLine_2.setAuxiliary(True)
1753 sketch.setCoincident(SketchAPI_Point(SketchPoint_1).coordinates(), SketchLine_2.startPoint())
1754 sketch.setCoincident(SketchPoint_2.coordinates(), SketchLine_2.endPoint())
1755 sketch.setPerpendicular(SketchLine_1.result(), SketchLine_2.result())
1757 SketchCircle_1 = sketch.addCircle(0., 0., rayon_2)
1758 sketch.setCoincident(SketchPoint_2.result(), SketchCircle_1.center())
1759 sketch.setRadius(SketchCircle_1.results()[1], nom_par_2)
1762 nom_sketch = "{}_esquisse".format(self.nom_solide)
1763 sketch.setName(nom_sketch)
1764 sketch.result().setName(nom_sketch)
1766 # Création du tore complet
1767 nom_tore = "{}_tore".format(self.nom_solide)
1768 self._cree_revolution ( nom_sketch, nom_centre, coo_x, coo_y, coo_z, axe_x, axe_y, axe_z, nom_tore )
1770 # Intersection de la face torique avec le solide initial
1771 face = self._creation_face_inter ( nom_tore )
1775 #=========================== Fin de la méthode ==================================
1777 #=========================== Début de la méthode =================================
1779 def _cree_face_mediane_cone ( self, geompy, caract_face_1, caract_face_2, n_recur ):
1780 """Crée la face médiane entre deux autres - cas des cones
1783 :geompy: environnement de GEOM
1784 :caract_face_1, caract_face_2: les caractéristiques des 2 faces les plus grandes
1785 :n_recur: niveau de récursivité
1788 :face: la face médiane
1791 nom_fonction = __name__ + "/_cree_face_mediane_cone"
1792 blabla = "\nDans {} :".format(nom_fonction)
1795 if self._verbose_max:
1797 print_tab (n_recur, "face_1 : ", caract_face_1)
1798 print_tab (n_recur, "face_2 : ", caract_face_2)
1800 # Caractéristiques des cones
1801 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, n_recur )
1803 # Contrôle de la validité de l'épaisseur (bidon)
1804 erreur = self._verif_epaisseur ( EP_MIN*10. )
1806 # Création de la face
1808 face = self._cree_face_mediane_cone_1 ( coo_x, coo_y, coo_z, axe_x, axe_y, axe_z, rayon_1, rayon_2, hauteur )
1814 #=========================== Fin de la méthode ==================================
1816 #=========================== Début de la méthode =================================
1818 def _cree_face_mediane_cone_0 ( self, geompy, caract_face_1, caract_face_2, n_recur ):
1819 """Crée la face médiane entre deux autres - cas des cones
1821 Décodage des caractéristiques
1824 :geompy: environnement de GEOM
1825 :caract_face_1, caract_face_2: les caractéristiques des 2 faces les plus grandes
1826 :n_recur: niveau de récursivité
1829 :coo_x, coo_y, coo_z: coordonnées du centre de la base
1830 :axe_x, axe_y, axe_z: coordonnées de l'axe
1831 :rayon_1, rayon_2: rayons moyens du côté de la base et à l'opposé
1832 :hauteur: hauteur du cone
1835 nom_fonction = __name__ + "/_cree_face_mediane_cone_0"
1836 blabla = "\nDans {} :".format(nom_fonction)
1839 if self._verbose_max:
1841 print_tab (n_recur, "face_1 : ", caract_face_1)
1842 print_tab (n_recur, "face_2 : ", caract_face_2)
1844 # Coordonnées du centre de la base
1845 coo_x = caract_face_1[2][1]
1846 coo_y = caract_face_1[2][2]
1847 coo_z = caract_face_1[2][3]
1848 # Coordonnées de l'axe
1849 axe_x = caract_face_1[2][4]
1850 axe_y = caract_face_1[2][5]
1851 axe_z = caract_face_1[2][6]
1853 # Pour un cone complet, les caractéristiques fournies par GEOM sont correctes
1854 # Mais s'il est découpé, malheureusement,bug dans GEOM et caract_face_2[2][8] est toujours nul !
1855 # Alors on passe par le décodage des arêtes
1856 #rayon_1 = (caract_face_2[2][7]+caract_face_1[2][7])/2.
1857 #rayon_2 = (caract_face_2[2][8]+caract_face_1[2][8])/2.
1858 caract_arete_face_1 = self._calcul_caract_aretes_face ( geompy, caract_face_1 )
1859 caract_arete_face_2 = self._calcul_caract_aretes_face ( geompy, caract_face_2 )
1862 for caract_aretes_face in [caract_arete_face_1,caract_arete_face_2]:
1864 for l_aux in caract_aretes_face:
1865 if ( l_aux[0] in ( geompy.kind.CIRCLE, geompy.kind.ARC_CIRCLE ) ):
1866 #print ("R =",l_aux[7])
1875 hauteur = caract_face_1[2][9]
1877 return coo_x, coo_y, coo_z, axe_x, axe_y, axe_z, rayon_1, rayon_2, hauteur
1879 #=========================== Fin de la méthode ==================================
1881 #=========================== Début de la méthode =================================
1883 def _cree_face_mediane_cone_1 ( self, coo_x, coo_y, coo_z, axe_x, axe_y, axe_z, rayon_1, rayon_2, hauteur ):
1884 """Crée la face médiane entre deux autres - cas des cones
1886 Création des objets temporaires et de la face externe du cone support
1889 :coo_x, coo_y, coo_z: coordonnées du centre de la base
1890 :axe_x, axe_y, axe_z: coordonnées de l'axe
1891 :rayon_1, rayon_2: rayons moyens du côté de la base et à l'opposé
1892 :hauteur: hauteur du cone
1895 :face: la face externe du cone support
1897 nom_fonction = __name__ + "/_cree_face_mediane_cone_1"
1898 blabla = "\nDans {} :\n".format(nom_fonction)
1901 if self._verbose_max:
1903 texte += "Centre : ({}, {}, {})\n".format(coo_x, coo_y, coo_z)
1904 texte += "Axe : ({}, {}, {})\n".format(axe_x, axe_y, axe_z)
1905 texte += "Rayons : {}, {}\n".format(rayon_1, rayon_2)
1906 texte += "Hauteur : {}".format(hauteur)
1909 # Création du point central
1910 centre = model.addPoint(self.part_doc, coo_x, coo_y, coo_z)
1911 nom_centre = "{}_centre".format(self.nom_solide)
1912 centre.result().setName(nom_centre)
1915 axe = model.addAxis(self.part_doc, axe_x, axe_y, axe_z)
1916 nom_axe = "{}_axe".format(self.nom_solide)
1917 axe.result().setName(nom_axe)
1919 # Création d'un plan passant par ce centre et cet axe
1920 plan = model.addPlane(self.part_doc, model.selection("EDGE", nom_axe), model.selection("VERTEX", nom_centre), False)
1921 nom_plan = "{}_plan".format(self.nom_solide)
1922 plan.result().setName(nom_plan)
1924 # Création de l'esquisse
1925 nom_par_1 = "{}_R_1".format(self.nom_solide)
1926 model.addParameter(self.part_doc, "{}".format(nom_par_1), "{}".format(rayon_1))
1927 nom_par_2 = "{}_R_2".format(self.nom_solide)
1928 model.addParameter(self.part_doc, "{}".format(nom_par_2), "{}".format(rayon_2))
1929 nom_par_3 = "{}_H".format(self.nom_solide)
1930 model.addParameter(self.part_doc, "{}".format(nom_par_3), "{}".format(hauteur))
1932 sketch = model.addSketch(self.part_doc, model.selection("FACE", nom_plan))
1934 SketchProjection_1 = sketch.addProjection(model.selection("VERTEX", nom_centre), False)
1935 SketchPoint_1 = SketchProjection_1.createdFeature()
1937 SketchProjection_2 = sketch.addProjection(model.selection("EDGE", nom_axe), False)
1938 SketchLine_1 = SketchProjection_2.createdFeature()
1940 SketchLine_2 = sketch.addLine(coo_x, coo_y, coo_x+rayon_1, coo_y+hauteur)
1941 SketchLine_2.setAuxiliary(True)
1942 sketch.setCoincident(SketchAPI_Point(SketchPoint_1).coordinates(), SketchLine_2.startPoint())
1943 sketch.setParallel(SketchLine_1.result(), SketchLine_2.result())
1944 sketch.setLength(SketchLine_2.result(), nom_par_3)
1946 SketchLine_3 = sketch.addLine(coo_x+rayon_1, coo_y, coo_x+rayon_1, coo_y+hauteur)
1947 sketch.setDistance(SketchLine_2.startPoint(), SketchLine_3.result(), nom_par_1, True)
1948 sketch.setDistance(SketchLine_2.endPoint(), SketchLine_3.result(), nom_par_2, True)
1949 sketch.setLength(SketchLine_3.result(), "2.5*{}".format(nom_par_3))
1951 SketchPoint_2 = sketch.addPoint(coo_x, coo_y)
1952 sketch.setCoincident(SketchPoint_2.coordinates(), SketchLine_3.result())
1953 sketch.setMiddlePoint(SketchPoint_2.coordinates(), SketchLine_3.result())
1955 SketchLine_4 = sketch.addLine(coo_x, coo_y, 1.2*coo_x, 1.2*coo_y)
1956 SketchLine_4.setAuxiliary(True)
1957 sketch.setCoincident(SketchAPI_Point(SketchPoint_1).coordinates(), SketchLine_4.startPoint())
1958 sketch.setCoincident(SketchPoint_2.coordinates(), SketchLine_4.endPoint())
1959 sketch.setHorizontal(SketchLine_4.result())
1962 nom_sketch = "{}_esquisse".format(self.nom_solide)
1963 sketch.setName(nom_sketch)
1964 sketch.result().setName(nom_sketch)
1966 # Création du cone complet
1967 nom_cone = "{}_cone".format(self.nom_solide)
1968 self._cree_revolution ( nom_sketch, nom_centre, coo_x, coo_y, coo_z, axe_x, axe_y, axe_z, nom_cone )
1970 # Intersection de la face conique avec le solide initial
1971 face = self._creation_face_inter ( nom_cone )
1975 #=========================== Fin de la méthode ==================================
1977 #=========================== Début de la méthode =================================
1979 def _calcul_boite_englobante ( self, objet, n_recur ):
1980 """Crée la hauteur englobant à coup sûr l'objet
1983 :objet: l'objet à traiter
1984 :n_recur: niveau de récursivité
1987 :l_diag: longueur de la diagonale de la boîte englobante
1990 nom_fonction = __name__ + "/_calcul_boite_englobante"
1991 blabla = "\nDans {} :".format(nom_fonction)
1993 if self._verbose_max:
1996 # Hauteur : la diagonale de la boîte englobante permet d'être certain de tout prendre
1997 if self._verbose_max:
1998 print_tab (n_recur, "Création de la boite englobante pour l'objet ", objet.name())
1999 print_tab (n_recur, "de type ", objet.shapeType())
2000 #print ('bbox = model.getBoundingBox(self.part_doc, model.selection("{}", "{}"))'.format(objet.shapeType(),objet.name()))
2001 bbox = model.getBoundingBox(self.part_doc, model.selection("{}".format(objet.shapeType()), "{}".format(objet.name())))
2004 bbox_nom = bbox.name()
2005 if self._verbose_max:
2006 print_tab (n_recur, "Boîte englobante : '{}' '{}'".format(bbox.name(), bbox.result().name()))
2008 if self._verbose_max:
2009 coo_min = model.getPointCoordinates(self.part_doc, \
2010 model.selection("VERTEX", "[{}_1/Back][{}_1/Left][{}_1/Bottom]".format(bbox_nom,bbox_nom,bbox_nom)))
2011 coo_max = model.getPointCoordinates(self.part_doc, \
2012 model.selection("VERTEX", "[{}_1/Front][{}_1/Right][{}_1/Top]".format(bbox_nom,bbox_nom,bbox_nom)))
2013 texte = "Xmin = {}, Xmax = {}\n".format(coo_min[0],coo_max[0])
2014 texte += "\tYmin = {}, Ymax = {}\n".format(coo_min[1],coo_max[1])
2015 texte += "\tZmin = {}, Zmax = {}".format(coo_min[2],coo_max[2])
2016 print_tab (n_recur, texte)
2018 l_diag = model.measureDistance(self.part_doc, \
2019 model.selection("VERTEX", "[{}_1/Back][{}_1/Left][{}_1/Bottom]".format(bbox_nom,bbox_nom,bbox_nom)), \
2020 model.selection("VERTEX", "[{}_1/Front][{}_1/Right][{}_1/Top]".format(bbox_nom,bbox_nom,bbox_nom)) )
2021 if self._verbose_max:
2022 print_tab (n_recur, "Longueur de la diagonale : ", l_diag)
2026 #=========================== Fin de la méthode ==================================
2028 #=========================== Début de la méthode =================================
2030 def _cree_revolution ( self, nom_sketch, nom_centre, coo_x, coo_y, coo_z, axe_x, axe_y, axe_z, nom_objet ):
2031 """Crée un volume de révolution
2034 :nom_sketch: nom de l'esquisse à révolutionner
2035 :nom_centre: nom du point associé au centre du volume de révolution
2036 :coo_x, coo_y, coo_z: coordonnées du centre du tore
2037 :axe_x, axe_y, axe_z: coordonnées de l'axe
2038 :rayon_1 : rayon principal
2039 :rayon_2 : rayon secondaire
2040 :nom_objet: nom de l'objet 2D créé
2043 nom_fonction = __name__ + "/_cree_revolution"
2044 blabla = "\nDans {} :\n".format(nom_fonction)
2046 if self._verbose_max:
2048 texte += "Centre : ({}, {}, {})\n".format(coo_x, coo_y, coo_z)
2049 texte += "Axe : ({}, {}, {})\n".format(axe_x, axe_y, axe_z)
2052 # Création d'un point décalé par rapport au point central
2053 point = model.addPoint(self.part_doc, coo_x+axe_x, coo_y+axe_y, coo_z+axe_z)
2054 nom_point = "{}_point".format(self.nom_solide)
2055 point.result().setName(nom_point)
2057 # Création de l'axe de la rotation
2058 axe_r = model.addAxis(self.part_doc, model.selection("VERTEX", nom_centre), model.selection("VERTEX", nom_point))
2059 nom_axe_r = "{}_axe_r".format(self.nom_solide)
2060 axe_r.result().setName(nom_axe_r)
2062 # Création de l'objet complet
2063 objet = model.addRevolution(self.part_doc, [model.selection("COMPOUND", nom_sketch)], model.selection("EDGE", nom_axe_r), 360, 0, "Edges")
2064 objet.setName(nom_objet)
2065 objet.result().setName(nom_objet)
2066 objet.result().setColor(85, 0, 255)
2070 #=========================== Fin de la méthode ==================================
2072 #=========================== Début de la méthode =================================
2074 def _creation_face_inter ( self, nom_objet ):
2075 """Crée la face par intersection entre l'objet initial et une face complète
2077 . Repère la face principale de l'objet support
2078 . Réalise l'intersection avec le solide initial
2081 :nom_objet: nom de l'objet 2D créé
2084 :face: la face externe de l'objet support intersecté avec le solide initial
2087 nom_fonction = __name__ + "/_creation_face_inter"
2088 blabla = "\nDans {} :\n".format(nom_fonction)
2090 if self._verbose_max:
2093 face = model.addCommon(self.part_doc, [model.selection("SOLID", self.nom_solide_aux), model.selection("FACE", nom_objet)], keepSubResults = True)
2097 #=========================== Fin de la méthode ==================================
2099 #=========================== Début de la méthode =================================
2101 def face_mediane_solide (self, solide, geompy, objet_geom, n_recur=0):
2102 """Calcul de la face médiane pour un solide
2105 :solide: solide SHAPER à traiter
2106 :geompy: environnement de GEOM
2107 :objet_geom: l'objet solide à traiter au format GEOM
2108 :n_recur: niveau de récursivité
2111 :erreur: code d'erreur
2112 :message: message d'erreur
2115 nom_fonction = __name__ + "/face_mediane_solide"
2116 blabla = "\nDans {} :\n".format(nom_fonction)
2118 if self._verbose_max:
2121 print_tab (n_recur, "Traitement du solide ", solide.name())
2130 # 2. Explosion du solide en faces
2132 erreur, message, l_faces_geom, l_faces = self._faces_du_solide ( geompy, objet_geom, solide, n_recur )
2136 # 3. Calcul des caractéristiques géométriques des faces
2138 tb_caract = self._calcul_caract_faces ( geompy, l_faces_geom )
2140 # 4. Tri des faces en fonction de leurs caractéristiques géométriques
2142 erreur, message, caract_face_1, caract_face_2 = self._tri_faces ( tb_caract )
2146 # 5. Création de la face médiane
2148 erreur, face = self._cree_face_mediane ( solide, geompy, caract_face_1, caract_face_2, n_recur )
2152 # 6. Exportation step
2154 if self._export_step:
2155 fichier = os.path.join(self.rep_step, "{}.stp".format(face.result().name()))
2156 export = model.exportToFile(self.part_doc, fichier, [model.selection(face.result().shapeType(), face.result().name())])
2157 export.execute(True)
2164 if ( erreur and self._verbose_max ):
2165 print (blabla, message)
2167 return erreur, message
2169 #=========================== Fin de la méthode ==================================
2171 #=========================== Début de la méthode =================================
2173 def _traitement_objet (self, solide=None, objet_geom=None, n_recur=0):
2174 """Traitement d'un objet
2177 :solide: solide SHAPER à traiter
2178 :objet_geom: l'objet GEOM équivalent
2179 :n_recur: niveau de récursivité
2182 :erreur: code d'erreur
2183 :message: message d'erreur
2186 nom_fonction = __name__ + "/_traitement_objet"
2187 blabla = "\nDans {} :".format(nom_fonction)
2189 if self._verbose_max:
2191 print_tab (n_recur, "solide = " , solide)
2192 print_tab (n_recur, "objet_geom = ", objet_geom)
2203 if self.affiche_aide_globale :
2206 # 3. Les imports pour salomé
2207 geompy = geomBuilder.New()
2209 # 4. En cas d'exportation step, répertoire de travail associé à l'éventuel fichier de départ
2210 # Attention à ne pas recréer le répertoire à chaque fois
2211 if self._export_step:
2213 if self._verbose_max:
2214 print_tab (n_recur, "Préparation de l'export STEP")
2216 if self.rep_step is None:
2217 if self.ficcao is None:
2218 self.rep_step = tempfile.mkdtemp(prefix="{}_".format(self.objet_principal.name()))
2220 self.rep_step = os.path.join(os.path.dirname(self.ficcao),"{}_M".format(self.objet_principal.name()))
2221 if os.path.isdir(self.rep_step):
2222 l_aux = os.listdir(self.rep_step)
2223 for nomfic in l_aux:
2224 os.remove(os.path.join(self.rep_step,nomfic))
2226 os.mkdir(self.rep_step)
2227 if self._verbose_max:
2228 print_tab (n_recur, "Les fichiers CAO des surfaces seront dans le répertoire {}".format(self.rep_step))
2230 # 5. Calcul réel de la face médiane
2233 self.nom_solide = objet_geom.GetName()
2235 erreur, message = self.face_mediane_solide (solide, geompy, objet_geom, n_recur)
2241 return erreur, message
2243 #=========================== Fin de la méthode ==================================
2245 #=========================== Début de la méthode =================================
2247 def surf_fic_cao (self, ficcao, nom_objet=None):
2248 """Calcule la surface médiane pour un objet dans un fichier passé en argument
2251 :ficcao: fichier de l'objet à traiter
2252 :nom_objet: un nom à donner à l'objet à traiter
2255 :erreur: code d'erreur
2256 :message: message d'erreur
2259 nom_fonction = __name__ + "/surf_fic_cao"
2260 blabla = "\nDans {} :\n".format(nom_fonction)
2262 if self._verbose_max:
2272 # 1. Définition de la pièce
2274 self.part_doc = model.activeDocument()
2275 if ( self.part_doc.kind() == "PartSet" ):
2276 part = model.addPart(self.part_doc)
2277 self.part_doc = part.document()
2279 # 2. Import de la CAO
2281 self.ficcao = ficcao
2282 print ("Traitement du fichier {}".format(ficcao))
2284 erreur, message, objet = import_cao (self.part_doc, ficcao, nom_objet, self._verbose_max)
2288 # 3. Calcul des surfaces
2290 erreur, message = self.surf_objet_shaper ( objet )
2299 if ( erreur and self._verbose_max ):
2300 print (blabla, message)
2302 return erreur, message
2304 #=========================== Fin de la méthode ==================================
2306 #=========================== Début de la méthode =================================
2308 def surf_objet_shaper (self, objet):
2309 """Calcule les surfaces médianes pour un objet SHAPER passé en argument
2312 :objet: objet à traiter
2315 :erreur: code d'erreur
2316 :message: message d'erreur
2319 nom_fonction = __name__ + "/surf_objet_shaper"
2320 blabla = "Dans {} :".format(nom_fonction)
2322 if self._verbose_max:
2325 # 1. Acquisition de la liste des noms des sous-objets solides
2327 self.d_statut_so = dict()
2328 self.l_noms_so = list()
2329 self.l_faces_m = list()
2331 _ = self._nom_sous_objets (objet, True)
2332 if self._verbose_max:
2333 print ("Noms des sous-objets : {}".format(self.l_noms_so))
2335 # 2. Les faces médianes
2337 erreur, message = self._surf_objet_shaper_0 ( objet )
2339 # 3. Gestion des faces créées
2341 self._surf_objet_shaper_1 ( )
2343 # 4. Futur message pour le résultat
2345 if ( self._export_step and not erreur ):
2346 message = "Les fichiers des CAO des surfaces sont dans le répertoire {}".format(self.rep_step)
2348 return erreur, message
2350 #=========================== Fin de la méthode ==================================
2352 #=========================== Début de la méthode =================================
2354 def _surf_objet_shaper_0 (self, objet, n_recur=0):
2355 """Calcule les surfaces médianes pour un objet SHAPER passé en argument
2358 :objet: objet à traiter
2359 :n_recur: niveau de récursivité
2362 :erreur: code d'erreur
2363 :message: message d'erreur
2366 nom_fonction = __name__ + "/_surf_objet_shaper_0"
2367 blabla = "Dans {} :\n".format(nom_fonction)
2369 if self._verbose_max:
2371 for _ in range(n_recur):
2373 texte = "\n{}{}".format(prefixe,blabla)
2374 texte += "{}n_recur = {}".format(prefixe,n_recur)
2382 # 1. Au premier passage, il faut récupérer la pièce et garder la référence au résultat principal
2384 if ( n_recur == 0 ):
2385 objet_0, l_faces = self._surf_objet_shaper_00 (objet)
2388 print_tab (n_recur, "Examen de l'objet ", objet.name(), saut_av=True)
2389 print_tab (n_recur, "Type python : ", type(objet))
2390 print_tab (n_recur, "Type ", objet.shapeType())
2392 # 2. On descend dans l'arborescence des sous-objets jusqu'à en trouver un qui n'en n'a pas
2394 nb_sub_results = objet_0.numberOfSubs()
2396 if self._verbose_max:
2397 print_tab (n_recur, "Examen de l'objet '{}' de type ".format(objet_0.name()), objet_0.shapeType())
2398 print_tab (n_recur, "objet.result().numberOfSubs() : ", nb_sub_results)
2400 for n_sobj in range(nb_sub_results):
2402 # 2.1. Exploration récursive de l'arborescence
2404 erreur, message = self._surf_objet_shaper_0 ( objet_0.subResult(n_sobj), n_recur+1 )
2411 # 2.2. Cet objet n'a pas de sous-objets. Si c'est un solide, on le traite
2413 if ( objet_0.shapeType() == "SOLID" ):
2414 erreur, message = self.surf_solide_shaper ( objet_0, n_recur )
2418 # 3. Futur message pour le résultat
2420 if self._export_step:
2421 message = "Les fichiers STEP des surfaces sont dans le répertoire {}".format(self.rep_step)
2425 return erreur, message
2427 #=========================== Fin de la méthode ==================================
2429 #=========================== Début de la méthode =================================
2431 def _surf_objet_shaper_00 (self, objet):
2432 """Liste les faces d'un objet SHAPER passé en argument
2435 :objet: objet à traiter
2438 :objet_0: le résultat associé à l'objet
2439 :l_faces: liste des faces
2442 nom_fonction = __name__ + "/_surf_objet_shaper_00"
2443 blabla = "Dans {} :\n".format(nom_fonction)
2445 if self._verbose_max:
2448 self.part_doc = model.activeDocument()
2449 objet_0 = objet.result()
2450 self.objet_principal = objet_0
2451 objet_bis = objet.defaultResult().shape()
2452 print_tab (0, "Examen de l'objet ", objet.result().name(), saut_av=True)
2453 print_tab (0, "Type python : ", type(objet))
2454 print_tab (0, "Type {} / {} ; volume = ".format(objet_bis.shapeType(),objet_bis.shapeTypeStr()), GeomAlgoAPI_ShapeTools.volume(objet_bis))
2456 exp = GeomAPI_ShapeExplorer(objet_bis, GeomAPI_Shape.SOLID)
2458 l_volumes.append(exp.current().solid())
2461 for ivolume, volume in enumerate(l_volumes):
2462 print_tab (1, "Type python : ", type(volume))
2463 print_tab (1, "Volume n°{} ; volume = ".format(ivolume), GeomAlgoAPI_ShapeTools.volume(volume))
2464 print_tab (1, "Type {} / ".format(volume.shapeType()), volume.shapeTypeStr())
2465 #print ("\tInformations : {}".format(volume.shapeInfo()))
2468 exp = GeomAPI_ShapeExplorer(volume, GeomAPI_Shape.FACE)
2470 l_faces.append(exp.current().face())
2473 for iface, face in enumerate(l_faces):
2474 print_tab (2, "Face n°{} ; surface = ".format(iface), GeomAlgoAPI_ShapeTools.area(face))
2476 return objet_0, l_faces
2478 #=========================== Fin de la méthode ==================================
2480 #=========================== Début de la méthode =================================
2482 def _surf_objet_shaper_1 (self, n_recur=0):
2483 """Gestion des surfaces médianes créées
2486 :n_recur: niveau de récursivité
2489 :erreur: code d'erreur
2490 :message: message d'erreur
2493 nom_fonction = __name__ + "/_surf_objet_shaper_1"
2494 blabla = "Dans {} :\n".format(nom_fonction)
2496 if self._verbose_max:
2499 # 1. Informations sur les faces à problème
2501 if self.faces_pb_nb:
2502 if ( self.faces_pb_nb == 1 ):
2503 texte = "1 face pose"
2505 texte = "{} faces posent".format(self.faces_pb_nb)
2506 print_tab (n_recur, "{} problème.".format(texte), self.faces_pb_msg, saut_av=True)
2508 # 2. Si plus d'une face a été créée
2509 if ( len(self.l_faces_m) > 1 ):
2511 # 2.1. Partition du paquet de faces
2513 if self._verbose_max:
2514 print_tab (n_recur, "Partitionnnement des faces créées.")
2517 for (face,_) in self.l_faces_m:
2518 l_objets.append(model.selection("COMPOUND", "all-in-{}".format(face.name())))
2520 Partition_1 = model.addPartition(self.part_doc, l_objets, keepSubResults = True)
2522 Partition_1.result().setName("{}_M".format(self.objet_principal.name()))
2523 for iaux, (face,_) in enumerate(self.l_faces_m):
2524 Partition_1.result().subResult(iaux).setName("{}".format(face.name()))
2525 self._couleur_objet (Partition_1, n_recur, coul_r=0, coul_g=170, coul_b=0)
2527 # 2.2. Récupération des faces individuelles
2529 if self._verbose_max:
2530 print_tab (n_recur, "Récupération des faces individuelles.")
2533 for iaux, (face,_) in enumerate(self.l_faces_m):
2534 l_objets.append(face.result())
2536 Recover_1 = model.addRecover(self.part_doc, Partition_1, l_objets)
2537 for iaux, (face,_) in enumerate(self.l_faces_m):
2538 Recover_1.results()[iaux].setName("{}".format(face.name()))
2539 Recover_1.results()[iaux].setColor(0, 170, 0)
2541 # 2.3. Mise en dossier
2543 if self._verbose_max:
2544 print_tab (n_recur, "Mise en dossier.")
2546 for (face,fonction_0) in self.l_faces_m:
2547 dossier = model.addFolder(self.part_doc, fonction_0, face)
2548 dossier.setName(face.name()[:-2])
2552 #=========================== Fin de la méthode ==================================
2554 #=========================== Début de la méthode =================================
2556 def surf_solide_shaper (self, solide, n_recur):
2557 """Calcule les surfaces médianes pour un solide SHAPER solide passé en argument
2560 :solide: solide SHAPER à traiter
2561 :n_recur: numéro de la récurrence
2564 :erreur: code d'erreur
2565 :message: message d'erreur
2568 nom_fonction = __name__ + "/surf_solide_shaper"
2569 blabla = "Dans {} :".format(nom_fonction)
2571 if self._verbose_max:
2579 self.nom_solide = solide.name()
2580 if self._verbose_max:
2581 print_tab (n_recur, "solide", self.nom_solide)
2583 # 1. Isolement du solide
2584 solide_aux, recover = self._isole_solide ( solide, n_recur )
2586 # 2. Exportation dans un fichier step pour traitement dans GEOM
2588 fichier = tempfile.mkstemp(suffix=".stp")[1]
2589 if self._verbose_max:
2590 print_tab (n_recur, "fichier = ", fichier)
2591 print_tab (n_recur, "solide = ", solide_aux.name())
2592 print_tab (n_recur, "de type = ", solide_aux.shapeType())
2593 export = model.exportToFile(self.part_doc, fichier, [model.selection(solide_aux.shapeType(), solide_aux.name())])
2594 export.execute(True)
2597 taille = os.path.getsize(fichier)
2599 message = "Export de SHAPER vers GEOM impossible pour le solide '{}' de type '{}'\n".format(solide_aux.name(), solide_aux.shapeType())
2600 message += "Le fichier {} est de taille {}".format(fichier,taille)
2604 # 3. Importation dans GEOM
2605 geompy = geomBuilder.New()
2606 objet_geom = geompy.ImportSTEP(fichier, False, True)
2609 # 4. Traitement de l'objet correspondant
2610 erreur, message = self._traitement_objet ( solide=solide_aux, objet_geom=objet_geom, n_recur=n_recur )
2612 if ( erreur and self._verbose_max ):
2613 print (blabla, message)
2615 # 5. Mise en forme de l'objet principal récupéré
2616 if ( recover is not None ):
2617 _ = self._nom_sous_objets (recover, False)
2619 # 6. Neutralisation des erreurs dues à l'épaisseur
2620 if ( erreur in (-2,-1,2) ):
2626 return erreur, message
2628 #=========================== Fin de la méthode ==================================
2630 #=========================== Début de la méthode =================================
2632 def surf_objet_geom (self, objet_geom):
2633 """Calcule la surface médiane pour un objet GEOM passé en argument
2636 :objet_geom: l'objet GEOM à traiter
2639 :erreur: code d'erreur
2640 :message: message d'erreur
2643 nom_fonction = __name__ + "/surf_objet_geom"
2644 blabla = "\nDans {} :\n".format(nom_fonction)
2646 if self._verbose_max:
2649 erreur, message = self._traitement_objet ( objet_geom=objet_geom )
2651 if ( erreur and self._verbose_max ):
2652 print (blabla, message)
2654 return erreur, message
2656 #=========================== Fin de la méthode ==================================
2658 #=========================== Début de la méthode =================================
2660 def lancement (self):
2665 :erreur: code d'erreur
2666 :message: message d'erreur
2669 nom_fonction = __name__ + "/lancement"
2670 blabla = "\nDans {} :\n".format(nom_fonction)
2672 if self._verbose_max:
2675 erreur, message = self._traitement_objet ( )
2677 if ( erreur and self._verbose_max ):
2678 print (blabla, message)
2680 return erreur, message
2682 #=========================== Fin de la méthode ==================================
2684 #========================== Fin de la classe ====================================
2686 #==================================================================================
2688 #==================================================================================
2690 if __name__ == "__main__" :
2692 HOME_SH_SM_EXCHANGE = os.environ["HOME_SH_SM_EXCHANGE"]
2694 #L_FIC_CAO.append(os.path.join(HOME_SH_SM_EXCHANGE, "SHAPER", "SurfaceMediane", "Solid_7.step"))
2695 #L_FIC_CAO.append(os.path.join(HOME_SH_SM_EXCHANGE, "SHAPER", "SurfaceMediane", "CAO_STEP", "Objet_1.stp"))
2696 #L_FIC_CAO.append(os.path.join(HOME_SH_SM_EXCHANGE, "SHAPER", "SurfaceMediane", "CAO_STEP", "Naval_007.stp"))
2697 ##L_FIC_CAO.append(os.path.join(HOME_SH_SM_EXCHANGE, "SHAPER", "SurfaceMediane", "CAO_STEP", "Naval.stp"))
2698 #L_FIC_CAO.append(os.path.join(HOME_SH_SM_EXCHANGE, "SHAPER", "SurfaceMediane", "CAO_STEP", "Partition_2.step"))
2699 #L_FIC_CAO.append(os.path.join(HOME_SH_SM_EXCHANGE, "SHAPER", "SurfaceMediane", "CAO_STEP", "Partition_2_1_22.step"))
2700 #L_FIC_CAO.append(os.path.join(HOME_SH_SM_EXCHANGE, "SHAPER", "SurfaceMediane", "CAO_STEP", "Partition_2_1_5.step"))
2701 L_FIC_CAO.append(os.path.join(HOME_SH_SM_EXCHANGE, "SHAPER", "SurfaceMediane", "CAO_STEP", "Observatoire.stp"))
2703 for FIC_CAO in L_FIC_CAO:
2708 #L_OPTIONS.append("-h")
2709 #L_OPTIONS.append("-v")
2710 L_OPTIONS.append("-vmax")
2711 L_OPTIONS.append("-export_step")
2713 # 2. Lancement de la classe
2715 #print ("L_OPTIONS :", L_OPTIONS)
2717 SURFACE_MEDIANE = SurfaceMediane(L_OPTIONS)
2718 if SURFACE_MEDIANE.affiche_aide_globale:
2719 sys.stdout.write(SURFACE_MEDIANE.__doc__+"\n")
2722 PARTSET = model.moduleDocument()
2723 _ = model.addPart(PARTSET)
2724 ERREUR, MESSAGE_ERREUR = SURFACE_MEDIANE.surf_fic_cao(FIC_CAO)
2726 MESSAGE_ERREUR += "\n Code d'erreur : %d\n" % ERREUR
2727 sys.stderr.write(MESSAGE_ERREUR)