Salome HOME
445cd5d73f28b47e3f14bb46b28a48dffcad52b0
[modules/smesh.git] / src / Tools / MacMesh / MacMesh / MacObject.py
1 class MacObject:
2         """ 
3         This represents a python class definition which contains 
4         all necessary information about the macro object being created
5         in Salome 
6         """
7
8         def __init__( self, ObjectType, GeoParameters, MeshParameters, **args ):
9                 """
10                 Initializes the macro object to be created, saves parameters inside of it, checks for neighboring objects,
11                 determines meshing parameters if necessary and finally launches the generation process.
12                 """
13                 import Config,GenFunctions
14                 if Config.debug : print "Initializing object No. " + str(len(Config.ListObj)+1)
15
16                 if 'publish' in args :
17                         if args['publish']==0 : Config.publish = 0
18                         else : Config.publish = 1
19                 else : Config.publish = 1
20                 
21                 if 'groups' in args :
22                         self.GroupNames = args['groups']
23                         for group in args['groups'] :
24                                 if not(group in Config.Groups) and group : Config.Groups.append(group)
25                 else : self.GroupNames = [None, None, None, None]
26                 
27                 if ObjectType == 'NonOrtho':
28                         if not(len(GeoParameters)==4): print "Error: trying to construct a non-ortho object but the 4 constitutive vertices are not given!"
29                         else :
30                                 Xmin = min([GeoParameters[i][0] for i in range(4)])
31                                 Xmax = max([GeoParameters[i][0] for i in range(4)])
32                                 Ymin = min([GeoParameters[i][1] for i in range(4)])
33                                 Ymax = max([GeoParameters[i][1] for i in range(4)])                        
34                                 self.GeoPar = [(0.5*(Xmin+Xmax),0.5*(Ymin+Ymax)),(Xmax-Xmin,Ymax-Ymin)]
35                                 self.PtCoor = GenFunctions.SortPoints(GeoParameters)
36                 else:
37                         self.GeoPar = GeoParameters
38                         [Xmin,Ymin,Xmax,Ymax] = [ self.GeoPar[0][0]-0.5*self.GeoPar[1][0], self.GeoPar[0][1]-0.5*self.GeoPar[1][1] ] + [ self.GeoPar[0][0]+0.5*self.GeoPar[1][0], self.GeoPar[0][1]+0.5*self.GeoPar[1][1] ]
39                         self.PtCoor = [(Xmin,Ymin),(Xmax,Ymin),(Xmax,Ymax),(Xmin,Ymax)]      
40                 
41                 self.Type = ObjectType
42                 self.LowBound = [ self.GeoPar[0][0]-0.5*self.GeoPar[1][0], self.GeoPar[0][1]-0.5*self.GeoPar[1][1] ]
43                 self.UpperBound = [ self.GeoPar[0][0]+0.5*self.GeoPar[1][0], self.GeoPar[0][1]+0.5*self.GeoPar[1][1] ]
44                 self.MeshPar = MeshParameters
45                 self.GeoChildren = []
46                 self.GeoChildrenNames = []
47                 self.Mesh = []
48                 self.MeshGroups = []
49                 self.CheckInterfaces()
50                 if 'auto' in MeshParameters : self.AutoParam()
51                 if not(self.MeshPar[0]<0): self.Generate()
52                 else : 
53                         Config.ListObj.append(self)
54                         print("Aborting object creation\n ")
55
56         def Generate(self) :
57                 """
58                 This method generates the geometrical object with the corresponding mesh once all verifications (CheckInterfaces and AutoParam) 
59                 have been accomplished
60                 """
61                 import GenFunctions, Alarms, Config
62                 self = {'Box11'    : lambda : GenFunctions.Box11(self),
63                         'Box42'    : lambda : GenFunctions.Box42(self),
64                         'BoxAng32' : lambda : GenFunctions.BoxAng32(self),
65                         'CompBox'  : lambda : GenFunctions.CompBox(self),
66                         'CompBoxF' : lambda : GenFunctions.CompBoxF(self),
67                         'NonOrtho' : lambda : GenFunctions.NonOrtho(self),
68                         'QuartCyl' : lambda : GenFunctions.QuartCyl(self) }[self.Type]()
69
70                 if Config.debug : Alarms.Message(self.status)   # notification on the result of the generation algorithm
71                 
72
73         def CheckInterfaces(self):
74                 """
75                 This method searches for neighbours for the object being created and saves them inside the Config.Connections
76                 array. This array contains 4 entries per object corresponding to West, East, South, and North neighbours.
77                 Note that an object may have more than one neighbour for a given direction. 
78                 """
79                 import Alarms, Config
80                 from GenFunctions import AddIfDifferent
81                 from CompositeBox import FindCommonSide
82                 
83                 Config.Connections.append([(-1,),(-1,),(-1,),(-1,)])
84                 itemID = len(Config.ListObj)
85                 # In all cases except non ortho, PrincipleBoxes is unitary and contains the box in question
86                 # In the non-ortho case it contains all possible combinations of boxes with 3 vertices 
87                 PrincipleBoxes = self.PrincipleBoxes()
88                 for i, TestObj in enumerate(Config.ListObj): 
89                         SecondaryBoxes = TestObj.PrincipleBoxes()                               
90                         ConnX = 0
91                         ConnY = 0
92                         for Box0 in PrincipleBoxes:
93                                 for Box1 in SecondaryBoxes:
94                                         # Along X
95                                         CenterDis = abs(Box1[0][0]-Box0[0][0])
96                                         Extension = 0.5*(Box1[1][0]+Box0[1][0])
97                                         if CenterDis - Extension < -1e-7 : 
98                                                 ConnX = -1
99                                         elif CenterDis - Extension < 1e-7 :
100                                                 if not(FindCommonSide(self.DirBoundaries(2),TestObj.DirBoundaries(3))==[0,0]) and Box1[0][0] < Box0[0][0] : ConnX = 1
101                                                 elif not(FindCommonSide(self.DirBoundaries(3),TestObj.DirBoundaries(2))==[0,0]) and Box1[0][0] >= Box0[0][0]: ConnX = 2
102                                                 else : ConnX = 0
103                                                 
104                                         # Along Y
105                                         CenterDis = abs(Box1[0][1]-Box0[0][1])
106                                         Extension = 0.5*(Box1[1][1]+Box0[1][1])
107                                         if CenterDis - Extension < -1e-7 : 
108                                                 ConnY = -1
109                                         elif CenterDis - Extension < 1e-7 :
110                                                 if not(FindCommonSide(self.DirBoundaries(0),TestObj.DirBoundaries(1))==[0,0]) and Box1[0][1] < Box0[0][1] : ConnY = 1
111                                                 elif not(FindCommonSide(self.DirBoundaries(1),TestObj.DirBoundaries(0))==[0,0]) and Box1[0][1] >= Box0[0][1]: ConnY = 2
112                                                 else : ConnY = 0
113
114                                         if not (ConnX*ConnY == 0) :
115                                                 if max(ConnX,ConnY) == -1 and not('NonOrtho' in [self.Type,TestObj.Type]) : Alarms.Message(3)
116                                                 else:
117                                                         if ConnX == 1 and ConnY == -1:
118                                                                 if Config.Connections[i][1] == (-1,) : Config.Connections[i][1] = (itemID,)
119                                                                 else : Config.Connections[i][1] = AddIfDifferent(Config.Connections[i][1],itemID)
120                                                                 if Config.Connections[itemID][0] == (-1,) : Config.Connections[itemID][0] = (i,)
121                                                                 else : Config.Connections[itemID][0] = AddIfDifferent(Config.Connections[itemID][0],i)
122                                                         elif ConnX == 2 and ConnY == -1:
123                                                                 if Config.Connections[i][0] == (-1,) : Config.Connections[i][0] = (itemID,)
124                                                                 else : Config.Connections[i][0] = AddIfDifferent(Config.Connections[i][0],itemID)
125                                                                 if Config.Connections[itemID][1] == (-1,) : Config.Connections[itemID][1] = (i,)
126                                                                 else : Config.Connections[itemID][1] = AddIfDifferent(Config.Connections[itemID][1],i)
127                                                         elif ConnY == 1 and ConnX == -1:
128                                                                 if Config.Connections[i][3] == (-1,) : Config.Connections[i][3] = (itemID,)
129                                                                 else : Config.Connections[i][3] = AddIfDifferent(Config.Connections[i][3],itemID)
130                                                                 if Config.Connections[itemID][2] == (-1,) : Config.Connections[itemID][2] = (i,)
131                                                                 else : Config.Connections[itemID][2] = AddIfDifferent(Config.Connections[itemID][2],i)
132                                                         elif ConnY ==2 and ConnX == -1:
133                                                                 if Config.Connections[i][2] == (-1,) : Config.Connections[i][2] = (itemID,)
134                                                                 else : Config.Connections[i][2] = AddIfDifferent(Config.Connections[i][2],itemID)
135                                                                 if Config.Connections[itemID][3] == (-1,) : Config.Connections[itemID][3] = (i,)
136                                                                 else : Config.Connections[itemID][3] = AddIfDifferent(Config.Connections[itemID][3],i)
137
138         def AutoParam (self):
139                 """
140                 This method is called only if the 'auto' keyword is used inside the meshing algorithm. It is based on the 
141                 connection results per object and tries to find the correct parameters for obtaining a final compatible mesh
142                 between the objects already present and the one being created. If this is not possible, the method gives an error
143                 message.
144                 """
145                 import Alarms, Config, GenFunctions, CompositeBox
146                 MeshPar = [0,0,0,0]     # initialize the mesh parameter value to be used to -1
147                 [(X0,Y0),(DX,DY)] = self.GeoPar
148                 ObjectsInvolved = []
149                 for i, Conn in enumerate(Config.Connections[-1]):
150                         if not ( Conn == (-1,) ):   # Meaning that there is one or more neighbors on this direction
151                                 for ObjID in Conn : 
152                                         ToLook0 = [2,3,0,1][i]
153                                         ToLook1 = [3,2,1,0][i]
154                                         CommonSide =  CompositeBox.FindCommonSide(Config.ListObj[ObjID].DirBoundaries(ToLook1),self.DirBoundaries(ToLook0))
155                                         #print "Common Side is:", CommonSide
156                                         ToLook2 = [1,0,3,2][i]
157                                         #print "Full Side is:", CompositeBox.IntLen(Config.ListObj[ObjID].DirBoundaries(ToLook1))
158                                         #print "Full Segments on this direction are:", Config.ListObj[ObjID].DirectionalMeshParams[ToLook2]
159                                         RealSegments = round(Config.ListObj[ObjID].DirectionalMeshParams[ToLook2]*CompositeBox.IntLen(CommonSide)/CompositeBox.IntLen(Config.ListObj[ObjID].DirBoundaries(ToLook1)))
160                                         #print "RealSegments :", RealSegments
161                                         
162                                         MeshPar[i] = MeshPar[i] + RealSegments
163                                         ObjectsInvolved.append(ObjID+1)
164                 self.DirectionalMeshParams =  MeshPar
165                 self.MeshPar[0] = GenFunctions.CompatibilityTest(self)
166
167                 if self.MeshPar[0] < 0 : 
168                         Alarms.Message(4)
169                         if self.MeshPar[0] == -1 : print ("Problem encountered with object(s) no. "+str(ObjectsInvolved))
170                         elif self.MeshPar[0] == -2 : print ("This object has no neighbours !!!")
171
172         def Boundaries (self):
173                 """
174                 This method returns the global boundaries of the MacObject. [Xmin,Xmax,Ymin,Ymax]
175                 """
176                 Xmin = min([self.DirBoundaries(i)[0] for i in [0,1]])
177                 Xmax = max([self.DirBoundaries(i)[1] for i in [0,1]])
178                 Ymin = min([self.DirBoundaries(i)[0] for i in [2,3]])
179                 Ymax = max([self.DirBoundaries(i)[1] for i in [2,3]])
180                 
181                 return [Xmin,Xmax,Ymin,Ymax]
182                 
183         def DirBoundaries (self, Direction):
184                 """
185                 This method returns a single interval giving [Xmin,Xmax] or [Ymin,Ymax] according to the required direction.
186                 This works particularly well for nonorthogonal objects.
187                 Direction : [0,1,2,3] <=> [South, North, West, East]
188                 """
189                 PtCoor = self.PtCoor
190                 PtCoor.append(self.PtCoor[0])
191                 if type(Direction) is str :
192                         Dir = { 'South'  : lambda : 0,
193                                 'North'  : lambda : 1,
194                                 'West'   : lambda : 2,
195                                 'East'   : lambda : 3,}[Direction]()
196                 else : Dir = int(Direction)
197                          
198                 PtIndex  = [0,2,3,1][Dir]
199                 DirIndex = [0,0,1,1][Dir]
200                              
201                 return sorted([PtCoor[PtIndex][DirIndex],PtCoor[PtIndex+1][DirIndex]])
202         def DirVectors (self, Direction):
203                 """
204                 This method returns for a given object, the real vectors which define a given direction
205                 The interest in using this method is for non-orthogonal objects where the sides can be 
206                 deviated from the orthogonal basis vectors
207                 """
208                 if type(Direction) is str :
209                         Dir = { 'South'  : lambda : 0,
210                                 'North'  : lambda : 1,
211                                 'West'   : lambda : 2,
212                                 'East'   : lambda : 3,}[Direction]()
213                 else : Dir = int(Direction)
214                 PtCoor = self.PtCoor
215                 PtCoor.append(self.PtCoor[0])
216                 PtIndex  = [0,2,3,1][Dir]
217                 return [PtCoor[PtIndex+1][0]-PtCoor[PtIndex][0],PtCoor[PtIndex+1][1]-PtCoor[PtIndex][1],0.]
218                                 
219         def GetBorder (self, Criterion):
220                 import geompy, GenFunctions
221                 
222                 if type(Criterion) is str :
223                         Crit = {'South'  : lambda : 0,
224                                 'North'  : lambda : 1,
225                                 'West'   : lambda : 2,
226                                 'East'   : lambda : 3,}[Criterion]()
227                 else : Crit = int(Criterion)
228                 
229                 AcceptedObj = []
230                 if Crit < 4 :
231                         Boundaries = self.Boundaries()
232                         Research = {0 : lambda : [self.DirVectors(0),1,Boundaries[2]],
233                                     1 : lambda : [self.DirVectors(1),1,Boundaries[3]],
234                                     2 : lambda : [self.DirVectors(2),0,Boundaries[0]],
235                                     3 : lambda : [self.DirVectors(3),0,Boundaries[1]], }[Crit]()
236                                                             
237                         for i,ElemObj in enumerate(self.GeoChildren):
238                                 EdgeIDs = geompy.ExtractShapes(ElemObj,6)# List of Edge IDs belonging to ElemObj
239                                 for Edge in EdgeIDs:
240                                         if GenFunctions.IsParallel(Edge,Research[0]):
241                                                 if abs( geompy.PointCoordinates(geompy.GetVertexByIndex(Edge,0))[Research[1]] - Research[2] )< 1e-6 or abs( geompy.PointCoordinates(geompy.GetVertexByIndex(Edge,1))[Research[1]] - Research[2] )< 1e-6 :
242                                                         AcceptedObj.append(Edge)
243                 else :
244                         CenterSrchPar = {'NE' : lambda : [-1., -1.],
245                                          'NW' : lambda : [ 1., -1.],
246                                          'SW' : lambda : [ 1.,  1.],
247                                          'SE' : lambda : [-1.,  1.], }[self.MeshPar[1]]()
248                         Radius = self.GeoPar[1][1]*float(self.MeshPar[2])/(self.MeshPar[2]+1)
249                         Center = (self.GeoPar[0][0]+CenterSrchPar[0]*self.GeoPar[1][0]/2.,self.GeoPar[0][1]+CenterSrchPar[1]*self.GeoPar[1][1]/2.,0.)
250                         for i,ElemObj in enumerate(self.GeoChildren):
251                                 EdgeIDs = geompy.ExtractShapes(ElemObj,6)# List of Edge IDs belonging to ElemObj
252                                 for Edge in EdgeIDs:
253                                         if GenFunctions.IsOnCircle(Edge,Center,Radius):
254                                                 AcceptedObj.append(Edge)
255                 return AcceptedObj
256
257         def PrincipleBoxes (self):
258                 """
259                 This function returns all possible combination rectangular shape objects that can contain at least 3 of the principle vertices
260                 constituting the MacObject. This is indispensible for the Non-ortho types and shall return a number of 24 possible combinations
261                 """
262                 from itertools import combinations
263                 Boxes = []
264                 if self.Type == 'NonOrtho':
265                         for combi in combinations(range(4),3):
266                                 Xmin = min([self.PtCoor[i][0] for i in combi])
267                                 Xmax = max([self.PtCoor[i][0] for i in combi])
268                                 Ymin = min([self.PtCoor[i][1] for i in combi])
269                                 Ymax = max([self.PtCoor[i][1] for i in combi])                        
270                                 Boxes.append([(0.5*(Xmin+Xmax),0.5*(Ymin+Ymax)),(Xmax-Xmin,Ymax-Ymin)])
271                 else :
272                         Boxes = [self.GeoPar]
273                 
274                 return Boxes     
275                         
276