Salome HOME
a2aae3805217a571c5136ee7395a29f896757613
[modules/shaper.git] / src / PythonAddons / macros / fibreNeutre / surfaceMediane.py
1 # -*- coding: utf-8 -*-
2 # Copyright (C) 2016-2021  CEA/DEN, EDF R&D
3 #
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.
8 #
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.
13 #
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
17 #
18 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
19 #
20 """Obtention des surfaces médianes à partir d'un objet GEOM ou SHAPER
21
22 On sait traiter les faces :
23   . planes
24   . cylindriques
25   . sphériques
26   . toriques
27   . coniques
28
29 Version initiale par :
30 alexandre.prunie@blastsolutions.io
31 guillaume.schweitzer@blastsolutions.io
32
33 Gérald NICOLAS
34 +33.1.78.19.43.52
35 """
36
37 __revision__ = "V10.09"
38
39 #========================= Les imports - Début ===================================
40
41 import os
42 import sys
43 import tempfile
44
45 import salome
46 import SALOMEDS
47 from salome.shaper import model
48 from salome.geom import geomBuilder
49 from salome.geom import geomtools
50 from salome.kernel.studyedit import getStudyEditor
51
52 import numpy as np
53
54 #========================== Les imports - Fin ====================================
55
56 D_FMT = dict()
57 D_FMT["stp"] = ["stp", "step"]
58 D_FMT["igs"] = ["igs", "iges"]
59 for CLE in ("brep", "xao"):
60   D_FMT[CLE] = [CLE]
61
62 #========================= Début de la fonction ==================================
63
64 def decode_cao (fmt_cao):
65   """Décode le format de la cao
66
67 Entrées :
68   :fmt_cao: format du fichier, step, iges, etc.
69 Sorties :
70   :fmt_cao_0: format décodé
71   """
72
73   fmt_cao_0 = ""
74
75   fmt_cao_low = fmt_cao.lower()
76
77   for cle, l_aux in D_FMT.items():
78     if ( fmt_cao_low in l_aux ):
79       fmt_cao_0 = cle
80       break
81
82   return fmt_cao_0
83
84 #=========================  Fin de la fonction ===================================
85
86 #========================= Début de la fonction ==================================
87
88 def import_cao (part_doc, ficcao, verbose=False):
89   """Importation d'une cao
90
91 Entrées :
92   :part_doc: part
93   :ficcao: le fichier de la CAO
94 Sorties :
95   :objet: l'objet importé dans SHAPER
96   """
97
98
99   erreur = 0
100   message = "Fichier '{}'\n".format(ficcao)
101   if verbose:
102     print (message)
103
104   objet = None
105
106   laux = ficcao.split(".")
107   fmt_cao_0 = decode_cao (laux[-1])
108
109   if ( fmt_cao_0 not in ("stp", "brep", "igs", "xao") ):
110     message += "Le format de CAO est inconnu"
111     erreur = 1
112
113   elif not ficcao:
114     message += "Le fichier de CAO n'a pas été décodé correctement."
115     erreur = 2
116
117   elif not os.path.isfile(ficcao):
118     message += "Le fichier de CAO est inconnu."
119     erreur = 3
120
121   else:
122
123     message = ""
124     objet = model.addImport(part_doc, ficcao)
125     objet.execute(True)
126     model.do()
127
128     if verbose:
129       texte  = "Objet   : '{}'\n".format(objet.result().name())
130       texte += "De type : '{}'".format(objet.result().shapeType())
131       print (texte)
132
133
134   return erreur, message, objet
135
136 #=========================  Fin de la fonction ===================================
137
138 #=================================== La classe ===================================
139
140 class SurfaceMediane (object):
141
142   """Calcul des surfaces médianes de solides minces
143
144 L'objectif de ce programme est de créer les surfaces médianes, encore appelées fibres neutres, pour \
145 une structure qui est un solide ou un assemblage de solides (compound).
146 Pour réaliser l'opération, deux façons de faire :
147
148 1. On sélectionne la structure dans l'arbre d'étude ou dans la fenêtre graphique de GEOM, puis on lance le script.
149
150 2. On écrit un script python dans lequel on réalise la création ou l'importation d'une CAO. \
151 On insère cette classe dans le script, puis on lance surf_fic_cao, surf_objet_shaper ou surf_objet_geom selon le point de départ.
152
153 Le programme crée les surfaces sous réserve que pour le solide envisagé, il a réussi à trouver deux faces \
154 de taille identique et supérieure aux autres faces du solide pour des polyèdres ou \
155 s'il a reconnu des formes canoniques.
156 Il crée alors une surface au milieu de ces deux grandes faces. Cette face est coloriée en vert.
157
158 Si les 2 faces les plus grandes sont planes mais que leurs tailles ne sont pas identiques, le programme \
159 crée néanmoins une face basée sur la plus grande de ces faces. Un message est émis et cette face médiane \
160 est coloriée en bleu. Le volume correspondant n'est pas détruit et est colorié en rouge.
161
162 On sait traiter les faces :
163   . planes
164   . cylindriques
165   . sphériques
166   . toriques
167   . coniques
168
169 Options obligatoires
170 ********************
171 Aucune
172
173 Options facultatives
174 ********************
175 . Suppression des solides et faces créés par l'explosion des objets. Par défaut, la suppression est faite.
176 -menage/-no_menage
177
178 . Retour dans Shaper. Par défaut, les faces restent dans GEOM.
179 -retour_shaper/-no_retour_shaper
180
181   """
182
183 # A. La base
184
185   message_info = ""
186   _verbose = 0
187   _verbose_max = 0
188   affiche_aide_globale = 0
189   _menage = True
190
191 # B. Les variables
192
193   _choix_objet = 0
194   _retour_shaper = False
195   nom_solide = None
196   epsilon = 5.e-3
197   part_doc = None
198
199   ficcao = None
200   rep_trav = None
201   objet_geom = None
202
203   l_faces_trans = list()
204
205   faces_pb_nb = 0
206   faces_pb_msg = ""
207
208 #=========================== Début de la méthode =================================
209
210   def __init__ ( self, liste_option ):
211
212     """Le constructeur de la classe SurfaceMediane
213
214 Décodage des arguments
215 On cherche ici les arguments généraux : aide, verbeux
216     """
217
218     for option in liste_option :
219
220       #print (option)
221       if isinstance(option,str):
222         saux = option.upper()
223       #print (saux)
224       if saux in ( "-H", "-HELP" ):
225         self.affiche_aide_globale = 1
226       elif saux == "-V" :
227         self._verbose = 1
228       elif saux == "-VMAX" :
229         self._verbose = 1
230         self._verbose_max = 1
231       elif saux == "-MENAGE" :
232         self._menage = True
233       elif saux == "-NO_MENAGE" :
234         self._menage = False
235       elif saux == "-RETOUR_SHAPER":
236         self._retour_shaper = True
237       elif saux == "-NO_RETOUR_SHAPER":
238         self._retour_shaper = False
239
240 #===========================  Fin de la méthode ==================================
241
242 #=========================== Début de la méthode =================================
243
244   def __del__(self):
245     """A la suppression de l'instance de classe"""
246     if self._verbose_max:
247       print ("Suppression de l'instance de la classe.")
248
249 #===========================  Fin de la méthode ==================================
250
251 #=========================== Début de la méthode =================================
252
253   def _selection_objet_graphique ( self, geompy ):
254     """Sélectionne l'objet dans la fenêtre graphique
255
256 Entrées :
257   :geompy: environnement de GEOM
258
259 Sorties :
260   :objet: objet à traiter
261     """
262
263     nom_fonction = __name__ + "/_selection_objet_graphique"
264     blabla = "\nDans {} :\n".format(nom_fonction)
265
266     erreur = 0
267     message = ""
268     objet = None
269
270     while ( not erreur ):
271
272 # 1. Contrôle du nombre d'objets sélectionnés graphiquement
273       nb_objet = salome.sg.SelectedCount()
274       if self._verbose_max:
275         print (blabla+"Nombre d'objets sélectionnés : {}.".format(nb_objet))
276
277       if ( nb_objet != 1 ):
278         message = "Nombre d'objets sélectionnés : {}.\nIl en faut un et un seul.".format(nb_objet)
279         erreur = 1
280         break
281
282 # 2. Récupération de l'ID de l'objet en cours
283       entry = salome.sg.getSelected(0)
284 #     Récupération de l'objet
285       objet = salome.myStudy.FindObjectID( entry ).GetObject()
286       if self._verbose_max:
287         print (geompy.WhatIs(objet))
288
289       break
290
291     return erreur, message, objet
292
293 #===========================  Fin de la méthode ==================================
294
295 #=========================== Début de la méthode =================================
296
297   def _les_solides ( self, geompy, objet ):
298     """Les solides de l'objet à traiter
299
300 Entrées :
301   :geompy: environnement de GEOM
302   :objet: l'objet à traiter
303
304 Sorties :
305   :l_solides: liste des solides de la sélection
306     """
307
308     nom_fonction = __name__ + "/_les_solides"
309     blabla = "\nDans {} :\n".format(nom_fonction)
310     if self._verbose_max:
311       print (blabla)
312
313     erreur = 0
314     message = ""
315     l_solides = list()
316
317     while ( not erreur ):
318
319 # 1. Nombre de solides composant l'objet à traiter
320       d_shape_info = geompy.ShapeInfo(objet)
321       n_solides = d_shape_info["SOLID"]
322       if self._verbose_max:
323         print ("Nombre de solides : {}".format(n_solides))
324
325       nom_objet = objet.GetName()
326       if self._verbose:
327         print (". Traitement de l'objet '{}'".format(nom_objet))
328
329 # 2. Liste des solides qui composent l'objet
330       if ( n_solides == 0 ):
331         message = "Aucun solide dans l'objet sélectionné."
332         erreur = 1
333         break
334       elif ( n_solides == 1 ):
335         l_solides.append(objet)
336       else:
337         l_solides = geompy.ExtractShapes(objet, geompy.ShapeType["SOLID"], True)
338         for iaux, solide in enumerate(l_solides):
339           geompy.addToStudyInFather( objet, solide, "{}_{:03d}".format(nom_objet,iaux+1) )
340         if self._verbose_max:
341           print ("l_solides : {}.".format(l_solides))
342           for iaux, solide in enumerate(l_solides):
343             print (geompy.WhatIs(solide))
344
345       break
346
347     return erreur, message, l_solides
348
349 #===========================  Fin de la méthode ==================================
350
351 #=========================== Début de la méthode =================================
352
353   def _faces_du_solide ( self, geompy, solide ):
354     """Détermine les faces d'un solide
355
356 Entrées :
357   :geompy: environnement de GEOM
358   :solide: le solide à traiter
359
360 Sorties :
361   :l_faces: liste des faces du solide
362     """
363
364     nom_fonction = __name__ + "/_faces_du_solide"
365     blabla = "\nDans {} :\n".format(nom_fonction)
366     if self._verbose_max:
367       print (blabla)
368
369     erreur = 0
370     message = ""
371     l_faces = list()
372
373     while ( not erreur ):
374
375       self.nom_solide = solide.GetName()
376       if self._verbose:
377         print (".. Traitement du solide '{}'".format(self.nom_solide))
378
379 # 1. Le solide est-il un solide unique ?
380       if self._verbose_max:
381         print (geompy.WhatIs(solide))
382         longueur, aire, volume = geompy.BasicProperties(solide)
383         if self._verbose_max:
384           print (". longueur, aire, volume : {}, {}, {}".format(longueur,aire,volume))
385 #     Contrôle du solide
386       d_shape_info = geompy.ShapeInfo(solide)
387       n_solides = d_shape_info["SOLID"]
388       if self._verbose_max:
389         print ("Nombre de solides : {}".format(n_solides))
390       if ( n_solides != 1 ):
391         message = "Nombre de solides : {}.\nIl en faut un et un seul.".format(n_solides)
392         erreur = 1
393         break
394
395 # 2. Liste des faces qui composent le solide
396       l_faces = geompy.ExtractShapes(solide, geompy.ShapeType["FACE"], True)
397       for iaux, face in enumerate(l_faces):
398         geompy.addToStudyInFather( solide, face, "Face_{}".format(iaux+1) )
399       if self._verbose_max:
400         print ("l_faces : {}".format(l_faces))
401         for iaux, face in enumerate(l_faces):
402           print (geompy.WhatIs(face))
403
404       break
405
406     return erreur, message, l_faces
407
408 #===========================  Fin de la méthode ==================================
409
410 #=========================== Début de la méthode =================================
411
412   def _calcul_caract_faces ( self, geompy, l_faces ):
413     """Calcule les caractéristiques géométriques des faces
414
415 Entrées :
416   :geompy: environnement de GEOM
417   :l_faces: liste des faces du solide
418
419 Sorties :
420   :tb_caract: tableau des caractéristiques géométriques des faces
421     """
422
423     nom_fonction = __name__ + "/_calcul_caract_faces"
424     blabla = "\nDans {} :\n".format(nom_fonction)
425
426     nb_faces = len(l_faces)
427     if self._verbose_max:
428       print (blabla+"Nombre de faces : {}.".format(nb_faces))
429
430     tb_caract = np.zeros((nb_faces,3), dtype = 'object')
431     for iaux, face in enumerate(l_faces):
432       _, aire, _ = geompy.BasicProperties(face)
433       #longueur, aire, volume = geompy.BasicProperties(face)
434       if self._verbose_max:
435         texte = "\t. Face numéro {}".format(iaux)
436         #texte += "\n\t. longueur, aire, volume : {}, {}, {}".format(longueur,aire,volume)
437         print (texte)
438
439       tb_caract [iaux][0] = face
440       tb_caract [iaux][1] = aire
441       tb_caract [iaux][2] = geompy.KindOfShape(face)
442       if self._verbose_max:
443         print ("\t. tb_caract : {} {}".format(aire,tb_caract[iaux][2]))
444
445     return tb_caract
446
447 #===========================  Fin de la méthode ==================================
448
449 #=========================== Début de la méthode =================================
450
451   def _tri_faces ( self, tb_caract ):
452     """Trie les faces en fonction de leurs surfaces
453
454 Entrées :
455   :geompy: environnement de GEOM
456
457 Sorties :
458   :tb_caract_1[-1], tb_caract_1[-2]: les caractéristiques des 2 faces les plus grandes
459     """
460
461     erreur = 0
462     message = ""
463
464     nom_fonction = __name__ + "/_tri_faces"
465     blabla = "\nDans {} :\n".format(nom_fonction)
466
467 # Tri du tableau en fonction des surfaces
468     if self._verbose_max:
469       print (blabla+"tb_caract brut : {}".format(tb_caract))
470     tb_caract_1 = sorted(tb_caract, key=lambda colonnes: colonnes[1])
471     if self._verbose_max:
472       print ("tb_caract trié : {}".format(tb_caract_1))
473
474     if self._verbose:
475       texte  = "\tSurface de la plus grande face : {}, de caractéristiques {}\n".format(tb_caract_1[-1][1],tb_caract_1[-1][2])
476       texte += "\tSurface de la face suivante    : {}, de caractéristiques {}".format(tb_caract_1[-2][1],tb_caract_1[-2][2])
477       print (texte)
478
479 # La surface suivante doit être différente, sinon ce n'est pas un solide mince
480     if ( np.abs((tb_caract_1[-1][1]-tb_caract_1[-3][1])/tb_caract_1[-1][1]) < self.epsilon ):
481       message += ". Surface de la plus grande face   : {}\n".format(tb_caract_1[-1][1])
482       message += ". Surface de la face suivante      : {}\n".format(tb_caract_1[-2][1])
483       message += ". Surface de la 3ème face suivante : {}\n".format(tb_caract_1[-3][1])
484       message += "==> L'écart est trop faible.\n"
485       message += "Impossible de créer la face médiane pour le solide '{}' ".format(self.nom_solide)
486       message += "car le solide n'est pas assez mince."
487       erreur = -1
488
489     return erreur, message, tb_caract_1[-1], tb_caract_1[-2]
490
491 #===========================  Fin de la méthode ==================================
492
493 #=========================== Début de la méthode =================================
494
495   def _calcul_caract_aretes_face ( self, geompy, caract_face ):
496     """Détermine les caractéristiques des arêtes d'une face
497
498 Entrées :
499   :geompy: environnement de GEOM
500   :caract_face: les caractéristiques de la face
501
502 Sorties :
503   :caract_arete_face: les caractéristiques des arêtes de la face
504     """
505
506     nom_fonction = __name__ + "/_calcul_caract_aretes_face"
507     blabla = "\nDans {} :\n".format(nom_fonction)
508
509     if self._verbose_max:
510       texte = blabla
511       texte += "face : {}\n".format(caract_face)
512       print (texte)
513
514 # Détermination des arêtes pour chaque face
515     face = caract_face[0]
516     l_aretes = geompy.ExtractShapes(face, geompy.ShapeType["EDGE"], True)
517     caract_arete_face = list()
518     for arete in l_aretes:
519       caract_arete_face.append(geompy.KindOfShape(arete))
520
521     if self._verbose_max:
522       print ("Aretes de la face : {}".format(caract_arete_face))
523
524     return caract_arete_face
525
526 #===========================  Fin de la méthode ==================================
527
528 #=========================== Début de la méthode =================================
529
530   def _cree_face_mediane ( self, geompy, solide, caract_face_1, caract_face_2 ):
531     """Crée la face médiane entre deux autres
532
533 Entrées :
534   :geompy: environnement de GEOM
535   :solide: l'objet solide à traiter
536   :caract_face_1, caract_face_2: les caractéristiques des 2 faces les plus grandes
537
538 Sorties :
539   :face: la face médiane
540     """
541     erreur = 0
542     message = ""
543     face =  None
544
545     nom_fonction = __name__ + "/_cree_face_mediane"
546     blabla = "\nDans {} :\n".format(nom_fonction)
547
548     if self._verbose_max:
549       texte = blabla
550       texte += "face_1 : {}\n".format(caract_face_1)
551       texte += "face_2 : {}".format(caract_face_2)
552       print (texte)
553
554     while not erreur:
555
556 # 1. Forme de la face
557       forme = caract_face_1[2][0]
558       if self._verbose_max:
559         print ("forme = {}".format(forme) )
560
561 # 2. Traitement selon la forme de la face
562 # 2.1. Face plane
563       if forme in ( geompy.kind.DISK_CIRCLE, geompy.kind.DISK_ELLIPSE, geompy.kind.POLYGON, geompy.kind.PLANE, geompy.kind.PLANAR):
564         erreur, message, face = self._cree_face_mediane_polygone ( geompy, caract_face_1, caract_face_2 )
565
566 # 2.2. Face cylindrique
567       elif forme == geompy.kind.CYLINDER2D:
568         face = self._cree_face_mediane_cylindre ( geompy, solide, caract_face_1, caract_face_2 )
569
570 # 2.3. Face sphérique
571       elif forme == geompy.kind.SPHERE2D:
572         face = self._cree_face_mediane_sphere ( geompy, solide, caract_face_1, caract_face_2 )
573
574 # 2.4. Face torique
575       elif forme == geompy.kind.TORUS2D:
576         face = self._cree_face_mediane_tore ( geompy, solide, caract_face_1, caract_face_2 )
577
578 # 2.5. Face conique
579       elif forme == geompy.kind.CONE2D:
580         face = self._cree_face_mediane_cone ( geompy, solide, caract_face_1, caract_face_2 )
581
582 # 2.N. Face de forme inconnue
583       else:
584         self.faces_pb_msg += "Impossible de créer la face médiane pour le solide '{}' ".format(self.nom_solide)
585         self.faces_pb_msg += "car sa face la plus grande est de forme : {}\n".format(forme)
586         self.faces_pb_nb += 1
587
588 # 3. Gestion de la face produite
589
590       if face is not None:
591         erreur, message = self._cree_face_mediane_0 ( geompy, face )
592
593       break
594
595     return erreur, message, face
596
597 #===========================  Fin de la méthode ==================================
598
599 #=========================== Début de la méthode =================================
600
601   def _cree_face_mediane_0 ( self, geompy, face ):
602     """Gestion de la face médiane créée entre deux autres
603
604 Entrées :
605   :geompy: environnement de GEOM
606   :face: la face médiane créée
607     """
608     erreur = 0
609     message = ""
610
611     nom_fonction = __name__ + "/_cree_face_mediane_0"
612     blabla = "\nDans {} :\n".format(nom_fonction)
613
614     if self._verbose_max:
615       texte = blabla
616       print (texte)
617
618     while not erreur:
619
620 # 3.1. Insertion dans l'étude
621       nom_face = self.nom_solide+"_M"
622       geompy.addToStudy (face,nom_face)
623
624 # 3.2. Transfert éventuel de GEOM vers SHAPER
625       if self._retour_shaper:
626
627 # 3.2.1. Le fichier doit être différent à chaque fois
628         #print ("l_faces_trans = {}".format(self.l_faces_trans))
629         nom_fic = nom_face
630         iaux = 0
631         while True:
632           if nom_fic in self.l_faces_trans:
633             nom_fic = "{}_{}".format(nom_face,iaux)
634             iaux += 1
635           else:
636             break
637         self.l_faces_trans.append(nom_fic)
638         fichier = os.path.join(self.rep_trav, "{}.stp".format(nom_fic))
639
640 # 3.2.2. Exportation depuis GEOM
641         if self._verbose_max:
642           texte = "Exportation depuis GEOM de la face médiane '{}' dans le fichier {}".format(nom_face,fichier)
643           print (texte)
644         try:
645           geompy.ExportSTEP (face, fichier)
646         except OSError as err:
647           print (err)
648           message += "Impossible d'exporter la face médiane '{}' dans le fichier {}".format(nom_face,fichier)
649           erreur = 1
650           break
651
652 # 3.2.3. Importation dans SHAPER
653         if self._verbose_max:
654           texte = "Importation dans SHAPER de la face médiane '{}' depuis le fichier {}".format(nom_face,fichier)
655           print (texte)
656         face_mediane = model.addImportSTEP(self.part_doc, fichier, False, False, False)
657         face_mediane.execute(True)
658         model.do()
659
660 #       Le nom
661         face_mediane.setName(nom_face)
662         face_mediane.result().setName(nom_face)
663
664 #       La couleur. Attention aux conventions différents entr GEOM et SHAPER
665         while True:
666           tbaux = np.array(face.GetColor()._tuple())
667           np_aux = (tbaux<0.).nonzero()
668           if np.any(np_aux):
669             break
670           np_aux = (tbaux>1.).nonzero()
671           if np.any(np_aux):
672             break
673           tbaux *= 255.
674           face_mediane.result().setColor(int(tbaux[0]), int(tbaux[1]), int(tbaux[2]))
675           break
676
677       break
678
679     return erreur, message
680
681 #===========================  Fin de la méthode ==================================
682
683 #=========================== Début de la méthode =================================
684
685   def _cree_face_mediane_polygone ( self, geompy, caract_face_1, caract_face_2 ):
686     """Crée la face médiane entre deux autres - cas des polygones
687
688 Entrées :
689   :geompy: environnement de GEOM
690   :caract_face_1, caract_face_2: les caractéristiques des 2 faces les plus grandes
691
692 Sorties :
693   :face: la face médiane
694     """
695     erreur = 0
696     message = ""
697     face =  None
698
699     nom_fonction = __name__ + "/_cree_face_mediane_polygone"
700     blabla = "\nDans {} :\n".format(nom_fonction)
701
702     while not erreur:
703
704 #     Les deux faces
705       face_1 = caract_face_1[0]
706       face_2 = caract_face_2[0]
707       if self._verbose_max:
708         texte = blabla
709         texte += "face_1 : {}\n".format(caract_face_1)
710         texte += "face_2 : {}".format(caract_face_2)
711         print (texte)
712
713 #     Les 2 surfaces doivent être les mêmes, sinon c'est qu'elles ne sont pas similaires
714       ecart = np.abs((caract_face_1[1]-caract_face_2[1])/caract_face_1[1])
715       if ( ecart > self.epsilon ):
716         if self._verbose:
717           message += ". Surface de la plus grande face : {}\n".format(caract_face_1[1])
718           message += ". Surface de la face suivante    : {}\n".format(caract_face_2[1])
719
720 #     Distance entre les deux faces
721       d_face_1_2 = geompy.MinDistance(face_1, face_2)
722       if self._verbose:
723         print ("\tDistance entre les deux faces = {}".format(d_face_1_2))
724
725 #     Copie de la plus grande face
726       face_1_copie= geompy.MakeCopy(face_1)
727       if self._verbose_max:
728         geompy.addToStudy(face_1_copie, face_1.GetName()+"_copie" )
729
730 #     On la translate d'une demi épaisseur
731 #     Attention : les normales des faces issues de l'explosion du solide sont dirigées vers l'extérieur.
732 #                 Comme il faut translater la face vers l'intérieur, on le fait avec une distance négative.
733       vnorm_face_1_copie = geompy.GetNormal(face_1_copie)
734       face = geompy.TranslateVectorDistance (face_1_copie, vnorm_face_1_copie, -0.5*d_face_1_2)
735
736 #     Si les 2 surfaces ne sont pas similaires, on a quand même tenté la création mais on le signale
737       if ( ecart > self.epsilon ):
738         face.SetColor(SALOMEDS.Color(0,0,1))
739         message += "Problème pour créer la face médiane pour le solide '{}' : ".format(self.nom_solide)
740         message += "ce n'est pas un véritable polyèdre."
741         if self._verbose:
742           message += "\nL'écart de surface entre les 2 plus grandes faces est trop grand : {:5.2f}%.\n".format(ecart*100.)
743           message += "Tentative de création à partir de la plus grande des faces du solide."
744         erreur = -2
745       else:
746         face.SetColor(SALOMEDS.Color(0,1,0))
747
748       break
749
750     return erreur, message, face
751
752 #===========================  Fin de la méthode ==================================
753
754 #=========================== Début de la méthode =================================
755
756   def _cree_face_mediane_cylindre ( self, geompy, solide, caract_face_1, caract_face_2 ):
757     """Crée la face médiane entre deux autres - cas des cylindres
758
759 Entrées :
760   :geompy: environnement de GEOM
761   :solide: l'objet solide à traiter
762   :caract_face_1, caract_face_2: les caractéristiques des 2 faces les plus grandes
763
764 Sorties :
765   :face: la face médiane
766     """
767     face =  None
768
769     nom_fonction = __name__ + "/_cree_face_mediane_cylindre"
770     blabla = "\nDans {} :\n".format(nom_fonction)
771
772 #   Les deux faces
773     if self._verbose_max:
774       texte = blabla
775       texte += "face_1 : {}\n".format(caract_face_1)
776       texte += "face_2 : {}".format(caract_face_2)
777       print (texte)
778
779 #   Caractéristiques des cylindres
780     coo_x, coo_y, coo_z, axe_x, axe_y, axe_z, rayon, hauteur = self._cree_face_mediane_cylindre_0 ( geompy, solide, caract_face_1, caract_face_2 )
781
782 #   Création de la face
783     centre, axe, cylindre = self._cree_face_mediane_cylindre_1 ( geompy, coo_x, coo_y, coo_z, axe_x, axe_y, axe_z, rayon, hauteur )
784
785 #   Gestion de l'intersection avec le solide initial
786     face = self._cree_face_mediane_cylindre_2 ( geompy, solide, centre, axe, cylindre )
787
788 #   Couleur verte
789     face.SetColor(SALOMEDS.Color(0,1,0))
790
791     return face
792
793 #===========================  Fin de la méthode ==================================
794
795 #=========================== Début de la méthode =================================
796
797   def _cree_face_mediane_cylindre_0 ( self, geompy, solide, caract_face_1, caract_face_2 ):
798     """Crée la face médiane entre deux autres - cas des cylindres
799
800 Décodage des caractéristiques
801
802 Entrées :
803   :geompy: environnement de GEOM
804   :solide: l'objet solide à traiter
805   :caract_face_1, caract_face_2: les caractéristiques des 2 faces les plus grandes
806
807 Sorties :
808   :coo_x, coo_y, coo_z: coordonnées du centre de la base
809   :axe_x, axe_y, axe_z: coordonnées de l'axe
810   :rayon: rayon moyen entre les deux faces
811   :hauteur: hauteur du cylindre
812     """
813
814     nom_fonction = __name__ + "/_cree_face_mediane_cylindre_0"
815     blabla = "\nDans {} :\n".format(nom_fonction)
816
817 #   Les deux faces
818     if self._verbose_max:
819       texte = blabla
820       texte += "face_1 : {}\n".format(caract_face_1)
821       texte += "face_2 : {}".format(caract_face_2)
822       print (texte)
823
824 #   Coordonnées du centre de la base
825     coo_x = caract_face_1[2][1]
826     coo_y = caract_face_1[2][2]
827     coo_z = caract_face_1[2][3]
828 #   Coordonnées de l'axe
829     axe_x = caract_face_1[2][4]
830     axe_y = caract_face_1[2][5]
831     axe_z = caract_face_1[2][6]
832 #   Rayons
833     rayon = (caract_face_2[2][7]+caract_face_1[2][7])/2.
834 #   Hauteur : la diagonale de la boîte englobante permet d'être certain de tout prendre
835     hauteur = self._calcul_hauteur_englobante ( geompy, solide )
836
837     return coo_x, coo_y, coo_z, axe_x, axe_y, axe_z, rayon, hauteur
838
839 #===========================  Fin de la méthode ==================================
840
841 #=========================== Début de la méthode =================================
842
843   def _cree_face_mediane_cylindre_1 ( self, geompy, coo_x, coo_y, coo_z, axe_x, axe_y, axe_z, rayon, hauteur ):
844     """Crée la face médiane entre deux autres - cas des cylindres
845
846 Création des objets temporaires et de la face externe du cylindre support
847
848 Entrées :
849   :geompy: environnement de GEOM
850   :coo_x, coo_y, coo_z: coordonnées du centre de la base
851   :axe_x, axe_y, axe_z: coordonnées de l'axe
852   :rayon: rayon moyen entre les deux faces
853   :hauteur: hauteur du cylindre
854
855 Sorties :
856   :centre: le centre de la base du cylindre médian
857   :axe: l'axe des cylindres
858   :cylindre: le cylindre support
859     """
860     nom_fonction = __name__ + "/_cree_face_mediane_cylindre_1"
861     blabla = "\nDans {} :\n".format(nom_fonction)
862
863 #   Les deux faces
864     if self._verbose_max:
865       texte = blabla
866       texte += "Centre : ({}, {}, {})\n".format(coo_x, coo_y, coo_z)
867       texte += "Axe    : ({}, {}, {})\n".format(axe_x, axe_y, axe_z)
868       texte += "Rayon : {}\n".format(rayon)
869       texte += "Hauteur : {}".format(hauteur)
870       print (texte)
871
872 #   Création du point central
873     centre = geompy.MakeVertex(coo_x, coo_y, coo_z)
874     #geompy.addToStudy( centre, "centre" )
875
876 #   Création de l'axe
877     axe = geompy.MakeVectorDXDYDZ(axe_x, axe_y, axe_z)
878     #geompy.addToStudy( axe, "axe" )
879
880 #   Création d'un cylindre
881     cylindre = geompy.MakeCylinder(centre, axe, rayon, hauteur)
882     if self._verbose_max:
883       geompy.addToStudy( cylindre, "cylindre médian" )
884
885     return centre, axe, cylindre
886
887 #===========================  Fin de la méthode ==================================
888
889 #=========================== Début de la méthode =================================
890
891   def _cree_face_mediane_cylindre_2 ( self, geompy, solide, centre, axe, cylindre ):
892     """Crée la face médiane entre deux autres - cas des cylindres
893
894 Intersection de la face cylindrique avec le solide initial
895
896 Entrées :
897   :geompy: environnement de GEOM
898   :solide: l'objet solide à traiter
899   :centre: le centre de la base du cylindre médian
900   :axe: l'axe des cylindres
901   :cylindre: le cylindre support
902
903 Sorties :
904   :face: la face médiane
905     """
906     face =  None
907
908     nom_fonction = __name__ + "/_cree_face_mediane_cylindre_2"
909     blabla = "\nDans {} :\n".format(nom_fonction)
910
911     if self._verbose_max:
912       print (blabla)
913
914 #   Récupération de la bonne face après intersection du cylindre avec le solide initial
915     face = self._creation_face_inter ( geompy, solide, cylindre, 1 )
916
917 #   Pour des raisons inconnues de moi, il arrive que l'axe donné par les caractéristiques soit dans le mauvais sens.
918 #   Dans ce cas l'intersection est vide, et il faut retourner la face créée précédemment et recalculer l'intersection.
919     tb_caract = geompy.KindOfShape(face)
920     if ( tb_caract[1] == 0 ):
921       if self._verbose_max:
922         print ("On opère un retournement du cylindre.")
923       plan_de_base = geompy.MakePlane(centre, axe, 100)
924       #geompy.addToStudy( plan_de_base, "plan_de_base" )
925       geompy.MirrorByPlane(cylindre, plan_de_base)
926 #     Récupération de la bonne face après intersection du cylindre retourné avec le solide initial
927       face = self._creation_face_inter ( geompy, solide, cylindre, 1 )
928
929     return face
930
931 #===========================  Fin de la méthode ==================================
932
933 #=========================== Début de la méthode =================================
934
935   def _cree_face_mediane_sphere ( self, geompy, solide, caract_face_1, caract_face_2 ):
936     """Crée la face médiane entre deux autres - cas des sphères
937
938 Entrées :
939   :geompy: environnement de GEOM
940   :solide: l'objet solide à traiter
941   :caract_face_1, caract_face_2: les caractéristiques des 2 faces les plus grandes
942
943 Sorties :
944   :face: la face médiane
945     """
946     face =  None
947
948     nom_fonction = __name__ + "/_cree_face_mediane_sphere"
949     blabla = "\nDans {} :\n".format(nom_fonction)
950
951 #   Les deux faces
952     if self._verbose_max:
953       texte = blabla
954       texte += "face_1 : {}\n".format(caract_face_1)
955       texte += "face_2 : {}".format(caract_face_2)
956       print (texte)
957
958 #   Caractéristiques des sphères
959     coo_x, coo_y, coo_z, rayon = self._cree_face_mediane_sphere_0 ( caract_face_1, caract_face_2 )
960
961 #   Création de la face
962     face = self._cree_face_mediane_sphere_1 ( geompy, solide, coo_x, coo_y, coo_z, rayon )
963
964 #   Couleur verte
965     face.SetColor(SALOMEDS.Color(0,1,0))
966
967     return face
968
969 #===========================  Fin de la méthode ==================================
970
971 #=========================== Début de la méthode =================================
972
973   def _cree_face_mediane_sphere_0 ( self, caract_face_1, caract_face_2 ):
974     """Crée la face médiane entre deux autres - cas des sphères
975
976 Décodage des caractéristiques
977
978 Entrées :
979   :caract_face_1, caract_face_2: les caractéristiques des 2 faces les plus grandes
980
981 Sorties :
982   :coo_x, coo_y, coo_z: coordonnées du centre de la sphère
983   :rayon: rayon moyen entre les deux faces
984     """
985
986     nom_fonction = __name__ + "/_cree_face_mediane_sphere_0"
987     blabla = "\nDans {} :\n".format(nom_fonction)
988
989 #   Les deux faces
990     if self._verbose_max:
991       texte = blabla
992       texte += "face_1 : {}\n".format(caract_face_1)
993       texte += "face_2 : {}".format(caract_face_2)
994       print (texte)
995
996 #   Coordonnées du centre de la sphère
997     coo_x = caract_face_1[2][1]
998     coo_y = caract_face_1[2][2]
999     coo_z = caract_face_1[2][3]
1000 #   Rayons
1001     rayon = (caract_face_2[2][4]+caract_face_1[2][4])/2.
1002
1003     return coo_x, coo_y, coo_z, rayon
1004
1005 #===========================  Fin de la méthode ==================================
1006
1007 #=========================== Début de la méthode =================================
1008
1009   def _cree_face_mediane_sphere_1 ( self, geompy, solide, coo_x, coo_y, coo_z, rayon ):
1010     """Crée la face médiane entre deux autres - cas des sphères
1011
1012 Création des objets temporaires et de la face externe de la sphère support
1013
1014 Entrées :
1015   :geompy: environnement de GEOM
1016   :solide: l'objet solide à traiter
1017   :coo_x, coo_y, coo_z: coordonnées du centre de la sphère
1018   :rayon: rayon moyen entre les deux faces
1019
1020 Sorties :
1021   :face: la face externe de la sphère support
1022     """
1023     face =  None
1024
1025     nom_fonction = __name__ + "/_cree_face_mediane_sphere_1"
1026     blabla = "\nDans {} :\n".format(nom_fonction)
1027
1028 #   Les deux faces
1029     if self._verbose_max:
1030       texte = blabla
1031       texte += "Centre : ({}, {}, {})\n".format(coo_x, coo_y, coo_z)
1032       texte += "Rayon : {}".format(rayon)
1033       print (texte)
1034
1035 #   Création du point central
1036     centre = geompy.MakeVertex(coo_x, coo_y, coo_z)
1037     #geompy.addToStudy( centre, "centre" )
1038
1039 #   Création d'une sphère médiane
1040     sphere = geompy.MakeSpherePntR(centre, rayon)
1041     if self._verbose_max:
1042       geompy.addToStudy( sphere, "sphère médiane" )
1043
1044 #   Récupération de la bonne face après intersection avec le solide initial
1045     face = self._creation_face_inter ( geompy, solide, sphere, 0 )
1046
1047     return face
1048
1049 #===========================  Fin de la méthode ==================================
1050
1051 #=========================== Début de la méthode =================================
1052
1053   def _cree_face_mediane_tore ( self, geompy, solide, caract_face_1, caract_face_2 ):
1054     """Crée la face médiane entre deux autres - cas des tores
1055
1056 Entrées :
1057   :geompy: environnement de GEOM
1058   :solide: l'objet solide à traiter
1059   :caract_face_1, caract_face_2: les caractéristiques des 2 faces les plus grandes
1060
1061 Sorties :
1062   :face: la face médiane
1063     """
1064     face =  None
1065
1066     nom_fonction = __name__ + "/_cree_face_mediane_tore"
1067     blabla = "\nDans {} :\n".format(nom_fonction)
1068
1069 #   Les deux faces
1070     if self._verbose_max:
1071       texte = blabla
1072       texte += "face_1 : {}\n".format(caract_face_1)
1073       texte += "face_2 : {}".format(caract_face_2)
1074       print (texte)
1075
1076 #   Caractéristiques des tores
1077     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 )
1078
1079 #   Création de la face
1080     face = self._cree_face_mediane_tore_1 ( geompy, solide, coo_x, coo_y, coo_z, axe_x, axe_y, axe_z, rayon_1, rayon_2 )
1081
1082 #   Couleur verte
1083     face.SetColor(SALOMEDS.Color(0,1,0))
1084
1085     return face
1086
1087 #===========================  Fin de la méthode ==================================
1088
1089 #=========================== Début de la méthode =================================
1090
1091   def _cree_face_mediane_tore_0 ( self, caract_face_1, caract_face_2 ):
1092     """Crée la face médiane entre deux autres - cas des tores
1093
1094 Décodage des caractéristiques
1095
1096 Entrées :
1097   :caract_face_1, caract_face_2: les caractéristiques des 2 faces les plus grandes
1098
1099 Sorties :
1100   :coo_x, coo_y, coo_z: coordonnées du centre du tore
1101   :axe_x, axe_y, axe_z: coordonnées de l'axe
1102   :rayon_1 : rayon principal
1103   :rayon_2 : rayon secondaire
1104     """
1105
1106     nom_fonction = __name__ + "/_cree_face_mediane_tore_0"
1107     blabla = "\nDans {} :\n".format(nom_fonction)
1108
1109 #   Les deux faces
1110     if self._verbose_max:
1111       texte = blabla
1112       texte += "face_1 : {}\n".format(caract_face_1)
1113       texte += "face_2 : {}".format(caract_face_2)
1114       print (texte)
1115
1116 #   Coordonnées du centre du tore
1117     coo_x = caract_face_1[2][1]
1118     coo_y = caract_face_1[2][2]
1119     coo_z = caract_face_1[2][3]
1120 #   Coordonnées de l'axe
1121     axe_x = caract_face_1[2][4]
1122     axe_y = caract_face_1[2][5]
1123     axe_z = caract_face_1[2][6]
1124 #   Rayons
1125     rayon_1 = caract_face_2[2][7]
1126     rayon_2 = (caract_face_2[2][8]+caract_face_1[2][8])/2.
1127
1128     return coo_x, coo_y, coo_z, axe_x, axe_y, axe_z, rayon_1, rayon_2
1129
1130 #===========================  Fin de la méthode ==================================
1131
1132 #=========================== Début de la méthode =================================
1133
1134   def _cree_face_mediane_tore_1 ( self, geompy, solide, coo_x, coo_y, coo_z, axe_x, axe_y, axe_z, rayon_1, rayon_2 ):
1135     """Crée la face médiane entre deux autres - cas des tores
1136
1137 Création des objets temporaires et de la face externe du tore support
1138
1139 Entrées :
1140   :geompy: environnement de GEOM
1141   :solide: l'objet solide à traiter
1142   :coo_x, coo_y, coo_z: coordonnées du centre du tore
1143   :axe_x, axe_y, axe_z: coordonnées de l'axe
1144   :rayon_1 : rayon principal
1145   :rayon_2 : rayon secondaire
1146
1147 Sorties :
1148   :face: la face externe du tore support
1149     """
1150     face =  None
1151
1152     nom_fonction = __name__ + "/_cree_face_mediane_tore_1"
1153     blabla = "\nDans {} :\n".format(nom_fonction)
1154
1155 #   Les deux faces
1156     if self._verbose_max:
1157       texte = blabla
1158       texte += "Centre : ({}, {}, {})\n".format(coo_x, coo_y, coo_z)
1159       texte += "Axe    : ({}, {}, {})\n".format(axe_x, axe_y, axe_z)
1160       texte += "Rayon principal : {}\n".format(rayon_1)
1161       texte += "Rayon secondaire : {}".format(rayon_2)
1162       print (texte)
1163
1164 #   Création du point central
1165     centre = geompy.MakeVertex(coo_x, coo_y, coo_z)
1166     #geompy.addToStudy( centre, "centre" )
1167
1168 #   Création de l'axe
1169     axe = geompy.MakeVectorDXDYDZ(axe_x, axe_y, axe_z)
1170     #geompy.addToStudy( axe, "axe" )
1171
1172 #   Création d'un tore médian
1173     tore = geompy.MakeTorus(centre, axe, rayon_1, rayon_2)
1174     if self._verbose_max:
1175       geompy.addToStudy( tore, "tore médian" )
1176
1177 #   Récupération de la bonne face après intersection avec le solide initial
1178     face = self._creation_face_inter ( geompy, solide, tore, 0 )
1179
1180     return face
1181
1182 #===========================  Fin de la méthode ==================================
1183
1184 #=========================== Début de la méthode =================================
1185
1186   def _cree_face_mediane_cone ( self, geompy, solide, caract_face_1, caract_face_2 ):
1187     """Crée la face médiane entre deux autres - cas des cones
1188
1189 Entrées :
1190   :geompy: environnement de GEOM
1191   :solide: l'objet solide à traiter
1192   :caract_face_1, caract_face_2: les caractéristiques des 2 faces les plus grandes
1193
1194 Sorties :
1195   :face: la face médiane
1196     """
1197     face =  None
1198
1199     nom_fonction = __name__ + "/_cree_face_mediane_cone"
1200     blabla = "\nDans {} :\n".format(nom_fonction)
1201
1202 #   Les deux faces
1203     if self._verbose_max:
1204       texte = blabla
1205       texte += "face_1 : {}\n".format(caract_face_1)
1206       texte += "face_2 : {}".format(caract_face_2)
1207       print (texte)
1208
1209 #   Caractéristiques des cones
1210     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 )
1211
1212 #   Création de la face
1213     centre, axe, cone = self._cree_face_mediane_cone_1 ( geompy, coo_x, coo_y, coo_z, axe_x, axe_y, axe_z, rayon_1, rayon_2, hauteur )
1214
1215 #   Gestion de l'intersection avec le solide initial
1216     face = self._cree_face_mediane_cone_2 ( geompy, solide, centre, axe, cone )
1217
1218 #   Couleur verte
1219     face.SetColor(SALOMEDS.Color(0,1,0))
1220
1221     return face
1222
1223 #===========================  Fin de la méthode ==================================
1224
1225 #=========================== Début de la méthode =================================
1226
1227   def _cree_face_mediane_cone_0 ( self, geompy, caract_face_1, caract_face_2 ):
1228     """Crée la face médiane entre deux autres - cas des cones
1229
1230 Décodage des caractéristiques
1231
1232 Entrées :
1233   :geompy: environnement de GEOM
1234   :caract_face_1, caract_face_2: les caractéristiques des 2 faces les plus grandes
1235
1236 Sorties :
1237   :coo_x, coo_y, coo_z: coordonnées du centre de la base
1238   :axe_x, axe_y, axe_z: coordonnées de l'axe
1239   :rayon_1, rayon_2: rayons moyens du côté de la base et à l'opposé
1240   :hauteur: hauteur du cone
1241     """
1242
1243     nom_fonction = __name__ + "/_cree_face_mediane_cone_0"
1244     blabla = "\nDans {} :\n".format(nom_fonction)
1245
1246 #   Les deux faces
1247     if self._verbose_max:
1248       texte = blabla
1249       texte += "face_1 : {}\n".format(caract_face_1)
1250       texte += "face_2 : {}".format(caract_face_2)
1251       print (texte)
1252
1253 #   Coordonnées du centre de la base
1254     coo_x = caract_face_1[2][1]
1255     coo_y = caract_face_1[2][2]
1256     coo_z = caract_face_1[2][3]
1257 #   Coordonnées de l'axe
1258     axe_x = caract_face_1[2][4]
1259     axe_y = caract_face_1[2][5]
1260     axe_z = caract_face_1[2][6]
1261 #   Rayons
1262 #   Pour un cone complet, les caractéristiques forunies par GEOM sont correctes
1263 #   Mais s'il est découpé, malheureusement,bug dans GEOM et caract_face_2[2][8] est toujours nul !
1264 #   Alors on passe par le décodage des arêtes
1265     #rayon_1 = (caract_face_2[2][7]+caract_face_1[2][7])/2.
1266     #rayon_2 = (caract_face_2[2][8]+caract_face_1[2][8])/2.
1267     caract_arete_face_1 = self._calcul_caract_aretes_face ( geompy, caract_face_1 )
1268     caract_arete_face_2 = self._calcul_caract_aretes_face ( geompy, caract_face_2 )
1269     rayon_1 = 0.
1270     rayon_2 = 0.
1271     for caract_aretes_face in [caract_arete_face_1,caract_arete_face_2]:
1272       prem = True
1273       for l_aux in caract_aretes_face:
1274         if ( l_aux[0] in ( geompy.kind.CIRCLE, geompy.kind.ARC_CIRCLE ) ):
1275           #print ("R =",l_aux[7])
1276           if prem:
1277             rayon_1 += l_aux[7]
1278             prem = False
1279           else:
1280             rayon_2 += l_aux[7]
1281     rayon_1 *= 0.5
1282     rayon_2 *= 0.5
1283 #   Hauteur
1284     hauteur = caract_face_1[2][9]
1285
1286     return coo_x, coo_y, coo_z, axe_x, axe_y, axe_z, rayon_1, rayon_2, hauteur
1287
1288 #===========================  Fin de la méthode ==================================
1289
1290 #=========================== Début de la méthode =================================
1291
1292   def _cree_face_mediane_cone_1 ( self, geompy, coo_x, coo_y, coo_z, axe_x, axe_y, axe_z, rayon_1, rayon_2, hauteur ):
1293     """Crée la face médiane entre deux autres - cas des cones
1294
1295 Création des objets temporaires et de la face externe du cone support
1296
1297 Entrées :
1298   :geompy: environnement de GEOM
1299   :coo_x, coo_y, coo_z: coordonnées du centre de la base
1300   :axe_x, axe_y, axe_z: coordonnées de l'axe
1301   :rayon_1, rayon_2: rayons moyens du côté de la base et à l'opposé
1302   :hauteur: hauteur du cone
1303
1304 Sorties :
1305   :centre: le centre de la base du cone médian
1306   :axe: l'axe des cones
1307   :cone: le cone support
1308     """
1309     nom_fonction = __name__ + "/_cree_face_mediane_cone_1"
1310     blabla = "\nDans {} :\n".format(nom_fonction)
1311
1312 #   Les deux faces
1313     if self._verbose_max:
1314       texte = blabla
1315       texte += "Centre : ({}, {}, {})\n".format(coo_x, coo_y, coo_z)
1316       texte += "Axe    : ({}, {}, {})\n".format(axe_x, axe_y, axe_z)
1317       texte += "Rayons : {}, {}\n".format(rayon_1, rayon_2)
1318       texte += "Hauteur : {}".format(hauteur)
1319       print (texte)
1320
1321 #   Création du point central
1322     centre = geompy.MakeVertex(coo_x, coo_y, coo_z)
1323     #geompy.addToStudy( centre, "centre" )
1324
1325 #   Création de l'axe
1326     axe = geompy.MakeVectorDXDYDZ(axe_x, axe_y, axe_z)
1327     #geompy.addToStudy( axe, "axe" )
1328
1329 #   Création d'un cone
1330     cone = geompy.MakeCone(centre, axe, rayon_1, rayon_2, hauteur)
1331     if self._verbose_max:
1332       geompy.addToStudy( cone, "cone médian" )
1333
1334     return centre, axe, cone
1335
1336 #===========================  Fin de la méthode ==================================
1337
1338 #=========================== Début de la méthode =================================
1339
1340   def _cree_face_mediane_cone_2 ( self, geompy, solide, centre, axe, cone ):
1341     """Crée la face médiane entre deux autres - cas des cones
1342
1343 Intersection de la face cylindrique avec le solide initial
1344
1345 Entrées :
1346   :geompy: environnement de GEOM
1347   :solide: l'objet solide à traiter
1348   :centre: le centre de la base du cone médian
1349   :axe: l'axe des cones
1350   :cone: le cone support
1351
1352 Sorties :
1353   :face: la face médiane
1354     """
1355     face =  None
1356
1357     nom_fonction = __name__ + "/_cree_face_mediane_cone_2"
1358     blabla = "\nDans {} :\n".format(nom_fonction)
1359
1360     if self._verbose_max:
1361       print (blabla)
1362
1363 #   Récupération de la bonne face après intersection du cone avec le solide initial
1364     face = self._creation_face_inter ( geompy, solide, cone, 1 )
1365
1366 #   Pour des raisons inconnues de moi, il arrive que l'axe donné par les caractéristiques soit dans le mauvais sens.
1367 #   Dans ce cas l'intersection est vide, et il faut retourner la face créée précédemment et recalculer l'intersection.
1368     tb_caract = geompy.KindOfShape(face)
1369     if ( tb_caract[1] == 0 ):
1370       if self._verbose_max:
1371         print ("On opère un retournement du cone.")
1372       plan_de_base = geompy.MakePlane(centre, axe, 100)
1373       #geompy.addToStudy( plan_de_base, "plan_de_base" )
1374       geompy.MirrorByPlane(cone, plan_de_base)
1375 #     Récupération de la bonne face après intersection du cone retourné avec le solide initial
1376       face = self._creation_face_inter ( geompy, solide, cone, 1 )
1377
1378     return face
1379
1380 #===========================  Fin de la méthode ==================================
1381
1382 #=========================== Début de la méthode =================================
1383
1384   def _calcul_hauteur_englobante ( self, geompy, solide ):
1385     """Crée la hauteur englobant à coup sûr le solide
1386
1387 Décodage des caractéristiques
1388
1389 Entrées :
1390   :geompy: environnement de GEOM
1391   :solide: l'objet solide à traiter
1392
1393 Sorties :
1394   :hauteur: hauteur englobante
1395     """
1396
1397     nom_fonction = __name__ + "/_calcul_hauteur_englobante"
1398     blabla = "\nDans {} :\n".format(nom_fonction)
1399
1400 #   Les deux faces
1401     if self._verbose_max:
1402       print (blabla[:-1])
1403
1404 #   Hauteur : la diagonale de la boîte englobante permet d'être certain de tout prendre
1405     bounding_box = geompy.BoundingBox(solide)
1406     if self._verbose_max:
1407       texte = "Boîte englobante du solide '{}'\n".format(self.nom_solide)
1408       texte += "\tXmin = {}, Xmax = {}\n".format(bounding_box[0],bounding_box[1])
1409       texte += "\tYmin = {}, Ymax = {}\n".format(bounding_box[2],bounding_box[3])
1410       texte += "\tZmin = {}, Zmax = {}".format(bounding_box[4],bounding_box[5])
1411       print(texte)
1412
1413     coo_1 = np.array([bounding_box[0],bounding_box[2],bounding_box[4]])
1414     coo_2 = np.array([bounding_box[1],bounding_box[3],bounding_box[5]])
1415     longueur = np.linalg.norm(coo_2-coo_1)
1416     if self._verbose_max:
1417       print ("Longueur de la diagonale {}".format(longueur))
1418     hauteur = 1.2*longueur
1419
1420     return hauteur
1421
1422 #===========================  Fin de la méthode ==================================
1423
1424 #=========================== Début de la méthode =================================
1425
1426   def _creation_face_inter ( self, geompy, solide, objet, numero ):
1427     """Crée la face
1428
1429 . Repère la face principale de l'objet support
1430 . Réalise l'intersection avec le solide initial
1431
1432 Entrées :
1433   :geompy: environnement de GEOM
1434   :solide: l'objet solide à traiter
1435   :objet: l'objet support de la face
1436   :numero: numero de la face dans l'explosion de l'objet support
1437
1438 Sorties :
1439   :face: la face externe de l'objet support intersecté avec le solide initial
1440     """
1441
1442     nom_fonction = __name__ + "/_creation_face_inter"
1443     blabla = "\nDans {} :\n".format(nom_fonction)
1444
1445 #   Les deux faces
1446     if self._verbose_max:
1447       print (blabla[:-1])
1448
1449 #   Récupération de la bonne face
1450     l_aux = geompy.ExtractShapes(objet, geompy.ShapeType["FACE"], True)
1451     face_1 = geompy.MakeShell([l_aux[numero]])
1452     #geompy.addToStudy( face_1, "face externe" )
1453
1454 #   Intersection entre la face externe du solide médian et le solide initial
1455     face = geompy.MakeCommonList([solide, face_1], True)
1456     #geompy.addToStudy( face, "face" )
1457
1458     return face
1459
1460 #===========================  Fin de la méthode ==================================
1461
1462 #=========================== Début de la méthode =================================
1463
1464   def _menage_faces ( self, gst, l_faces ):
1465     """Fait le ménage des faces dans l'étude
1466
1467 Entrées :
1468   :gst: environnement de GeomStudyTools
1469   :l_faces: liste des faces du solide
1470     """
1471
1472     nom_fonction = __name__ + "/_menage_faces"
1473     blabla = "\nDans {} :\n".format(nom_fonction)
1474
1475     if self._verbose_max:
1476       texte = blabla
1477       texte += "Nombre de faces à supprimer : {}\n".format(len(l_faces))
1478       print (texte)
1479
1480 # Suppression des faces incluses dans l'étude
1481     if self._menage:
1482       for face in l_faces:
1483         if self._verbose_max:
1484           print ("\tSuppression de {}".format(face.GetName()))
1485         gst.deleteShape(face.GetStudyEntry())
1486
1487 # Rafraichissement de l'affichage
1488     salome.sg.updateObjBrowser()
1489
1490     return
1491
1492 #===========================  Fin de la méthode ==================================
1493
1494 #=========================== Début de la méthode =================================
1495
1496   def face_mediane_solide (self, geompy, gst, solide):
1497
1498     """Calcul de la face médiane pour un solide
1499
1500 Entrées :
1501   :geompy: environnement de GEOM
1502   :gst: environnement de GeomStudyTools
1503   :solide: l'objet solide à traiter
1504
1505 Sorties :
1506   :erreur: code d'erreur
1507   :message: message d'erreur
1508     """
1509
1510     nom_fonction = __name__ + "/face_mediane_solide"
1511     blabla = "\nDans {} :\n".format(nom_fonction)
1512
1513     if self._verbose_max:
1514       print (blabla)
1515     if self._verbose:
1516       print ("Traitement du solide '{}'".format(solide.GetName()))
1517
1518 # 1. Préalables
1519
1520     erreur = 0
1521     message = ""
1522
1523     while not erreur :
1524
1525 # 2. Explosion du solide en faces
1526
1527       erreur, message, l_faces = self._faces_du_solide ( geompy, solide )
1528       if erreur:
1529         break
1530
1531 # 3. Calcul des caractéristiques géométriques des faces
1532
1533       tb_caract = self._calcul_caract_faces ( geompy, l_faces )
1534
1535 # 4. Tri des faces en fonction de leurs caractéristiques géométriques
1536
1537       erreur, message, caract_face_1, caract_face_2 = self._tri_faces ( tb_caract )
1538       if erreur:
1539         break
1540
1541 # 5. Création de la face médiane
1542
1543       erreur, message, face = self._cree_face_mediane ( geompy, solide, caract_face_1, caract_face_2 )
1544       if erreur:
1545         break
1546
1547 # 6. Ménage des faces
1548
1549       if salome.sg.hasDesktop():
1550         if self._retour_shaper:
1551           l_faces.append(face)
1552         self._menage_faces ( gst, l_faces )
1553
1554       break
1555
1556 # 7. La fin
1557
1558     if ( erreur and self._verbose_max ):
1559       print (blabla, message)
1560
1561     return erreur, message
1562
1563 #===========================  Fin de la méthode ==================================
1564
1565 #=========================== Début de la méthode =================================
1566
1567   def _menage_solides ( self, gst, l_solides, l_solides_m, type_selection, objet ):
1568     """Fait le ménage des solides dans l'étude
1569
1570 Entrées :
1571   :gst: environnement de GeomStudyTools
1572   :l_solides: liste des solides de l'objet
1573   :l_solides_m: liste des solides de l'objet dont on veut le ménage
1574   :type_selection: type de sélection de l'objet à traiter (0: graphique, 1: GEOM, 2;SHAPER)
1575   :objet: l'objet à traiter
1576     """
1577
1578     nom_fonction = __name__ + "/_menage_solides"
1579     blabla = "\nDans {} :\n".format(nom_fonction)
1580
1581     if self._verbose_max:
1582       texte = blabla
1583       texte += "Nombre de solides de l'objet  : {}\n".format(len(l_solides))
1584       texte += "Nombre de solides à supprimer : {}".format(len(l_solides_m))
1585       print (texte)
1586
1587     if self._menage:
1588
1589 # Suppression des solides inclus dans l'étude dans le cas d'un assemblage explosé
1590       if ( len(l_solides) > 1 ):
1591         for solide in l_solides_m:
1592           if self._verbose_max:
1593             print ("\tSuppression de {}".format(solide.GetName()))
1594           gst.deleteShape(solide.GetStudyEntry())
1595
1596 # Suppression de l'objet initial quand il vient d'une exportation depuis SHAPER si ça s'est mal passé
1597       if ( type_selection == 2 ):
1598         if ( len(l_solides) != len(l_solides_m) ):
1599           pass
1600         else:
1601           if self._verbose_max:
1602             print ("\tSuppression de {}".format(objet.GetName()))
1603           gst.deleteShape(objet.GetStudyEntry())
1604
1605 # Mise en évidence des solides non détruits
1606       for solide in l_solides:
1607         if solide not in l_solides_m:
1608           solide.SetColor(SALOMEDS.Color(1,0,0))
1609
1610 # Rafraichissement de l'affichage
1611     salome.sg.updateObjBrowser()
1612
1613     return
1614
1615 #===========================  Fin de la méthode ==================================
1616
1617 #=========================== Début de la méthode =================================
1618
1619   def _traitement_objet (self, type_selection=0, objet=None ):
1620     """Traitement d'un objet
1621
1622 Entrées :
1623   :type_selection: type de sélection de l'objet à traiter (0: graphique, 1: GEOM, 2;SHAPER)
1624   :objet: l'objet à traiter quand il passe par argument
1625
1626 Sorties :
1627   :erreur: code d'erreur
1628   :message: message d'erreur
1629     """
1630
1631     nom_fonction = __name__ + "/_traitement_objet"
1632     blabla = "\nDans {} :\n".format(nom_fonction)
1633
1634     if self._verbose_max:
1635       texte = blabla
1636       texte += "type_selection = {}".format(type_selection)
1637       print (texte)
1638
1639 # 1. Préalables
1640
1641     erreur = 0
1642     message = ""
1643
1644     while not erreur :
1645
1646 # 2. L'aide
1647
1648       if self.affiche_aide_globale :
1649         break
1650
1651 # 3. Les imports pour salomé
1652       geompy = geomBuilder.New()
1653       gst = geomtools.GeomStudyTools(getStudyEditor())
1654
1655 # 4. Sélection de l'objet
1656       if ( type_selection == 0 ):
1657         erreur, message, objet = self._selection_objet_graphique ( geompy )
1658       elif ( type_selection in (1,2) ):
1659         pass
1660       else:
1661         message = "Le type d'objet {} est inconnu.".format(type_selection)
1662         erreur = 4
1663       if erreur:
1664         break
1665
1666 # 5. En cas de retour vers shaper, répertoire de travail associé à l'éventuel fichier de départ
1667       if self._retour_shaper:
1668         if self.ficcao is None:
1669           self.rep_trav = tempfile.mkdtemp(prefix="{}_".format(objet.GetName()))
1670         else:
1671           self.rep_trav = os.path.join(os.path.dirname(self.ficcao),"{}_M".format(objet.GetName()))
1672           if not os.path.isdir(self.rep_trav):
1673             os.mkdir(self.rep_trav)
1674         if self._verbose_max:
1675           print ("Les fichiers CAO des surfaces seront dans le répertoire {}".format(self.rep_trav))
1676
1677 # 6. Liste des solides qui composent l'objet
1678       erreur, message, l_solides = self._les_solides ( geompy, objet )
1679       if erreur:
1680         break
1681
1682 # 7. Calcul des surfaces médianes pour chaque solide
1683       l_solides_m = list()
1684       for solide in l_solides:
1685         erreur, message = self.face_mediane_solide (geompy, gst, solide)
1686         if erreur:
1687           break
1688         l_solides_m.append(solide)
1689       if erreur:
1690         break
1691
1692 # 8. Ménage des solides
1693
1694       if salome.sg.hasDesktop():
1695         self._menage_solides ( gst, l_solides, l_solides_m, type_selection, objet )
1696
1697 # 9. Informations sur les faces à problème
1698       if self.faces_pb_nb:
1699         if ( self.faces_pb_nb == 1 ):
1700           texte = "1 face pose"
1701         else:
1702           texte = "{} faces posent".format(self.faces_pb_nb)
1703         print ("{} problème.\n{}".format(texte,self.faces_pb_msg))
1704
1705 # 10. Final
1706       print ("Les fichiers CAO des surfaces sont dans le répertoire {}".format(self.rep_trav))
1707
1708       break
1709
1710     return erreur, message
1711
1712 #===========================  Fin de la méthode ==================================
1713
1714 #=========================== Début de la méthode =================================
1715
1716   def surf_fic_cao (self, ficcao):
1717     """Calcule la surface médiane pour un objet dans un fichier passé en argument
1718
1719 Entrées :
1720   :ficcao: fichier de l'objet à traiter
1721
1722 Sorties :
1723   :erreur: code d'erreur
1724   :message: message d'erreur
1725     """
1726
1727     nom_fonction = __name__ + "/surf_fic_cao"
1728     blabla = "\nDans {} :\n".format(nom_fonction)
1729
1730     if self._verbose_max:
1731       print (blabla)
1732
1733     erreur = 0
1734     message = ""
1735
1736     while not erreur :
1737
1738 # 1. Définition de la pièce
1739
1740       self.part_doc = model.activeDocument()
1741
1742 # 2. Import de la CAO
1743
1744       self.ficcao = ficcao
1745       print ("Traitement du fichier {}".format(self.ficcao))
1746
1747       erreur, message, objet = import_cao (self.part_doc, self.ficcao, self._verbose_max)
1748       if erreur:
1749         break
1750
1751 # 3. Calcul des surfaces
1752
1753       erreur, message = self.surf_objet_shaper ( objet.result().name(), objet.result().shapeType() )
1754
1755       if ( erreur and self._verbose_max ):
1756         print (blabla, message)
1757
1758       break
1759
1760     return erreur, message
1761
1762 #===========================  Fin de la méthode ==================================
1763
1764 #=========================== Début de la méthode =================================
1765
1766   def surf_objet_shaper (self, nom_objet, type_objet):
1767     """Calcule la surface médiane pour un objet SHAPER passé en argument
1768
1769 Entrées :
1770   :nom_objet: nom de l'objet à traiter
1771   :type_objet: type de l'objet à traiter "SOLID"/"COMPOUND"
1772
1773 Sorties :
1774   :erreur: code d'erreur
1775   :message: message d'erreur
1776     """
1777
1778     nom_fonction = __name__ + "/surf_objet_shaper"
1779     blabla = "\nDans {} :\n".format(nom_fonction)
1780
1781     if self._verbose_max:
1782       print (blabla)
1783
1784     erreur = 0
1785     message = ""
1786
1787     while not erreur :
1788
1789 # 1. Transfert vers GEOM
1790 # 1.1. Le départ est-il un fichier au format step ?
1791       deja_step = False
1792       if self.ficcao is not None:
1793         laux = self.ficcao.split(".")
1794         fmt_cao_0 = decode_cao (laux[-1])
1795         if ( fmt_cao_0 == "stp" ):
1796           deja_step = True
1797       if self._verbose_max:
1798         print ("deja_step = {}".format(deja_step))
1799
1800 # 1.1. Exportation si le fichier de départ n'est pas au format step
1801       if deja_step:
1802         fichier = self.ficcao
1803       else:
1804         fichier = tempfile.mkstemp(suffix=".stp")[1]
1805         if self._verbose_max:
1806           print ('fichier    = {}'.format(fichier))
1807           print ('nom_objet  = {}'.format(nom_objet))
1808           print ('type_objet = {}'.format(type_objet))
1809         export = model.exportToFile(self.part_doc, fichier, [model.selection(type_objet, nom_objet)])
1810         export.execute(True)
1811         model.do()
1812         taille = os.path.getsize(fichier)
1813         if ( taille <= 0 ):
1814           message = "Export de SHAPER vers GEOM impossible pour l'objet '{}' de type '{}'\n".format(nom_objet, type_objet)
1815           message += "Le fichier {} est de taille {}".format(fichier,taille)
1816           erreur = 2
1817           break
1818
1819 # 1.2. Importation
1820       geompy = geomBuilder.New()
1821       objet = geompy.ImportSTEP(fichier, False, True)
1822       geompy.addToStudy( objet, nom_objet )
1823       if not deja_step:
1824         os.remove(fichier)
1825
1826 # 2. Traitement de l'objet GEOM correspondant
1827       erreur, message = self._traitement_objet ( 2, objet )
1828
1829       if ( erreur and self._verbose_max ):
1830         print (blabla, message)
1831
1832       break
1833
1834     return erreur, message
1835
1836 #===========================  Fin de la méthode ==================================
1837
1838 #=========================== Début de la méthode =================================
1839
1840   def surf_objet_geom (self, objet):
1841     """Calcule la surface médiane pour un objet GEOM passé en argument
1842
1843 Entrées :
1844   :objet: l'objet à traiter
1845
1846 Sorties :
1847   :erreur: code d'erreur
1848   :message: message d'erreur
1849     """
1850
1851     nom_fonction = __name__ + "/surf_objet_geom"
1852     blabla = "\nDans {} :\n".format(nom_fonction)
1853
1854     if self._verbose_max:
1855       print (blabla)
1856
1857     erreur, message = self._traitement_objet ( 1, objet )
1858
1859     if ( erreur and self._verbose_max ):
1860       print (blabla, message)
1861
1862     return erreur, message
1863
1864 #===========================  Fin de la méthode ==================================
1865
1866 #=========================== Début de la méthode =================================
1867
1868   def lancement (self):
1869
1870     """Lancement
1871
1872 Sorties :
1873   :erreur: code d'erreur
1874   :message: message d'erreur
1875     """
1876
1877     nom_fonction = __name__ + "/lancement"
1878     blabla = "\nDans {} :\n".format(nom_fonction)
1879
1880     if self._verbose_max:
1881       print (blabla)
1882
1883     erreur, message = self._traitement_objet ( )
1884
1885     if ( erreur and self._verbose_max ):
1886       print (blabla, message)
1887
1888     return erreur, message
1889
1890 #===========================  Fin de la méthode ==================================
1891
1892 #==========================  Fin de la classe ====================================
1893
1894 #==================================================================================
1895 # Lancement
1896 #==================================================================================
1897
1898 if __name__ == "__main__" :
1899
1900 # 1. Options
1901
1902   L_OPTIONS = list()
1903   #L_OPTIONS.append("-h")
1904   #L_OPTIONS.append("-v")
1905   #L_OPTIONS.append("-vmax")
1906   #L_OPTIONS.append("-no_menage")
1907   #L_OPTIONS.append("-retour_shaper")
1908
1909 # 2. Lancement de la classe
1910
1911   #print ("L_OPTIONS :", L_OPTIONS)
1912   SURFACE_MEDIANE = SurfaceMediane(L_OPTIONS)
1913   if SURFACE_MEDIANE.affiche_aide_globale:
1914     sys.stdout.write(SURFACE_MEDIANE.__doc__+"\n")
1915   else:
1916     ERREUR, MESSAGE_ERREUR = SURFACE_MEDIANE.lancement()
1917     if ERREUR:
1918       MESSAGE_ERREUR += "\n Code d'erreur : %d\n" % ERREUR
1919       sys.stderr.write(MESSAGE_ERREUR)
1920
1921   del SURFACE_MEDIANE
1922
1923   #sys.exit(0)