1 # Copyright (C) 2014-2015 EDF R&D
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.
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.
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
17 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
24 This represents a python class definition which contains
25 all necessary information about the macro object being created
29 def __init__( self, ObjectType, GeoParameters, MeshParameters, **args ):
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.
34 import Config,GenFunctions
35 if Config.debug : print "Initializing object No. " + str(len(Config.ListObj)+1)
37 if 'publish' in args :
38 if args['publish']==0 : Config.publish = 0
39 else : Config.publish = 1
40 else : Config.publish = 1
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]
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!"
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)
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)]
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
67 self.GeoChildrenNames = []
70 self.CheckInterfaces()
71 if 'auto' in MeshParameters : self.AutoParam()
72 if not(self.MeshPar[0]<0): self.Generate()
74 Config.ListObj.append(self)
75 print("Aborting object creation\n ")
79 This method generates the geometrical object with the corresponding mesh once all verifications (CheckInterfaces and AutoParam)
80 have been accomplished
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]()
91 if Config.debug : Alarms.Message(self.status) # notification on the result of the generation algorithm
94 def CheckInterfaces(self):
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.
100 import Alarms, Config
101 from GenFunctions import AddIfDifferent
102 from CompositeBox import FindCommonSide
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()
113 for Box0 in PrincipleBoxes:
114 for Box1 in SecondaryBoxes:
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 :
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
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 :
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
135 if not (ConnX*ConnY == 0) :
136 if max(ConnX,ConnY) == -1 and not('NonOrtho' in [self.Type,TestObj.Type]) : Alarms.Message(3)
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)
159 def AutoParam (self):
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
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
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
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
183 MeshPar[i] = MeshPar[i] + RealSegments
184 ObjectsInvolved.append(ObjID+1)
185 self.DirectionalMeshParams = MeshPar
186 self.MeshPar[0] = GenFunctions.CompatibilityTest(self)
188 if self.MeshPar[0] < 0 :
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 !!!")
193 def Boundaries (self):
195 This method returns the global boundaries of the MacObject. [Xmin,Xmax,Ymin,Ymax]
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]])
202 return [Xmin,Xmax,Ymin,Ymax]
204 def DirBoundaries (self, Direction):
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]
211 PtCoor.append(self.PtCoor[0])
212 if type(Direction) is str :
213 Dir = { 'South' : lambda : 0,
214 'North' : lambda : 1,
216 'East' : lambda : 3,}[Direction]()
217 else : Dir = int(Direction)
219 PtIndex = [0,2,3,1][Dir]
220 DirIndex = [0,0,1,1][Dir]
222 return sorted([PtCoor[PtIndex][DirIndex],PtCoor[PtIndex+1][DirIndex]])
223 def DirVectors (self, Direction):
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
229 if type(Direction) is str :
230 Dir = { 'South' : lambda : 0,
231 'North' : lambda : 1,
233 'East' : lambda : 3,}[Direction]()
234 else : Dir = int(Direction)
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.]
240 def GetBorder (self, Criterion):
241 import GenFunctions, Config
243 from salome.geom import geomBuilder
244 geompy = geomBuilder.New( Config.theStudy )
246 if type(Criterion) is str :
247 Crit = {'South' : lambda : 0,
248 'North' : lambda : 1,
250 'East' : lambda : 3,}[Criterion]()
251 else : Crit = int(Criterion)
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]()
261 for i,ElemObj in enumerate(self.GeoChildren):
262 EdgeIDs = geompy.ExtractShapes(ElemObj,6)# List of Edge IDs belonging to ElemObj
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)
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
277 if GenFunctions.IsOnCircle(Edge,Center,Radius):
278 AcceptedObj.append(Edge)
281 def PrincipleBoxes (self):
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
286 from itertools import combinations
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)])
296 Boxes = [self.GeoPar]