Salome HOME
Copyright update 2022
[modules/shaper.git] / src / PythonAddons / macros / pipeNetwork / feature.py
1 # -*- coding: utf-8 -*-
2 # Copyright (C) 2016-2022  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
21 """pipeNetwork Feature
22 Author: Nathalie GORE - Gérald NICOLAS
23 Remarque : la fonction de partitionnement pour un futur maillage en hexa est désactivée.
24 """
25
26 __revision__ = "V02.17"
27
28 from salome.shaper import model
29 import ModelAPI
30 from GeomAPI import *
31
32 import numpy as np
33
34 # Si erreur :
35
36 def raiseException(texte):
37     """En cas d'erreur"""
38     print (texte)
39
40 def printverbose (texte, nb=0, verbose=False):
41     """Impression controlée"""
42     if verbose:
43         if nb:
44             texte_a = ""
45             for _ in range(nb):
46                 texte_a += "="
47             print (texte_a)
48         print (texte)
49
50 class pipeNetwork(model.Feature):
51     """Creation of a network of pipes"""
52     lfeatures = list()
53     ledges = list()
54     folder = None
55     isHexa = False
56     twopartwo = "2par2"
57     parligne = "par_ligne"
58     radius = 0.5
59     infoPoints = dict()
60     connectivities = dict()
61
62     _verbose = False
63     _verbose_max = False
64
65 # Feature initializations
66
67     def __init__(self):
68         """x.__init__(...) initializes x; see x.__class__.__doc__ for signature"""
69         model.Feature.__init__(self)
70
71     @staticmethod
72     def ID():
73         """Return Id of the Feature."""
74         return "pipeNetwork"
75
76     @staticmethod
77     def FILE_ID():
78         """Returns ID of the file select parameter."""
79         return "file_path"
80
81     #@staticmethod
82     #def HEXAS_ID():
83         #"""Returns ID of the radius parameter."""
84         #return "blocking"
85
86     def getKind(self):
87         """Override Feature.getKind()"""
88         return pipeNetwork.ID()
89
90
91 #====================================================================================
92 # Initialization of the dialog panel
93
94     def initAttributes(self):
95         """Override Feature.initAttributes()"""
96         # Creating the input argument of the feature
97         self.data().addAttribute(self.FILE_ID(), ModelAPI.ModelAPI_AttributeString_typeId())
98         #self.data().addAttribute(self.HEXAS_ID(), ModelAPI.ModelAPI_AttributeBoolean_typeId())
99
100 #====================================================================================
101 # Retrieve parent pipe
102
103     def decodingCode(self, code):
104         """decodingCode"""
105         splitCode = code.split(".")
106         if len(splitCode) <= 1:
107             previousCode = ""
108         else:
109             previousCode = code[:len(code)-len(splitCode[-1])-1]
110         return previousCode
111
112 #====================================================================================
113
114     def readNodeInfo(self, line):
115         """Lecture des noeuds
116
117 La ligne à décoder est formée des informations :
118 . l'identifiant du noeud
119 . si les coordonnées sont données en absolu : "-" suivi des 3 coordonnées
120 . si les coordonnées sont données en relatif : l'identifiant du noeud de départ, suivi des 3 coordonnées de la translation
121 Par défaut, on supposera que la connection est angulaire et que ce n'est pas une extrémité.
122         """
123         #print(line)
124         texte = line
125         splitLine = line.split()
126         if ( len(splitLine) != 5 ):
127             diagno = 1
128         elif splitLine[0] in self.infoPoints:
129             texte += "\nThis node was already declared."
130             diagno = 2
131         elif ( splitLine[1] not in self.infoPoints ) and ( splitLine[1] != "-" ):
132             texte += "\nThe starting point was not seen before."
133             diagno = 3
134         else:
135             diagno = 0
136             self.infoPoints[splitLine[0]] = dict()
137             self.infoPoints[splitLine[0]]["Ref"] = splitLine[1]
138             if splitLine[1] == "-":
139                 self.infoPoints[splitLine[0]]["X"] = float(splitLine[2])
140                 self.infoPoints[splitLine[0]]["Y"] = float(splitLine[3])
141                 self.infoPoints[splitLine[0]]["Z"] = float(splitLine[4])
142             else :
143                 self.infoPoints[splitLine[0]]["X"] = self.infoPoints[splitLine[1]]["X"] + float(splitLine[2])
144                 self.infoPoints[splitLine[0]]["Y"] = self.infoPoints[splitLine[1]]["Y"] + float(splitLine[3])
145                 self.infoPoints[splitLine[0]]["Z"] = self.infoPoints[splitLine[1]]["Z"] + float(splitLine[4])
146             printverbose ("Enregistrement du point ({},{},{})".format(self.infoPoints[splitLine[0]]["X"],self.infoPoints[splitLine[0]]["Y"],self.infoPoints[splitLine[0]]["Z"]), verbose=self._verbose)
147             self.infoPoints[splitLine[0]]["Fillet"] = "angular_connection"
148             self.infoPoints[splitLine[0]]["isEnd"] = False
149         #print ("Retour de readNodeInfo = {}".format(diagno))
150         return diagno, texte
151
152 #====================================================================================
153
154     def readConnectivity(self, line, method):
155         """Lecture des connectivités
156
157 La ligne à décoder est formée des informations :
158 . si la méthode est par ligne : la liste des identifiants des noeuds formant le trajet
159 . si la méthode est 2 par 2 : chaque tronçon est décrit par les identifiants des 2 noeuds
160 Par défaut, on supposera que la méthode est par ligne.
161         """
162         splitLine = line.split()
163         printverbose ("Enregistrement du tronçon : {}".format(splitLine),verbose=self._verbose)
164         diagno = 0
165         if ( method == self.twopartwo ):
166             if self.connectivities:
167                 # Recherche si le tronçon existe déjà ou s'il est nouveau
168                 existe = False
169                 for key, val in self.connectivities.items():
170                     #print(key, " ******* {}".format(val))
171                     if val['chainage'][-1] == splitLine[0]:
172                         # Le tronçon existe
173                         val['chainage'].append(splitLine[1])
174                         #print("On complète le tronçon")
175                         existe = True
176                         break
177                 # Le tronçon n'existe pas
178                 if not existe:
179                     #print("On démarre un nouveau tronçon - Cas 2")
180                     self.newConnectivity(splitLine[0], splitLine)
181             else :
182                 #print("On démarre un nouveau tronçon - Cas 1")
183                 self.newConnectivity(splitLine[0], splitLine)
184         else :
185             self.newConnectivity(splitLine[0], splitLine)
186         #print ("Retour de readConnectivity = {}".format(diagno))
187
188         return diagno
189
190 #====================================================================================
191
192     def correctConnectivity(self):
193         """Correction des connectivités pour tenir compte de points alignés
194
195 Si 3 points sont alignés sur une ligne et qu'aucune ligne ne part du point central,
196 il faut scinder la ligne au niveau de ce point pour traiter correctement la suite : on se mettrait
197 à créer un plan avec ces 3 points alignés et tout s'effondre ensuite.
198         """
199         while True:
200             # On explore toutes les lignes et on cherche un cas où sur une ligne 3 points consécutifs sont alignés
201             for _, value in self.connectivities.items():
202                 # Sur cette ligne, a-t-on 3 points consécutifs alignés ?
203                 modif = self.correctConnectivity_a(value["chainage"])
204                 # Si on a modifié la description des connectivités, on recommence l'analyse
205                 if modif:
206                     break
207             # Si plus rien n'a été modifié, c'est fini
208             if not modif:
209                 break
210
211     def correctConnectivity_a(self, l_noeuds):
212         """On explore toutes les lignes et on cherche un cas où sur une ligne 3 points consécutifs sont alignés
213
214 Entrées :
215   :l_noeuds: liste des noeuds de la ligne
216
217 Sorties :
218   :modif: on a modifié ou non la description des lignes
219         """
220         modif = False
221         nb_points = len(l_noeuds)
222         printverbose ("Analyse de {}".format(l_noeuds), verbose=self._verbose_max)
223         #print ("nb_points = {}".format(nb_points))
224
225         indice = 0
226         nb_test = nb_points - 2
227         for iaux in range(nb_test):
228             # Calcul de l'angle entre les 3 points de la séquence
229             vect = list()
230             #print ("({},{},{}".format(l_noeuds[iaux],l_noeuds[iaux+1],l_noeuds[iaux+2]))
231             for jaux in range(3):
232                 coox = self.infoPoints[l_noeuds[iaux+jaux]]["X"]
233                 cooy = self.infoPoints[l_noeuds[iaux+jaux]]["Y"]
234                 cooz = self.infoPoints[l_noeuds[iaux+jaux]]["Z"]
235                 vect.append(np.array((coox,cooy,cooz),np.float))
236             cosinus = np.dot(vect[1]-vect[0],vect[1]-vect[2])/(np.linalg.norm(vect[1]-vect[0])* np.linalg.norm(vect[1]-vect[2]))
237             #print ("cosinus = {}".format(cosinus))
238             # Si l'angle est plat, c'est que les 3 points sont alignés : on arrête... sauf si ce point est un départ d'une autre !
239             if ( (1.-np.abs(cosinus)) < 1.e-4 ):
240                 indice = iaux+1
241                 if l_noeuds[indice] not in self.connectivities:
242                     break
243                 else:
244                     indice = 0
245         # Si un angle plat a été trouvé, on scinde la ligne
246         if indice:
247             #print ("id_noeud_debut = {}, {}".format(l_noeuds[0], l_noeuds[:indice+1]))
248             #print ("id_noeud_new   = {}, {}".format(l_noeuds[indice], l_noeuds[indice:]))
249             self.newConnectivity(l_noeuds[0], l_noeuds[:indice+1])
250             self.newConnectivity(l_noeuds[indice], l_noeuds[indice:])
251             modif = True
252
253         return modif
254
255 #====================================================================================
256
257     def newConnectivity(self, key, value):
258         """newConnectivity"""
259         self.connectivities[key] = dict()
260         self.connectivities[key]['chainage'] = value
261
262 #====================================================================================
263
264     def readFillet(self, line):
265         """Décodage des caractéristiques de la connection entre deux tuyaux
266
267 La ligne est formée de deux informations :
268 . l'identifiant du noeud
269 . la caractérisation de la connection : "angular_connection" ou "radius=xxx"
270         """
271         splitLine = line.split()
272         if len(splitLine) != 2:
273             print(line)
274             diagno = 1
275         elif not splitLine[0] in self.infoPoints:
276             print(line)
277             diagno = 2
278         elif splitLine[1] == "angular_connection":
279             self.infoPoints[splitLine[0]]["Fillet"] = "angular_connection"
280             diagno = 0
281         elif splitLine[1][:7] == "radius=":
282             self.infoPoints[splitLine[0]]["Fillet"] = "radius"
283             self.infoPoints[splitLine[0]]["Radius"] = float(splitLine[1][7:])
284             diagno = 0
285         else:
286             print(line)
287             diagno = 3
288         #print ("Retour de readFillet = {}".format(diagno))
289         return diagno
290
291 #====================================================================================
292
293     def retrieveSubshapesforWire(self, copy, key, ind):
294         """retrieveSubshapesforWire"""
295         exp = GeomAPI_ShapeExplorer(copy.defaultResult().shape(), GeomAPI_Shape.EDGE)
296
297         end = False
298         subshapesForWire = list()
299         currentInd = 0
300         isPipe = True
301         #print("Current chainage : {}".format(self.connectivities[key]['chainage'][ind:]))
302         #print("Indice de démarrage = {}".format(ind))
303
304         while exp.more() and not end :
305             #print("Analyse Edge n°", currentInd)
306             #print(" => ", self.connectivities[key]['chainage'][currentInd], " - ", self.connectivities[key]['chainage'][currentInd+1])
307             #print(" ==> ", self.infoPoints[self.connectivities[key]['chainage'][currentInd]]["isAngular"], " - ", self.infoPoints[self.connectivities[key]['chainage'][currentInd+1]]["isAngular"])
308             cur = exp.current().edge()
309             if currentInd < ind:
310                 #print("Edge non prise en compte")
311                 #print("test si fillet : ", currentInd+1, ind, self.infoPoints[self.connectivities[key]['chainage'][currentInd+1]]["Fillet"])
312                 if currentInd+1 <= ind and self.infoPoints[self.connectivities[key]['chainage'][currentInd+1]]["Fillet"] == "radius" and not self.infoPoints[self.connectivities[key]['chainage'][currentInd]]["isAngular"]:
313                     #print("Fillet à ne pas prendre en compte")
314                     exp.next()
315                     cur = exp.current().edge()
316             else :
317                 subshapesForWire.append(model.selection(copy.defaultResult(), cur))
318                 #print("Mode normal - Nb segments dans le wire : {}".format(len(subshapesForWire)))
319                 # Cas du fillet : on récupère l'edge suivante
320                 if self.infoPoints[self.connectivities[key]['chainage'][currentInd]]["isAngular"] or self.infoPoints[self.connectivities[key]['chainage'][currentInd+1]]["isAngular"]:
321                     end = True
322                     #print("Nb segments dans le wire : {}".format(len(subshapesForWire)))
323                     if ( len(subshapesForWire) == 1 ):
324                         #print("Coude droit en cours")
325                         currentInd += 1
326                         isPipe = False
327                     else :
328                         #print("Coude droit à venir")
329                         subshapesForWire = subshapesForWire[:-1]
330                 elif self.infoPoints[self.connectivities[key]['chainage'][currentInd]]["Fillet"] == "radius":
331                     #print("Ajout edge start Fillet")
332                     exp.next()
333                     cur = exp.current().edge()
334                     subshapesForWire.append(model.selection(copy.defaultResult(), cur))
335                     #currentInd = currentInd+1
336                     #print("Mode Fillet - Nb segments dans le wire : {}".format(len(subshapesForWire)))
337                 elif self.infoPoints[self.connectivities[key]['chainage'][currentInd+1]]["Fillet"] == "radius":
338                     #print("Ajout edge end Fillet")
339                     exp.next()
340                     cur = exp.current().edge()
341                     subshapesForWire.append(model.selection(copy.defaultResult(), cur))
342                     #print("Mode Fillet - Nb segments dans le wire : {}".format(len(subshapesForWire)))
343                 else :
344                     if self.infoPoints[self.connectivities[key]['chainage'][currentInd+1]]["isEnd"]:
345                         #print("Fin détecte")
346                         currentInd = currentInd+1
347                         end = True
348                     #else :
349                         #print("Branchement")
350             if not end:
351                 currentInd = currentInd+1
352             exp.next()
353             #print("End = {} {}".format(end,self.connectivities[key]['chainage'][currentInd]))
354
355         return subshapesForWire, currentInd, isPipe, self.connectivities[key]['chainage'][currentInd]
356
357 #====================================================================================
358
359     def retrieveLastElement(self, obj, typeOfElement):
360         """retrieveLastElement"""
361         exp = GeomAPI_ShapeExplorer(obj.defaultResult().shape(), typeOfElement)
362         while exp.more():
363             cur = None
364             if typeOfElement == GeomAPI_Shape.VERTEX :
365                 cur = exp.current().vertex()
366             elif typeOfElement == GeomAPI_Shape.EDGE :
367                 cur = exp.current().edge()
368             elif typeOfElement == GeomAPI_Shape.FACE :
369                 cur = exp.current().face()
370             elif typeOfElement == GeomAPI_Shape.SOLID :
371                 cur = exp.current().solid()
372             if cur is not None:
373                 exp.next()
374                 cur = model.selection(obj.defaultResult(), cur)
375         return cur
376
377 #====================================================================================
378
379     def retrieveFirstElement(self, obj, typeOfElement):
380         """retrieveFirstElement"""
381         exp = GeomAPI_ShapeExplorer(obj.defaultResult().shape(), typeOfElement)
382         cur = None
383         if typeOfElement == GeomAPI_Shape.VERTEX :
384             cur = exp.current().vertex()
385         elif typeOfElement == GeomAPI_Shape.EDGE :
386             cur = exp.current().edge()
387         elif typeOfElement == GeomAPI_Shape.FACE :
388             cur = exp.current().face()
389         elif typeOfElement == GeomAPI_Shape.SOLID :
390             cur = exp.current().solid()
391         if cur is not None:
392             exp.next()
393             cur = model.selection(obj.defaultResult(), cur)
394         return cur
395
396 #====================================================================================
397
398     def createPipe(self, part, connectivityInfos):
399         """createPipe"""
400         lPipes = list()
401         startFace = None
402         fuse = None
403         for ind in range(len(connectivityInfos['paths'])):
404             printverbose ("Step = {}".format(ind), 80, verbose=self._verbose_max)
405             if ind == 0:
406                 startFace = connectivityInfos['sketch']
407             if connectivityInfos['isPipe'][ind] :
408                 pipe = model.addPipe(part, [startFace], connectivityInfos['paths'][ind].result())
409             else :
410                 # recherche du plan
411                 if self.infoPoints[connectivityInfos['ends'][ind]]['isAngular']:
412                     pipe = model.addExtrusion(part, [startFace], model.selection(), self.infoPoints[connectivityInfos['ends'][ind]]['plane'], 0, model.selection(), 0, "Faces|Wires")
413                 else :
414                     # le plan cible n'existe pas
415                     edge = model.addAxis(part, self.infoPoints[connectivityInfos['starts'][ind]]['point'], self.infoPoints[connectivityInfos['ends'][ind]]['point'])
416                     edge.execute(True)
417                     self.lfeatures.append(edge)# self.retrieveFirstElement(connectivityInfos['paths'][ind], GeomAPI_Shape.EDGE)
418                     self.ledges.append(edge)
419                     point = self.retrieveLastElement(connectivityInfos['paths'][ind], GeomAPI_Shape.VERTEX)
420                     plane = model.addPlane(part, edge.result(), point, True)
421                     plane.execute(True)
422                     self.lfeatures.append(plane)
423                     pipe = model.addExtrusion(part, [startFace], edge.result(), plane.result(), 0, model.selection(), 0, "Faces|Wires")
424             pipe.execute(True)
425             self.lfeatures.append(pipe)
426             lPipes.append(pipe.result())
427             if ( ind < len(connectivityInfos['paths'])-1 ):
428                 copy = model.addCopy(part, [model.selection(pipe.defaultResult())], 1)
429                 copy.execute(True)
430                 self.lfeatures.append(copy)
431                 startFace = self.retrieveLastElement(copy, GeomAPI_Shape.FACE)
432
433         if len(lPipes) > 1 :
434             fuse = model.addFuse(part, lPipes, False)
435             fuse.execute(True)
436             self.lfeatures.append(fuse)
437         else :
438             return pipe
439         return fuse
440
441 #==========================================================
442
443 #==========================================================
444 # Création des différents éléments
445     def createPoints(self, part):
446         """Création des points
447
448 Le point est créé en tant qu'objet de construction avec ses coordonnées.
449 Il est nommé conformément au texte donné dans le fichier de données. Cela n'a qu'un intérêt graphique mais agréable en débogage.
450 """
451         print("========================= Création des noeuds ============================")
452         for key, value in self.infoPoints.items():
453             printverbose ("Noeud : '{}'".format(key), verbose=self._verbose)
454             point = model.addPoint(part, value['X'], value['Y'], value['Z'])
455             point.execute(True)
456             point.setName(key)
457             point.result().setName(key)
458             self.lfeatures.append(point)
459             value["point"] = point.result()
460
461     def createPolylines(self, part):
462         """Création des polylines
463
464 La polyligne est créée en tant que résultat en enchaînant ses points.
465 Elle est nommée conformément aux 1er et dernier noeud. Cela n'a qu'un intérêt graphique mais agréable en débogage.
466 """
467         print("========================= Création des polylines =========================")
468         for key, value in self.connectivities.items():
469             printverbose ("Ligne : {}".format(value['chainage']), verbose=self._verbose)
470             lPoints = list()
471             for id_noeud in value['chainage']:
472                 lPoints.append(self.infoPoints[id_noeud]["point"])
473                 id_noeud_fin = id_noeud
474             polyline = model.addPolyline3D(part, lPoints, False)
475             polyline.execute(True)
476             nom = "L_{}_{}".format(key,id_noeud_fin)
477             polyline.setName(nom)
478             polyline.result().setName(nom)
479             self.lfeatures.append(polyline)
480             value["polyline"] = polyline
481
482     def createFillets(self, part):
483         """Création des fillets
484
485 Le fillet est créé en tant que résultat.
486 Il est nommé conformément au noeud d'application. Cela n'a qu'un intérêt graphique mais agréable en débogage.
487 """
488         print("========================= Création des fillets ===========================")
489         for key, value in self.connectivities.items():
490             printverbose ("Examen de la ligne démarrant sur le noeud '{}'".format(key), verbose=self._verbose)
491             # recherche des noeuds fillets
492             value["fillet"] = value["polyline"]
493             for id_noeud in value['chainage']:
494                 if self.infoPoints[id_noeud]["Fillet"] == "radius" :
495                     printverbose ("\tFillet sur le noeud '{}'".format(id_noeud), verbose=self._verbose)
496                     fillet1D = model.addFillet(part, [model.selection("VERTEX", (self.infoPoints[id_noeud]["X"],self.infoPoints[id_noeud]["Y"],self.infoPoints[id_noeud]["Z"]))], self.infoPoints[id_noeud]["Radius"])
497                     fillet1D.execute(True)
498                     nom = "F_{}".format(id_noeud)
499                     fillet1D.setName(nom)
500                     fillet1D.result().setName(nom)
501                     self.lfeatures.append(fillet1D)
502                     value["fillet"] = fillet1D
503
504 #==========================================================
505
506     def searchRightConnections(self, part):
507         """Recherche des coudes droits"""
508         print("========================= Recherche des coudes droits ====================")
509         for key, value in self.connectivities.items():
510             printverbose ("Examen de la ligne démarrant sur le noeud '{}'".format(key), verbose=self._verbose)
511             # recherche des noeuds fillets
512             for ind, id_noeud in enumerate(value['chainage']):
513                 printverbose ("\tNoeud '{}' : {}".format(id_noeud,self.infoPoints[id_noeud]["Fillet"]), verbose=self._verbose)
514                 if ( ( ind == 0 ) or ( ind == len(value['chainage'])-1 ) ):
515                     self.infoPoints[id_noeud]["isAngular"] = False
516                 else :
517                     if self.infoPoints[id_noeud]["Fillet"] == "radius" :
518                         self.infoPoints[id_noeud]["isAngular"] = False
519                     else :
520                         if id_noeud in self.connectivities:
521                             self.infoPoints[id_noeud]["isAngular"] = False
522                         else :
523                             self.infoPoints[id_noeud]["isAngular"] = True
524                             # Axe d'extrusion
525                             #print(ind-1, ind, ind+1)
526                             printverbose ("\t\tCréation du plan passant par les points : ('{}','{}','{}')".format(value["chainage"][ind-1], id_noeud, value["chainage"][ind+1]), verbose=self._verbose)
527                             #print(self.infoPoints[value["chainage"][ind-1]]["point"])
528
529                             tmpPlane = model.addPlane(part, self.infoPoints[value["chainage"][ind-1]]["point"], self.infoPoints[id_noeud]["point"], self.infoPoints[value["chainage"][ind+1]]["point"])
530                             tmpPlane.execute(True)
531                             self.lfeatures.append(tmpPlane)
532                             axis =  model.addAxis(part, tmpPlane.result(), self.infoPoints[id_noeud]["point"])
533                             axis.execute(True)
534                             self.lfeatures.append(axis)
535                             self.infoPoints[id_noeud]["axis"] = axis.result()
536
537                             # Edge à extruder
538                             tmpEdge = model.addEdge(part, self.infoPoints[id_noeud]["point"], self.infoPoints[value["chainage"][ind+1]]["point"])
539                             tmpEdge.execute(True)
540                             self.lfeatures.append(tmpEdge)
541                             length = model.measureDistance(part, self.infoPoints[value["chainage"][ind-1]]["point"], self.infoPoints[id_noeud]["point"])
542                             point =  model.addPoint(part, tmpEdge.result(), length, False, False)
543                             point.execute(True)
544                             self.lfeatures.append(point)
545                             baseEdge = model.addEdge(part, self.infoPoints[value["chainage"][ind-1]]["point"], point.result())
546                             baseEdge.execute(True)
547                             self.lfeatures.append(baseEdge)
548                             middlePoint = model.addPoint(part, baseEdge.result(), 0.5, True, False)
549                             middlePoint.execute(True)
550                             self.lfeatures.append(middlePoint)
551                             Edge = model.addEdge(part, self.infoPoints[id_noeud]["point"], middlePoint.result())
552                             Edge.execute(True)
553                             self.lfeatures.append(Edge)
554                             self.ledges.append(Edge)
555
556                             # Extrusion
557                             plane = model.addExtrusion(part, [Edge.result()], axis.result(), 10, 0)
558                             plane.execute(True)
559                             self.lfeatures.append(plane)
560                             self.infoPoints[id_noeud]["plane"] = plane.result()
561
562     def createPaths(self, part):
563         """Création des paths pour le pipeNetwork"""
564         print("========================= Création des paths =============================")
565         for key, value in self.connectivities.items():
566             printverbose ("Ligne démarrant sur le noeud '{}'".format(key), verbose=self._verbose)
567             # recherche des noeuds fillets
568             value["paths"] = list()
569             value["isPipe"] = list()
570             value["starts"] = list()
571             value["ends"] = list()
572             ind = 0
573             copy = value['fillet']
574             while ind < len(value['chainage'])-1:
575                 value["starts"].append(self.connectivities[key]['chainage'][ind])
576                 objectsForPath, ind, isPipe, end_noeud = self.retrieveSubshapesforWire(copy, key, ind)
577                 if self._verbose_max:
578                     print("************************* ind = {}".format(ind))
579                     print("************************* objectsForPath = {}".format(objectsForPath))
580                 path = model.addWire(part, objectsForPath, False)
581                 path.execute(True)
582                 self.lfeatures.append(path)
583                 value["paths"].append(path)
584                 value["isPipe"].append(isPipe)
585                 value["ends"].append(end_noeud)
586                 if ind < len(value['chainage'])-1:
587                     copy = model.addCopy(part, [model.selection(copy.defaultResult())], 1)
588                     copy.execute(True)
589                     self.lfeatures.append(copy)
590
591     def createSketches(self, part):
592         """Création des sketchs"""
593         print("========================= Création des sketchs =========================")
594         for key, value in self.connectivities.items():
595             printverbose ("Ligne démarrant sur le noeud '{}'".format(key), verbose=self._verbose)
596             # Creating sketch
597             edge = model.addEdge(part, self.infoPoints[value["chainage"][0]]["point"], self.infoPoints[value["chainage"][1]]["point"])
598             edge.execute(True)
599             self.lfeatures.append(edge)
600             plane = model.addPlane(part, edge.result(), self.infoPoints[value["chainage"][0]]["point"], True)
601             plane.execute(True)
602             self.lfeatures.append(plane)
603             sketch = model.addSketch(part, plane.result())
604             sketch.execute(True)
605             self.lfeatures.append(sketch)
606             SketchProjection = sketch.addProjection(self.infoPoints[value["chainage"][0]]["point"], False)
607             SketchProjection.execute(True)
608             SketchPoint = SketchProjection.createdFeature()
609             SketchPoint.execute(True)
610             SketchCircle = sketch.addCircle(0,0,self.radius)
611             SketchCircle.execute(True)
612             sketch.setCoincident(SketchPoint.result(), SketchCircle.center())
613             sketch.setRadius(SketchCircle.results()[1], self.radius)
614             sketch.execute(True)
615             model.do()
616             value["sketch"] = sketch.result()
617
618     def createPipes(self, part, nameRes):
619         """Création des pipes"""
620         print("========================= Création des pipes =========================")
621         for key, value in self.connectivities.items():
622             printverbose ("Ligne démarrant sur le noeud '{}'".format(key), verbose=self._verbose)
623             pipe = self.createPipe(part, value)
624             value["pipe"] = pipe.result()
625
626         # Fusion des pipes
627         print("========================= Fusion des pipes =========================")
628         lPipes = list()
629         for key, value in self.connectivities.items():
630             lPipes.append(value["pipe"])
631         if len(lPipes) > 1 :
632             fuse = model.addFuse(part, lPipes, False)
633             fuse.execute(True)
634             fuse.setName(nameRes)
635             fuse.result().setName(nameRes)
636         else:
637             lPipes[0].setName(nameRes)
638
639 #==========================================================
640
641     def print_info (self, verbose, comment=""):
642         """Impression si verbose est valide. Avec un comentaire introductif éventuellement."""
643         if verbose:
644             texte = "\n+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"
645             texte += "\nRécapitulatif"
646             if comment:
647                 texte += " {}".format(comment)
648             texte += "\ninfos points ="
649             for key, value in self.infoPoints.items():
650                 texte += "\n{} : {}".format(key, value)
651             texte += "\nconnectivities ="
652             for key, value in self.connectivities.items():
653                 texte += "\n{} : {}".format(key, value)
654             texte += "\n+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"
655             print(texte+"\n")
656
657 #==========================================================
658
659 # Execution of the Import
660
661     def execute(self):
662         """F.execute() -- execute the Feature"""
663         # Retrieving the user input
664         apath    = self.string(self.FILE_ID())
665
666         filepath = apath.value()
667         if filepath != "" :
668
669             # A. Initialisation
670             part = model.activeDocument()
671
672             if self.lfeatures :
673                 for feature in self.lfeatures:
674                     part.removeFeature(feature.feature())
675                 self.lfeatures = list()
676                 model.removeFolder(self.folder)
677
678             self.infoPoints = dict()
679             self.connectivities = dict()
680
681             from os.path import basename
682             filename = basename(filepath)
683             if ( "." in filename ):
684                 laux= filename.split(".")
685                 nameRes = laux[0]
686                 for saux in laux[1:-1]:
687                     nameRes+="."+saux
688             else:
689                 nameRes = filename
690
691             # Creating the construction points in the current document
692
693             # B. Traitement du fichier
694             print ("\n=============== Traitement du fichier {}".format(filepath))
695             error = 0
696             while True:
697
698                 # B.1. Lecture du fichier
699                 with open(filepath) as afile:
700                     summary = 0
701                     method = self.parligne
702                     for line in afile:
703                         printverbose  (line[:-1], verbose=self._verbose_max)
704
705                         # B.1.1. Repérages
706                         if line == "\n":
707                             printverbose ("========================= Saut de ligne =========================", verbose=self._verbose_max)
708                             continue
709                         if line[0] == "#" or line[:3] == "...":
710                             continue
711                         if summary == 0 and line[:-1] == "nodes section" :
712                             printverbose ("========================= Lecture des coordonnées ==============================", 80, verbose=self._verbose)
713                             summary = 1
714                             continue
715                         if summary == 1 and line[:-1] == "connectivity section" :
716                             printverbose ("========================= Lecture de la connectivité ===========================", 80, verbose=self._verbose)
717                             summary = 2
718                             continue
719                         if summary == 2 and line[:6] == "method" :
720                             printverbose ("===================== summary == 2 method =========================", verbose=self._verbose_max)
721                             method = line[7:-1]
722                             printverbose ("Méthode : '{}'".format(method), verbose=self._verbose)
723                             if method not in (self.twopartwo, self.parligne):
724                                 raiseException("Problem with type of connectivity")
725                             continue
726                         if summary == 2 and line[:-1] == "fillets section" :
727                             printverbose ("========================= Lecture des fillets =========================", 80, verbose=self._verbose)
728                             summary = 3
729                             continue
730
731                         # B.1.2. Enregistrement des données
732                         if summary == 1:
733                             printverbose ("===================== summary == 1 =========================", 80, verbose=self._verbose_max)
734                             diagno, texte = self.readNodeInfo(line[:-1])
735                             if diagno:
736                                 raiseException("{}\nProblem with description of nodes.".format(texte))
737                             continue
738                         if summary == 2:
739                             printverbose ("===================== summary == 2 =========================", 80, verbose=self._verbose_max)
740                             diagno = self.readConnectivity(line[:-1],method)
741                             if diagno:
742                                 raiseException("Problem with description of connectivities")
743                             continue
744                         if summary == 3:
745                             printverbose ("===================== summary == 3 =========================", 80, verbose=self._verbose_max)
746                             diagno = self.readFillet(line[:-1])
747                             if diagno:
748                                 raiseException("Problem with description of fillets")
749                             continue
750
751                         printverbose ("===================== Rien =========================", 80, verbose=self._verbose_max)
752                         if diagno:
753                             error = diagno
754                             break
755
756                 if error:
757                     break
758
759
760                 # B.2. Gestion des points alignés
761                 self.print_info (self._verbose_max, "avant gestion des points alignés")
762
763                 self.correctConnectivity ()
764
765                 # B.3. Signalement de la fin d'une chaine
766                 for _, value in self.connectivities.items():
767                     self.infoPoints[value['chainage'][-1]]["isEnd"] = True
768
769                 self.print_info (self._verbose_max, "avant les création de points, etc.")
770
771                 # B.4. Creation des points
772                 self.createPoints(part)
773
774                 # B.5. Creation des polylines
775                 self.createPolylines(part)
776
777                 # B.6. Creation des fillets
778                 self.createFillets(part)
779
780                 # B.7. Recherche des coudes droits
781                 self.searchRightConnections(part)
782
783                 # B.8. Création des paths pour le pipeNetwork
784                 self.createPaths(part)
785
786                 # B.9. Création des sketchs pour le pipeNetwork
787                 self.createSketches(part)
788
789                 self.print_info (self._verbose_max, "après la création des sketchs")
790
791                 # B.10. Création des pipes
792                 self.createPipes(part, nameRes)
793
794                 # B.11. Dossier pour les opérations internes
795                 print("========================= Mise en dossier =========================")
796                 self.folder = model.addFolder(part, self.lfeatures[0], self.lfeatures[-1])
797                 self.folder.setName("{}_inter".format(nameRes))
798
799                 # B.12. Ménage des résultats inutiles
800                 print("========================= Ménage des résultats inutiles ==================")
801                 laux = list()
802                 for iaux in range(len(self.ledges)):
803                     laux.append(model.selection("EDGE", "Edge_{}_1".format(iaux)))
804                 _ = model.addRemoveResults(part, laux)
805
806                 break
807
808             return
809
810     def isMacro(self):
811         """Override Feature.initAttributes().
812         F.isMacro() -> True
813
814         pipeNetwork feature is macro: removes itself on the creation transaction
815         finish.
816         """
817         return False