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
40 __revision__ = "V10.48"
42 #========================= Les imports - Début ===================================
54 from SketchAPI import *
55 from salome.shaper import model
57 from GeomAlgoAPI import *
59 from salome.geom import geomBuilder
63 #========================== Les imports - Fin ====================================
66 D_FMT["stp"] = ["stp", "step"]
67 D_FMT["igs"] = ["igs", "iges"]
68 for CLE in ("brep", "xao"):
71 # statut = 0 si pas encore traité, 1 si traité avec succès, 2 si trop mince, -1 si pas assez mince, -2 si impossible.
90 # Transparence des solides traités correctement
93 # Limite basse de l'épaisseur pour pouvoir faire les intersections
96 #========================= Début de la fonction ==================================
98 def decode_cao (fmt_cao):
99 """Décode le format de la cao
102 :fmt_cao: format du fichier, step, iges, etc.
104 :fmt_cao_0: format décodé
109 fmt_cao_low = fmt_cao.lower()
111 for cle, l_aux in D_FMT.items():
112 if ( fmt_cao_low in l_aux ):
118 #========================= Fin de la fonction ===================================
120 #========================= Début de la fonction ==================================
122 def import_cao (part_doc, ficcao, nom_objet=None, verbose=False):
123 """Importation d'une cao
127 :ficcao: le fichier de la CAO
129 :objet: l'objet importé dans SHAPER
134 message = "Fichier '{}'\n".format(ficcao)
140 laux = ficcao.split(".")
141 fmt_cao_0 = decode_cao (laux[-1])
143 if ( fmt_cao_0 not in ("stp", "brep", "igs", "xao") ):
144 message += "Le format de CAO est inconnu"
148 message += "Le fichier de CAO n'a pas été décodé correctement."
151 elif not os.path.isfile(ficcao):
152 message += "Le fichier de CAO est inconnu."
158 objet = model.addImport(part_doc, ficcao)
162 if nom_objet is not None:
163 objet.result().setName(nom_objet)
166 texte = "Objet : '{}'\n".format(objet.result().name())
167 texte += "De type : '{}'".format(objet.result().shapeType())
171 return erreur, message, objet
173 #========================= Fin de la fonction ===================================
175 #=================================== La classe ===================================
177 class SurfaceMediane (object):
179 """Calcul des surfaces médianes de solides minces
181 L'objectif de ce programme est de créer les surfaces médianes, encore appelées fibres neutres, pour \
182 une structure qui est un solide ou un assemblage de solides (compound).
183 Pour réaliser l'opération, trois façons de faire :
185 1. On lance le script en précisant le fichier à analyser dans la zone d'auto-test.
187 2. Si on part d'un script qui manipule un fichier au format CAO, on crée une instance de la classe SurfaceMediane \
188 puis on appelle la méthode surf_fic_cao avec ce fichier en argument.
190 3. Si on part d'un script qui crée un objet SHAPER, on crée une instance de la classe SurfaceMediane \
191 puis on appelle la méthode surf_objet_shaper avec cet objet en argument.
194 Le programme crée les surfaces sous réserve que pour le solide envisagé, il a réussi à trouver deux faces \
195 de taille identique et supérieure aux tailles des autres faces du solide. \
196 Cela fonctionne pour des surfaces planes ou de forme canonique.
197 Il crée alors une surface au milieu de ces deux grandes faces. \
198 Cette face est coloriée en vert, le solide est en vert et transparent.
200 On sait traiter les faces :
207 Si la création n'a pas eu lieu, un message est émis et les solides sont mise en couleur :
208 . Rouge : le solide n'est pas assez mince.
209 . Bleu : le solide est trop mince, vis-à-vis de la précision de SHAPER.
210 . Orange : la forme de la face n'est pas reconnue.
218 . Exportation finale dans un fichier step. Par défaut, pas d'export.
219 -export_step/-no_export_step
228 affiche_aide_globale = 0
235 nom_solide_aux = None
241 objet_principal = None
243 # Pour chaque sous-objet dans l'ordre de l'arborescence : nom
245 # Statut de chaque sous-objet connu par son nom :
246 # 0 si pas encore traité, 1 si traité avec succès, 2 si trop mince, -1 si pas assez mince, -2 si impossible.
248 # Liste des faces médianes créées et des fonctions initiales
250 # La fonction initiale
256 #=========================== Début de la méthode =================================
258 def __init__ ( self, liste_option ):
260 """Le constructeur de la classe SurfaceMediane
262 Décodage des arguments
263 On cherche ici les arguments généraux : aide, verbeux
266 for option in liste_option :
269 if isinstance(option,str):
270 saux = option.upper()
272 if saux in ( "-H", "-HELP" ):
273 self.affiche_aide_globale = 1
276 elif saux == "-VMAX" :
278 self._verbose_max = 1
279 elif saux == "-EXPORT_STEP":
280 self._export_step = True
281 elif saux == "-NO_EXPORT_STEP":
282 self._export_step = False
284 #=========================== Fin de la méthode ==================================
286 #=========================== Début de la méthode =================================
289 """A la suppression de l'instance de classe"""
290 if self._verbose_max:
291 print ("Suppression de l'instance de la classe.")
293 #=========================== Fin de la méthode ==================================
295 #=========================== Début de la méthode =================================
297 def _nom_sous_objets (self, objet, lecture, n_recur=0, rang=0):
298 """Gère les noms des sous_objets solides
301 :objet: objet à traiter
302 :lecture: vrai pour lire les noms, faux pour les attribuer
303 :n_recur: niveau de récursivité
304 :rang: rang du sous-objet
307 :rang: rang du sous-objet
310 nom_fonction = __name__ + "/_nom_sous_objets"
311 blabla = "Dans {} :\n".format(nom_fonction)
313 if self._verbose_max:
315 for _ in range(n_recur):
317 texte = "\n{}{}".format(prefixe,blabla)
318 texte += "{}n_recur = {}".format(prefixe,n_recur)
319 texte += "\n{}lecture = {}".format(prefixe,lecture)
322 # 1. Au premier passage, il faut garder la référence au résultat principal
325 objet_0 = objet.result()
326 if self._verbose_max:
327 print ("d_statut_so = {}".format(self.d_statut_so))
331 # 2. On descend dans l'arborescence des sous-objets jusqu'à en trouver un qui n'en n'a pas
333 nb_sub_results = objet_0.numberOfSubs()
335 if self._verbose_max:
336 texte = "{}Examen de l'objet '{}' ".format(prefixe,objet_0.name())
337 texte += "de type '{}'".format(objet_0.shapeType())
338 texte += "\n{}objet.result().numberOfSubs() : {}".format(prefixe,nb_sub_results)
341 for n_sobj in range(nb_sub_results):
343 # 2.1. Exploration récursive de l'arborescence
345 rang = self._nom_sous_objets ( objet_0.subResult(n_sobj), lecture, n_recur+1, rang )
347 # 2.2. Cet objet n'a pas de sous-objets. Si c'est un solide, on le traite
349 if ( objet_0.shapeType() == "SOLID" ):
350 # A la lecture, on enregistre le nom
353 self.l_noms_so.append(nom)
354 self.d_statut_so[nom] = 0
355 # A la récupération, on redonne le nom et on affecte une couleur dépendant de l'état
357 nom = self.l_noms_so[rang]
359 etat = self.d_statut_so[nom]
360 objet_0.setColor (D_COLOR_R[etat],D_COLOR_G[etat],D_COLOR_B[etat])
362 objet_0.setTransparency (TRANSPARENCE)
367 #=========================== Fin de la méthode ==================================
369 #=========================== Début de la méthode =================================
371 def _couleur_objet (self, objet, n_recur=0, coul_r=1, coul_g=0, coul_b=0):
372 """Appliquer une couleur à un objet et à ses sous_objets
375 :objet: objet à traiter
376 :n_recur: niveau de récursivité
377 :coul_r,coul_g,coul_b: code RGB de la couleur à appliquer
380 :rang: rang du sous-objet
383 nom_fonction = __name__ + "/_couleur_objet"
384 blabla = "Dans {} :\n".format(nom_fonction)
386 if self._verbose_max:
388 for _ in range(n_recur):
390 texte = "\n{}{}".format(prefixe,blabla)
391 texte += "{}n_recur = {}".format(prefixe,n_recur)
392 texte += "\n{}RGB = ({},{},{})".format(prefixe,coul_r,coul_g,coul_b)
395 # 1. Au premier passage, il faut garder la référence au résultat principal
398 objet_0 = objet.result()
402 # 2. On descend dans l'arborescence des sous-objets jusqu'à en trouver un qui n'en n'a pas
404 nb_sub_results = objet_0.numberOfSubs()
406 if self._verbose_max:
407 texte = "{}Examen de l'objet '{}' ".format(prefixe,objet_0.name())
408 texte += "de type '{}' ".format(objet_0.shapeType())
409 texte += "et de {} sous-objets".format(nb_sub_results)
412 for n_sobj in range(nb_sub_results):
414 # 2.1. Exploration récursive de l'arborescence
416 self._couleur_objet ( objet_0.subResult(n_sobj), n_recur+1, coul_r, coul_g, coul_b )
418 # 2.2. Cet objet n'a pas de sous-objets : on le colore
419 if self._verbose_max:
420 texte = "{}Couleur affectée à l'objet '{}' ".format(prefixe,objet_0.name())
422 objet_0.setColor (int(coul_r),int(coul_g),int(coul_b))
424 #print ("sortie de {}".format(nom_fonction))
428 #=========================== Fin de la méthode ==================================
430 #=========================== Début de la méthode =================================
432 def _isole_solide ( self, solide ):
433 """Isole le solide de son arboresence
436 :solide: le solide à traiter
439 :objet: le solide isolé
440 :recover: la fonction de récupération
443 nom_fonction = __name__ + "/_isole_solide"
444 blabla = "\nDans {} :\n".format(nom_fonction)
445 if self._verbose_max:
447 texte += "Pour le solide '{}' ".format(solide.name())
448 texte += "de l'objet principal '{}'".format(self.objet_principal.name())
451 if ( solide.name() != self.objet_principal.name() ):
453 if self._verbose_max:
454 print (". Extraction du solide")
456 # 1. Extraction du solide
457 remove_subshapes = model.addRemoveSubShapes(self.part_doc, model.selection("COMPOUND", self.objet_principal.name()))
458 remove_subshapes.setSubShapesToKeep([model.selection("SOLID", solide.name())])
460 self.nom_solide_aux = "{}_S".format(solide.name())
461 remove_subshapes.result().setName(self.nom_solide_aux)
463 self.fonction_0 = remove_subshapes
465 # 2. Récupération de l'objet principal
466 recover = model.addRecover(self.part_doc, remove_subshapes, [self.objet_principal])
467 recover.result().setName(self.objet_principal.name())
469 objet = remove_subshapes.result()
473 if self._verbose_max:
474 print (". Mise en place du solide")
477 self.nom_solide_aux = self.objet_principal.name()
478 self.fonction_0 = None
481 if self._verbose_max:
482 texte = "objet final : '{}'\n".format(objet.name())
483 texte += "fonction_0 : {}".format(self.fonction_0)
484 texte += "recover : {}".format(recover)
487 return objet, recover
489 #=========================== Fin de la méthode ==================================
491 #=========================== Début de la méthode =================================
493 def _faces_du_solide ( self, geompy, solide ):
494 """Détermine les faces d'un solide
497 :geompy: environnement de GEOM
498 :solide: le solide à traiter
501 :l_faces: liste des faces du solide
504 nom_fonction = __name__ + "/_faces_du_solide"
505 blabla = "\nDans {} :\n".format(nom_fonction)
506 if self._verbose_max:
513 while ( not erreur ):
515 if self._verbose_max:
516 print (".. Traitement du solide '{}'".format(self.nom_solide))
517 longueur, aire, volume = geompy.BasicProperties(solide)
518 texte = "{}".format(geompy.WhatIs(solide))
519 texte += ". longueur, aire, volume : {}, {}, {}".format(longueur,aire,volume)
522 # Liste des faces qui composent le solide
523 l_faces = geompy.ExtractShapes(solide, geompy.ShapeType["FACE"], True)
524 #if self._verbose_max:
525 #print ("Liste des {} faces qui composent le solide :".format(len(l_faces)))
526 #for iaux, face in enumerate(l_faces):
527 #print ("Face n° {} :\n {}".format(iaux,geompy.WhatIs(face)))
531 return erreur, message, l_faces
533 #=========================== Fin de la méthode ==================================
535 #=========================== Début de la méthode =================================
537 def _calcul_caract_faces ( self, geompy, l_faces ):
538 """Calcule les caractéristiques géométriques des faces
541 :geompy: environnement de GEOM
542 :l_faces: liste des faces du solide
545 :tb_caract: tableau des caractéristiques géométriques des faces
548 nom_fonction = __name__ + "/_calcul_caract_faces"
549 blabla = "\nDans {} :\n".format(nom_fonction)
551 nb_faces = len(l_faces)
552 if self._verbose_max:
553 print (blabla+"Nombre de faces : {}.".format(nb_faces))
555 tb_caract = np.zeros((nb_faces,3), dtype = 'object')
556 for iaux, face in enumerate(l_faces):
557 _, aire, _ = geompy.BasicProperties(face)
558 #longueur, aire, volume = geompy.BasicProperties(face)
559 if self._verbose_max:
560 texte = "\t. Face numéro {}".format(iaux)
561 #texte += "\n\t. longueur, aire, volume : {}, {}, {}".format(longueur,aire,volume)
564 tb_caract [iaux][0] = face
565 tb_caract [iaux][1] = aire
566 tb_caract [iaux][2] = geompy.KindOfShape(face)
567 if self._verbose_max:
568 print ("\t. tb_caract : {} {}".format(aire,tb_caract[iaux][2]))
572 #=========================== Fin de la méthode ==================================
574 #=========================== Début de la méthode =================================
576 def _tri_faces ( self, tb_caract ):
577 """Trie les faces en fonction de leurs surfaces
580 :tb_caract: tableau des caractéristiques géométriques des faces
583 :tb_caract_1[-1], tb_caract_1[-2]: les caractéristiques des 2 faces les plus grandes
589 nom_fonction = __name__ + "/_tri_faces"
590 blabla = "\nDans {} :\n".format(nom_fonction)
592 # Tri du tableau en fonction des surfaces
593 if self._verbose_max:
594 print (blabla+"tb_caract brut : {}".format(tb_caract))
595 tb_caract_1 = sorted(tb_caract, key=lambda colonnes: colonnes[1])
596 if self._verbose_max:
597 print ("tb_caract trié : {}".format(tb_caract_1))
599 if self._verbose_max:
600 texte = "\tSurface de la plus grande face : {}, de caractéristiques {}\n".format(tb_caract_1[-1][1],tb_caract_1[-1][2])
601 texte += "\tSurface de la face suivante : {}, de caractéristiques {}".format(tb_caract_1[-2][1],tb_caract_1[-2][2])
602 if self._verbose_max:
603 texte += "\n\tSurface de la 3ème face suivante : {}, de caractéristiques {}".format(tb_caract_1[-3][1],tb_caract_1[-3][2])
606 # La surface suivante doit être différente, sinon ce n'est pas un solide mince
607 ecart = np.abs((tb_caract_1[-1][1]-tb_caract_1[-3][1])/tb_caract_1[-1][1])
608 if ( ecart < self._epsilon ):
609 message = "\nSolide '{}'\n".format(self.nom_solide)
610 message += ". Surface de la plus grande face : {}\n".format(tb_caract_1[-1][1])
611 message += ". Surface de la 1ère face suivante : {}\n".format(tb_caract_1[-2][1])
612 message += ". Surface de la 2ème face suivante : {}\n".format(tb_caract_1[-3][1])
613 if self._verbose_max:
614 message += ". Ecart relatif :{:4.1f}%\n".format(ecart*100.)
615 message += "L'écart est trop faible par rapport à la limite de {}%.\n".format(self._epsilon*100.)
616 message += "==> Impossible de créer la face médiane car le solide n'est pas assez mince.\n"
618 self.d_statut_so[self.nom_solide] = -1
619 self.faces_pb_nb += 1
620 self.faces_pb_msg += message
622 return erreur, message, tb_caract_1[-1], tb_caract_1[-2]
624 #=========================== Fin de la méthode ==================================
626 #=========================== Début de la méthode =================================
628 def _calcul_caract_aretes_face ( self, geompy, caract_face ):
629 """Détermine les caractéristiques des arêtes d'une face
632 :geompy: environnement de GEOM
633 :caract_face: les caractéristiques de la face
636 :caract_arete_face: les caractéristiques des arêtes de la face
639 nom_fonction = __name__ + "/_calcul_caract_aretes_face"
640 blabla = "\nDans {} :\n".format(nom_fonction)
642 if self._verbose_max:
644 texte += "face : {}\n".format(caract_face)
647 # Détermination des arêtes pour chaque face
648 face = caract_face[0]
649 l_aretes = geompy.ExtractShapes(face, geompy.ShapeType["EDGE"], True)
650 caract_arete_face = list()
651 for arete in l_aretes:
652 caract_arete_face.append(geompy.KindOfShape(arete))
654 if self._verbose_max:
655 print ("Aretes de la face : {}".format(caract_arete_face))
657 return caract_arete_face
659 #=========================== Fin de la méthode ==================================
661 #=========================== Début de la méthode =================================
663 def _verif_epaisseur ( self, epaisseur ):
664 """Contrôle de la validité de l'épaisseur
667 :epaisseur: épaisseur du solide
670 nom_fonction = __name__ + "/_verif_epaisseur"
671 blabla = "\nDans {} :\n".format(nom_fonction)
673 if self._verbose_max:
675 texte += ". Epaisseur du solide : {}\n".format(epaisseur)
676 texte += ". EP_MIN : {}".format(EP_MIN)
679 if ( epaisseur <= EP_MIN ):
680 message = "\nSolide '{}'\n".format(self.nom_solide)
681 message += ". Epaisseur : {}\n".format(epaisseur)
682 message += "L'épaisseur est trop faible par rapport à la limite de {}.\n".format(EP_MIN)
683 message += "==> Impossible de créer la face médiane car le solide est trop mince.\n"
685 self.d_statut_so[self.nom_solide] = 2
686 self.faces_pb_nb += 1
687 self.faces_pb_msg += message
694 #=========================== Fin de la méthode ==================================
696 #=========================== Début de la méthode =================================
698 def _cree_face_mediane ( self, solide, geompy, caract_face_1, caract_face_2 ):
699 """Crée la face médiane entre deux autres
702 :solide: solide SHAPER à traiter
703 :geompy: environnement de GEOM
704 :caract_face_1, caract_face_2: les caractéristiques des 2 faces les plus grandes
707 :face: la face médiane créée
710 nom_fonction = __name__ + "/_cree_face_mediane"
711 blabla = "\nDans {} :\n".format(nom_fonction)
713 if self._verbose_max:
715 texte += "face_1 : {}\n".format(caract_face_1)
716 texte += "face_2 : {}".format(caract_face_2)
722 # 1. Forme de la face
723 forme = caract_face_1[2][0]
724 if self._verbose_max:
725 print ("forme = {}".format(forme) )
727 # 2. Traitement selon la forme de la face
729 if forme in ( geompy.kind.DISK_CIRCLE, geompy.kind.DISK_ELLIPSE, geompy.kind.POLYGON, geompy.kind.PLANE, geompy.kind.PLANAR):
730 erreur, face = self._cree_face_mediane_plane ( geompy, solide, caract_face_1, caract_face_2 )
732 # 2.2. Face cylindrique
733 elif forme == geompy.kind.CYLINDER2D:
734 erreur, face = self._cree_face_mediane_cylindre ( solide, caract_face_1, caract_face_2 )
736 # 2.3. Face sphérique
737 elif forme == geompy.kind.SPHERE2D:
738 erreur, face = self._cree_face_mediane_sphere ( caract_face_1, caract_face_2 )
741 elif forme == geompy.kind.TORUS2D:
742 erreur, face = self._cree_face_mediane_tore ( caract_face_1, caract_face_2 )
745 elif forme == geompy.kind.CONE2D:
746 erreur, face = self._cree_face_mediane_cone ( geompy, caract_face_1, caract_face_2 )
748 # 2.N. Face de forme inconnue
750 message = "\nSolide '{}'\n".format(self.nom_solide)
751 message += "sa face la plus grande est de forme : {}\n".format(forme)
752 message += "==> Impossible de créer la face médiane.\n"
754 self.d_statut_so[self.nom_solide] = -2
755 self.faces_pb_nb += 1
756 self.faces_pb_msg += message
758 # 3. Gestion de la face produite
761 self._cree_face_mediane_0 ( face )
765 #=========================== Fin de la méthode ==================================
767 #=========================== Début de la méthode =================================
769 def _cree_face_mediane_0 ( self, face ):
770 """Gestion de la face médiane créée entre deux autres
773 :face: la face médiane créée
776 nom_fonction = __name__ + "/_cree_face_mediane_0"
777 blabla = "\nDans {} :\n".format(nom_fonction)
779 if self._verbose_max:
784 nom_face = self.nom_solide+"_M"
785 #if ( self.nom_solide_aux != self.objet_principal.name() ):
787 face.setName(nom_face)
788 face.result().setName(nom_face)
790 # 2. Mémorisation de la face et de la fonction initiale
791 self.l_faces_m.append((face, self.fonction_0))
793 # 3. Couleur verte pour la face
794 self._couleur_objet (face, coul_r=0, coul_g=170, coul_b=0)
796 # 4. Changement de statut pour le solide
797 self.d_statut_so[self.nom_solide] = 1
801 #=========================== Fin de la méthode ==================================
803 #=========================== Début de la méthode =================================
805 def _cree_face_mediane_plane ( self, geompy, solide, caract_face_1, caract_face_2 ):
806 """Crée la face médiane entre deux autres - cas des surfaces planes
809 :geompy: environnement de GEOM
810 :solide: l'objet solide à traiter
811 :caract_face_1, caract_face_2: les caractéristiques des 2 faces les plus grandes
814 :face: la face médiane
817 nom_fonction = __name__ + "/_cree_face_mediane_plane"
818 blabla = "\nDans {} :\n".format(nom_fonction)
819 if self._verbose_max:
822 # Caractéristiques des surfaces
823 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 )
825 # Contrôle de la validité de l'épaisseur
826 erreur = self._verif_epaisseur ( d_face_1_2 )
828 # Création de la face
830 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 )
836 #=========================== Fin de la méthode ==================================
838 #=========================== Début de la méthode =================================
840 def _cree_face_mediane_plane_0 ( self, geompy, solide, caract_face_1, caract_face_2 ):
841 """Crée la face médiane entre deux autres - cas des surfaces planes
843 Décodage des caractéristiques
846 :geompy: environnement de GEOM
847 :solide: l'objet solide à traiter
848 :caract_face_1, caract_face_2: les caractéristiques des 2 faces les plus grandes
851 :coo_x, coo_y, coo_z: coordonnées du centre de la base
852 :vnor_x, vnor_y, vnor_z: coordonnées du vecteur normal
853 :taille: estimation de la taille de la future face
854 :d_face_1_2: la distance entre les deux faces
857 nom_fonction = __name__ + "/_cree_face_mediane_plane_0"
858 blabla = "\nDans {} :\n".format(nom_fonction)
860 if self._verbose_max:
862 texte += "face_1 : {}\n".format(caract_face_1)
863 texte += "face_2 : {}".format(caract_face_2)
866 # 1. Caractéristiques de la base
867 # Coordonnées du centre de la base
868 coo_x = caract_face_1[2][1]
869 coo_y = caract_face_1[2][2]
870 coo_z = caract_face_1[2][3]
871 # Coordonnées du vecteur normal
872 vnor_x = caract_face_1[2][4]
873 vnor_y = caract_face_1[2][5]
874 vnor_z = caract_face_1[2][6]
875 # taille : la diagonale de la boîte englobante permet d'être certain de tout prendre
876 l_diag = self._calcul_boite_englobante ( solide )
878 if self._verbose_max:
879 print ("Taille englobante : {}".format(taille))
881 # 2. Distance entre les deux faces
882 face_1 = caract_face_1[0]
883 face_2 = caract_face_2[0]
884 d_face_1_2 = geompy.MinDistance(face_1, face_2)
885 if self._verbose_max:
886 print ("Distance entre les deux faces = {}".format(d_face_1_2))
888 return coo_x, coo_y, coo_z, vnor_x, vnor_y, vnor_z, taille, d_face_1_2
890 #=========================== Fin de la méthode ==================================
892 #=========================== Début de la méthode =================================
894 def _cree_face_mediane_plane_1 ( self, solide, coo_x, coo_y, coo_z, vnor_x, vnor_y, vnor_z, taille, d_face_1_2 ):
895 """Crée la face médiane entre deux autres - cas des surfaces planes
897 Création des objets temporaires et de la face médiane
900 :solide: l'objet solide à traiter
901 :coo_x, coo_y, coo_z: coordonnées du centre de la base
902 :vnor_x, vnor_y, vnor_z: coordonnées du vecteur normal
903 :taille: estimation de la taille de la future face
904 :d_face_1_2: la distance entre les deux faces
907 :face: la face médiane
910 nom_fonction = __name__ + "/_cree_face_mediane_plane_1"
911 blabla = "\nDans {} :\n".format(nom_fonction)
912 if self._verbose_max:
914 texte += "Centre : ({}, {}, {})\n".format(coo_x, coo_y, coo_z)
915 texte += "Normale : ({}, {}, {})\n".format(vnor_x, vnor_y, vnor_z)
916 texte += "Taille : {}\n".format(taille)
917 texte += "Distance entre les deux faces : {}".format(d_face_1_2)
920 # Création de paramètres
921 nom_par_1 = "{}_taille".format(self.nom_solide)
922 model.addParameter(self.part_doc, "{}".format(nom_par_1), "{}".format(taille))
924 # Création du point central
925 centre = model.addPoint(self.part_doc, coo_x, coo_y, coo_z)
926 nom_centre = "{}_centre".format(self.nom_solide)
927 centre.result().setName(nom_centre)
929 # Création du vecteur normal
930 v_norm = model.addAxis(self.part_doc, vnor_x, vnor_y, vnor_z)
931 nom_normal = "{}_normale".format(self.nom_solide)
932 v_norm.result().setName(nom_normal)
934 # Création du plan perpendiculaire au vecteur normal
935 plan = model.addPlane(self.part_doc, model.selection("EDGE", nom_normal), model.selection("VERTEX", nom_centre), True)
936 nom_plan = "{}_plan".format(self.nom_solide)
937 plan.result().setName(nom_plan)
939 # Création d'un sketch
940 sketch = model.addSketch(self.part_doc, model.selection("FACE", nom_plan))
942 SketchProjection_1 = sketch.addProjection(model.selection("VERTEX", nom_centre), False)
943 SketchPoint_1 = SketchProjection_1.createdFeature()
945 ### Create SketchLine
946 SketchLine_1 = sketch.addLine(-taille/2., taille/2., taille/2., taille/2.)
948 ### Create SketchLine
949 SketchLine_2 = sketch.addLine(taille/2., taille/2., taille/2., -taille/2.)
951 ### Create SketchLine
952 SketchLine_3 = sketch.addLine(taille/2., -taille/2., -taille/2., -taille/2.)
954 ### Create SketchLine
955 SketchLine_4 = sketch.addLine(-taille/2., -taille/2., -taille/2., taille/2.)
956 sketch.setCoincident(SketchLine_4.endPoint(), SketchLine_1.startPoint())
957 sketch.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
958 sketch.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
959 sketch.setCoincident(SketchLine_3.endPoint(), SketchLine_4.startPoint())
961 ### Create SketchLine
962 SketchLine_5 = sketch.addLine(-taille/2., taille/2., taille/2., -taille/2.)
963 SketchLine_5.setAuxiliary(True)
965 ### Create SketchLine
966 SketchLine_6 = sketch.addLine(taille/2., taille/2., -taille/2., -taille/2.)
967 SketchLine_6.setAuxiliary(True)
968 sketch.setCoincident(SketchLine_1.startPoint(), SketchLine_5.startPoint())
969 sketch.setCoincident(SketchLine_2.startPoint(), SketchLine_6.startPoint())
970 sketch.setCoincident(SketchLine_3.startPoint(), SketchLine_5.endPoint())
971 sketch.setCoincident(SketchLine_4.startPoint(), SketchLine_6.endPoint())
972 sketch.setCoincident(SketchAPI_Point(SketchPoint_1).coordinates(), SketchLine_5.result())
973 sketch.setCoincident(SketchAPI_Point(SketchPoint_1).coordinates(), SketchLine_6.result())
974 sketch.setHorizontal(SketchLine_1.result())
975 sketch.setVertical(SketchLine_2.result())
976 sketch.setHorizontal(SketchLine_3.result())
977 sketch.setVertical(SketchLine_4.result())
978 sketch.setLength(SketchLine_3.result(), nom_par_1)
979 sketch.setEqual(SketchLine_3.result(), SketchLine_4.result())
982 nom_sketch = "{}_esquisse".format(self.nom_solide)
983 sketch.setName(nom_sketch)
984 sketch.result().setName(nom_sketch)
986 ### Create LinearCopy
987 LinearCopy_1 = model.addMultiTranslation(self.part_doc, [model.selection("SOLID", self.nom_solide_aux)], model.selection("EDGE", "PartSet/OX"), 0, 1, keepSubResults = True)
988 LinearCopy_1.result().subResult(0).setName("{}_0".format(self.nom_solide_aux))
991 Recover_1 = model.addRecover(self.part_doc, LinearCopy_1, [solide])
992 Recover_1.result().setName("{}_1".format(self.nom_solide_aux))
994 # Création d'une face ; on la translate d'une demi-épaisseur.
995 for iaux in range(2):
997 distance = -0.5*d_face_1_2*float(2*iaux-1)
998 nom_solide = "{}_{}".format(self.nom_solide_aux,iaux)
999 face = self._cree_face_mediane_plane_2 ( nom_sketch, nom_normal, nom_solide, distance, iaux )
1002 # Si on traite un objet solide unique, on le récupère
1003 if ( self.nom_solide_aux == self.objet_principal.name() ):
1004 if self._verbose_max:
1005 print ("On traite un objet solide unique ==> on le récupère.")
1006 Recover_2 = model.addRecover(self.part_doc, face, [Recover_1.result()])
1007 Recover_2.result().setName("{}_S".format(self.nom_solide_aux))
1008 nb_inter = face.result().numberOfSubs()
1009 if self._verbose_max:
1010 print ("Nombre d'intersections : {}".format(nb_inter))
1011 # Une seule intersection : c'est la bonne
1012 # Sinon, c'est que le solide est trop mince. On fusionnerait les faces.
1014 face = self._cree_face_mediane_plane_3 ( face )
1016 # Si l'intersection est vide, on la translate dans l'autre sens
1018 if self._verbose_max:
1019 print ("L'intersection est vide.")
1024 #=========================== Fin de la méthode ==================================
1026 #=========================== Début de la méthode =================================
1028 def _cree_face_mediane_plane_2 ( self, nom_sketch, nom_normal, nom_solide, distance, icpt=0 ):
1029 """Crée la face médiane entre deux autres - cas des surfaces planes
1031 Intersection de la face avec le solide
1034 :nom_sketch: nom du sketch
1035 :nom_normal: nom du vecteur normal
1036 :nom_solide: nom du solide à intersecter
1037 :distance: la distance de translation
1038 :icpt: numéro de la tentative
1041 :face: la face médiane
1044 nom_fonction = __name__ + "/_cree_face_mediane_plane_2"
1045 blabla = "\nDans {} :\n".format(nom_fonction)
1046 if self._verbose_max:
1048 texte += "nom_sketch : {}\n".format(nom_sketch)
1049 texte += "nom_normal : {}\n".format(nom_normal)
1050 texte += "nom_solide : {}\n".format(nom_solide)
1051 texte += "distance : {}".format(distance)
1054 # Création d'une face
1055 Face_1 = model.addFace(self.part_doc, [model.selection("COMPOUND", "all-in-{}".format(nom_sketch))])
1056 nom_face_1 = "{}_face_1_{}".format(self.nom_solide_aux,icpt)
1057 Face_1.result().setName(nom_face_1)
1060 Translation_1 = model.addTranslation(self.part_doc, [model.selection("FACE", nom_face_1)], axis = model.selection("EDGE", nom_normal), distance = distance, keepSubResults = True)
1061 nom_trans = "{}_trans_{}".format(self.nom_solide_aux,icpt)
1062 Translation_1.setName(nom_trans)
1063 Translation_1.result().setName(nom_trans)
1064 Translation_1.result().setColor(85, 0, 255)
1066 # Intersection de cette face avec le solide initial
1067 face = model.addCommon(self.part_doc, [model.selection("SOLID", nom_solide), model.selection("FACE", nom_trans)], keepSubResults = True)
1071 #=========================== Fin de la méthode ==================================
1073 #=========================== Début de la méthode =================================
1075 def _cree_face_mediane_plane_3 ( self, face ):
1076 """Crée la face médiane entre deux autres - cas des surfaces planes
1078 Fusion des 2 intersections
1081 :face: la face médiane composée de plusieurs intersections
1084 :face_m: la face médiane
1087 nom_fonction = __name__ + "/_cree_face_mediane_plane_3"
1088 blabla = "\nDans {} :\n".format(nom_fonction)
1089 if self._verbose_max:
1093 # Nommage des sous-objets
1095 for iaux in range(face.result().numberOfSubs()):
1096 nom = "{}_common_{}".format(self.nom_solide_aux,iaux)
1097 face.result().subResult(iaux).setName(nom)
1098 l_fuse.append(model.selection("FACE", '{}'.format(nom)))
1101 if self._verbose_max:
1102 print ("Fusion de {} faces.".format(len(l_fuse)))
1103 face_m = model.addFuse(self.part_doc, l_fuse, keepSubResults = True)
1107 #=========================== Fin de la méthode ==================================
1109 #=========================== Début de la méthode =================================
1111 def _cree_face_mediane_cylindre ( self, solide, caract_face_1, caract_face_2 ):
1112 """Crée la face médiane entre deux autres - cas des cylindres
1115 :solide: solide SHAPER à traiter
1116 :caract_face_1, caract_face_2: les caractéristiques des 2 faces les plus grandes
1119 :face: la face médiane
1122 nom_fonction = __name__ + "/_cree_face_mediane_cylindre"
1123 blabla = "\nDans {} :\n".format(nom_fonction)
1126 if self._verbose_max:
1128 texte += "face_1 : {}\n".format(caract_face_1)
1129 texte += "face_2 : {}".format(caract_face_2)
1132 # Caractéristiques des cylindres
1133 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 )
1135 # Contrôle de la validité de l'épaisseur
1136 erreur = self._verif_epaisseur ( epaisseur )
1138 # Création de la face
1140 face = self._cree_face_mediane_cylindre_1 ( coo_x, coo_y, coo_z, axe_x, axe_y, axe_z, rayon, hauteur )
1142 self._couleur_objet (solide, coul_r=0, coul_g=0, coul_b=255)
1147 #=========================== Fin de la méthode ==================================
1149 #=========================== Début de la méthode =================================
1151 def _cree_face_mediane_cylindre_0 ( self, solide, caract_face_1, caract_face_2 ):
1152 """Crée la face médiane entre deux autres - cas des cylindres
1154 Décodage des caractéristiques
1157 :solide: l'objet solide à traiter
1158 :caract_face_1, caract_face_2: les caractéristiques des 2 faces les plus grandes
1161 :coo_x, coo_y, coo_z: coordonnées du centre de la base
1162 :axe_x, axe_y, axe_z: coordonnées de l'axe
1163 :rayon: rayon moyen entre les deux faces
1164 :hauteur: hauteur du cylindre
1165 :epaisseur: épaisseur de l'interface entre les deux faces
1168 nom_fonction = __name__ + "/_cree_face_mediane_cylindre_0"
1169 blabla = "\nDans {} :\n".format(nom_fonction)
1171 if self._verbose_max:
1173 texte += "face_1 : {}\n".format(caract_face_1)
1174 texte += "face_2 : {}".format(caract_face_2)
1177 # Coordonnées du centre de la base
1178 coo_x = caract_face_1[2][1]
1179 coo_y = caract_face_1[2][2]
1180 coo_z = caract_face_1[2][3]
1181 # Coordonnées de l'axe
1182 axe_x = caract_face_1[2][4]
1183 axe_y = caract_face_1[2][5]
1184 axe_z = caract_face_1[2][6]
1186 rayon = (caract_face_2[2][7]+caract_face_1[2][7])/2.
1187 # Hauteur : la diagonale de la boîte englobante permet d'être certain de tout prendre
1188 l_diag = self._calcul_boite_englobante ( solide )
1189 hauteur = 10.*l_diag
1190 if self._verbose_max:
1191 print ("Hauteur englobante : {}".format(hauteur))
1193 epaisseur = np.abs(caract_face_2[2][7]-caract_face_1[2][7])
1195 return coo_x, coo_y, coo_z, axe_x, axe_y, axe_z, rayon, hauteur, epaisseur
1197 #=========================== Fin de la méthode ==================================
1199 #=========================== Début de la méthode =================================
1201 def _cree_face_mediane_cylindre_1 ( self, coo_x, coo_y, coo_z, axe_x, axe_y, axe_z, rayon, hauteur ):
1202 """Crée la face médiane entre deux autres - cas des cylindres
1204 Création des objets temporaires et de la face externe du cylindre support
1207 :coo_x, coo_y, coo_z: coordonnées du centre de la base
1208 :axe_x, axe_y, axe_z: coordonnées de l'axe
1209 :rayon: rayon moyen entre les deux faces
1210 :hauteur: hauteur du cylindre
1213 :face: la face médiane
1215 nom_fonction = __name__ + "/_cree_face_mediane_cylindre_1"
1216 blabla = "\nDans {} :\n".format(nom_fonction)
1218 # Les caractéristiques du cylindre à créer
1219 if self._verbose_max:
1221 texte += "Centre : ({}, {}, {})\n".format(coo_x, coo_y, coo_z)
1222 texte += "Axe : ({}, {}, {})\n".format(axe_x, axe_y, axe_z)
1223 texte += "Rayon : {}\n".format(rayon)
1224 texte += "Hauteur : {}".format(hauteur)
1227 # Création du point central
1228 centre = model.addPoint(self.part_doc, coo_x, coo_y, coo_z)
1229 nom_centre = "{}_centre".format(self.nom_solide)
1230 centre.result().setName(nom_centre)
1233 axe = model.addAxis(self.part_doc, axe_x, axe_y, axe_z)
1234 nom_axe = "{}_axe".format(self.nom_solide)
1235 axe.result().setName(nom_axe)
1237 # Création du plan perpendiculaire à l'axe
1238 plan = model.addPlane(self.part_doc, model.selection("EDGE", nom_axe), model.selection("VERTEX", nom_centre), True)
1239 nom_plan = "{}_plan".format(self.nom_solide)
1240 plan.result().setName(nom_plan)
1242 # Création d'un sketch
1243 nom_par_1 = "{}_R".format(self.nom_solide)
1244 model.addParameter(self.part_doc, "{}".format(nom_par_1), "{}".format(rayon))
1245 nom_par_2 = "{}_H".format(self.nom_solide)
1246 model.addParameter(self.part_doc, "{}".format(nom_par_2), "{}".format(hauteur))
1248 sketch = model.addSketch(self.part_doc, model.selection("FACE", nom_plan))
1250 SketchProjection_1 = sketch.addProjection(model.selection("VERTEX", nom_centre), False)
1251 SketchPoint_1 = SketchProjection_1.createdFeature()
1253 SketchCircle_1 = sketch.addCircle(0., 0., rayon)
1254 sketch.setCoincident(SketchPoint_1.result(), SketchCircle_1.center())
1255 sketch.setRadius(SketchCircle_1.results()[1], nom_par_1)
1257 nom_sketch = "{}_esquisse".format(self.nom_solide)
1258 sketch.setName(nom_sketch)
1259 sketch.result().setName(nom_sketch)
1261 # Création du cylindre complet
1262 cylindre = model.addExtrusion(self.part_doc, [model.selection("COMPOUND", "all-in-{}".format(nom_sketch))], model.selection(), nom_par_2, nom_par_2, "Edges")
1263 nom_cylindre = "{}_cylindre".format(self.nom_solide)
1264 cylindre.setName(nom_cylindre)
1265 cylindre.result().setName(nom_cylindre)
1266 cylindre.result().setColor(85, 0, 255)
1268 # Intersection de la face cylindrique avec le solide initial
1269 face = self._creation_face_inter ( nom_cylindre )
1273 #=========================== Fin de la méthode ==================================
1275 #=========================== Début de la méthode =================================
1277 def _cree_face_mediane_sphere ( self, caract_face_1, caract_face_2 ):
1278 """Crée la face médiane entre deux autres - cas des sphères
1281 :caract_face_1, caract_face_2: les caractéristiques des 2 faces les plus grandes
1284 :face: la face médiane
1287 nom_fonction = __name__ + "/_cree_face_mediane_sphere"
1288 blabla = "\nDans {} :\n".format(nom_fonction)
1291 if self._verbose_max:
1293 texte += "face_1 : {}\n".format(caract_face_1)
1294 texte += "face_2 : {}".format(caract_face_2)
1297 # Caractéristiques des sphères
1298 coo_x, coo_y, coo_z, rayon, epaisseur = self._cree_face_mediane_sphere_0 ( caract_face_1, caract_face_2 )
1300 # Contrôle de la validité de l'épaisseur
1301 erreur = self._verif_epaisseur ( epaisseur )
1303 # Création de la face
1305 face = self._cree_face_mediane_sphere_1 ( coo_x, coo_y, coo_z, rayon )
1311 #=========================== Fin de la méthode ==================================
1313 #=========================== Début de la méthode =================================
1315 def _cree_face_mediane_sphere_0 ( self, caract_face_1, caract_face_2 ):
1316 """Crée la face médiane entre deux autres - cas des sphères
1318 Décodage des caractéristiques
1321 :caract_face_1, caract_face_2: les caractéristiques des 2 faces les plus grandes
1324 :coo_x, coo_y, coo_z: coordonnées du centre de la sphère
1325 :rayon: rayon moyen entre les deux faces
1326 :epaisseur: épaisseur de l'interface entre les deux faces
1329 nom_fonction = __name__ + "/_cree_face_mediane_sphere_0"
1330 blabla = "\nDans {} :\n".format(nom_fonction)
1333 if self._verbose_max:
1335 texte += "face_1 : {}\n".format(caract_face_1)
1336 texte += "face_2 : {}".format(caract_face_2)
1339 # Coordonnées du centre de la sphère
1340 coo_x = caract_face_1[2][1]
1341 coo_y = caract_face_1[2][2]
1342 coo_z = caract_face_1[2][3]
1344 rayon = (caract_face_2[2][4]+caract_face_1[2][4])/2.
1346 epaisseur = np.abs(caract_face_2[2][4]-caract_face_1[2][4])
1348 return coo_x, coo_y, coo_z, rayon, epaisseur
1350 #=========================== Fin de la méthode ==================================
1352 #=========================== Début de la méthode =================================
1354 def _cree_face_mediane_sphere_1 ( self, coo_x, coo_y, coo_z, rayon ):
1355 """Crée la face médiane entre deux autres - cas des sphères
1357 Création des objets temporaires et de la face externe de la sphère support
1360 :coo_x, coo_y, coo_z: coordonnées du centre de la sphère
1361 :rayon: rayon moyen entre les deux faces
1364 :face: la face externe de la sphère support
1367 nom_fonction = __name__ + "/_cree_face_mediane_sphere_1"
1368 blabla = "\nDans {} :\n".format(nom_fonction)
1370 # Les caractéristiques de la sphère à créer
1371 if self._verbose_max:
1373 texte += "Centre : ({}, {}, {})\n".format(coo_x, coo_y, coo_z)
1374 texte += "Rayon : {}".format(rayon)
1377 # Création du point central
1378 centre = model.addPoint(self.part_doc, coo_x, coo_y, coo_z)
1379 nom_centre = "{}_centre".format(self.nom_solide)
1380 centre.result().setName(nom_centre)
1382 # Création d'un plan passant par ce centre et cet axe
1383 plan = model.addPlane(self.part_doc, model.selection("EDGE", "PartSet/OX"), model.selection("VERTEX", nom_centre), False)
1384 nom_plan = "{}_plan".format(self.nom_solide)
1385 plan.result().setName(nom_plan)
1387 # Création d'un sketch
1388 nom_par_1 = "{}_R".format(self.nom_solide)
1389 model.addParameter(self.part_doc, "{}".format(nom_par_1), "{}".format(rayon))
1391 sketch = model.addSketch(self.part_doc, model.selection("FACE", nom_plan))
1393 SketchProjection_1 = sketch.addProjection(model.selection("VERTEX", nom_centre), False)
1394 SketchPoint_1 = SketchProjection_1.createdFeature()
1396 ### Create SketchArc
1397 SketchArc_1 = sketch.addArc(coo_x, coo_y, coo_x-rayon, coo_y, coo_x+rayon, coo_y, False)
1398 sketch.setRadius(SketchArc_1.results()[1], nom_par_1)
1399 sketch.setCoincident(SketchPoint_1.result(), SketchArc_1.center())
1401 ### Create SketchLine
1402 SketchLine_1 = sketch.addLine(coo_x-rayon, coo_y, coo_x+rayon, coo_y)
1403 nom_ligne = "{}_ligne".format(self.nom_solide)
1404 SketchLine_1.setName(nom_ligne)
1405 SketchLine_1.result().setName(nom_ligne)
1406 SketchLine_1.setAuxiliary(True)
1407 sketch.setHorizontal(SketchLine_1.result())
1408 sketch.setCoincident(SketchArc_1.startPoint(), SketchLine_1.startPoint())
1409 sketch.setCoincident(SketchArc_1.endPoint(), SketchLine_1.endPoint())
1410 sketch.setCoincident(SketchAPI_Point(SketchPoint_1).coordinates(), SketchLine_1.result())
1413 nom_sketch = "{}_esquisse".format(self.nom_solide)
1414 sketch.setName(nom_sketch)
1415 sketch.result().setName(nom_sketch)
1417 # Création de la sphère complète
1418 sphere = model.addRevolution(self.part_doc, [model.selection("COMPOUND", nom_sketch)], model.selection("EDGE", "{}/{}".format(nom_sketch,nom_ligne)), 360, 0, "Edges")
1419 nom_sphere = "{}_sphere".format(self.nom_solide)
1420 sphere.setName(nom_sphere)
1421 sphere.result().setName(nom_sphere)
1422 sphere.result().setColor(85, 0, 255)
1424 # Intersection de la face sphérique avec le solide initial
1425 face = self._creation_face_inter ( nom_sphere )
1429 #=========================== Fin de la méthode ==================================
1431 #=========================== Début de la méthode =================================
1433 def _cree_face_mediane_tore ( self, caract_face_1, caract_face_2 ):
1434 """Crée la face médiane entre deux autres - cas des tores
1437 :caract_face_1, caract_face_2: les caractéristiques des 2 faces les plus grandes
1440 :face: la face médiane
1443 nom_fonction = __name__ + "/_cree_face_mediane_tore"
1444 blabla = "\nDans {} :\n".format(nom_fonction)
1447 if self._verbose_max:
1449 texte += "face_1 : {}\n".format(caract_face_1)
1450 texte += "face_2 : {}".format(caract_face_2)
1453 # Caractéristiques des tores
1454 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 )
1456 # Contrôle de la validité de l'épaisseur (bidon)
1457 erreur = self._verif_epaisseur ( EP_MIN*10. )
1459 # Création de la face
1461 face = self._cree_face_mediane_tore_1 ( coo_x, coo_y, coo_z, axe_x, axe_y, axe_z, rayon_1, rayon_2 )
1467 #=========================== Fin de la méthode ==================================
1469 #=========================== Début de la méthode =================================
1471 def _cree_face_mediane_tore_0 ( self, caract_face_1, caract_face_2 ):
1472 """Crée la face médiane entre deux autres - cas des tores
1474 Décodage des caractéristiques
1477 :caract_face_1, caract_face_2: les caractéristiques des 2 faces les plus grandes
1480 :coo_x, coo_y, coo_z: coordonnées du centre du tore
1481 :axe_x, axe_y, axe_z: coordonnées de l'axe
1482 :rayon_1 : rayon principal
1483 :rayon_2 : rayon secondaire
1486 nom_fonction = __name__ + "/_cree_face_mediane_tore_0"
1487 blabla = "\nDans {} :\n".format(nom_fonction)
1490 if self._verbose_max:
1492 texte += "face_1 : {}\n".format(caract_face_1)
1493 texte += "face_2 : {}".format(caract_face_2)
1496 # Coordonnées du centre du tore
1497 coo_x = caract_face_1[2][1]
1498 coo_y = caract_face_1[2][2]
1499 coo_z = caract_face_1[2][3]
1500 # Coordonnées de l'axe
1501 axe_x = caract_face_1[2][4]
1502 axe_y = caract_face_1[2][5]
1503 axe_z = caract_face_1[2][6]
1505 rayon_1 = caract_face_2[2][7]
1506 rayon_2 = (caract_face_2[2][8]+caract_face_1[2][8])/2.
1508 return coo_x, coo_y, coo_z, axe_x, axe_y, axe_z, rayon_1, rayon_2
1510 #=========================== Fin de la méthode ==================================
1512 #=========================== Début de la méthode =================================
1514 def _cree_face_mediane_tore_1 ( self, coo_x, coo_y, coo_z, axe_x, axe_y, axe_z, rayon_1, rayon_2 ):
1515 """Crée la face médiane entre deux autres - cas des tores
1517 Création des objets temporaires et de la face externe du tore support
1520 :coo_x, coo_y, coo_z: coordonnées du centre du tore
1521 :axe_x, axe_y, axe_z: coordonnées de l'axe
1522 :rayon_1 : rayon principal
1523 :rayon_2 : rayon secondaire
1526 :face: la face externe du tore support
1529 nom_fonction = __name__ + "/_cree_face_mediane_tore_1"
1530 blabla = "\nDans {} :\n".format(nom_fonction)
1533 if self._verbose_max:
1535 texte += "Centre : ({}, {}, {})\n".format(coo_x, coo_y, coo_z)
1536 texte += "Axe : ({}, {}, {})\n".format(axe_x, axe_y, axe_z)
1537 texte += "Rayon principal : {}\n".format(rayon_1)
1538 texte += "Rayon secondaire : {}".format(rayon_2)
1541 # Création du point central
1542 centre = model.addPoint(self.part_doc, coo_x, coo_y, coo_z)
1543 nom_centre = "{}_centre".format(self.nom_solide)
1544 centre.result().setName(nom_centre)
1547 axe = model.addAxis(self.part_doc, axe_x, axe_y, axe_z)
1548 nom_axe = "{}_axe".format(self.nom_solide)
1549 axe.result().setName(nom_axe)
1551 # Création d'un plan passant par ce centre et cet axe
1552 plan = model.addPlane(self.part_doc, model.selection("EDGE", nom_axe), model.selection("VERTEX", nom_centre), False)
1553 nom_plan = "{}_plan".format(self.nom_solide)
1554 plan.result().setName(nom_plan)
1556 # Création d'un sketch
1557 nom_par_1 = "{}_R_1".format(self.nom_solide)
1558 model.addParameter(self.part_doc, "{}".format(nom_par_1), "{}".format(rayon_1))
1559 nom_par_2 = "{}_R_2".format(self.nom_solide)
1560 model.addParameter(self.part_doc, "{}".format(nom_par_2), "{}".format(rayon_2))
1562 sketch = model.addSketch(self.part_doc, model.selection("FACE", nom_plan))
1564 SketchProjection_1 = sketch.addProjection(model.selection("VERTEX", nom_centre), False)
1565 SketchPoint_1 = SketchProjection_1.createdFeature()
1567 SketchProjection_2 = sketch.addProjection(model.selection("EDGE", nom_axe), False)
1568 SketchLine_1 = SketchProjection_2.createdFeature()
1570 SketchPoint_2 = sketch.addPoint(rayon_1, 0.)
1571 sketch.setDistance(SketchPoint_1.result(), SketchPoint_2.coordinates(), nom_par_1, True)
1573 SketchLine_2 = sketch.addLine(0., 0., rayon_1, 0.)
1574 SketchLine_2.setAuxiliary(True)
1575 sketch.setCoincident(SketchAPI_Point(SketchPoint_1).coordinates(), SketchLine_2.startPoint())
1576 sketch.setCoincident(SketchPoint_2.coordinates(), SketchLine_2.endPoint())
1577 sketch.setPerpendicular(SketchLine_1.result(), SketchLine_2.result())
1579 SketchCircle_1 = sketch.addCircle(0., 0., rayon_2)
1580 sketch.setCoincident(SketchPoint_2.result(), SketchCircle_1.center())
1581 sketch.setRadius(SketchCircle_1.results()[1], nom_par_2)
1584 nom_sketch = "{}_esquisse".format(self.nom_solide)
1585 sketch.setName(nom_sketch)
1586 sketch.result().setName(nom_sketch)
1588 # Création du tore complet
1589 nom_tore = "{}_tore".format(self.nom_solide)
1590 self._cree_revolution ( nom_sketch, nom_centre, coo_x, coo_y, coo_z, axe_x, axe_y, axe_z, nom_tore )
1592 # Intersection de la face torique avec le solide initial
1593 face = self._creation_face_inter ( nom_tore )
1597 #=========================== Fin de la méthode ==================================
1599 #=========================== Début de la méthode =================================
1601 def _cree_face_mediane_cone ( self, geompy, caract_face_1, caract_face_2 ):
1602 """Crée la face médiane entre deux autres - cas des cones
1605 :geompy: environnement de GEOM
1606 :caract_face_1, caract_face_2: les caractéristiques des 2 faces les plus grandes
1609 :face: la face médiane
1612 nom_fonction = __name__ + "/_cree_face_mediane_cone"
1613 blabla = "\nDans {} :\n".format(nom_fonction)
1616 if self._verbose_max:
1618 texte += "face_1 : {}\n".format(caract_face_1)
1619 texte += "face_2 : {}".format(caract_face_2)
1622 # Caractéristiques des cones
1623 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 )
1625 # Contrôle de la validité de l'épaisseur (bidon)
1626 erreur = self._verif_epaisseur ( EP_MIN*10. )
1628 # Création de la face
1630 face = self._cree_face_mediane_cone_1 ( coo_x, coo_y, coo_z, axe_x, axe_y, axe_z, rayon_1, rayon_2, hauteur )
1636 #=========================== Fin de la méthode ==================================
1638 #=========================== Début de la méthode =================================
1640 def _cree_face_mediane_cone_0 ( self, geompy, caract_face_1, caract_face_2 ):
1641 """Crée la face médiane entre deux autres - cas des cones
1643 Décodage des caractéristiques
1646 :geompy: environnement de GEOM
1647 :caract_face_1, caract_face_2: les caractéristiques des 2 faces les plus grandes
1650 :coo_x, coo_y, coo_z: coordonnées du centre de la base
1651 :axe_x, axe_y, axe_z: coordonnées de l'axe
1652 :rayon_1, rayon_2: rayons moyens du côté de la base et à l'opposé
1653 :hauteur: hauteur du cone
1656 nom_fonction = __name__ + "/_cree_face_mediane_cone_0"
1657 blabla = "\nDans {} :\n".format(nom_fonction)
1660 if self._verbose_max:
1662 texte += "face_1 : {}\n".format(caract_face_1)
1663 texte += "face_2 : {}".format(caract_face_2)
1666 # Coordonnées du centre de la base
1667 coo_x = caract_face_1[2][1]
1668 coo_y = caract_face_1[2][2]
1669 coo_z = caract_face_1[2][3]
1670 # Coordonnées de l'axe
1671 axe_x = caract_face_1[2][4]
1672 axe_y = caract_face_1[2][5]
1673 axe_z = caract_face_1[2][6]
1675 # Pour un cone complet, les caractéristiques fournies par GEOM sont correctes
1676 # Mais s'il est découpé, malheureusement,bug dans GEOM et caract_face_2[2][8] est toujours nul !
1677 # Alors on passe par le décodage des arêtes
1678 #rayon_1 = (caract_face_2[2][7]+caract_face_1[2][7])/2.
1679 #rayon_2 = (caract_face_2[2][8]+caract_face_1[2][8])/2.
1680 caract_arete_face_1 = self._calcul_caract_aretes_face ( geompy, caract_face_1 )
1681 caract_arete_face_2 = self._calcul_caract_aretes_face ( geompy, caract_face_2 )
1684 for caract_aretes_face in [caract_arete_face_1,caract_arete_face_2]:
1686 for l_aux in caract_aretes_face:
1687 if ( l_aux[0] in ( geompy.kind.CIRCLE, geompy.kind.ARC_CIRCLE ) ):
1688 #print ("R =",l_aux[7])
1697 hauteur = caract_face_1[2][9]
1699 return coo_x, coo_y, coo_z, axe_x, axe_y, axe_z, rayon_1, rayon_2, hauteur
1701 #=========================== Fin de la méthode ==================================
1703 #=========================== Début de la méthode =================================
1705 def _cree_face_mediane_cone_1 ( self, coo_x, coo_y, coo_z, axe_x, axe_y, axe_z, rayon_1, rayon_2, hauteur ):
1706 """Crée la face médiane entre deux autres - cas des cones
1708 Création des objets temporaires et de la face externe du cone support
1711 :coo_x, coo_y, coo_z: coordonnées du centre de la base
1712 :axe_x, axe_y, axe_z: coordonnées de l'axe
1713 :rayon_1, rayon_2: rayons moyens du côté de la base et à l'opposé
1714 :hauteur: hauteur du cone
1717 :face: la face externe du cone support
1719 nom_fonction = __name__ + "/_cree_face_mediane_cone_1"
1720 blabla = "\nDans {} :\n".format(nom_fonction)
1723 if self._verbose_max:
1725 texte += "Centre : ({}, {}, {})\n".format(coo_x, coo_y, coo_z)
1726 texte += "Axe : ({}, {}, {})\n".format(axe_x, axe_y, axe_z)
1727 texte += "Rayons : {}, {}\n".format(rayon_1, rayon_2)
1728 texte += "Hauteur : {}".format(hauteur)
1731 # Création du point central
1732 centre = model.addPoint(self.part_doc, coo_x, coo_y, coo_z)
1733 nom_centre = "{}_centre".format(self.nom_solide)
1734 centre.result().setName(nom_centre)
1737 axe = model.addAxis(self.part_doc, axe_x, axe_y, axe_z)
1738 nom_axe = "{}_axe".format(self.nom_solide)
1739 axe.result().setName(nom_axe)
1741 # Création d'un plan passant par ce centre et cet axe
1742 plan = model.addPlane(self.part_doc, model.selection("EDGE", nom_axe), model.selection("VERTEX", nom_centre), False)
1743 nom_plan = "{}_plan".format(self.nom_solide)
1744 plan.result().setName(nom_plan)
1746 # Création d'un sketch
1747 nom_par_1 = "{}_R_1".format(self.nom_solide)
1748 model.addParameter(self.part_doc, "{}".format(nom_par_1), "{}".format(rayon_1))
1749 nom_par_2 = "{}_R_2".format(self.nom_solide)
1750 model.addParameter(self.part_doc, "{}".format(nom_par_2), "{}".format(rayon_2))
1751 nom_par_3 = "{}_H".format(self.nom_solide)
1752 model.addParameter(self.part_doc, "{}".format(nom_par_3), "{}".format(hauteur))
1754 sketch = model.addSketch(self.part_doc, model.selection("FACE", nom_plan))
1756 SketchProjection_1 = sketch.addProjection(model.selection("VERTEX", nom_centre), False)
1757 SketchPoint_1 = SketchProjection_1.createdFeature()
1759 SketchProjection_2 = sketch.addProjection(model.selection("EDGE", nom_axe), False)
1760 SketchLine_1 = SketchProjection_2.createdFeature()
1762 SketchLine_2 = sketch.addLine(coo_x, coo_y, coo_x+rayon_1, coo_y+hauteur)
1763 SketchLine_2.setAuxiliary(True)
1764 sketch.setCoincident(SketchAPI_Point(SketchPoint_1).coordinates(), SketchLine_2.startPoint())
1765 sketch.setParallel(SketchLine_1.result(), SketchLine_2.result())
1766 sketch.setLength(SketchLine_2.result(), nom_par_3)
1768 SketchLine_3 = sketch.addLine(coo_x+rayon_1, coo_y, coo_x+rayon_1, coo_y+hauteur)
1769 sketch.setDistance(SketchLine_2.startPoint(), SketchLine_3.result(), nom_par_1, True)
1770 sketch.setDistance(SketchLine_2.endPoint(), SketchLine_3.result(), nom_par_2, True)
1771 sketch.setLength(SketchLine_3.result(), "2.5*{}".format(nom_par_3))
1773 SketchPoint_2 = sketch.addPoint(coo_x, coo_y)
1774 sketch.setCoincident(SketchPoint_2.coordinates(), SketchLine_3.result())
1775 sketch.setMiddlePoint(SketchPoint_2.coordinates(), SketchLine_3.result())
1777 SketchLine_4 = sketch.addLine(coo_x, coo_y, 1.2*coo_x, 1.2*coo_y)
1778 SketchLine_4.setAuxiliary(True)
1779 sketch.setCoincident(SketchAPI_Point(SketchPoint_1).coordinates(), SketchLine_4.startPoint())
1780 sketch.setCoincident(SketchPoint_2.coordinates(), SketchLine_4.endPoint())
1781 sketch.setHorizontal(SketchLine_4.result())
1784 nom_sketch = "{}_esquisse".format(self.nom_solide)
1785 sketch.setName(nom_sketch)
1786 sketch.result().setName(nom_sketch)
1788 # Création du cone complet
1789 nom_cone = "{}_cone".format(self.nom_solide)
1790 self._cree_revolution ( nom_sketch, nom_centre, coo_x, coo_y, coo_z, axe_x, axe_y, axe_z, nom_cone )
1792 # Intersection de la face conique avec le solide initial
1793 face = self._creation_face_inter ( nom_cone )
1797 #=========================== Fin de la méthode ==================================
1799 #=========================== Début de la méthode =================================
1801 def _calcul_boite_englobante ( self, objet ):
1802 """Crée la hauteur englobant à coup sûr l'objet
1805 :objet: l'objet à traiter
1808 :l_diag: longueur de la diagonale de la boîte englobante
1811 nom_fonction = __name__ + "/_calcul_boite_englobante"
1812 blabla = "\nDans {} :\n".format(nom_fonction)
1814 if self._verbose_max:
1818 # Hauteur : la diagonale de la boîte englobante permet d'être certain de tout prendre
1819 if self._verbose_max:
1820 texte = "Création de la boite englobante pour l'objet '{}' ".format(objet.name())
1821 texte += "de type '{}'".format(objet.shapeType())
1823 bbox = model.getBoundingBox(self.part_doc, model.selection("{}".format(objet.shapeType()), "{}".format(objet.name())))
1825 bbox_nom = bbox.name()
1826 if self._verbose_max:
1827 print ("Boîte englobante : '{}' '{}'".format(bbox.name(), bbox.result().name()))
1829 if self._verbose_max:
1830 coo_min = model.getPointCoordinates(self.part_doc, \
1831 model.selection("VERTEX", "[{}_1/Back][{}_1/Left][{}_1/Bottom]".format(bbox_nom,bbox_nom,bbox_nom)))
1832 coo_max = model.getPointCoordinates(self.part_doc, \
1833 model.selection("VERTEX", "[{}_1/Front][{}_1/Right][{}_1/Top]".format(bbox_nom,bbox_nom,bbox_nom)))
1834 texte = "\tXmin = {}, Xmax = {}\n".format(coo_min[0],coo_max[0])
1835 texte += "\tYmin = {}, Ymax = {}\n".format(coo_min[1],coo_max[1])
1836 texte += "\tZmin = {}, Zmax = {}".format(coo_min[2],coo_max[2])
1839 l_diag = model.measureDistance(self.part_doc, \
1840 model.selection("VERTEX", "[{}_1/Back][{}_1/Left][{}_1/Bottom]".format(bbox_nom,bbox_nom,bbox_nom)), \
1841 model.selection("VERTEX", "[{}_1/Front][{}_1/Right][{}_1/Top]".format(bbox_nom,bbox_nom,bbox_nom)) )
1842 if self._verbose_max:
1843 print ("Longueur de la diagonale : {}".format(l_diag))
1847 #=========================== Fin de la méthode ==================================
1849 #=========================== Début de la méthode =================================
1851 def _cree_revolution ( self, nom_sketch, nom_centre, coo_x, coo_y, coo_z, axe_x, axe_y, axe_z, nom_objet ):
1852 """Crée un volume de révolution
1855 :nom_sketch: nom du sketch à révolutionner
1856 :nom_centre: nom du point associé au centre du volume de révolution
1857 :coo_x, coo_y, coo_z: coordonnées du centre du tore
1858 :axe_x, axe_y, axe_z: coordonnées de l'axe
1859 :rayon_1 : rayon principal
1860 :rayon_2 : rayon secondaire
1861 :nom_objet: nom de l'objet 2D créé
1864 nom_fonction = __name__ + "/_cree_revolution"
1865 blabla = "\nDans {} :\n".format(nom_fonction)
1867 if self._verbose_max:
1869 texte += "Centre : ({}, {}, {})\n".format(coo_x, coo_y, coo_z)
1870 texte += "Axe : ({}, {}, {})\n".format(axe_x, axe_y, axe_z)
1873 # Création d'un point décalé par rapport au point central
1874 point = model.addPoint(self.part_doc, coo_x+axe_x, coo_y+axe_y, coo_z+axe_z)
1875 nom_point = "{}_point".format(self.nom_solide)
1876 point.result().setName(nom_point)
1878 # Création de l'axe de la rotation
1879 axe_r = model.addAxis(self.part_doc, model.selection("VERTEX", nom_centre), model.selection("VERTEX", nom_point))
1880 nom_axe_r = "{}_axe_r".format(self.nom_solide)
1881 axe_r.result().setName(nom_axe_r)
1883 # Création de l'objet complet
1884 objet = model.addRevolution(self.part_doc, [model.selection("COMPOUND", nom_sketch)], model.selection("EDGE", nom_axe_r), 360, 0, "Edges")
1885 objet.setName(nom_objet)
1886 objet.result().setName(nom_objet)
1887 objet.result().setColor(85, 0, 255)
1891 #=========================== Fin de la méthode ==================================
1893 #=========================== Début de la méthode =================================
1895 def _creation_face_inter ( self, nom_objet ):
1896 """Crée la face par intersection entre l'objet initial et une face complète
1898 . Repère la face principale de l'objet support
1899 . Réalise l'intersection avec le solide initial
1902 :nom_objet: nom de l'objet 2D créé
1905 :face: la face externe de l'objet support intersecté avec le solide initial
1908 nom_fonction = __name__ + "/_creation_face_inter"
1909 blabla = "\nDans {} :\n".format(nom_fonction)
1911 if self._verbose_max:
1914 face = model.addCommon(self.part_doc, [model.selection("SOLID", self.nom_solide_aux), model.selection("FACE", nom_objet)], keepSubResults = True)
1918 #=========================== Fin de la méthode ==================================
1920 #=========================== Début de la méthode =================================
1922 def face_mediane_solide (self, solide, geompy, objet_geom):
1923 """Calcul de la face médiane pour un solide
1926 :solide: solide SHAPER à traiter
1927 :geompy: environnement de GEOM
1928 :objet_geom: l'objet solide au format GEOM à traiter
1931 :erreur: code d'erreur
1932 :message: message d'erreur
1935 nom_fonction = __name__ + "/face_mediane_solide"
1936 blabla = "\nDans {} :\n".format(nom_fonction)
1938 if self._verbose_max:
1941 print ("Traitement du solide '{}'".format(solide.name()))
1950 # 2. Explosion du solide en faces
1952 erreur, message, l_faces = self._faces_du_solide ( geompy, objet_geom )
1956 # 3. Calcul des caractéristiques géométriques des faces
1958 tb_caract = self._calcul_caract_faces ( geompy, l_faces )
1960 # 4. Tri des faces en fonction de leurs caractéristiques géométriques
1962 erreur, message, caract_face_1, caract_face_2 = self._tri_faces ( tb_caract )
1966 # 5. Création de la face médiane
1968 erreur, face = self._cree_face_mediane ( solide, geompy, caract_face_1, caract_face_2 )
1972 # 6. Exportation step
1974 if self._export_step:
1975 fichier = os.path.join(self.rep_step, "{}.stp".format(face.result().name()))
1976 export = model.exportToFile(self.part_doc, fichier, [model.selection(face.result().shapeType(), face.result().name())])
1977 export.execute(True)
1984 if ( erreur and self._verbose_max ):
1985 print (blabla, message)
1987 return erreur, message
1989 #=========================== Fin de la méthode ==================================
1991 #=========================== Début de la méthode =================================
1993 def _traitement_objet (self, solide=None, objet_geom=None):
1994 """Traitement d'un objet
1997 :solide: solide SHAPER à traiter
1998 :objet_geom: l'objet GEOM équivalent
2001 :erreur: code d'erreur
2002 :message: message d'erreur
2005 nom_fonction = __name__ + "/_traitement_objet"
2006 blabla = "\nDans {} :\n".format(nom_fonction)
2008 if self._verbose_max:
2020 if self.affiche_aide_globale :
2023 # 3. Les imports pour salomé
2024 geompy = geomBuilder.New()
2026 # 4. En cas d'exportation step, répertoire de travail associé à l'éventuel fichier de départ
2027 # Attention à ne pas recréer le répertoire à chaque fois
2028 if self._export_step:
2030 if self._verbose_max:
2031 print ("Préparation de l'export STEP")
2033 if self.rep_step is None:
2034 if self.ficcao is None:
2035 self.rep_step = tempfile.mkdtemp(prefix="{}_".format(self.objet_principal.name()))
2037 self.rep_step = os.path.join(os.path.dirname(self.ficcao),"{}_M".format(self.objet_principal.name()))
2038 if os.path.isdir(self.rep_step):
2039 l_aux = os.listdir(self.rep_step)
2040 for nomfic in l_aux:
2041 os.remove(os.path.join(self.rep_step,nomfic))
2043 os.mkdir(self.rep_step)
2044 if self._verbose_max:
2045 print ("Les fichiers CAO des surfaces seront dans le répertoire {}".format(self.rep_step))
2047 # 5. Calcul réel de la face médiane
2050 self.nom_solide = objet_geom.GetName()
2052 erreur, message = self.face_mediane_solide (solide, geompy, objet_geom)
2058 return erreur, message
2060 #=========================== Fin de la méthode ==================================
2062 #=========================== Début de la méthode =================================
2064 def surf_fic_cao (self, ficcao, nom_objet=None):
2065 """Calcule la surface médiane pour un objet dans un fichier passé en argument
2068 :ficcao: fichier de l'objet à traiter
2069 :nom_objet: un nom à donner à l'objet à traiter
2072 :erreur: code d'erreur
2073 :message: message d'erreur
2076 nom_fonction = __name__ + "/surf_fic_cao"
2077 blabla = "\nDans {} :\n".format(nom_fonction)
2079 if self._verbose_max:
2089 # 1. Définition de la pièce
2091 self.part_doc = model.activeDocument()
2093 # 2. Import de la CAO
2095 self.ficcao = ficcao
2096 print ("Traitement du fichier {}".format(ficcao))
2098 erreur, message, objet = import_cao (self.part_doc, ficcao, nom_objet, self._verbose_max)
2102 # 3. Calcul des surfaces
2104 erreur, message = self.surf_objet_shaper ( objet )
2113 if ( erreur and self._verbose_max ):
2114 print (blabla, message)
2116 return erreur, message
2118 #=========================== Fin de la méthode ==================================
2120 #=========================== Début de la méthode =================================
2122 def surf_objet_shaper (self, objet):
2123 """Calcule les surfaces médianes pour un objet SHAPER passé en argument
2126 :objet: objet à traiter
2129 :erreur: code d'erreur
2130 :message: message d'erreur
2133 nom_fonction = __name__ + "/surf_objet_shaper"
2134 blabla = "Dans {} :\n".format(nom_fonction)
2136 if self._verbose_max:
2139 # 1. Acquisition de la liste des noms des sous-objets solides
2141 self.d_statut_so = dict()
2142 self.l_noms_so = list()
2143 self.l_faces_m = list()
2145 _ = self._nom_sous_objets (objet, True)
2146 if self._verbose_max:
2147 print ("Noms des sous-objets : {}".format(self.l_noms_so))
2149 # 2. Les faces médianes
2151 erreur, message = self._surf_objet_shaper_0 ( objet )
2153 # 3. Gestion des faces créées
2155 self._surf_objet_shaper_1 ( )
2157 # 4. Futur message pour le résultat
2159 if ( self._export_step and not erreur ):
2160 message = "Les fichiers des CAO des surfaces sont dans le répertoire {}".format(self.rep_step)
2162 return erreur, message
2164 #=========================== Fin de la méthode ==================================
2166 #=========================== Début de la méthode =================================
2168 def _surf_objet_shaper_0 (self, objet, n_recur=0):
2169 """Calcule les surfaces médianes pour un objet SHAPER passé en argument
2172 :objet: objet à traiter
2173 :n_recur: niveau de récursivité
2176 :erreur: code d'erreur
2177 :message: message d'erreur
2180 nom_fonction = __name__ + "/_surf_objet_shaper_0"
2181 blabla = "Dans {} :\n".format(nom_fonction)
2183 if self._verbose_max:
2185 for _ in range(n_recur):
2187 texte = "\n{}{}".format(prefixe,blabla)
2188 texte += "{}n_recur = {}".format(prefixe,n_recur)
2196 # 1. Au premier passage, il faut récupérer la pièce et garder la référence au résultat principal
2198 if ( n_recur == 0 ):
2199 self.part_doc = model.activeDocument()
2200 objet_0 = objet.result()
2201 self.objet_principal = objet_0
2205 # 2. On descend dans l'arborescence des sous-objets jusqu'à en trouver un qui n'en n'a pas
2207 nb_sub_results = objet_0.numberOfSubs()
2209 if self._verbose_max:
2210 texte = "Examen de l'objet '{}' ".format(objet_0.name())
2211 texte += "de type '{}'".format(objet_0.shapeType())
2212 texte += "\nobjet.result().numberOfSubs() : {}".format(nb_sub_results)
2215 for n_sobj in range(nb_sub_results):
2217 # 2.1. Exploration récursive de l'arborescence
2219 erreur, message = self._surf_objet_shaper_0 ( objet_0.subResult(n_sobj), n_recur+1 )
2223 # 2.2. Cet objet n'a pas de sous-objets. Si c'est un solide, on le traite
2225 if ( objet_0.shapeType() == "SOLID" ):
2226 erreur, message = self.surf_solide_shaper ( objet_0 )
2233 # 3. Futur message pour le résultat
2235 if self._export_step:
2236 message = "Les fichiers STEP des surfaces sont dans le répertoire {}".format(self.rep_step)
2240 return erreur, message
2242 #=========================== Fin de la méthode ==================================
2244 #=========================== Début de la méthode =================================
2246 def _surf_objet_shaper_1 (self):
2247 """Gestion des surfaces médianes créées
2250 :erreur: code d'erreur
2251 :message: message d'erreur
2254 nom_fonction = __name__ + "/_surf_objet_shaper_1"
2255 blabla = "Dans {} :\n".format(nom_fonction)
2257 if self._verbose_max:
2260 # 1. Informations sur les faces à problème
2262 if self.faces_pb_nb:
2263 if ( self.faces_pb_nb == 1 ):
2264 texte = "1 face pose"
2266 texte = "{} faces posent".format(self.faces_pb_nb)
2267 print ("\n{} problème.\n{}".format(texte,self.faces_pb_msg))
2269 # 2. Si plus d'une face a été créée
2270 if ( len(self.l_faces_m) > 1 ):
2272 # 2.1. Partition du paquet de faces
2274 if self._verbose_max:
2275 print ("Partitionnnement des faces créées.")
2278 for (face,_) in self.l_faces_m:
2279 l_objets.append(model.selection("COMPOUND", "all-in-{}".format(face.name())))
2281 Partition_1 = model.addPartition(self.part_doc, l_objets, keepSubResults = True)
2283 Partition_1.result().setName("{}_M".format(self.objet_principal.name()))
2284 for iaux, (face,_) in enumerate(self.l_faces_m):
2285 Partition_1.result().subResult(iaux).setName("{}".format(face.name()))
2286 self._couleur_objet (Partition_1, coul_r=0, coul_g=170, coul_b=0)
2288 # 2.2. Récupération des faces individuelles
2290 if self._verbose_max:
2291 print ("Récupération des faces individuelles.")
2294 for iaux, (face,_) in enumerate(self.l_faces_m):
2295 l_objets.append(face.result())
2297 Recover_1 = model.addRecover(self.part_doc, Partition_1, l_objets)
2298 for iaux, (face,_) in enumerate(self.l_faces_m):
2299 Recover_1.results()[iaux].setName("{}".format(face.name()))
2300 Recover_1.results()[iaux].setColor(0, 170, 0)
2302 # 2.3. Mise en dossier
2304 if self._verbose_max:
2305 print ("Mise en dossier.")
2307 for (face,fonction_0) in self.l_faces_m:
2308 dossier = model.addFolder(self.part_doc, fonction_0, face)
2309 dossier.setName(face.name()[:-2])
2313 #=========================== Fin de la méthode ==================================
2315 #=========================== Début de la méthode =================================
2317 def surf_solide_shaper (self, solide):
2318 """Calcule les surfaces médianes pour un solide SHAPER solide passé en argument
2321 :solide: solide SHAPER à traiter
2324 :erreur: code d'erreur
2325 :message: message d'erreur
2328 nom_fonction = __name__ + "/surf_solide_shaper"
2329 blabla = "Dans {} :".format(nom_fonction)
2331 if self._verbose_max:
2339 self.nom_solide = solide.name()
2340 if self._verbose_max:
2341 print ("solide '{}'".format(self.nom_solide))
2343 # 1. Isolement du solide
2344 solide_aux, recover = self._isole_solide ( solide )
2346 # 2. Exportation dans un fichier step pour traitement dans GEOM
2348 fichier = tempfile.mkstemp(suffix=".stp")[1]
2349 if self._verbose_max:
2350 print ("fichier = {}".format(fichier))
2351 print ("solide = {}".format(solide_aux.name()))
2352 print ("de type = {}".format(solide_aux.shapeType()))
2353 export = model.exportToFile(self.part_doc, fichier, [model.selection(solide_aux.shapeType(), solide_aux.name())])
2354 export.execute(True)
2357 taille = os.path.getsize(fichier)
2359 message = "Export de SHAPER vers GEOM impossible pour le solide '{}' de type '{}'\n".format(solide_aux.name(), solide_aux.shapeType())
2360 message += "Le fichier {} est de taille {}".format(fichier,taille)
2364 # 3. Importation dans GEOM
2365 geompy = geomBuilder.New()
2366 objet_geom = geompy.ImportSTEP(fichier, False, True)
2369 # 4. Traitement de l'objet correspondant
2370 erreur, message = self._traitement_objet ( solide=solide_aux, objet_geom=objet_geom )
2372 if ( erreur and self._verbose_max ):
2373 print (blabla, message)
2375 # 5. Mise en forme de l'objet principal récupéré
2376 if ( recover is not None ):
2377 _ = self._nom_sous_objets (recover, False)
2379 # 6. Neutralisation des erreurs dues à l'épaisseur
2380 if ( erreur in (-2,-1,2) ):
2386 return erreur, message
2388 #=========================== Fin de la méthode ==================================
2390 #=========================== Début de la méthode =================================
2392 def surf_objet_geom (self, objet_geom):
2393 """Calcule la surface médiane pour un objet GEOM passé en argument
2396 :objet_geom: l'objet GEOM à traiter
2399 :erreur: code d'erreur
2400 :message: message d'erreur
2403 nom_fonction = __name__ + "/surf_objet_geom"
2404 blabla = "\nDans {} :\n".format(nom_fonction)
2406 if self._verbose_max:
2409 erreur, message = self._traitement_objet ( objet_geom=objet_geom )
2411 if ( erreur and self._verbose_max ):
2412 print (blabla, message)
2414 return erreur, message
2416 #=========================== Fin de la méthode ==================================
2418 #=========================== Début de la méthode =================================
2420 def lancement (self):
2425 :erreur: code d'erreur
2426 :message: message d'erreur
2429 nom_fonction = __name__ + "/lancement"
2430 blabla = "\nDans {} :\n".format(nom_fonction)
2432 if self._verbose_max:
2435 erreur, message = self._traitement_objet ( )
2437 if ( erreur and self._verbose_max ):
2438 print (blabla, message)
2440 return erreur, message
2442 #=========================== Fin de la méthode ==================================
2444 #========================== Fin de la classe ====================================
2446 #==================================================================================
2448 #==================================================================================
2450 if __name__ == "__main__" :
2455 L_OPTIONS.append("-vmax")
2456 #L_OPTIONS.append("-export_step")
2457 FIC_CAO = os.path.join(os.getenv("SHAPER_ROOT_DIR"), "bin", "salome", "macros", "midSurface", "midSurface.stp")
2458 #FIC_CAO = os.path.join(os.getenv("HOME"), "salome-dev", "DEV_package", "modules", "src", "SHAPER", "src", "PythonAddons", "macros", "midSurface", "Objet_1.stp")
2460 # 2. Lancement de la classe
2462 #print ("L_OPTIONS :", L_OPTIONS)
2464 SURFACE_MEDIANE = SurfaceMediane(L_OPTIONS)
2465 if SURFACE_MEDIANE.affiche_aide_globale:
2466 sys.stdout.write(SURFACE_MEDIANE.__doc__+"\n")
2469 PARTSET = model.moduleDocument()
2470 _ = model.addPart(PARTSET)
2471 ERREUR, MESSAGE_ERREUR = SURFACE_MEDIANE.surf_fic_cao(FIC_CAO)
2473 MESSAGE_ERREUR += "\n Code d'erreur : %d\n" % ERREUR
2474 sys.stderr.write(MESSAGE_ERREUR)