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