1 # Copyright (C) 2007-2016 CEA/DEN, EDF R&D, OPEN CASCADE
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
19 # File : smeshBuilder.py
20 # Author : Francis KLOSS, OCC
24 from salome.geom import geomBuilder
26 import SMESH # This is necessary for back compatibility
27 import omniORB # back compatibility
28 SMESH.MED_V2_1 = 11 #omniORB.EnumItem("MED_V2_1", 11) # back compatibility: use number > MED minor version
29 SMESH.MED_V2_2 = 12 #omniORB.EnumItem("MED_V2_2", 12) # back compatibility: latest minor will be used
30 SMESH.MED_MINOR_0 = 20 # back compatibility
31 SMESH.MED_MINOR_1 = 21 # back compatibility
32 SMESH.MED_MINOR_2 = 22 # back compatibility
33 SMESH.MED_MINOR_3 = 23 # back compatibility
34 SMESH.MED_MINOR_4 = 24 # back compatibility
35 SMESH.MED_MINOR_5 = 25 # back compatibility
36 SMESH.MED_MINOR_6 = 26 # back compatibility
37 SMESH.MED_MINOR_7 = 27 # back compatibility
38 SMESH.MED_MINOR_8 = 28 # back compatibility
39 SMESH.MED_MINOR_9 = 29 # back compatibility
42 from salome.smesh.smesh_algorithm import Mesh_Algorithm
49 # In case the omniORBpy EnumItem class does not fully support Python 3
50 # (for instance in version 4.2.1-2), the comparison ordering methods must be
54 SMESH.Entity_Triangle < SMESH.Entity_Quadrangle
56 def enumitem_eq(self, other):
58 if isinstance(other, omniORB.EnumItem):
59 if other._parent_id == self._parent_id:
60 return self._v == other._v
62 return self._parent_id == other._parent_id
64 return id(self) == id(other)
66 return id(self) == id(other)
68 def enumitem_lt(self, other):
70 if isinstance(other, omniORB.EnumItem):
71 if other._parent_id == self._parent_id:
72 return self._v < other._v
74 return self._parent_id < other._parent_id
76 return id(self) < id(other)
78 return id(self) < id(other)
80 def enumitem_le(self, other):
82 if isinstance(other, omniORB.EnumItem):
83 if other._parent_id == self._parent_id:
84 return self._v <= other._v
86 return self._parent_id <= other._parent_id
88 return id(self) <= id(other)
90 return id(self) <= id(other)
92 def enumitem_gt(self, other):
94 if isinstance(other, omniORB.EnumItem):
95 if other._parent_id == self._parent_id:
96 return self._v > other._v
98 return self._parent_id > other._parent_id
100 return id(self) > id(other)
102 return id(self) > id(other)
104 def enumitem_ge(self, other):
106 if isinstance(other, omniORB.EnumItem):
107 if other._parent_id == self._parent_id:
108 return self._v >= other._v
110 return self._parent_id >= other._parent_id
112 return id(self) >= id(other)
114 return id(self) >= id(other)
116 omniORB.EnumItem.__eq__ = enumitem_eq
117 omniORB.EnumItem.__lt__ = enumitem_lt
118 omniORB.EnumItem.__le__ = enumitem_le
119 omniORB.EnumItem.__gt__ = enumitem_gt
120 omniORB.EnumItem.__ge__ = enumitem_ge
123 class MeshMeta(type):
124 """Private class used to workaround a problem that sometimes isinstance(m, Mesh) returns False
126 def __instancecheck__(cls, inst):
127 """Implement isinstance(inst, cls)."""
128 return any(cls.__subclasscheck__(c)
129 for c in {type(inst), inst.__class__})
131 def __subclasscheck__(cls, sub):
132 """Implement issubclass(sub, cls)."""
133 return type.__subclasscheck__(cls, sub) or (cls.__name__ == sub.__name__ and cls.__module__ == sub.__module__)
135 def DegreesToRadians(AngleInDegrees):
136 """Convert an angle from degrees to radians
139 return AngleInDegrees * pi / 180.0
141 import salome_notebook
142 notebook = salome_notebook.notebook
143 # Salome notebook variable separator
146 def ParseParameters(*args):
148 Return list of variable values from salome notebook.
149 The last argument, if is callable, is used to modify values got from notebook
155 if args and callable(args[-1]):
156 args, varModifFun = args[:-1], args[-1]
157 for parameter in args:
159 Parameters += str(parameter) + var_separator
161 if isinstance(parameter,str):
162 # check if there is an inexistent variable name
163 if not notebook.isVariable(parameter):
164 raise ValueError("Variable with name '" + parameter + "' doesn't exist!!!")
165 parameter = notebook.get(parameter)
168 parameter = varModifFun(parameter)
171 Result.append(parameter)
174 Parameters = Parameters[:-1]
175 Result.append( Parameters )
176 Result.append( hasVariables )
179 def ParseAngles(*args):
181 Parse parameters while converting variables to radians
183 return ParseParameters( *( args + (DegreesToRadians, )))
185 def __initPointStruct(point,*args):
187 Substitute PointStruct.__init__() to create SMESH.PointStruct using notebook variables.
188 Parameters are stored in PointStruct.parameters attribute
190 point.x, point.y, point.z, point.parameters,hasVars = ParseParameters(*args)
192 SMESH.PointStruct.__init__ = __initPointStruct
194 def __initAxisStruct(ax,*args):
196 Substitute AxisStruct.__init__() to create SMESH.AxisStruct using notebook variables.
197 Parameters are stored in AxisStruct.parameters attribute
200 raise RuntimeError("Bad nb args (%s) passed in SMESH.AxisStruct(x,y,z,dx,dy,dz)"%(len( args )))
201 ax.x, ax.y, ax.z, ax.vx, ax.vy, ax.vz, ax.parameters,hasVars = ParseParameters(*args)
203 SMESH.AxisStruct.__init__ = __initAxisStruct
205 smeshPrecisionConfusion = 1.e-07
206 def IsEqual(val1, val2, tol=smeshPrecisionConfusion):
207 """Compare real values using smeshPrecisionConfusion as tolerance
209 if abs(val1 - val2) < tol:
217 Return a name of an object
224 if isinstance(obj, SALOMEDS._objref_SObject):
228 ior = salome.orb.object_to_string(obj)
232 sobj = salome.myStudy.FindObjectIOR(ior)
234 return sobj.GetName()
235 if hasattr(obj, "GetName"):
236 # unknown CORBA object, having GetName() method
239 # unknown CORBA object, no GetName() method
242 if hasattr(obj, "GetName"):
243 # unknown non-CORBA object, having GetName() method
246 raise RuntimeError("Null or invalid object")
248 def TreatHypoStatus(status, hypName, geomName, isAlgo, mesh):
250 Print error message if a hypothesis was not assigned.
253 hypType = "algorithm"
255 hypType = "hypothesis"
258 if hasattr( status, "__getitem__" ):
259 status, reason = status[0], status[1]
260 if status == HYP_UNKNOWN_FATAL:
261 reason = "for unknown reason"
262 elif status == HYP_INCOMPATIBLE:
263 reason = "this hypothesis mismatches the algorithm"
264 elif status == HYP_NOTCONFORM:
265 reason = "a non-conform mesh would be built"
266 elif status == HYP_ALREADY_EXIST:
267 if isAlgo: return # it does not influence anything
268 reason = hypType + " of the same dimension is already assigned to this shape"
269 elif status == HYP_BAD_DIM:
270 reason = hypType + " mismatches the shape"
271 elif status == HYP_CONCURRENT :
272 reason = "there are concurrent hypotheses on sub-shapes"
273 elif status == HYP_BAD_SUBSHAPE:
274 reason = "the shape is neither the main one, nor its sub-shape, nor a valid group"
275 elif status == HYP_BAD_GEOMETRY:
276 reason = "the algorithm is not applicable to this geometry"
277 elif status == HYP_HIDDEN_ALGO:
278 reason = "it is hidden by an algorithm of an upper dimension, which generates elements of all dimensions"
279 elif status == HYP_HIDING_ALGO:
280 reason = "it hides algorithms of lower dimensions by generating elements of all dimensions"
281 elif status == HYP_NEED_SHAPE:
282 reason = "algorithm can't work without shape"
283 elif status == HYP_INCOMPAT_HYPS:
289 where = '"%s"' % geomName
291 meshName = GetName( mesh )
292 if meshName and meshName != NO_NAME:
293 where = '"%s" shape in "%s" mesh ' % ( geomName, meshName )
294 if status < HYP_UNKNOWN_FATAL and where:
295 print('"%s" was assigned to %s but %s' %( hypName, where, reason ))
297 print('"%s" was not assigned to %s : %s' %( hypName, where, reason ))
299 print('"%s" was not assigned : %s' %( hypName, reason ))
302 def AssureGeomPublished(mesh, geom, name=''):
304 Private method. Add geom (sub-shape of the main shape) into the study if not yet there
306 if not mesh.smeshpyD.IsEnablePublish():
308 if not isinstance( geom, geomBuilder.GEOM._objref_GEOM_Object ):
310 if not geom.GetStudyEntry():
312 if not name and geom.GetShapeType() != geomBuilder.GEOM.COMPOUND:
313 # for all groups SubShapeName() return "Compound_-1"
314 name = mesh.geompyD.SubShapeName(geom, mesh.geom)
316 name = "%s_%s"%(geom.GetShapeType(), id(geom)%10000)
318 mesh.geompyD.addToStudyInFather( mesh.geom, geom, name )
321 def FirstVertexOnCurve(mesh, edge):
324 the first vertex of a geometrical edge by ignoring orientation
326 vv = mesh.geompyD.SubShapeAll( edge, geomBuilder.geomBuilder.ShapeType["VERTEX"])
328 raise TypeError("Given object has no vertices")
329 if len( vv ) == 1: return vv[0]
330 v0 = mesh.geompyD.MakeVertexOnCurve(edge,0.)
331 xyz = mesh.geompyD.PointCoordinates( v0 ) # coords of the first vertex
332 xyz1 = mesh.geompyD.PointCoordinates( vv[0] )
333 xyz2 = mesh.geompyD.PointCoordinates( vv[1] )
336 dist1 += abs( xyz[i] - xyz1[i] )
337 dist2 += abs( xyz[i] - xyz2[i] )
346 smeshInst is a singleton
352 class smeshBuilder( SMESH._objref_SMESH_Gen, object ):
354 This class allows to create, load or manipulate meshes.
355 It has a set of methods to create, load or copy meshes, to combine several meshes, etc.
356 It also has methods to get infos and measure meshes.
359 # MirrorType enumeration
360 POINT = SMESH_MeshEditor.POINT
361 AXIS = SMESH_MeshEditor.AXIS
362 PLANE = SMESH_MeshEditor.PLANE
364 # Smooth_Method enumeration
365 LAPLACIAN_SMOOTH = SMESH_MeshEditor.LAPLACIAN_SMOOTH
366 CENTROIDAL_SMOOTH = SMESH_MeshEditor.CENTROIDAL_SMOOTH
368 PrecisionConfusion = smeshPrecisionConfusion
370 # TopAbs_State enumeration
371 [TopAbs_IN, TopAbs_OUT, TopAbs_ON, TopAbs_UNKNOWN] = list(range(4))
373 # Methods of splitting a hexahedron into tetrahedra
374 Hex_5Tet, Hex_6Tet, Hex_24Tet, Hex_2Prisms, Hex_4Prisms = 1, 2, 3, 1, 2
376 def __new__(cls, *args):
380 #print("==== __new__", engine, smeshInst, doLcc)
382 if smeshInst is None:
383 # smesh engine is either retrieved from engine, or created
385 # Following test avoids a recursive loop
387 if smeshInst is not None:
388 # smesh engine not created: existing engine found
392 # FindOrLoadComponent called:
393 # 1. CORBA resolution of server
394 # 2. the __new__ method is called again
395 #print("==== smeshInst = lcc.FindOrLoadComponent ", engine, smeshInst, doLcc)
396 smeshInst = salome.lcc.FindOrLoadComponent( "FactoryServer", "SMESH" )
398 # FindOrLoadComponent not called
399 if smeshInst is None:
400 # smeshBuilder instance is created from lcc.FindOrLoadComponent
401 #print("==== smeshInst = super(smeshBuilder,cls).__new__(cls) ", engine, smeshInst, doLcc)
402 smeshInst = super(smeshBuilder,cls).__new__(cls)
404 # smesh engine not created: existing engine found
405 #print("==== existing ", engine, smeshInst, doLcc)
407 #print("====1 ", smeshInst)
410 #print("====2 ", smeshInst)
413 def __init__(self, *args):
415 #print("--------------- smeshbuilder __init__ ---", created)
418 SMESH._objref_SMESH_Gen.__init__(self, *args)
421 def DumpPython(self, theStudy, theIsPublished=True, theIsMultiFile=True):
423 Dump component to the Python script.
424 This method overrides IDL function to allow default values for the parameters.
427 return SMESH._objref_SMESH_Gen.DumpPython(self, theStudy, theIsPublished, theIsMultiFile)
429 def SetDumpPythonHistorical(self, isHistorical):
431 Set mode of DumpPython(), *historical* or *snapshot*.
432 In the *historical* mode, the Python Dump script includes all commands
433 performed by SMESH engine. In the *snapshot* mode, commands
434 relating to objects removed from the Study are excluded from the script
435 as well as commands not influencing the current state of meshes
438 if isHistorical: val = "true"
440 SMESH._objref_SMESH_Gen.SetOption(self, "historical_python_dump", val)
442 def init_smesh(self,geompyD = None):
444 Set Geometry component
447 self.UpdateStudy(geompyD)
448 notebook.myStudy = salome.myStudy
450 def Mesh(self, obj=0, name=0):
452 Create a mesh. This mesh can be either
454 * an empty mesh not bound to geometry, if *obj* == 0
455 * an empty mesh bound to geometry, if *obj* is GEOM.GEOM_Object
456 * a mesh wrapping a :class:`CORBA mesh <SMESH.SMESH_Mesh>` given as *obj* parameter.
461 1. a :class:`CORBA mesh <SMESH.SMESH_Mesh>` got by calling e.g.
464 salome.myStudy.FindObjectID("0:1:2:3").GetObject()
466 2. a geometrical object for meshing
468 name: the name for the new mesh.
471 an instance of class :class:`Mesh`.
474 if isinstance(obj,str):
476 return Mesh(self, self.geompyD, obj, name)
478 def EnumToLong(self,theItem):
480 Return a long value from enumeration
485 def ColorToString(self,c):
487 Convert SALOMEDS.Color to string.
488 To be used with filters.
491 c: color value (SALOMEDS.Color)
494 a string representation of the color.
498 if isinstance(c, SALOMEDS.Color):
499 val = "%s;%s;%s" % (c.R, c.G, c.B)
500 elif isinstance(c, str):
503 raise ValueError("Color value should be of string or SALOMEDS.Color type")
506 def GetPointStruct(self,theVertex):
508 Get :class:`SMESH.PointStruct` from vertex
511 theVertex (GEOM.GEOM_Object): vertex
514 :class:`SMESH.PointStruct`
517 [x, y, z] = self.geompyD.PointCoordinates(theVertex)
518 return PointStruct(x,y,z)
520 def GetDirStruct(self,theVector):
522 Get :class:`SMESH.DirStruct` from vector
525 theVector (GEOM.GEOM_Object): vector
528 :class:`SMESH.DirStruct`
531 vertices = self.geompyD.SubShapeAll( theVector, geomBuilder.geomBuilder.ShapeType["VERTEX"] )
532 if(len(vertices) != 2):
533 print("Error: vector object is incorrect.")
535 p1 = self.geompyD.PointCoordinates(vertices[0])
536 p2 = self.geompyD.PointCoordinates(vertices[1])
537 pnt = PointStruct(p2[0]-p1[0], p2[1]-p1[1], p2[2]-p1[2])
538 dirst = DirStruct(pnt)
541 def MakeDirStruct(self,x,y,z):
543 Make :class:`SMESH.DirStruct` from a triplet of floats
546 x,y,z (float): vector components
549 :class:`SMESH.DirStruct`
552 pnt = PointStruct(x,y,z)
553 return DirStruct(pnt)
555 def GetAxisStruct(self,theObj):
557 Get :class:`SMESH.AxisStruct` from a geometrical object
560 theObj (GEOM.GEOM_Object): line or plane
563 :class:`SMESH.AxisStruct`
566 edges = self.geompyD.SubShapeAll( theObj, geomBuilder.geomBuilder.ShapeType["EDGE"] )
569 vertex1, vertex2 = self.geompyD.SubShapeAll( edges[0], geomBuilder.geomBuilder.ShapeType["VERTEX"] )
570 vertex3, vertex4 = self.geompyD.SubShapeAll( edges[1], geomBuilder.geomBuilder.ShapeType["VERTEX"] )
571 vertex1 = self.geompyD.PointCoordinates(vertex1)
572 vertex2 = self.geompyD.PointCoordinates(vertex2)
573 vertex3 = self.geompyD.PointCoordinates(vertex3)
574 vertex4 = self.geompyD.PointCoordinates(vertex4)
575 v1 = [vertex2[0]-vertex1[0], vertex2[1]-vertex1[1], vertex2[2]-vertex1[2]]
576 v2 = [vertex4[0]-vertex3[0], vertex4[1]-vertex3[1], vertex4[2]-vertex3[2]]
577 normal = [ v1[1]*v2[2]-v2[1]*v1[2], v1[2]*v2[0]-v2[2]*v1[0], v1[0]*v2[1]-v2[0]*v1[1] ]
578 axis = AxisStruct(vertex1[0], vertex1[1], vertex1[2], normal[0], normal[1], normal[2])
579 axis._mirrorType = SMESH.SMESH_MeshEditor.PLANE
580 elif len(edges) == 1:
581 vertex1, vertex2 = self.geompyD.SubShapeAll( edges[0], geomBuilder.geomBuilder.ShapeType["VERTEX"] )
582 p1 = self.geompyD.PointCoordinates( vertex1 )
583 p2 = self.geompyD.PointCoordinates( vertex2 )
584 axis = AxisStruct(p1[0], p1[1], p1[2], p2[0]-p1[0], p2[1]-p1[1], p2[2]-p1[2])
585 axis._mirrorType = SMESH.SMESH_MeshEditor.AXIS
586 elif theObj.GetShapeType() == GEOM.VERTEX:
587 x,y,z = self.geompyD.PointCoordinates( theObj )
588 axis = AxisStruct( x,y,z, 1,0,0,)
589 axis._mirrorType = SMESH.SMESH_MeshEditor.POINT
592 # From SMESH_Gen interface:
593 # ------------------------
595 def SetName(self, obj, name):
597 Set the given name to an object
600 obj: the object to rename
601 name: a new object name
604 if isinstance( obj, Mesh ):
606 elif isinstance( obj, Mesh_Algorithm ):
607 obj = obj.GetAlgorithm()
608 ior = salome.orb.object_to_string(obj)
609 SMESH._objref_SMESH_Gen.SetName(self, ior, name)
611 def SetEmbeddedMode( self,theMode ):
616 SMESH._objref_SMESH_Gen.SetEmbeddedMode(self,theMode)
618 def IsEmbeddedMode(self):
623 return SMESH._objref_SMESH_Gen.IsEmbeddedMode(self)
625 def UpdateStudy( self, geompyD = None ):
627 Update the current study. Calling UpdateStudy() allows to
628 update meshes at switching GEOM->SMESH
632 from salome.geom import geomBuilder
633 geompyD = geomBuilder.geom
635 geompyD = geomBuilder.New()
638 self.SetGeomEngine(geompyD)
639 SMESH._objref_SMESH_Gen.UpdateStudy(self)
640 sb = salome.myStudy.NewBuilder()
641 sc = salome.myStudy.FindComponent("SMESH")
643 sb.LoadWith(sc, self)
646 def SetEnablePublish( self, theIsEnablePublish ):
648 Set enable publishing in the study. Calling SetEnablePublish( False ) allows to
649 switch **off** publishing in the Study of mesh objects.
651 #self.SetEnablePublish(theIsEnablePublish)
652 SMESH._objref_SMESH_Gen.SetEnablePublish(self,theIsEnablePublish)
654 notebook = salome_notebook.NoteBook( theIsEnablePublish )
657 def CreateMeshesFromUNV( self,theFileName ):
659 Create a Mesh object importing data from the given UNV file
662 an instance of class :class:`Mesh`
665 aSmeshMesh = SMESH._objref_SMESH_Gen.CreateMeshesFromUNV(self,theFileName)
666 aMesh = Mesh(self, self.geompyD, aSmeshMesh)
669 def CreateMeshesFromMED( self,theFileName ):
671 Create a Mesh object(s) importing data from the given MED file
674 a tuple ( list of class :class:`Mesh` instances,
675 :class:`SMESH.DriverMED_ReadStatus` )
678 aSmeshMeshes, aStatus = SMESH._objref_SMESH_Gen.CreateMeshesFromMED(self,theFileName)
679 aMeshes = [ Mesh(self, self.geompyD, m) for m in aSmeshMeshes ]
680 return aMeshes, aStatus
682 def CreateMeshesFromSAUV( self,theFileName ):
684 Create a Mesh object(s) importing data from the given SAUV file
687 a tuple ( list of class :class:`Mesh` instances, :class:`SMESH.DriverMED_ReadStatus` )
690 aSmeshMeshes, aStatus = SMESH._objref_SMESH_Gen.CreateMeshesFromSAUV(self,theFileName)
691 aMeshes = [ Mesh(self, self.geompyD, m) for m in aSmeshMeshes ]
692 return aMeshes, aStatus
694 def CreateMeshesFromSTL( self, theFileName ):
696 Create a Mesh object importing data from the given STL file
699 an instance of class :class:`Mesh`
702 aSmeshMesh = SMESH._objref_SMESH_Gen.CreateMeshesFromSTL(self,theFileName)
703 aMesh = Mesh(self, self.geompyD, aSmeshMesh)
706 def CreateMeshesFromCGNS( self, theFileName ):
708 Create Mesh objects importing data from the given CGNS file
711 a tuple ( list of class :class:`Mesh` instances, :class:`SMESH.DriverMED_ReadStatus` )
714 aSmeshMeshes, aStatus = SMESH._objref_SMESH_Gen.CreateMeshesFromCGNS(self,theFileName)
715 aMeshes = [ Mesh(self, self.geompyD, m) for m in aSmeshMeshes ]
716 return aMeshes, aStatus
718 def CreateMeshesFromGMF( self, theFileName ):
720 Create a Mesh object importing data from the given GMF file.
721 GMF files must have .mesh extension for the ASCII format and .meshb for
725 ( an instance of class :class:`Mesh`, :class:`SMESH.ComputeError` )
728 aSmeshMesh, error = SMESH._objref_SMESH_Gen.CreateMeshesFromGMF(self,
731 if error.comment: print("*** CreateMeshesFromGMF() errors:\n", error.comment)
732 return Mesh(self, self.geompyD, aSmeshMesh), error
734 def Concatenate( self, meshes, uniteIdenticalGroups,
735 mergeNodesAndElements = False, mergeTolerance = 1e-5, allGroups = False,
738 Concatenate the given meshes into one mesh. All groups of input meshes will be
739 present in the new mesh.
742 meshes: :class:`meshes, sub-meshes, groups or filters <SMESH.SMESH_IDSource>` to combine into one mesh
743 uniteIdenticalGroups: if True, groups with same names are united, else they are renamed
744 mergeNodesAndElements: if True, equal nodes and elements are merged
745 mergeTolerance: tolerance for merging nodes
746 allGroups: forces creation of groups corresponding to every input mesh
747 name: name of a new mesh
750 an instance of class :class:`Mesh`
753 if not meshes: return None
754 for i,m in enumerate(meshes):
755 if isinstance(m, Mesh):
756 meshes[i] = m.GetMesh()
757 mergeTolerance,Parameters,hasVars = ParseParameters(mergeTolerance)
758 meshes[0].SetParameters(Parameters)
760 aSmeshMesh = SMESH._objref_SMESH_Gen.ConcatenateWithGroups(
761 self,meshes,uniteIdenticalGroups,mergeNodesAndElements,mergeTolerance)
763 aSmeshMesh = SMESH._objref_SMESH_Gen.Concatenate(
764 self,meshes,uniteIdenticalGroups,mergeNodesAndElements,mergeTolerance)
765 aMesh = Mesh(self, self.geompyD, aSmeshMesh, name=name)
768 def CopyMesh( self, meshPart, meshName, toCopyGroups=False, toKeepIDs=False):
770 Create a mesh by copying a part of another mesh.
773 meshPart: a part of mesh to copy, either
774 :class:`mesh, sub-mesh, group or filter <SMESH.SMESH_IDSource>`.
775 To copy nodes or elements not forming any mesh object,
776 pass result of :meth:`Mesh.GetIDSource` as *meshPart*
777 meshName: a name of the new mesh
778 toCopyGroups: to create in the new mesh groups the copied elements belongs to
779 toKeepIDs: to preserve order of the copied elements or not
782 an instance of class :class:`Mesh`
785 if isinstance( meshPart, Mesh ):
786 meshPart = meshPart.GetMesh()
787 mesh = SMESH._objref_SMESH_Gen.CopyMesh( self,meshPart,meshName,toCopyGroups,toKeepIDs )
788 return Mesh(self, self.geompyD, mesh)
790 def CopyMeshWithGeom( self, sourceMesh, newGeom, meshName="", toCopyGroups=True,
791 toReuseHypotheses=True, toCopyElements=True):
793 Create a mesh by copying a mesh definition (hypotheses and groups) to a new geometry.
794 It is supposed that the new geometry is a modified geometry of *sourceMesh*.
795 To facilitate and speed up the operation, consider using
796 "Set presentation parameters and sub-shapes from arguments" option in
797 a dialog of geometrical operation used to create the new geometry.
800 sourceMesh: the mesh to copy definition of.
801 newGeom: the new geomtry.
802 meshName: an optional name of the new mesh. If omitted, the mesh name is kept.
803 toCopyGroups: to create groups in the new mesh.
804 toReuseHypotheses: to reuse hypotheses of the *sourceMesh*.
805 toCopyElements: to copy mesh elements present on non-modified sub-shapes of
808 tuple ( ok, newMesh, newGroups, newSubMeshes, newHypotheses, invalidEntries )
809 *invalidEntries* are study entries of objects whose
810 counterparts are not found in the *newGeom*, followed by entries
811 of mesh sub-objects that are invalid because they depend on a not found
814 if isinstance( sourceMesh, Mesh ):
815 sourceMesh = sourceMesh.GetMesh()
817 ok, newMesh, newGroups, newSubMeshes, newHypotheses, invalidEntries = \
818 SMESH._objref_SMESH_Gen.CopyMeshWithGeom( self, sourceMesh, newGeom, meshName,
822 return ( ok, Mesh(self, self.geompyD, newMesh),
823 newGroups, newSubMeshes, newHypotheses, invalidEntries )
825 def GetSubShapesId( self, theMainObject, theListOfSubObjects ):
827 Return IDs of sub-shapes
830 theMainObject (GEOM.GEOM_Object): a shape
831 theListOfSubObjects: sub-shapes (list of GEOM.GEOM_Object)
833 the list of integer values
836 return SMESH._objref_SMESH_Gen.GetSubShapesId(self,theMainObject, theListOfSubObjects)
838 def GetPattern(self):
840 Create a pattern mapper.
843 an instance of :class:`SMESH.SMESH_Pattern`
845 :ref:`Example of Patterns usage <tui_pattern_mapping>`
848 return SMESH._objref_SMESH_Gen.GetPattern(self)
850 def SetBoundaryBoxSegmentation(self, nbSegments):
852 Set number of segments per diagonal of boundary box of geometry, by which
853 default segment length of appropriate 1D hypotheses is defined in GUI.
857 SMESH._objref_SMESH_Gen.SetBoundaryBoxSegmentation(self,nbSegments)
859 # Filtering. Auxiliary functions:
860 # ------------------------------
862 def GetEmptyCriterion(self):
864 Create an empty criterion
867 :class:`SMESH.Filter.Criterion`
870 Type = self.EnumToLong(FT_Undefined)
871 Compare = self.EnumToLong(FT_Undefined)
875 UnaryOp = self.EnumToLong(FT_Undefined)
876 BinaryOp = self.EnumToLong(FT_Undefined)
879 Precision = -1 ##@1e-07
880 return Filter.Criterion(Type, Compare, Threshold, ThresholdStr, ThresholdID,
881 UnaryOp, BinaryOp, Tolerance, TypeOfElement, Precision)
883 def GetCriterion(self,elementType,
885 Compare = FT_EqualTo,
887 UnaryOp=FT_Undefined,
888 BinaryOp=FT_Undefined,
891 Create a criterion by the given parameters
892 Criterion structures allow to define complex filters by combining them with logical operations (AND / OR) (see example below)
895 elementType: the :class:`type of elements <SMESH.ElementType>` (SMESH.NODE, SMESH.EDGE, SMESH.FACE, SMESH.VOLUME)
896 CritType: the type of criterion :class:`SMESH.FunctorType` (SMESH.FT_Taper, SMESH.FT_Area, etc.).
897 Note that the items starting from FT_LessThan are not suitable for *CritType*.
898 Compare: belongs to {SMESH.FT_LessThan, SMESH.FT_MoreThan, SMESH.FT_EqualTo}
899 Threshold: the threshold value (range of ids as string, shape, numeric)
900 UnaryOp: SMESH.FT_LogicalNOT or SMESH.FT_Undefined
901 BinaryOp: a binary logical operation SMESH.FT_LogicalAND, SMESH.FT_LogicalOR or
903 Tolerance: the tolerance used by SMESH.FT_BelongToGeom, SMESH.FT_BelongToSurface,
904 SMESH.FT_LyingOnGeom, SMESH.FT_CoplanarFaces criteria
907 :class:`SMESH.Filter.Criterion`
909 Example: :ref:`combining_filters`
912 if not CritType in SMESH.FunctorType._items:
913 raise TypeError("CritType should be of SMESH.FunctorType")
914 aCriterion = self.GetEmptyCriterion()
915 aCriterion.TypeOfElement = elementType
916 aCriterion.Type = self.EnumToLong(CritType)
917 aCriterion.Tolerance = Tolerance
919 aThreshold = Threshold
921 if Compare in [FT_LessThan, FT_MoreThan, FT_EqualTo]:
922 aCriterion.Compare = self.EnumToLong(Compare)
923 elif Compare == "=" or Compare == "==":
924 aCriterion.Compare = self.EnumToLong(FT_EqualTo)
926 aCriterion.Compare = self.EnumToLong(FT_LessThan)
928 aCriterion.Compare = self.EnumToLong(FT_MoreThan)
929 elif Compare != FT_Undefined:
930 aCriterion.Compare = self.EnumToLong(FT_EqualTo)
933 if CritType in [FT_BelongToGeom, FT_BelongToPlane, FT_BelongToGenSurface,
934 FT_BelongToCylinder, FT_LyingOnGeom]:
935 # Check that Threshold is GEOM object
936 if isinstance(aThreshold, geomBuilder.GEOM._objref_GEOM_Object):
937 aCriterion.ThresholdStr = GetName(aThreshold)
938 aCriterion.ThresholdID = aThreshold.GetStudyEntry()
939 if not aCriterion.ThresholdID:
940 name = aCriterion.ThresholdStr
942 name = "%s_%s"%(aThreshold.GetShapeType(), id(aThreshold)%10000)
943 aCriterion.ThresholdID = self.geompyD.addToStudy( aThreshold, name )
944 # or a name of GEOM object
945 elif isinstance( aThreshold, str ):
946 aCriterion.ThresholdStr = aThreshold
948 raise TypeError("The Threshold should be a shape.")
949 if isinstance(UnaryOp,float):
950 aCriterion.Tolerance = UnaryOp
951 UnaryOp = FT_Undefined
953 elif CritType == FT_BelongToMeshGroup:
954 # Check that Threshold is a group
955 if isinstance(aThreshold, SMESH._objref_SMESH_GroupBase):
956 if aThreshold.GetType() != elementType:
957 raise ValueError("Group type mismatches Element type")
958 aCriterion.ThresholdStr = aThreshold.GetName()
959 aCriterion.ThresholdID = salome.orb.object_to_string( aThreshold )
960 study = salome.myStudy
962 so = study.FindObjectIOR( aCriterion.ThresholdID )
966 aCriterion.ThresholdID = entry
968 raise TypeError("The Threshold should be a Mesh Group")
969 elif CritType == FT_RangeOfIds:
970 # Check that Threshold is string
971 if isinstance(aThreshold, str):
972 aCriterion.ThresholdStr = aThreshold
974 raise TypeError("The Threshold should be a string.")
975 elif CritType == FT_CoplanarFaces:
976 # Check the Threshold
977 if isinstance(aThreshold, int):
978 aCriterion.ThresholdID = str(aThreshold)
979 elif isinstance(aThreshold, str):
982 raise ValueError("Invalid ID of mesh face: '%s'"%aThreshold)
983 aCriterion.ThresholdID = aThreshold
985 raise TypeError("The Threshold should be an ID of mesh face and not '%s'"%aThreshold)
986 elif CritType == FT_ConnectedElements:
987 # Check the Threshold
988 if isinstance(aThreshold, geomBuilder.GEOM._objref_GEOM_Object): # shape
989 aCriterion.ThresholdID = aThreshold.GetStudyEntry()
990 if not aCriterion.ThresholdID:
991 name = aThreshold.GetName()
993 name = "%s_%s"%(aThreshold.GetShapeType(), id(aThreshold)%10000)
994 aCriterion.ThresholdID = self.geompyD.addToStudy( aThreshold, name )
995 elif isinstance(aThreshold, int): # node id
996 aCriterion.Threshold = aThreshold
997 elif isinstance(aThreshold, list): # 3 point coordinates
998 if len( aThreshold ) < 3:
999 raise ValueError("too few point coordinates, must be 3")
1000 aCriterion.ThresholdStr = " ".join( [str(c) for c in aThreshold[:3]] )
1001 elif isinstance(aThreshold, str):
1002 if aThreshold.isdigit():
1003 aCriterion.Threshold = aThreshold # node id
1005 aCriterion.ThresholdStr = aThreshold # hope that it's point coordinates
1007 raise TypeError("The Threshold should either a VERTEX, or a node ID, "\
1008 "or a list of point coordinates and not '%s'"%aThreshold)
1009 elif CritType == FT_ElemGeomType:
1010 # Check the Threshold
1012 aCriterion.Threshold = self.EnumToLong(aThreshold)
1013 assert( aThreshold in SMESH.GeometryType._items )
1015 if isinstance(aThreshold, int):
1016 aCriterion.Threshold = aThreshold
1018 raise TypeError("The Threshold should be an integer or SMESH.GeometryType.")
1021 elif CritType == FT_EntityType:
1022 # Check the Threshold
1024 aCriterion.Threshold = self.EnumToLong(aThreshold)
1025 assert( aThreshold in SMESH.EntityType._items )
1027 if isinstance(aThreshold, int):
1028 aCriterion.Threshold = aThreshold
1030 raise TypeError("The Threshold should be an integer or SMESH.EntityType.")
1034 elif CritType == FT_GroupColor:
1035 # Check the Threshold
1037 aCriterion.ThresholdStr = self.ColorToString(aThreshold)
1039 raise TypeError("The threshold value should be of SALOMEDS.Color type")
1041 elif CritType in [FT_FreeBorders, FT_FreeEdges, FT_FreeNodes, FT_FreeFaces,
1042 FT_LinearOrQuadratic, FT_BadOrientedVolume,
1043 FT_BareBorderFace, FT_BareBorderVolume,
1044 FT_OverConstrainedFace, FT_OverConstrainedVolume,
1045 FT_EqualNodes,FT_EqualEdges,FT_EqualFaces,FT_EqualVolumes ]:
1046 # At this point the Threshold is unnecessary
1047 if aThreshold == FT_LogicalNOT:
1048 aCriterion.UnaryOp = self.EnumToLong(FT_LogicalNOT)
1049 elif aThreshold in [FT_LogicalAND, FT_LogicalOR]:
1050 aCriterion.BinaryOp = aThreshold
1054 aThreshold = float(aThreshold)
1055 aCriterion.Threshold = aThreshold
1057 raise TypeError("The Threshold should be a number.")
1060 if Threshold == FT_LogicalNOT or UnaryOp == FT_LogicalNOT:
1061 aCriterion.UnaryOp = self.EnumToLong(FT_LogicalNOT)
1063 if Threshold in [FT_LogicalAND, FT_LogicalOR]:
1064 aCriterion.BinaryOp = self.EnumToLong(Threshold)
1066 if UnaryOp in [FT_LogicalAND, FT_LogicalOR]:
1067 aCriterion.BinaryOp = self.EnumToLong(UnaryOp)
1069 if BinaryOp in [FT_LogicalAND, FT_LogicalOR]:
1070 aCriterion.BinaryOp = self.EnumToLong(BinaryOp)
1074 def GetFilter(self,elementType,
1075 CritType=FT_Undefined,
1078 UnaryOp=FT_Undefined,
1082 Create a filter with the given parameters
1085 elementType: the :class:`type of elements <SMESH.ElementType>` (SMESH.NODE, SMESH.EDGE, SMESH.FACE, SMESH.VOLUME)
1086 CritType: the :class:`type of criterion <SMESH.FunctorType>` (SMESH.FT_Taper, SMESH.FT_Area, etc.).
1087 Note that the items starting from FT_LessThan are not suitable for CritType.
1088 Compare: belongs to {SMESH.FT_LessThan, SMESH.FT_MoreThan, SMESH.FT_EqualTo}
1089 Threshold: the threshold value (range of ids as string, shape, numeric)
1090 UnaryOp: SMESH.FT_LogicalNOT or SMESH.FT_Undefined
1091 Tolerance: the tolerance used by SMESH.FT_BelongToGeom, SMESH.FT_BelongToSurface,
1092 SMESH.FT_LyingOnGeom, SMESH.FT_CoplanarFaces and SMESH.FT_EqualNodes criteria
1093 mesh: the mesh to initialize the filter with
1096 :class:`SMESH.Filter`
1099 See :doc:`Filters usage examples <tui_filters>`
1102 aCriterion = self.GetCriterion(elementType, CritType, Compare, Threshold, UnaryOp, FT_Undefined,Tolerance)
1103 aFilterMgr = self.CreateFilterManager()
1104 aFilter = aFilterMgr.CreateFilter()
1106 aCriteria.append(aCriterion)
1107 aFilter.SetCriteria(aCriteria)
1109 if isinstance( mesh, Mesh ): aFilter.SetMesh( mesh.GetMesh() )
1110 else : aFilter.SetMesh( mesh )
1111 aFilterMgr.UnRegister()
1114 def GetFilterFromCriteria(self,criteria, binOp=SMESH.FT_LogicalAND):
1116 Create a filter from criteria
1119 criteria: a list of :class:`SMESH.Filter.Criterion`
1120 binOp: binary operator used when binary operator of criteria is undefined
1123 :class:`SMESH.Filter`
1126 See :doc:`Filters usage examples <tui_filters>`
1129 for i in range( len( criteria ) - 1 ):
1130 if criteria[i].BinaryOp == self.EnumToLong( SMESH.FT_Undefined ):
1131 criteria[i].BinaryOp = self.EnumToLong( binOp )
1132 aFilterMgr = self.CreateFilterManager()
1133 aFilter = aFilterMgr.CreateFilter()
1134 aFilter.SetCriteria(criteria)
1135 aFilterMgr.UnRegister()
1138 def GetFunctor(self,theCriterion):
1140 Create a numerical functor by its type
1143 theCriterion (SMESH.FunctorType): functor type.
1144 Note that not all items correspond to numerical functors.
1147 :class:`SMESH.NumericalFunctor`
1150 if isinstance( theCriterion, SMESH._objref_NumericalFunctor ):
1152 aFilterMgr = self.CreateFilterManager()
1154 if theCriterion == FT_AspectRatio:
1155 functor = aFilterMgr.CreateAspectRatio()
1156 elif theCriterion == FT_AspectRatio3D:
1157 functor = aFilterMgr.CreateAspectRatio3D()
1158 elif theCriterion == FT_Warping:
1159 functor = aFilterMgr.CreateWarping()
1160 elif theCriterion == FT_MinimumAngle:
1161 functor = aFilterMgr.CreateMinimumAngle()
1162 elif theCriterion == FT_Taper:
1163 functor = aFilterMgr.CreateTaper()
1164 elif theCriterion == FT_Skew:
1165 functor = aFilterMgr.CreateSkew()
1166 elif theCriterion == FT_Area:
1167 functor = aFilterMgr.CreateArea()
1168 elif theCriterion == FT_Volume3D:
1169 functor = aFilterMgr.CreateVolume3D()
1170 elif theCriterion == FT_MaxElementLength2D:
1171 functor = aFilterMgr.CreateMaxElementLength2D()
1172 elif theCriterion == FT_MaxElementLength3D:
1173 functor = aFilterMgr.CreateMaxElementLength3D()
1174 elif theCriterion == FT_MultiConnection:
1175 functor = aFilterMgr.CreateMultiConnection()
1176 elif theCriterion == FT_MultiConnection2D:
1177 functor = aFilterMgr.CreateMultiConnection2D()
1178 elif theCriterion == FT_Length:
1179 functor = aFilterMgr.CreateLength()
1180 elif theCriterion == FT_Length2D:
1181 functor = aFilterMgr.CreateLength2D()
1182 elif theCriterion == FT_Deflection2D:
1183 functor = aFilterMgr.CreateDeflection2D()
1184 elif theCriterion == FT_NodeConnectivityNumber:
1185 functor = aFilterMgr.CreateNodeConnectivityNumber()
1186 elif theCriterion == FT_BallDiameter:
1187 functor = aFilterMgr.CreateBallDiameter()
1189 print("Error: given parameter is not numerical functor type.")
1190 aFilterMgr.UnRegister()
1193 def CreateHypothesis(self, theHType, theLibName="libStdMeshersEngine.so"):
1198 theHType (string): mesh hypothesis type
1199 theLibName (string): mesh plug-in library name
1202 created hypothesis instance
1204 hyp = SMESH._objref_SMESH_Gen.CreateHypothesis(self, theHType, theLibName )
1206 if isinstance( hyp, SMESH._objref_SMESH_Algo ):
1209 # wrap hypothesis methods
1210 for meth_name in dir( hyp.__class__ ):
1211 if not meth_name.startswith("Get") and \
1212 not meth_name in dir ( SMESH._objref_SMESH_Hypothesis ):
1213 method = getattr ( hyp.__class__, meth_name )
1214 if callable(method):
1215 setattr( hyp, meth_name, hypMethodWrapper( hyp, method ))
1219 def GetMeshInfo(self, obj):
1221 Get the mesh statistic.
1222 Use :meth:`smeshBuilder.EnumToLong` to get an integer from
1223 an item of :class:`SMESH.EntityType`.
1226 dictionary { :class:`SMESH.EntityType` - "count of elements" }
1229 if isinstance( obj, Mesh ):
1232 if hasattr(obj, "GetMeshInfo"):
1233 values = obj.GetMeshInfo()
1234 for i in range(SMESH.Entity_Last._v):
1235 if i < len(values): d[SMESH.EntityType._item(i)]=values[i]
1239 def MinDistance(self, src1, src2=None, id1=0, id2=0, isElem1=False, isElem2=False):
1241 Get minimum distance between two objects
1243 * If *src2* is None, and *id2* = 0, distance from *src1* / *id1* to the origin is computed.
1244 * If *src2* is None, and *id2* != 0, it is assumed that both *id1* and *id2* belong to *src1*.
1247 src1 (SMESH.SMESH_IDSource): first source object
1248 src2 (SMESH.SMESH_IDSource): second source object
1249 id1 (int): node/element id from the first source
1250 id2 (int): node/element id from the second (or first) source
1251 isElem1 (boolean): *True* if *id1* is element id, *False* if it is node id
1252 isElem2 (boolean): *True* if *id2* is element id, *False* if it is node id
1255 minimum distance value
1258 :meth:`GetMinDistance`
1261 result = self.GetMinDistance(src1, src2, id1, id2, isElem1, isElem2)
1265 result = result.value
1268 def GetMinDistance(self, src1, src2=None, id1=0, id2=0, isElem1=False, isElem2=False):
1270 Get :class:`SMESH.Measure` structure specifying minimum distance data between two objects
1272 * If *src2* is None, and *id2* = 0, distance from *src1* / *id1* to the origin is computed.
1273 * If *src2* is None, and *id2* != 0, it is assumed that both *id1* and *id2* belong to *src1*.
1276 src1 (SMESH.SMESH_IDSource): first source object
1277 src2 (SMESH.SMESH_IDSource): second source object
1278 id1 (int): node/element id from the first source
1279 id2 (int): node/element id from the second (or first) source
1280 isElem1 (boolean): *True* if **id1** is element id, *False* if it is node id
1281 isElem2 (boolean): *True* if **id2** is element id, *False* if it is node id
1284 :class:`SMESH.Measure` structure or None if input data is invalid
1289 if isinstance(src1, Mesh): src1 = src1.mesh
1290 if isinstance(src2, Mesh): src2 = src2.mesh
1291 if src2 is None and id2 != 0: src2 = src1
1292 if not hasattr(src1, "_narrow"): return None
1293 src1 = src1._narrow(SMESH.SMESH_IDSource)
1294 if not src1: return None
1295 unRegister = genObjUnRegister()
1298 e = m.GetMeshEditor()
1300 src1 = e.MakeIDSource([id1], SMESH.FACE)
1302 src1 = e.MakeIDSource([id1], SMESH.NODE)
1303 unRegister.set( src1 )
1305 if hasattr(src2, "_narrow"):
1306 src2 = src2._narrow(SMESH.SMESH_IDSource)
1307 if src2 and id2 != 0:
1309 e = m.GetMeshEditor()
1311 src2 = e.MakeIDSource([id2], SMESH.FACE)
1313 src2 = e.MakeIDSource([id2], SMESH.NODE)
1314 unRegister.set( src2 )
1317 aMeasurements = self.CreateMeasurements()
1318 unRegister.set( aMeasurements )
1319 result = aMeasurements.MinDistance(src1, src2)
1322 def BoundingBox(self, objects):
1324 Get bounding box of the specified object(s)
1327 objects (SMESH.SMESH_IDSource): single source object or list of source objects
1330 tuple of six values (minX, minY, minZ, maxX, maxY, maxZ)
1333 :meth:`GetBoundingBox`
1336 result = self.GetBoundingBox(objects)
1340 result = (result.minX, result.minY, result.minZ, result.maxX, result.maxY, result.maxZ)
1343 def GetBoundingBox(self, objects):
1345 Get :class:`SMESH.Measure` structure specifying bounding box data of the specified object(s)
1348 objects (SMESH.SMESH_IDSource): single source object or list of source objects
1351 :class:`SMESH.Measure` structure
1357 if isinstance(objects, tuple):
1358 objects = list(objects)
1359 if not isinstance(objects, list):
1363 if isinstance(o, Mesh):
1364 srclist.append(o.mesh)
1365 elif hasattr(o, "_narrow"):
1366 src = o._narrow(SMESH.SMESH_IDSource)
1367 if src: srclist.append(src)
1370 aMeasurements = self.CreateMeasurements()
1371 result = aMeasurements.BoundingBox(srclist)
1372 aMeasurements.UnRegister()
1375 def GetLength(self, obj):
1377 Get sum of lengths of all 1D elements in the mesh object.
1380 obj: :class:`mesh, sub-mesh, group or filter <SMESH.SMESH_IDSource>`
1383 sum of lengths of all 1D elements
1386 if isinstance(obj, Mesh): obj = obj.mesh
1387 if isinstance(obj, Mesh_Algorithm): obj = obj.GetSubMesh()
1388 aMeasurements = self.CreateMeasurements()
1389 value = aMeasurements.Length(obj)
1390 aMeasurements.UnRegister()
1393 def GetArea(self, obj):
1395 Get sum of areas of all 2D elements in the mesh object.
1398 obj: :class:`mesh, sub-mesh, group or filter <SMESH.SMESH_IDSource>`
1401 sum of areas of all 2D elements
1404 if isinstance(obj, Mesh): obj = obj.mesh
1405 if isinstance(obj, Mesh_Algorithm): obj = obj.GetSubMesh()
1406 aMeasurements = self.CreateMeasurements()
1407 value = aMeasurements.Area(obj)
1408 aMeasurements.UnRegister()
1411 def GetVolume(self, obj):
1413 Get sum of volumes of all 3D elements in the mesh object.
1416 obj: :class:`mesh, sub-mesh, group or filter <SMESH.SMESH_IDSource>`
1419 sum of volumes of all 3D elements
1422 if isinstance(obj, Mesh): obj = obj.mesh
1423 if isinstance(obj, Mesh_Algorithm): obj = obj.GetSubMesh()
1424 aMeasurements = self.CreateMeasurements()
1425 value = aMeasurements.Volume(obj)
1426 aMeasurements.UnRegister()
1429 def GetGravityCenter(self, obj):
1431 Get gravity center of all nodes of the mesh object.
1434 obj: :class:`mesh, sub-mesh, group or filter <SMESH.SMESH_IDSource>`
1437 Three components of the gravity center (x,y,z)
1439 if isinstance(obj, Mesh): obj = obj.mesh
1440 if isinstance(obj, Mesh_Algorithm): obj = obj.GetSubMesh()
1441 aMeasurements = self.CreateMeasurements()
1442 pointStruct = aMeasurements.GravityCenter(obj)
1443 aMeasurements.UnRegister()
1444 return pointStruct.x, pointStruct.y, pointStruct.z
1446 pass # end of class smeshBuilder
1449 omniORB.registerObjref(SMESH._objref_SMESH_Gen._NP_RepositoryId, smeshBuilder)
1450 """Registering the new proxy for SMESH.SMESH_Gen"""
1453 def New( instance=None, instanceGeom=None):
1455 Create a new smeshBuilder instance. The smeshBuilder class provides the Python
1456 interface to create or load meshes.
1461 salome.salome_init()
1462 from salome.smesh import smeshBuilder
1463 smesh = smeshBuilder.New()
1466 instance: CORBA proxy of SMESH Engine. If None, the default Engine is used.
1467 instanceGeom: CORBA proxy of GEOM Engine. If None, the default Engine is used.
1469 :class:`smeshBuilder` instance
1474 if instance and isinstance( instance, SALOMEDS._objref_Study ):
1476 sys.stderr.write("Warning: 'study' argument is no more needed in smeshBuilder.New(). Consider updating your script!!!\n\n")
1481 smeshInst = smeshBuilder()
1482 assert isinstance(smeshInst,smeshBuilder), "Smesh engine class is %s but should be smeshBuilder.smeshBuilder. Import salome.smesh.smeshBuilder before creating the instance."%smeshInst.__class__
1483 smeshInst.init_smesh(instanceGeom)
1487 # Public class: Mesh
1488 # ==================
1491 class Mesh(metaclass = MeshMeta):
1493 This class allows defining and managing a mesh.
1494 It has a set of methods to build a mesh on the given geometry, including the definition of sub-meshes.
1495 It also has methods to define groups of mesh elements, to modify a mesh (by addition of
1496 new nodes and elements and by changing the existing entities), to get information
1497 about a mesh and to export a mesh in different formats.
1504 def __init__(self, smeshpyD, geompyD, obj=0, name=0):
1509 Create a mesh on the shape *obj* (or an empty mesh if *obj* is equal to 0) and
1510 sets the GUI name of this mesh to *name*.
1513 smeshpyD: an instance of smeshBuilder class
1514 geompyD: an instance of geomBuilder class
1515 obj: Shape to be meshed or :class:`SMESH.SMESH_Mesh` object
1516 name: Study name of the mesh
1519 self.smeshpyD = smeshpyD
1520 self.geompyD = geompyD
1525 if isinstance(obj, geomBuilder.GEOM._objref_GEOM_Object):
1528 # publish geom of mesh (issue 0021122)
1529 if not self.geom.GetStudyEntry():
1533 geo_name = name + " shape"
1535 geo_name = "%s_%s to mesh"%(self.geom.GetShapeType(), id(self.geom)%100)
1536 geompyD.addToStudy( self.geom, geo_name )
1537 self.SetMesh( self.smeshpyD.CreateMesh(self.geom) )
1539 elif isinstance(obj, SMESH._objref_SMESH_Mesh):
1542 self.SetMesh( self.smeshpyD.CreateEmptyMesh() )
1544 self.smeshpyD.SetName(self.mesh, name)
1546 self.smeshpyD.SetName(self.mesh, GetName(obj)) # + " mesh"
1549 self.geom = self.mesh.GetShapeToMesh()
1551 self.editor = self.mesh.GetMeshEditor()
1552 self.functors = [None] * SMESH.FT_Undefined._v
1554 # set self to algoCreator's
1555 for attrName in dir(self):
1556 attr = getattr( self, attrName )
1557 if isinstance( attr, algoCreator ):
1558 setattr( self, attrName, attr.copy( self ))
1565 Destructor. Clean-up resources
1568 #self.mesh.UnRegister()
1572 def SetMesh(self, theMesh):
1574 Initialize the Mesh object from an instance of :class:`SMESH.SMESH_Mesh` interface
1577 theMesh: a :class:`SMESH.SMESH_Mesh` object
1581 # do not call Register() as this prevents mesh servant deletion at closing study
1582 #if self.mesh: self.mesh.UnRegister()
1585 #self.mesh.Register()
1586 self.geom = self.mesh.GetShapeToMesh()
1591 Return the mesh, that is an encapsulated instance of :class:`SMESH.SMESH_Mesh` interface
1594 a :class:`SMESH.SMESH_Mesh` object
1601 Get the name of the mesh
1604 the name of the mesh as a string
1607 name = GetName(self.GetMesh())
1610 def SetName(self, name):
1612 Set a name to the mesh
1615 name: a new name of the mesh
1618 self.smeshpyD.SetName(self.GetMesh(), name)
1620 def GetSubMesh(self, geom, name):
1622 Get a sub-mesh object associated to a *geom* geometrical object.
1625 geom: a geometrical object (shape)
1626 name: a name for the sub-mesh in the Object Browser
1629 an object of type :class:`SMESH.SMESH_subMesh`, representing a part of mesh,
1630 which lies on the given shape
1633 A sub-mesh is implicitly created when a sub-shape is specified at
1634 creating an algorithm, for example::
1636 algo1D = mesh.Segment(geom=Edge_1)
1638 create a sub-mesh on *Edge_1* and assign Wire Discretization algorithm to it.
1639 The created sub-mesh can be retrieved from the algorithm::
1641 submesh = algo1D.GetSubMesh()
1644 AssureGeomPublished( self, geom, name )
1645 submesh = self.mesh.GetSubMesh( geom, name )
1650 Return the shape associated to the mesh
1658 def SetShape(self, geom):
1660 Associate the given shape to the mesh (entails the recreation of the mesh)
1663 geom: the shape to be meshed (GEOM_Object)
1666 self.mesh = self.smeshpyD.CreateMesh(geom)
1668 def HasShapeToMesh(self):
1670 Return ``True`` if this mesh is based on geometry
1672 return self.mesh.HasShapeToMesh()
1676 Load mesh from the study after opening the study
1680 def IsReadyToCompute(self, theSubObject):
1682 Return true if the hypotheses are defined well
1685 theSubObject: a sub-shape of a mesh shape
1691 return self.smeshpyD.IsReadyToCompute(self.mesh, theSubObject)
1693 def GetAlgoState(self, theSubObject):
1695 Return errors of hypotheses definition.
1696 The list of errors is empty if everything is OK.
1699 theSubObject: a sub-shape of a mesh shape
1705 return self.smeshpyD.GetAlgoState(self.mesh, theSubObject)
1707 def GetGeometryByMeshElement(self, theElementID, theGeomName):
1709 Return a geometrical object on which the given element was built.
1710 The returned geometrical object, if not nil, is either found in the
1711 study or published by this method with the given name
1714 theElementID: the id of the mesh element
1715 theGeomName: the user-defined name of the geometrical object
1718 GEOM.GEOM_Object instance
1721 return self.smeshpyD.GetGeometryByMeshElement( self.mesh, theElementID, theGeomName )
1723 def MeshDimension(self):
1725 Return the mesh dimension depending on the dimension of the underlying shape
1726 or, if the mesh is not based on any shape, basing on deimension of elements
1729 mesh dimension as an integer value [0,3]
1732 if self.mesh.HasShapeToMesh():
1733 shells = self.geompyD.SubShapeAllIDs( self.geom, self.geompyD.ShapeType["SOLID"] )
1734 if len( shells ) > 0 :
1736 elif self.geompyD.NumberOfFaces( self.geom ) > 0 :
1738 elif self.geompyD.NumberOfEdges( self.geom ) > 0 :
1743 if self.NbVolumes() > 0: return 3
1744 if self.NbFaces() > 0: return 2
1745 if self.NbEdges() > 0: return 1
1748 def Evaluate(self, geom=0):
1750 Evaluate size of prospective mesh on a shape
1753 a list where i-th element is a number of elements of i-th :class:`SMESH.EntityType`.
1754 To know predicted number of e.g. edges, inquire it this way::
1756 Evaluate()[ smesh.EnumToLong( SMESH.Entity_Edge )]
1759 if geom == 0 or not isinstance(geom, geomBuilder.GEOM._objref_GEOM_Object):
1761 geom = self.mesh.GetShapeToMesh()
1764 return self.smeshpyD.Evaluate(self.mesh, geom)
1767 def Compute(self, geom=0, discardModifs=False, refresh=False):
1769 Compute the mesh and return the status of the computation
1772 geom: geomtrical shape on which mesh data should be computed
1773 discardModifs: if True and the mesh has been edited since
1774 a last total re-compute and that may prevent successful partial re-compute,
1775 then the mesh is cleaned before Compute()
1776 refresh: if *True*, Object Browser is automatically updated (when running in GUI)
1782 if geom == 0 or not isinstance(geom, geomBuilder.GEOM._objref_GEOM_Object):
1784 geom = self.mesh.GetShapeToMesh()
1789 if discardModifs and self.mesh.HasModificationsToDiscard(): # issue 0020693
1791 ok = self.smeshpyD.Compute(self.mesh, geom)
1792 except SALOME.SALOME_Exception as ex:
1793 print("Mesh computation failed, exception caught:")
1794 print(" ", ex.details.text)
1797 print("Mesh computation failed, exception caught:")
1798 traceback.print_exc()
1802 # Treat compute errors
1803 computeErrors = self.smeshpyD.GetComputeErrors( self.mesh, geom )
1805 for err in computeErrors:
1806 if self.mesh.HasShapeToMesh():
1807 shapeText = " on %s" % self.GetSubShapeName( err.subShapeID )
1809 stdErrors = ["OK", #COMPERR_OK
1810 "Invalid input mesh", #COMPERR_BAD_INPUT_MESH
1811 "std::exception", #COMPERR_STD_EXCEPTION
1812 "OCC exception", #COMPERR_OCC_EXCEPTION
1813 "..", #COMPERR_SLM_EXCEPTION
1814 "Unknown exception", #COMPERR_EXCEPTION
1815 "Memory allocation problem", #COMPERR_MEMORY_PB
1816 "Algorithm failed", #COMPERR_ALGO_FAILED
1817 "Unexpected geometry", #COMPERR_BAD_SHAPE
1818 "Warning", #COMPERR_WARNING
1819 "Computation cancelled",#COMPERR_CANCELED
1820 "No mesh on sub-shape"] #COMPERR_NO_MESH_ON_SHAPE
1822 if err.code < len(stdErrors): errText = stdErrors[err.code]
1824 errText = "code %s" % -err.code
1825 if errText: errText += ". "
1826 errText += err.comment
1827 if allReasons: allReasons += "\n"
1829 allReasons += '- "%s"%s - %s' %(err.algoName, shapeText, errText)
1831 allReasons += '- "%s" failed%s. Error: %s' %(err.algoName, shapeText, errText)
1835 errors = self.smeshpyD.GetAlgoState( self.mesh, geom )
1837 if err.isGlobalAlgo:
1845 reason = '%s %sD algorithm is missing' % (glob, dim)
1846 elif err.state == HYP_MISSING:
1847 reason = ('%s %sD algorithm "%s" misses %sD hypothesis'
1848 % (glob, dim, name, dim))
1849 elif err.state == HYP_NOTCONFORM:
1850 reason = 'Global "Not Conform mesh allowed" hypothesis is missing'
1851 elif err.state == HYP_BAD_PARAMETER:
1852 reason = ('Hypothesis of %s %sD algorithm "%s" has a bad parameter value'
1853 % ( glob, dim, name ))
1854 elif err.state == HYP_BAD_GEOMETRY:
1855 reason = ('%s %sD algorithm "%s" is assigned to mismatching'
1856 'geometry' % ( glob, dim, name ))
1857 elif err.state == HYP_HIDDEN_ALGO:
1858 reason = ('%s %sD algorithm "%s" is ignored due to presence of a %s '
1859 'algorithm of upper dimension generating %sD mesh'
1860 % ( glob, dim, name, glob, dim ))
1862 reason = ("For unknown reason. "
1863 "Developer, revise Mesh.Compute() implementation in smeshBuilder.py!")
1865 if allReasons: allReasons += "\n"
1866 allReasons += "- " + reason
1868 if not ok or allReasons != "":
1869 msg = '"' + GetName(self.mesh) + '"'
1870 if ok: msg += " has been computed with warnings"
1871 else: msg += " has not been computed"
1872 if allReasons != "": msg += ":"
1877 if salome.sg.hasDesktop():
1878 if not isinstance( refresh, list): # not a call from subMesh.Compute()
1879 if refresh: salome.sg.updateObjBrowser()
1883 def GetComputeErrors(self, shape=0 ):
1885 Return a list of error messages (:class:`SMESH.ComputeError`) of the last :meth:`Compute`
1889 shape = self.mesh.GetShapeToMesh()
1890 return self.smeshpyD.GetComputeErrors( self.mesh, shape )
1892 def GetSubShapeName(self, subShapeID ):
1894 Return a name of a sub-shape by its ID.
1895 Possible variants (for *subShapeID* == 3):
1897 - **"Face_12"** - published sub-shape
1898 - **FACE #3** - not published sub-shape
1899 - **sub-shape #3** - invalid sub-shape ID
1900 - **#3** - error in this function
1903 subShapeID: a unique ID of a sub-shape
1906 a string describing the sub-shape
1910 if not self.mesh.HasShapeToMesh():
1914 mainIOR = salome.orb.object_to_string( self.GetShape() )
1916 mainSO = s.FindObjectIOR(mainIOR)
1919 shapeText = '"%s"' % mainSO.GetName()
1920 subIt = s.NewChildIterator(mainSO)
1922 subSO = subIt.Value()
1924 obj = subSO.GetObject()
1925 if not obj: continue
1926 go = obj._narrow( geomBuilder.GEOM._objref_GEOM_Object )
1929 ids = self.geompyD.GetSubShapeID( self.GetShape(), go )
1932 if ids == subShapeID:
1933 shapeText = '"%s"' % subSO.GetName()
1936 shape = self.geompyD.GetSubShape( self.GetShape(), [subShapeID])
1938 shapeText = '%s #%s' % (shape.GetShapeType(), subShapeID)
1940 shapeText = 'sub-shape #%s' % (subShapeID)
1942 shapeText = "#%s" % (subShapeID)
1945 def GetFailedShapes(self, publish=False):
1947 Return a list of sub-shapes meshing of which failed, grouped into GEOM groups by
1948 error of an algorithm
1951 publish: if *True*, the returned groups will be published in the study
1954 a list of GEOM groups each named after a failed algorithm
1959 computeErrors = self.smeshpyD.GetComputeErrors( self.mesh, self.GetShape() )
1960 for err in computeErrors:
1961 shape = self.geompyD.GetSubShape( self.GetShape(), [err.subShapeID])
1962 if not shape: continue
1963 if err.algoName in algo2shapes:
1964 algo2shapes[ err.algoName ].append( shape )
1966 algo2shapes[ err.algoName ] = [ shape ]
1970 for algoName, shapes in list(algo2shapes.items()):
1972 groupType = self.smeshpyD.EnumToLong( shapes[0].GetShapeType() )
1973 otherTypeShapes = []
1975 group = self.geompyD.CreateGroup( self.geom, groupType )
1976 for shape in shapes:
1977 if shape.GetShapeType() == shapes[0].GetShapeType():
1978 sameTypeShapes.append( shape )
1980 otherTypeShapes.append( shape )
1981 self.geompyD.UnionList( group, sameTypeShapes )
1983 group.SetName( "%s %s" % ( algoName, shapes[0].GetShapeType() ))
1985 group.SetName( algoName )
1986 groups.append( group )
1987 shapes = otherTypeShapes
1990 for group in groups:
1991 self.geompyD.addToStudyInFather( self.geom, group, group.GetName() )
1994 def GetMeshOrder(self):
1996 Return sub-mesh objects list in meshing order
1999 list of lists of :class:`sub-meshes <SMESH.SMESH_subMesh>`
2002 return self.mesh.GetMeshOrder()
2004 def SetMeshOrder(self, submeshes):
2006 Set order in which concurrent sub-meshes should be meshed
2009 submeshes: list of lists of :class:`sub-meshes <SMESH.SMESH_subMesh>`
2012 return self.mesh.SetMeshOrder(submeshes)
2014 def Clear(self, refresh=False):
2016 Remove all nodes and elements generated on geometry. Imported elements remain.
2019 refresh: if *True*, Object browser is automatically updated (when running in GUI)
2023 if ( salome.sg.hasDesktop() ):
2024 if refresh: salome.sg.updateObjBrowser()
2026 def ClearSubMesh(self, geomId, refresh=False):
2028 Remove all nodes and elements of indicated shape
2031 geomId: the ID of a sub-shape to remove elements on
2032 refresh: if *True*, Object browser is automatically updated (when running in GUI)
2035 self.mesh.ClearSubMesh(geomId)
2036 if salome.sg.hasDesktop():
2037 if refresh: salome.sg.updateObjBrowser()
2039 def AutomaticTetrahedralization(self, fineness=0):
2041 Compute a tetrahedral mesh using AutomaticLength + MEFISTO + Tetrahedron
2044 fineness: [0.0,1.0] defines mesh fineness
2050 dim = self.MeshDimension()
2052 self.RemoveGlobalHypotheses()
2053 self.Segment().AutomaticLength(fineness)
2055 self.Triangle().LengthFromEdges()
2060 return self.Compute()
2062 def AutomaticHexahedralization(self, fineness=0):
2064 Compute an hexahedral mesh using AutomaticLength + Quadrangle + Hexahedron
2067 fineness: [0.0, 1.0] defines mesh fineness
2073 dim = self.MeshDimension()
2074 # assign the hypotheses
2075 self.RemoveGlobalHypotheses()
2076 self.Segment().AutomaticLength(fineness)
2083 return self.Compute()
2085 def AddHypothesis(self, hyp, geom=0):
2090 hyp: a hypothesis to assign
2091 geom: a subhape of mesh geometry
2094 :class:`SMESH.Hypothesis_Status`
2097 if isinstance( hyp, geomBuilder.GEOM._objref_GEOM_Object ):
2098 hyp, geom = geom, hyp
2099 if isinstance( hyp, Mesh_Algorithm ):
2100 hyp = hyp.GetAlgorithm()
2105 geom = self.mesh.GetShapeToMesh()
2108 if self.mesh.HasShapeToMesh():
2109 hyp_type = hyp.GetName()
2110 lib_name = hyp.GetLibName()
2111 # checkAll = ( not geom.IsSame( self.mesh.GetShapeToMesh() ))
2112 # if checkAll and geom:
2113 # checkAll = geom.GetType() == 37
2115 isApplicable = self.smeshpyD.IsApplicable(hyp_type, lib_name, geom, checkAll)
2117 AssureGeomPublished( self, geom, "shape for %s" % hyp.GetName())
2118 status = self.mesh.AddHypothesis(geom, hyp)
2120 status = HYP_BAD_GEOMETRY, ""
2121 hyp_name = GetName( hyp )
2124 geom_name = geom.GetName()
2125 isAlgo = hyp._narrow( SMESH_Algo )
2126 TreatHypoStatus( status, hyp_name, geom_name, isAlgo, self )
2129 def IsUsedHypothesis(self, hyp, geom):
2131 Return True if an algorithm or hypothesis is assigned to a given shape
2134 hyp: an algorithm or hypothesis to check
2135 geom: a subhape of mesh geometry
2141 if not hyp: # or not geom
2143 if isinstance( hyp, Mesh_Algorithm ):
2144 hyp = hyp.GetAlgorithm()
2146 hyps = self.GetHypothesisList(geom)
2148 if h.GetId() == hyp.GetId():
2152 def RemoveHypothesis(self, hyp, geom=0):
2154 Unassign a hypothesis
2157 hyp (SMESH.SMESH_Hypothesis): a hypothesis to unassign
2158 geom (GEOM.GEOM_Object): a sub-shape of mesh geometry
2161 :class:`SMESH.Hypothesis_Status`
2166 if isinstance( hyp, Mesh_Algorithm ):
2167 hyp = hyp.GetAlgorithm()
2173 if self.IsUsedHypothesis( hyp, shape ):
2174 return self.mesh.RemoveHypothesis( shape, hyp )
2175 hypName = GetName( hyp )
2176 geoName = GetName( shape )
2177 print("WARNING: RemoveHypothesis() failed as '%s' is not assigned to '%s' shape" % ( hypName, geoName ))
2180 def GetHypothesisList(self, geom):
2182 Get the list of hypotheses added on a geometry
2185 geom (GEOM.GEOM_Object): a sub-shape of mesh geometry
2188 the sequence of :class:`SMESH.SMESH_Hypothesis`
2191 return self.mesh.GetHypothesisList( geom )
2193 def RemoveGlobalHypotheses(self):
2195 Remove all global hypotheses
2198 current_hyps = self.mesh.GetHypothesisList( self.geom )
2199 for hyp in current_hyps:
2200 self.mesh.RemoveHypothesis( self.geom, hyp )
2203 def ExportMED(self, *args, **kwargs):
2205 Export the mesh in a file in MED format
2206 allowing to overwrite the file if it exists or add the exported data to its contents
2209 fileName: is the file name
2210 auto_groups (boolean): parameter for creating/not creating
2211 the groups Group_On_All_Nodes, Group_On_All_Faces, ... ;
2212 the typical use is auto_groups=False.
2213 minor (int): define the minor version (y, where version is x.y.z) of MED file format.
2214 The minor must be between 0 and the current minor version of MED file library.
2215 If minor is equal to -1, the minor version is not changed (default).
2216 The major version (x, where version is x.y.z) cannot be changed.
2217 overwrite (boolean): parameter for overwriting/not overwriting the file
2218 meshPart: a part of mesh (:class:`sub-mesh, group or filter <SMESH.SMESH_IDSource>`) to export instead of the mesh
2219 autoDimension: if *True* (default), a space dimension of a MED mesh can be either
2221 - 1D if all mesh nodes lie on OX coordinate axis, or
2222 - 2D if all mesh nodes lie on XOY coordinate plane, or
2223 - 3D in the rest cases.
2225 If *autoDimension* is *False*, the space dimension is always 3.
2226 fields: list of GEOM fields defined on the shape to mesh.
2227 geomAssocFields: each character of this string means a need to export a
2228 corresponding field; correspondence between fields and characters
2231 - 'v' stands for "_vertices_" field;
2232 - 'e' stands for "_edges_" field;
2233 - 'f' stands for "_faces_" field;
2234 - 's' stands for "_solids_" field.
2236 zTolerance (float): tolerance in Z direction. If Z coordinate of a node is
2237 close to zero within a given tolerance, the coordinate is set to zero.
2238 If *ZTolerance* is negative (default), the node coordinates are kept as is.
2240 # process positional arguments
2241 #args = [i for i in args if i not in [SMESH.MED_V2_1, SMESH.MED_V2_2]] # backward compatibility
2243 auto_groups = args[1] if len(args) > 1 else False
2244 minor = args[2] if len(args) > 2 else -1
2245 overwrite = args[3] if len(args) > 3 else True
2246 meshPart = args[4] if len(args) > 4 else None
2247 autoDimension = args[5] if len(args) > 5 else True
2248 fields = args[6] if len(args) > 6 else []
2249 geomAssocFields = args[7] if len(args) > 7 else ''
2250 z_tolerance = args[8] if len(args) > 8 else -1.
2251 # process keywords arguments
2252 auto_groups = kwargs.get("auto_groups", auto_groups)
2253 minor = kwargs.get("minor", minor)
2254 overwrite = kwargs.get("overwrite", overwrite)
2255 meshPart = kwargs.get("meshPart", meshPart)
2256 autoDimension = kwargs.get("autoDimension", autoDimension)
2257 fields = kwargs.get("fields", fields)
2258 geomAssocFields = kwargs.get("geomAssocFields", geomAssocFields)
2259 z_tolerance = kwargs.get("zTolerance", z_tolerance)
2261 # invoke engine's function
2262 if meshPart or fields or geomAssocFields or z_tolerance > 0:
2263 unRegister = genObjUnRegister()
2264 if isinstance( meshPart, list ):
2265 meshPart = self.GetIDSource( meshPart, SMESH.ALL )
2266 unRegister.set( meshPart )
2268 z_tolerance,Parameters,hasVars = ParseParameters(z_tolerance)
2269 self.mesh.SetParameters(Parameters)
2271 self.mesh.ExportPartToMED( meshPart, fileName, auto_groups, minor, overwrite, autoDimension,
2272 fields, geomAssocFields, z_tolerance)
2274 self.mesh.ExportMED(fileName, auto_groups, minor, overwrite, autoDimension)
2276 def ExportSAUV(self, f, auto_groups=0):
2278 Export the mesh in a file in SAUV format
2283 auto_groups: boolean parameter for creating/not creating
2284 the groups Group_On_All_Nodes, Group_On_All_Faces, ... ;
2285 the typical use is auto_groups=False.
2288 self.mesh.ExportSAUV(f, auto_groups)
2290 def ExportDAT(self, f, meshPart=None):
2292 Export the mesh in a file in DAT format
2296 meshPart: a part of mesh (:class:`sub-mesh, group or filter <SMESH.SMESH_IDSource>`) to export instead of the mesh
2300 unRegister = genObjUnRegister()
2301 if isinstance( meshPart, list ):
2302 meshPart = self.GetIDSource( meshPart, SMESH.ALL )
2303 unRegister.set( meshPart )
2304 self.mesh.ExportPartToDAT( meshPart, f )
2306 self.mesh.ExportDAT(f)
2308 def ExportUNV(self, f, meshPart=None):
2310 Export the mesh in a file in UNV format
2314 meshPart: a part of mesh (:class:`sub-mesh, group or filter <SMESH.SMESH_IDSource>`) to export instead of the mesh
2318 unRegister = genObjUnRegister()
2319 if isinstance( meshPart, list ):
2320 meshPart = self.GetIDSource( meshPart, SMESH.ALL )
2321 unRegister.set( meshPart )
2322 self.mesh.ExportPartToUNV( meshPart, f )
2324 self.mesh.ExportUNV(f)
2326 def ExportSTL(self, f, ascii=1, meshPart=None):
2328 Export the mesh in a file in STL format
2332 ascii: defines the file encoding
2333 meshPart: a part of mesh (:class:`sub-mesh, group or filter <SMESH.SMESH_IDSource>`) to export instead of the mesh
2337 unRegister = genObjUnRegister()
2338 if isinstance( meshPart, list ):
2339 meshPart = self.GetIDSource( meshPart, SMESH.ALL )
2340 unRegister.set( meshPart )
2341 self.mesh.ExportPartToSTL( meshPart, f, ascii )
2343 self.mesh.ExportSTL(f, ascii)
2345 def ExportCGNS(self, f, overwrite=1, meshPart=None, groupElemsByType=False):
2347 Export the mesh in a file in CGNS format
2351 overwrite: boolean parameter for overwriting/not overwriting the file
2352 meshPart: a part of mesh (:class:`sub-mesh, group or filter <SMESH.SMESH_IDSource>`) to export instead of the mesh
2353 groupElemsByType: if True all elements of same entity type are exported at ones,
2354 else elements are exported in order of their IDs which can cause creation
2355 of multiple cgns sections
2358 unRegister = genObjUnRegister()
2359 if isinstance( meshPart, list ):
2360 meshPart = self.GetIDSource( meshPart, SMESH.ALL )
2361 unRegister.set( meshPart )
2362 if isinstance( meshPart, Mesh ):
2363 meshPart = meshPart.mesh
2365 meshPart = self.mesh
2366 self.mesh.ExportCGNS(meshPart, f, overwrite, groupElemsByType)
2368 def ExportGMF(self, f, meshPart=None):
2370 Export the mesh in a file in GMF format.
2371 GMF files must have .mesh extension for the ASCII format and .meshb for
2372 the bynary format. Other extensions are not allowed.
2376 meshPart: a part of mesh (:class:`sub-mesh, group or filter <SMESH.SMESH_IDSource>`) to export instead of the mesh
2379 unRegister = genObjUnRegister()
2380 if isinstance( meshPart, list ):
2381 meshPart = self.GetIDSource( meshPart, SMESH.ALL )
2382 unRegister.set( meshPart )
2383 if isinstance( meshPart, Mesh ):
2384 meshPart = meshPart.mesh
2386 meshPart = self.mesh
2387 self.mesh.ExportGMF(meshPart, f, True)
2389 def ExportToMED(self, *args, **kwargs):
2391 Deprecated, used only for compatibility! Please, use :meth:`ExportMED` method instead.
2392 Export the mesh in a file in MED format
2393 allowing to overwrite the file if it exists or add the exported data to its contents
2396 fileName: the file name
2397 opt (boolean): parameter for creating/not creating
2398 the groups Group_On_All_Nodes, Group_On_All_Faces, ...
2399 overwrite: boolean parameter for overwriting/not overwriting the file
2400 autoDimension: if *True* (default), a space dimension of a MED mesh can be either
2402 - 1D if all mesh nodes lie on OX coordinate axis, or
2403 - 2D if all mesh nodes lie on XOY coordinate plane, or
2404 - 3D in the rest cases.
2406 If **autoDimension** is *False*, the space dimension is always 3.
2409 print("WARNING: ExportToMED() is deprecated, use ExportMED() instead")
2410 # process positional arguments
2411 #args = [i for i in args if i not in [SMESH.MED_V2_1, SMESH.MED_V2_2]] # backward compatibility
2413 auto_groups = args[1] if len(args) > 1 else False
2414 overwrite = args[2] if len(args) > 2 else True
2415 autoDimension = args[3] if len(args) > 3 else True
2416 # process keywords arguments
2417 auto_groups = kwargs.get("opt", auto_groups) # old keyword name
2418 auto_groups = kwargs.get("auto_groups", auto_groups) # new keyword name
2419 overwrite = kwargs.get("overwrite", overwrite)
2420 autoDimension = kwargs.get("autoDimension", autoDimension)
2422 # invoke engine's function
2423 self.mesh.ExportMED(fileName, auto_groups, minor, overwrite, autoDimension)
2425 def ExportToMEDX(self, *args, **kwargs):
2427 Deprecated, used only for compatibility! Please, use ExportMED() method instead.
2428 Export the mesh in a file in MED format
2431 fileName: the file name
2432 opt (boolean): parameter for creating/not creating
2433 the groups Group_On_All_Nodes, Group_On_All_Faces, ...
2434 overwrite: boolean parameter for overwriting/not overwriting the file
2435 autoDimension: if *True* (default), a space dimension of a MED mesh can be either
2437 - 1D if all mesh nodes lie on OX coordinate axis, or
2438 - 2D if all mesh nodes lie on XOY coordinate plane, or
2439 - 3D in the rest cases.
2441 If **autoDimension** is *False*, the space dimension is always 3.
2444 print("WARNING: ExportToMEDX() is deprecated, use ExportMED() instead")
2445 # process positional arguments
2446 #args = [i for i in args if i not in [SMESH.MED_V2_1, SMESH.MED_V2_2]] # backward compatibility
2448 auto_groups = args[1] if len(args) > 1 else False
2449 overwrite = args[2] if len(args) > 2 else True
2450 autoDimension = args[3] if len(args) > 3 else True
2451 # process keywords arguments
2452 auto_groups = kwargs.get("auto_groups", auto_groups)
2453 overwrite = kwargs.get("overwrite", overwrite)
2454 autoDimension = kwargs.get("autoDimension", autoDimension)
2456 # invoke engine's function
2457 self.mesh.ExportMED(fileName, auto_groups, minor, overwrite, autoDimension)
2459 # Operations with groups:
2460 # ----------------------
2461 def CreateEmptyGroup(self, elementType, name):
2463 Create an empty standalone mesh group
2466 elementType: the :class:`type <SMESH.ElementType>` of elements in the group;
2467 either of (SMESH.NODE, SMESH.EDGE, SMESH.FACE, SMESH.VOLUME)
2468 name: the name of the mesh group
2471 :class:`SMESH.SMESH_Group`
2474 return self.mesh.CreateGroup(elementType, name)
2476 def Group(self, grp, name=""):
2478 Create a mesh group based on the geometric object *grp*
2479 and give it a *name*.
2480 If *name* is not defined the name of the geometric group is used
2483 Works like :meth:`GroupOnGeom`.
2486 grp: a geometric group, a vertex, an edge, a face or a solid
2487 name: the name of the mesh group
2490 :class:`SMESH.SMESH_GroupOnGeom`
2493 return self.GroupOnGeom(grp, name)
2495 def GroupOnGeom(self, grp, name="", typ=None):
2497 Create a mesh group based on the geometrical object *grp*
2498 and give it a *name*.
2499 if *name* is not defined the name of the geometric group is used
2502 grp: a geometrical group, a vertex, an edge, a face or a solid
2503 name: the name of the mesh group
2504 typ: the type of elements in the group; either of
2505 (SMESH.NODE, SMESH.EDGE, SMESH.FACE, SMESH.VOLUME). If not set, it is
2506 automatically detected by the type of the geometry
2509 :class:`SMESH.SMESH_GroupOnGeom`
2512 AssureGeomPublished( self, grp, name )
2514 name = grp.GetName()
2516 typ = self._groupTypeFromShape( grp )
2517 return self.mesh.CreateGroupFromGEOM(typ, name, grp)
2519 def _groupTypeFromShape( self, shape ):
2521 Pivate method to get a type of group on geometry
2523 tgeo = str(shape.GetShapeType())
2524 if tgeo == "VERTEX":
2526 elif tgeo == "EDGE":
2528 elif tgeo == "FACE" or tgeo == "SHELL":
2530 elif tgeo == "SOLID" or tgeo == "COMPSOLID":
2532 elif tgeo == "COMPOUND":
2533 sub = self.geompyD.SubShapeAll( shape, self.geompyD.ShapeType["SHAPE"])
2535 raise ValueError("_groupTypeFromShape(): empty geometric group or compound '%s'" % GetName(shape))
2536 return self._groupTypeFromShape( sub[0] )
2538 raise ValueError("_groupTypeFromShape(): invalid geometry '%s'" % GetName(shape))
2541 def GroupOnFilter(self, typ, name, filter):
2543 Create a mesh group with given *name* based on the *filter*.
2544 It is a special type of group dynamically updating it's contents during
2548 typ: the type of elements in the group; either of
2549 (SMESH.NODE, SMESH.EDGE, SMESH.FACE, SMESH.VOLUME).
2550 name: the name of the mesh group
2551 filter (SMESH.Filter): the filter defining group contents
2554 :class:`SMESH.SMESH_GroupOnFilter`
2557 return self.mesh.CreateGroupFromFilter(typ, name, filter)
2559 def MakeGroupByIds(self, groupName, elementType, elemIDs):
2561 Create a mesh group by the given ids of elements
2564 groupName: the name of the mesh group
2565 elementType: the type of elements in the group; either of
2566 (SMESH.NODE, SMESH.EDGE, SMESH.FACE, SMESH.VOLUME).
2567 elemIDs: either the list of ids, :class:`mesh, sub-mesh, group or filter <SMESH.SMESH_IDSource>`
2570 :class:`SMESH.SMESH_Group`
2573 group = self.mesh.CreateGroup(elementType, groupName)
2574 if isinstance( elemIDs, Mesh ):
2575 elemIDs = elemIDs.GetMesh()
2576 if hasattr( elemIDs, "GetIDs" ):
2577 if hasattr( elemIDs, "SetMesh" ):
2578 elemIDs.SetMesh( self.GetMesh() )
2579 group.AddFrom( elemIDs )
2587 CritType=FT_Undefined,
2590 UnaryOp=FT_Undefined,
2593 Create a mesh group by the given conditions
2596 groupName: the name of the mesh group
2597 elementType (SMESH.ElementType): the type of elements (SMESH.NODE, SMESH.EDGE, SMESH.FACE, SMESH.VOLUME)
2598 CritType (SMESH.FunctorType): the type of criterion (SMESH.FT_Taper, SMESH.FT_Area, etc.).
2599 Note that the items starting from FT_LessThan are not suitable for CritType.
2600 Compare (SMESH.FunctorType): belongs to {SMESH.FT_LessThan, SMESH.FT_MoreThan, SMESH.FT_EqualTo}
2601 Threshold: the threshold value (range of ids as string, shape, numeric, depending on *CritType*)
2602 UnaryOp (SMESH.FunctorType): SMESH.FT_LogicalNOT or SMESH.FT_Undefined
2603 Tolerance (float): the tolerance used by SMESH.FT_BelongToGeom, SMESH.FT_BelongToSurface,
2604 SMESH.FT_LyingOnGeom, SMESH.FT_CoplanarFaces criteria
2607 :class:`SMESH.SMESH_GroupOnFilter`
2610 aCriterion = self.smeshpyD.GetCriterion(elementType, CritType, Compare, Threshold, UnaryOp, FT_Undefined,Tolerance)
2611 group = self.MakeGroupByCriterion(groupName, aCriterion)
2614 def MakeGroupByCriterion(self, groupName, Criterion):
2616 Create a mesh group by the given criterion
2619 groupName: the name of the mesh group
2620 Criterion: the instance of :class:`SMESH.Filter.Criterion` class
2623 :class:`SMESH.SMESH_GroupOnFilter`
2626 :meth:`smeshBuilder.GetCriterion`
2629 return self.MakeGroupByCriteria( groupName, [Criterion] )
2631 def MakeGroupByCriteria(self, groupName, theCriteria, binOp=SMESH.FT_LogicalAND):
2633 Create a mesh group by the given criteria (list of :class:`SMESH.Filter.Criterion`)
2636 groupName: the name of the mesh group
2637 theCriteria: the list of :class:`SMESH.Filter.Criterion`
2638 binOp: binary operator (SMESH.FT_LogicalAND or SMESH.FT_LogicalOR ) used when binary operator of criteria is undefined
2641 :class:`SMESH.SMESH_GroupOnFilter`
2644 :meth:`smeshBuilder.GetCriterion`
2647 aFilter = self.smeshpyD.GetFilterFromCriteria( theCriteria, binOp )
2648 group = self.MakeGroupByFilter(groupName, aFilter)
2651 def MakeGroupByFilter(self, groupName, theFilter):
2653 Create a mesh group by the given filter
2656 groupName (string): the name of the mesh group
2657 theFilter (SMESH.Filter): the filter
2660 :class:`SMESH.SMESH_GroupOnFilter`
2663 :meth:`smeshBuilder.GetFilter`
2666 #group = self.CreateEmptyGroup(theFilter.GetElementType(), groupName)
2667 #theFilter.SetMesh( self.mesh )
2668 #group.AddFrom( theFilter )
2669 group = self.GroupOnFilter( theFilter.GetElementType(), groupName, theFilter )
2672 def RemoveGroup(self, group):
2677 group (SMESH.SMESH_GroupBase): group to remove
2680 self.mesh.RemoveGroup(group)
2682 def RemoveGroupWithContents(self, group):
2684 Remove a group with its contents
2687 group (SMESH.SMESH_GroupBase): group to remove
2690 self.mesh.RemoveGroupWithContents(group)
2692 def GetGroups(self, elemType = SMESH.ALL):
2694 Get the list of groups existing in the mesh in the order of creation
2695 (starting from the oldest one)
2698 elemType (SMESH.ElementType): type of elements the groups contain;
2699 by default groups of elements of all types are returned
2702 a list of :class:`SMESH.SMESH_GroupBase`
2705 groups = self.mesh.GetGroups()
2706 if elemType == SMESH.ALL:
2710 if g.GetType() == elemType:
2711 typedGroups.append( g )
2718 Get the number of groups existing in the mesh
2721 the quantity of groups as an integer value
2724 return self.mesh.NbGroups()
2726 def GetGroupNames(self):
2728 Get the list of names of groups existing in the mesh
2734 groups = self.GetGroups()
2736 for group in groups:
2737 names.append(group.GetName())
2740 def GetGroupByName(self, name, elemType = None):
2742 Find groups by name and type
2745 name (string): name of the group of interest
2746 elemType (SMESH.ElementType): type of elements the groups contain;
2747 by default one group of any type is returned;
2748 if elemType == SMESH.ALL then all groups of any type are returned
2751 a list of :class:`SMESH.SMESH_GroupBase`
2755 for group in self.GetGroups():
2756 if group.GetName() == name:
2757 if elemType is None:
2759 if ( elemType == SMESH.ALL or
2760 group.GetType() == elemType ):
2761 groups.append( group )
2764 def UnionGroups(self, group1, group2, name):
2766 Produce a union of two groups.
2767 A new group is created. All mesh elements that are
2768 present in the initial groups are added to the new one
2771 group1 (SMESH.SMESH_GroupBase): a group
2772 group2 (SMESH.SMESH_GroupBase): another group
2775 instance of :class:`SMESH.SMESH_Group`
2778 return self.mesh.UnionGroups(group1, group2, name)
2780 def UnionListOfGroups(self, groups, name):
2782 Produce a union list of groups.
2783 New group is created. All mesh elements that are present in
2784 initial groups are added to the new one
2787 groups: list of :class:`SMESH.SMESH_GroupBase`
2790 instance of :class:`SMESH.SMESH_Group`
2792 return self.mesh.UnionListOfGroups(groups, name)
2794 def IntersectGroups(self, group1, group2, name):
2796 Prodice an intersection of two groups.
2797 A new group is created. All mesh elements that are common
2798 for the two initial groups are added to the new one.
2801 group1 (SMESH.SMESH_GroupBase): a group
2802 group2 (SMESH.SMESH_GroupBase): another group
2805 instance of :class:`SMESH.SMESH_Group`
2808 return self.mesh.IntersectGroups(group1, group2, name)
2810 def IntersectListOfGroups(self, groups, name):
2812 Produce an intersection of groups.
2813 New group is created. All mesh elements that are present in all
2814 initial groups simultaneously are added to the new one
2817 groups: a list of :class:`SMESH.SMESH_GroupBase`
2820 instance of :class:`SMESH.SMESH_Group`
2822 return self.mesh.IntersectListOfGroups(groups, name)
2824 def CutGroups(self, main_group, tool_group, name):
2826 Produce a cut of two groups.
2827 A new group is created. All mesh elements that are present in
2828 the main group but are not present in the tool group are added to the new one
2831 main_group (SMESH.SMESH_GroupBase): a group to cut from
2832 tool_group (SMESH.SMESH_GroupBase): a group to cut by
2835 an instance of :class:`SMESH.SMESH_Group`
2838 return self.mesh.CutGroups(main_group, tool_group, name)
2840 def CutListOfGroups(self, main_groups, tool_groups, name):
2842 Produce a cut of groups.
2843 A new group is created. All mesh elements that are present in main groups
2844 but do not present in tool groups are added to the new one
2847 main_group: groups to cut from (list of :class:`SMESH.SMESH_GroupBase`)
2848 tool_group: groups to cut by (list of :class:`SMESH.SMESH_GroupBase`)
2851 an instance of :class:`SMESH.SMESH_Group`
2854 return self.mesh.CutListOfGroups(main_groups, tool_groups, name)
2856 def CreateDimGroup(self, groups, elemType, name,
2857 nbCommonNodes = SMESH.ALL_NODES, underlyingOnly = True):
2859 Create a standalone group of entities basing on nodes of other groups.
2862 groups: list of reference :class:`sub-meshes, groups or filters <SMESH.SMESH_IDSource>`, of any type.
2863 elemType: a type of elements to include to the new group; either of
2864 (SMESH.NODE, SMESH.EDGE, SMESH.FACE, SMESH.VOLUME).
2865 name: a name of the new group.
2866 nbCommonNodes: a criterion of inclusion of an element to the new group
2867 basing on number of element nodes common with reference *groups*.
2868 Meaning of possible values are:
2870 - SMESH.ALL_NODES - include if all nodes are common,
2871 - SMESH.MAIN - include if all corner nodes are common (meaningful for a quadratic mesh),
2872 - SMESH.AT_LEAST_ONE - include if one or more node is common,
2873 - SMEHS.MAJORITY - include if half of nodes or more are common.
2874 underlyingOnly: if *True* (default), an element is included to the
2875 new group provided that it is based on nodes of an element of *groups*;
2876 in this case the reference *groups* are supposed to be of higher dimension
2877 than *elemType*, which can be useful for example to get all faces lying on
2878 volumes of the reference *groups*.
2881 an instance of :class:`SMESH.SMESH_Group`
2884 if isinstance( groups, SMESH._objref_SMESH_IDSource ):
2886 return self.mesh.CreateDimGroup(groups, elemType, name, nbCommonNodes, underlyingOnly)
2888 def FaceGroupsSeparatedByEdges( self, sharpAngle, createEdges=False, useExistingEdges=False ):
2890 Distribute all faces of the mesh between groups using sharp edges and optionally
2891 existing 1D elements as group boundaries.
2894 sharpAngle: edge is considered sharp if an angle between normals of
2895 adjacent faces is more than \a sharpAngle in degrees.
2896 createEdges (boolean): to create 1D elements for detected sharp edges.