X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FSMESH_SWIG%2FsmeshDC.py;h=6552a9e197cfea5f10ba16097187b4becbbc1d32;hb=1974e88472a327fd8dacfd36df4c3acd4478a8a8;hp=4789415c96b2ac875e48a97c99d1d6f60d907771;hpb=2daa321efae3d0c6ce41199fa5a2482630d505d9;p=modules%2Fsmesh.git diff --git a/src/SMESH_SWIG/smeshDC.py b/src/SMESH_SWIG/smeshDC.py index 4789415c9..6552a9e19 100644 --- a/src/SMESH_SWIG/smeshDC.py +++ b/src/SMESH_SWIG/smeshDC.py @@ -1,8 +1,5 @@ # -*- coding: iso-8859-1 -*- -# Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE -# -# Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -# CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +# Copyright (C) 2007-2010 CEA/DEN, EDF R&D, OPEN CASCADE # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public @@ -20,6 +17,7 @@ # # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com # + # File : smesh.py # Author : Francis KLOSS, OCC # Module : SMESH @@ -52,6 +50,7 @@ ## @defgroup l3_hypos_ghs3dh GHS3D Parameters hypothesis ## @defgroup l3_hypos_blsurf BLSURF Parameters hypothesis ## @defgroup l3_hypos_hexotic Hexotic Parameters hypothesis +## @defgroup l3_hypos_quad Quadrangle Parameters hypothesis ## @defgroup l3_hypos_additi Additional Hypotheses ## @} @@ -89,6 +88,7 @@ ## @defgroup l2_modif_tofromqu Convert to/from Quadratic Mesh ## @} +## @defgroup l1_measurements Measurements import salome import geompyDC @@ -99,6 +99,7 @@ from SMESH import * import StdMeshers import SALOME +import SALOMEDS # import NETGENPlugin module if possible noNETGENPlugin = 0 @@ -162,6 +163,8 @@ Hexa = 8 Hexotic = 9 BLSURF = 10 GHS3DPRL = 11 +QUADRANGLE = 0 +RADIAL_QUAD = 1 # MirrorType enumeration POINT = SMESH_MeshEditor.POINT @@ -194,6 +197,15 @@ DefaultSize, DefaultGeom, Custom = 0,0,1 PrecisionConfusion = 1e-07 +# TopAbs_State enumeration +[TopAbs_IN, TopAbs_OUT, TopAbs_ON, TopAbs_UNKNOWN] = range(4) + +# Methods of splitting a hexahedron into tetrahedra +Hex_5Tet, Hex_6Tet, Hex_24Tet = 1, 2, 3 + +# import items of enum QuadType +for e in StdMeshers.QuadType._items: exec('%s = StdMeshers.%s'%(e,e)) + ## Converts an angle from degrees to radians def DegreesToRadians(AngleInDegrees): from math import pi @@ -391,13 +403,33 @@ NO_NAME = "NoName" ## Gets object name def GetName(obj): - ior = salome.orb.object_to_string(obj) - sobj = salome.myStudy.FindObjectIOR(ior) - if sobj is None: - return NO_NAME - else: - attr = sobj.FindAttribute("AttributeName")[1] - return attr.Value() + if obj: + # object not null + if isinstance(obj, SALOMEDS._objref_SObject): + # study object + return obj.GetName() + ior = salome.orb.object_to_string(obj) + if ior: + # CORBA object + studies = salome.myStudyManager.GetOpenStudies() + for sname in studies: + s = salome.myStudyManager.GetStudyByName(sname) + if not s: continue + sobj = s.FindObjectIOR(ior) + if not sobj: continue + return sobj.GetName() + if hasattr(obj, "GetName"): + # unknown CORBA object, having GetName() method + return obj.GetName() + else: + # unknown CORBA object, no GetName() method + return NO_NAME + pass + if hasattr(obj, "GetName"): + # unknown non-CORBA object, having GetName() method + return obj.GetName() + pass + raise RuntimeError, "Null or invalid object" ## Prints error message if a hypothesis was not assigned. def TreatHypoStatus(status, hypName, geomName, isAlgo): @@ -413,6 +445,7 @@ def TreatHypoStatus(status, hypName, geomName, isAlgo): elif status == HYP_NOTCONFORM : reason = "a non-conform mesh would be built" elif status == HYP_ALREADY_EXIST : + if isAlgo: return # it does not influence anything reason = hypType + " of the same dimension is already assigned to this shape" elif status == HYP_BAD_DIM : reason = hypType + " mismatches the shape" @@ -432,10 +465,12 @@ def TreatHypoStatus(status, hypName, geomName, isAlgo): return hypName = '"' + hypName + '"' geomName= '"' + geomName+ '"' - if status < HYP_UNKNOWN_FATAL: + if status < HYP_UNKNOWN_FATAL and not geomName =='""': print hypName, "was assigned to", geomName,"but", reason - else: + elif not geomName == '""': print hypName, "was not assigned to",geomName,":", reason + else: + print hypName, "was not assigned:", reason pass ## Check meshing plugin availability @@ -485,6 +520,20 @@ class smeshDC(SMESH._objref_SMESH_Gen): def EnumToLong(self,theItem): return theItem._v + ## Returns a string representation of the color. + # To be used with filters. + # @param c color value (SALOMEDS.Color) + # @ingroup l1_controls + def ColorToString(self,c): + val = "" + if isinstance(c, SALOMEDS.Color): + val = "%s;%s;%s" % (c.R, c.G, c.B) + elif isinstance(c, str): + val = c + else: + raise ValueError, "Color value should be of string or SALOMEDS.Color type" + return val + ## Gets PointStruct from vertex # @param theVertex a GEOM object(vertex) # @return SMESH.PointStruct @@ -645,6 +694,9 @@ class smeshDC(SMESH._objref_SMESH_Gen): def Concatenate( self, meshes, uniteIdenticalGroups, mergeNodesAndElements = False, mergeTolerance = 1e-5, allGroups = False): mergeTolerance,Parameters = geompyDC.ParseParameters(mergeTolerance) + for i,m in enumerate(meshes): + if isinstance(m, Mesh): + meshes[i] = m.GetMesh() if allGroups: aSmeshMesh = SMESH._objref_SMESH_Gen.ConcatenateWithGroups( self,meshes,uniteIdenticalGroups,mergeNodesAndElements,mergeTolerance) @@ -725,8 +777,40 @@ class smeshDC(SMESH._objref_SMESH_Gen): else: print "Error: The treshold should be a string." return None + elif CritType == FT_CoplanarFaces: + # Checks the treshold + if isinstance(aTreshold, int): + aCriterion.ThresholdID = "%s"%aTreshold + elif isinstance(aTreshold, str): + ID = int(aTreshold) + if ID < 1: + raise ValueError, "Invalid ID of mesh face: '%s'"%aTreshold + aCriterion.ThresholdID = aTreshold + else: + raise ValueError,\ + "The treshold should be an ID of mesh face and not '%s'"%aTreshold + elif CritType == FT_ElemGeomType: + # Checks the treshold + try: + aCriterion.Threshold = self.EnumToLong(aTreshold) + except: + if isinstance(aTreshold, int): + aCriterion.Threshold = aTreshold + else: + print "Error: The treshold should be an integer or SMESH.GeometryType." + return None + pass + pass + elif CritType == FT_GroupColor: + # Checks the treshold + try: + aCriterion.ThresholdStr = self.ColorToString(aTreshold) + except: + print "Error: The threshold value should be of SALOMEDS.Color type" + return None + pass elif CritType in [FT_FreeBorders, FT_FreeEdges, FT_BadOrientedVolume, FT_FreeNodes, - FT_FreeFaces, FT_ElemGeomType, FT_GroupColor]: + FT_FreeFaces, FT_LinearOrQuadratic]: # At this point the treshold is unnecessary if aTreshold == FT_LogicalNOT: aCriterion.UnaryOp = self.EnumToLong(FT_LogicalNOT) @@ -774,6 +858,7 @@ class smeshDC(SMESH._objref_SMESH_Gen): aCriteria = [] aCriteria.append(aCriterion) aFilter.SetCriteria(aCriteria) + aFilterMgr.Destroy() return aFilter ## Creates a numerical functor by its type @@ -798,6 +883,10 @@ class smeshDC(SMESH._objref_SMESH_Gen): return aFilterMgr.CreateArea() elif theCriterion == FT_Volume3D: return aFilterMgr.CreateVolume3D() + elif theCriterion == FT_MaxElementLength2D: + return aFilterMgr.CreateMaxElementLength2D() + elif theCriterion == FT_MaxElementLength3D: + return aFilterMgr.CreateMaxElementLength3D() elif theCriterion == FT_MultiConnection: return aFilterMgr.CreateMultiConnection() elif theCriterion == FT_MultiConnection2D: @@ -830,6 +919,110 @@ class smeshDC(SMESH._objref_SMESH_Gen): pass return d + ## Get minimum distance between two objects + # + # If @a src2 is None, and @a id2 = 0, distance from @a src1 / @a id1 to the origin is computed. + # If @a src2 is None, and @a id2 != 0, it is assumed that both @a id1 and @a id2 belong to @a src1. + # + # @param src1 first source object + # @param src2 second source object + # @param id1 node/element id from the first source + # @param id2 node/element id from the second (or first) source + # @param isElem1 @c True if @a id1 is element id, @c False if it is node id + # @param isElem2 @c True if @a id2 is element id, @c False if it is node id + # @return minimum distance value + # @sa GetMinDistance() + # @ingroup l1_measurements + def MinDistance(self, src1, src2=None, id1=0, id2=0, isElem1=False, isElem2=False): + result = self.GetMinDistance(src1, src2, id1, id2, isElem1, isElem2) + if result is None: + result = 0.0 + else: + result = result.value + return result + + ## Get measure structure specifying minimum distance data between two objects + # + # If @a src2 is None, and @a id2 = 0, distance from @a src1 / @a id1 to the origin is computed. + # If @a src2 is None, and @a id2 != 0, it is assumed that both @a id1 and @a id2 belong to @a src1. + # + # @param src1 first source object + # @param src2 second source object + # @param id1 node/element id from the first source + # @param id2 node/element id from the second (or first) source + # @param isElem1 @c True if @a id1 is element id, @c False if it is node id + # @param isElem2 @c True if @a id2 is element id, @c False if it is node id + # @return Measure structure or None if input data is invalid + # @sa MinDistance() + # @ingroup l1_measurements + def GetMinDistance(self, src1, src2=None, id1=0, id2=0, isElem1=False, isElem2=False): + if isinstance(src1, Mesh): src1 = src1.mesh + if isinstance(src2, Mesh): src2 = src2.mesh + if src2 is None and id2 != 0: src2 = src1 + if not hasattr(src1, "_narrow"): return None + src1 = src1._narrow(SMESH.SMESH_IDSource) + if not src1: return None + if id1 != 0: + m = src1.GetMesh() + e = m.GetMeshEditor() + if isElem1: + src1 = e.MakeIDSource([id1], SMESH.FACE) + else: + src1 = e.MakeIDSource([id1], SMESH.NODE) + pass + if hasattr(src2, "_narrow"): + src2 = src2._narrow(SMESH.SMESH_IDSource) + if src2 and id2 != 0: + m = src2.GetMesh() + e = m.GetMeshEditor() + if isElem2: + src2 = e.MakeIDSource([id2], SMESH.FACE) + else: + src2 = e.MakeIDSource([id2], SMESH.NODE) + pass + pass + aMeasurements = self.CreateMeasurements() + result = aMeasurements.MinDistance(src1, src2) + aMeasurements.Destroy() + return result + + ## Get bounding box of the specified object(s) + # @param objects single source object or list of source objects + # @return tuple of six values (minX, minY, minZ, maxX, maxY, maxZ) + # @sa GetBoundingBox() + # @ingroup l1_measurements + def BoundingBox(self, objects): + result = self.GetBoundingBox(objects) + if result is None: + result = (0.0,)*6 + else: + result = (result.minX, result.minY, result.minZ, result.maxX, result.maxY, result.maxZ) + return result + + ## Get measure structure specifying bounding box data of the specified object(s) + # @param objects single source object or list of source objects + # @return Measure structure + # @sa BoundingBox() + # @ingroup l1_measurements + def GetBoundingBox(self, objects): + if isinstance(objects, tuple): + objects = list(objects) + if not isinstance(objects, list): + objects = [objects] + srclist = [] + for o in objects: + if isinstance(o, Mesh): + srclist.append(o.mesh) + elif hasattr(o, "_narrow"): + src = o._narrow(SMESH.SMESH_IDSource) + if src: srclist.append(src) + pass + pass + aMeasurements = self.CreateMeasurements() + result = aMeasurements.BoundingBox(srclist) + aMeasurements.Destroy() + return result + import omniORB #Registering the new proxy for SMESH_Gen omniORB.registerObjref(SMESH._objref_SMESH_Gen._NP_RepositoryId, smeshDC) @@ -995,6 +1188,24 @@ class Mesh: else: return Mesh_Segment(self, geom) + ## Creates 1D algorithm importing segments conatined in groups of other mesh. + # If the optional \a geom parameter is not set, this algorithm is global. + # Otherwise, this algorithm defines a submesh based on \a geom subshape. + # @param geom If defined the subshape is to be meshed + # @return an instance of Mesh_UseExistingElements class + # @ingroup l3_algos_basic + def UseExisting1DElements(self, geom=0): + return Mesh_UseExistingElements(1,self, geom) + + ## Creates 2D algorithm importing faces conatined in groups of other mesh. + # If the optional \a geom parameter is not set, this algorithm is global. + # Otherwise, this algorithm defines a submesh based on \a geom subshape. + # @param geom If defined the subshape is to be meshed + # @return an instance of Mesh_UseExistingElements class + # @ingroup l3_algos_basic + def UseExisting2DElements(self, geom=0): + return Mesh_UseExistingElements(2,self, geom) + ## Enables creation of nodes and segments usable by 2D algoritms. # The added nodes and segments must be bound to edges and vertices by # SetNodeOnVertex(), SetNodeOnEdge() and SetMeshElementOnShape() @@ -1031,17 +1242,20 @@ class Mesh: if (isinstance(algo, geompyDC.GEOM._objref_GEOM_Object)): geom = algo algo = MEFISTO - return Mesh_Triangle(self, algo, geom) ## Creates a quadrangle 2D algorithm for faces. # If the optional \a geom parameter is not set, this algorithm is global. # \n Otherwise, this algorithm defines a submesh based on \a geom subshape. # @param geom If defined, the subshape to be meshed (GEOM_Object) + # @param algo values are: smesh.QUADRANGLE || smesh.RADIAL_QUAD # @return an instance of Mesh_Quadrangle algorithm # @ingroup l3_algos_basic - def Quadrangle(self, geom=0): - return Mesh_Quadrangle(self, geom) + def Quadrangle(self, geom=0, algo=QUADRANGLE): + if algo==RADIAL_QUAD: + return Mesh_RadialQuadrangle1D2D(self,geom) + else: + return Mesh_Quadrangle(self, geom) ## Creates a tetrahedron 3D algorithm for solids. # The parameter \a algo permits to choose the algorithm: NETGEN or GHS3D @@ -1123,7 +1337,9 @@ class Mesh: return Mesh_RadialPrism3D(self, geom) ## Evaluates size of prospective mesh on a shape - # @return True or False + # @return a list where i-th element is a number of elements of i-th SMESH.EntityType + # To know predicted number of e.g. edges, inquire it this way + # Evaluate()[ EnumToLong( Entity_Edge )] def Evaluate(self, geom=0): if geom == 0 or not isinstance(geom, geompyDC.GEOM._objref_GEOM_Object): if self.geom == 0: @@ -1134,9 +1350,13 @@ class Mesh: ## Computes the mesh and returns the status of the computation + # @param geom geomtrical shape on which mesh data should be computed + # @param discardModifs if True and the mesh has been edited since + # a last total re-compute and that may prevent successful partial re-compute, + # then the mesh is cleaned before Compute() # @return True or False # @ingroup l2_construct - def Compute(self, geom=0): + def Compute(self, geom=0, discardModifs=False): if geom == 0 or not isinstance(geom, geompyDC.GEOM._objref_GEOM_Object): if self.geom == 0: geom = self.mesh.GetShapeToMesh() @@ -1144,6 +1364,8 @@ class Mesh: geom = self.geom ok = False try: + if discardModifs and self.mesh.HasModificationsToDiscard(): # issue 0020693 + self.mesh.Clear() ok = self.smeshpyD.Compute(self.mesh, geom) except SALOME.SALOME_Exception, ex: print "Mesh computation failed, exception caught:" @@ -1153,8 +1375,64 @@ class Mesh: print "Mesh computation failed, exception caught:" traceback.print_exc() if True:#not ok: - errors = self.smeshpyD.GetAlgoState( self.mesh, geom ) allReasons = "" + + # Treat compute errors + computeErrors = self.smeshpyD.GetComputeErrors( self.mesh, geom ) + for err in computeErrors: + shapeText = "" + if self.mesh.HasShapeToMesh(): + try: + mainIOR = salome.orb.object_to_string(geom) + for sname in salome.myStudyManager.GetOpenStudies(): + s = salome.myStudyManager.GetStudyByName(sname) + if not s: continue + mainSO = s.FindObjectIOR(mainIOR) + if not mainSO: continue + if err.subShapeID == 1: + shapeText = ' on "%s"' % mainSO.GetName() + subIt = s.NewChildIterator(mainSO) + while subIt.More(): + subSO = subIt.Value() + subIt.Next() + obj = subSO.GetObject() + if not obj: continue + go = obj._narrow( geompyDC.GEOM._objref_GEOM_Object ) + if not go: continue + ids = go.GetSubShapeIndices() + if len(ids) == 1 and ids[0] == err.subShapeID: + shapeText = ' on "%s"' % subSO.GetName() + break + if not shapeText: + shape = self.geompyD.GetSubShape( geom, [err.subShapeID]) + if shape: + shapeText = " on %s #%s" % (shape.GetShapeType(), err.subShapeID) + else: + shapeText = " on subshape #%s" % (err.subShapeID) + except: + shapeText = " on subshape #%s" % (err.subShapeID) + errText = "" + stdErrors = ["OK", #COMPERR_OK + "Invalid input mesh", #COMPERR_BAD_INPUT_MESH + "std::exception", #COMPERR_STD_EXCEPTION + "OCC exception", #COMPERR_OCC_EXCEPTION + "SALOME exception", #COMPERR_SLM_EXCEPTION + "Unknown exception", #COMPERR_EXCEPTION + "Memory allocation problem", #COMPERR_MEMORY_PB + "Algorithm failed", #COMPERR_ALGO_FAILED + "Unexpected geometry"]#COMPERR_BAD_SHAPE + if err.code > 0: + if err.code < len(stdErrors): errText = stdErrors[err.code] + else: + errText = "code %s" % -err.code + if errText: errText += ". " + errText += err.comment + if allReasons != "":allReasons += "\n" + allReasons += '"%s" failed%s. Error: %s' %(err.algoName, shapeText, errText) + pass + + # Treat hyp errors + errors = self.smeshpyD.GetAlgoState( self.mesh, geom ) for err in errors: if err.isGlobalAlgo: glob = "global" @@ -1180,9 +1458,7 @@ class Mesh: reason = "For unknown reason."+\ " Revise Mesh.Compute() implementation in smeshDC.py!" pass - if allReasons != "": - allReasons += "\n" - pass + if allReasons != "":allReasons += "\n" allReasons += reason pass if allReasons != "": @@ -1201,6 +1477,18 @@ class Mesh: pass return ok + ## Return submesh objects list in meshing order + # @return list of list of submesh objects + # @ingroup l2_construct + def GetMeshOrder(self): + return self.mesh.GetMeshOrder() + + ## Return submesh objects list in meshing order + # @return list of list of submesh objects + # @ingroup l2_construct + def SetMeshOrder(self, submeshes): + return self.mesh.SetMeshOrder(submeshes) + ## Removes all nodes and elements # @ingroup l2_construct def Clear(self): @@ -1271,7 +1559,11 @@ class Mesh: pass status = self.mesh.AddHypothesis(geom, hyp) isAlgo = hyp._narrow( SMESH_Algo ) - TreatHypoStatus( status, GetName( hyp ), GetName( geom ), isAlgo ) + hyp_name = GetName( hyp ) + geom_name = "" + if geom: + geom_name = GetName( geom ) + TreatHypoStatus( status, hyp_name, geom_name, isAlgo ) return status ## Unassigns a hypothesis @@ -1316,25 +1608,29 @@ class Mesh: def Group(self, grp, name=""): return self.GroupOnGeom(grp, name) - ## Deprecated, used only for compatibility! Please, use ExportMED() method instead. + ## Deprecated, used only for compatibility! Please, use ExportToMEDX() method instead. # Exports the mesh in a file in MED format and chooses the \a version of MED format + ## allowing to overwrite the file if it exists or add the exported data to its contents # @param f the file name # @param version values are SMESH.MED_V2_1, SMESH.MED_V2_2 # @param opt boolean parameter for creating/not creating # the groups Group_On_All_Nodes, Group_On_All_Faces, ... + # @param overwrite boolean parameter for overwriting/not overwriting the file # @ingroup l2_impexp - def ExportToMED(self, f, version, opt=0): - self.mesh.ExportToMED(f, opt, version) + def ExportToMED(self, f, version, opt=0, overwrite=1): + self.mesh.ExportToMEDX(f, opt, version, overwrite) - ## Exports the mesh in a file in MED format + ## Exports the mesh in a file in MED format and chooses the \a version of MED format + ## allowing to overwrite the file if it exists or add the exported data to its contents # @param f is the file name # @param auto_groups boolean parameter for creating/not creating # the groups Group_On_All_Nodes, Group_On_All_Faces, ... ; # the typical use is auto_groups=false. # @param version MED format version(MED_V2_1 or MED_V2_2) + # @param overwrite boolean parameter for overwriting/not overwriting the file # @ingroup l2_impexp - def ExportMED(self, f, auto_groups=0, version=MED_V2_2): - self.mesh.ExportToMED(f, auto_groups, version) + def ExportMED(self, f, auto_groups=0, version=MED_V2_2, overwrite=1): + self.mesh.ExportToMEDX(f, auto_groups, version, overwrite) ## Exports the mesh in a file in DAT format # @param f the file name @@ -1473,6 +1769,7 @@ class Mesh: aCriteria.append(Criterion) aFilter.SetCriteria(aCriteria) group = self.MakeGroupByFilter(groupName, aFilter) + aFilterMgr.Destroy() return group ## Creates a mesh group by the given criteria (list of criteria) @@ -1485,6 +1782,7 @@ class Mesh: aFilter = aFilterMgr.CreateFilter() aFilter.SetCriteria(theCriteria) group = self.MakeGroupByFilter(groupName, aFilter) + aFilterMgr.Destroy() return group ## Creates a mesh group by the given filter @@ -1493,9 +1791,9 @@ class Mesh: # @return SMESH_Group # @ingroup l2_grps_create def MakeGroupByFilter(self, groupName, theFilter): - anIds = theFilter.GetElementsId(self.mesh) - anElemType = theFilter.GetElementType() - group = self.MakeGroupByIds(groupName, anElemType, anIds) + group = self.CreateEmptyGroup(theFilter.GetElementType(), groupName) + theFilter.SetMesh( self.mesh ) + group.AddFrom( theFilter ) return group ## Passes mesh elements through the given filter and return IDs of fitting elements @@ -1503,7 +1801,8 @@ class Mesh: # @return a list of ids # @ingroup l1_controls def GetIdsFromFilter(self, theFilter): - return theFilter.GetElementsId(self.mesh) + theFilter.SetMesh( self.mesh ) + return theFilter.GetIDs() ## Verifies whether a 2D mesh element has free edges (edges connected to one face only)\n # Returns a list of special structures (borders). @@ -1514,6 +1813,7 @@ class Mesh: aPredicate = aFilterMgr.CreateFreeEdges() aPredicate.SetMesh(self.mesh) aBorders = aPredicate.GetBorders() + aFilterMgr.Destroy() return aBorders ## Removes a group @@ -1855,7 +2155,7 @@ class Mesh: return self.mesh.GetElementsId() ## Returns the list of IDs of mesh elements with the given type - # @param elementType the required type of elements + # @param elementType the required type of elements (SMESH.NODE, SMESH.EDGE, SMESH.FACE or SMESH.VOLUME) # @return list of integer values # @ingroup l1_meshinfo def GetElementsByType(self, elementType): @@ -1876,6 +2176,12 @@ class Mesh: def GetElementType(self, id, iselem): return self.mesh.GetElementType(id, iselem) + ## Returns the geometric type of mesh element + # @return the value from SMESH::EntityType enumeration + # @ingroup l1_meshinfo + def GetElementGeomType(self, id): + return self.mesh.GetElementGeomType(id) + ## Returns the list of submesh elements IDs # @param Shape a geom object(subshape) IOR # Shape must be the subshape of a ShapeToMesh() @@ -1999,6 +2305,16 @@ class Mesh: def ElemNbFaces(self, id): return self.mesh.ElemNbFaces(id) + ## Returns nodes of given face (counted from zero) for given volumic element. + # @ingroup l1_meshinfo + def GetElemFaceNodes(self,elemId, faceIndex): + return self.mesh.GetElemFaceNodes(elemId, faceIndex) + + ## Returns an element based on all given nodes. + # @ingroup l1_meshinfo + def FindElementByNodes(self,nodes): + return self.mesh.FindElementByNodes(nodes) + ## Returns true if the given element is a polygon # @ingroup l1_meshinfo def IsPoly(self, id): @@ -2017,6 +2333,95 @@ class Mesh: return self.mesh.BaryCenter(id) + # Get mesh measurements information: + # ------------------------------------ + + ## Get minimum distance between two nodes, elements or distance to the origin + # @param id1 first node/element id + # @param id2 second node/element id (if 0, distance from @a id1 to the origin is computed) + # @param isElem1 @c True if @a id1 is element id, @c False if it is node id + # @param isElem2 @c True if @a id2 is element id, @c False if it is node id + # @return minimum distance value + # @sa GetMinDistance() + def MinDistance(self, id1, id2=0, isElem1=False, isElem2=False): + aMeasure = self.GetMinDistance(id1, id2, isElem1, isElem2) + return aMeasure.value + + ## Get measure structure specifying minimum distance data between two objects + # @param id1 first node/element id + # @param id2 second node/element id (if 0, distance from @a id1 to the origin is computed) + # @param isElem1 @c True if @a id1 is element id, @c False if it is node id + # @param isElem2 @c True if @a id2 is element id, @c False if it is node id + # @return Measure structure + # @sa MinDistance() + def GetMinDistance(self, id1, id2=0, isElem1=False, isElem2=False): + if isElem1: + id1 = self.editor.MakeIDSource([id1], SMESH.FACE) + else: + id1 = self.editor.MakeIDSource([id1], SMESH.NODE) + if id2 != 0: + if isElem2: + id2 = self.editor.MakeIDSource([id2], SMESH.FACE) + else: + id2 = self.editor.MakeIDSource([id2], SMESH.NODE) + pass + else: + id2 = None + + aMeasurements = self.smeshpyD.CreateMeasurements() + aMeasure = aMeasurements.MinDistance(id1, id2) + aMeasurements.Destroy() + return aMeasure + + ## Get bounding box of the specified object(s) + # @param objects single source object or list of source objects or list of nodes/elements IDs + # @param isElem if @a objects is a list of IDs, @c True value in this parameters specifies that @a objects are elements, + # @c False specifies that @a objects are nodes + # @return tuple of six values (minX, minY, minZ, maxX, maxY, maxZ) + # @sa GetBoundingBox() + def BoundingBox(self, objects=None, isElem=False): + result = self.GetBoundingBox(objects, isElem) + if result is None: + result = (0.0,)*6 + else: + result = (result.minX, result.minY, result.minZ, result.maxX, result.maxY, result.maxZ) + return result + + ## Get measure structure specifying bounding box data of the specified object(s) + # @param objects single source object or list of source objects or list of nodes/elements IDs + # @param isElem if @a objects is a list of IDs, @c True value in this parameters specifies that @a objects are elements, + # @c False specifies that @a objects are nodes + # @return Measure structure + # @sa BoundingBox() + def GetBoundingBox(self, IDs=None, isElem=False): + if IDs is None: + IDs = [self.mesh] + elif isinstance(IDs, tuple): + IDs = list(IDs) + if not isinstance(IDs, list): + IDs = [IDs] + if len(IDs) > 0 and isinstance(IDs[0], int): + IDs = [IDs] + srclist = [] + for o in IDs: + if isinstance(o, Mesh): + srclist.append(o.mesh) + elif hasattr(o, "_narrow"): + src = o._narrow(SMESH.SMESH_IDSource) + if src: srclist.append(src) + pass + elif isinstance(o, list): + if isElem: + srclist.append(self.editor.MakeIDSource(o, SMESH.FACE)) + else: + srclist.append(self.editor.MakeIDSource(o, SMESH.NODE)) + pass + pass + aMeasurements = self.smeshpyD.CreateMeasurements() + aMeasure = aMeasurements.BoundingBox(srclist) + aMeasurements.Destroy() + return aMeasure + # Mesh edition (SMESH_MeshEditor functionality): # --------------------------------------------- @@ -2034,6 +2439,12 @@ class Mesh: def RemoveNodes(self, IDsOfNodes): return self.editor.RemoveNodes(IDsOfNodes) + ## Removes all orphan (free) nodes from mesh + # @return number of the removed nodes + # @ingroup l2_modif_del + def RemoveOrphanNodes(self): + return self.editor.RemoveOrphanNodes() + ## Add a node to the mesh by coordinates # @return Id of the new node # @ingroup l2_modif_add @@ -2241,6 +2652,11 @@ class Mesh: def FindElementsByPoint(self, x, y, z, elementType = SMESH.ALL): return self.editor.FindElementsByPoint(x, y, z, elementType) + # Return point state in a closed 2D mesh in terms of TopAbs_State enumeration. + # TopAbs_UNKNOWN state means that either mesh is wrong or the analysis fails. + + def GetPointState(self, x, y, z): + return self.editor.GetPointState(x, y, z) ## Finds the node closest to a point and moves it to a point location # @param x the X coordinate of a point @@ -2373,6 +2789,18 @@ class Mesh: def BestSplit (self, IDOfQuad, theCriterion): return self.editor.BestSplit(IDOfQuad, self.smeshpyD.GetFunctor(theCriterion)) + ## Splits volumic elements into tetrahedrons + # @param elemIDs either list of elements or mesh or group or submesh + # @param method flags passing splitting method: Hex_5Tet, Hex_6Tet, Hex_24Tet + # Hex_5Tet - split the hexahedron into 5 tetrahedrons, etc + # @ingroup l2_modif_cutquadr + def SplitVolumesIntoTetra(self, elemIDs, method=Hex_5Tet ): + if isinstance( elemIDs, Mesh ): + elemIDs = elemIDs.GetMesh() + if ( isinstance( elemIDs, list )): + elemIDs = self.editor.MakeIDSource(elemIDs, SMESH.VOLUME) + self.editor.SplitVolumesIntoTetra(elemIDs, method) + ## Splits quadrangle faces near triangular facets of volumes # # @ingroup l1_auxiliary @@ -2585,6 +3013,9 @@ class Mesh: ## Converts the mesh to quadratic, deletes old elements, replacing # them with quadratic with the same id. + # @param theForce3d new node creation method: + # 0 - the medium node lies at the geometrical edge from which the mesh element is built + # 1 - the medium node lies at the middle of the line segments connecting start and end node of a mesh element # @ingroup l2_modif_tofromqu def ConvertToQuadratic(self, theForce3d): self.editor.ConvertToQuadratic(theForce3d) @@ -2602,7 +3033,34 @@ class Mesh: # @ingroup l2_modif_edit def Make2DMeshFrom3D(self): return self.editor. Make2DMeshFrom3D() - + + ## Creates missing boundary elements + # @param elements - elements whose boundary is to be checked: + # mesh, group, sub-mesh or list of elements + # @param dimension - defines type of boundary elements to create: + # SMESH.BND_2DFROM3D, SMESH.BND_1DFROM3D, SMESH.BND_1DFROM2D + # @param groupName - a name of group to store created boundary elements in, + # "" means not to create the group + # @param meshName - a name of new mesh to store created boundary elements in, + # "" means not to create the new mesh + # @param toCopyElements - if true, the checked elements will be copied into the new mesh + # @param toCopyExistingBondary - if true, not only new but also pre-existing + # boundary elements will be copied into the new mesh + # @return tuple (mesh, group) where bondary elements were added to + # @ingroup l2_modif_edit + def MakeBoundaryMesh(self, elements, dimension=SMESH.BND_2DFROM3D, groupName="", meshName="", + toCopyElements=False, toCopyExistingBondary=False): + if isinstance( elements, Mesh ): + elements = elements.GetMesh() + if ( isinstance( elements, list )): + elemType = SMESH.ALL + if elements: elemType = self.GetElementType( elements[0], iselem=True) + elements = self.editor.MakeIDSource(elements, elemType) + mesh, group = self.editor.MakeBoundaryMesh(elements,dimension,groupName,meshName, + toCopyElements,toCopyExistingBondary) + if mesh: mesh = self.smeshpyD.Mesh(mesh) + return mesh, group + ## Renumber mesh nodes # @ingroup l2_modif_renumber def RenumberNodes(self): @@ -3227,6 +3685,51 @@ class Mesh: mesh.SetParameters(Parameters) return Mesh( self.smeshpyD, self.geompyD, mesh ) + + + ## Scales the object + # @param theObject - the object to translate (mesh, submesh, or group) + # @param thePoint - base point for scale + # @param theScaleFact - list of 1-3 scale factors for axises + # @param Copy - allows copying the translated elements + # @param MakeGroups - forces the generation of new groups from existing + # ones (if Copy) + # @return list of created groups (SMESH_GroupBase) if MakeGroups=True, + # empty list otherwise + def Scale(self, theObject, thePoint, theScaleFact, Copy, MakeGroups=False): + if ( isinstance( theObject, Mesh )): + theObject = theObject.GetMesh() + if ( isinstance( theObject, list )): + theObject = self.editor.MakeIDSource(theObject, SMESH.ALL) + + thePoint, Parameters = ParsePointStruct(thePoint) + self.mesh.SetParameters(Parameters) + + if Copy and MakeGroups: + return self.editor.ScaleMakeGroups(theObject, thePoint, theScaleFact) + self.editor.Scale(theObject, thePoint, theScaleFact, Copy) + return [] + + ## Creates a new mesh from the translated object + # @param theObject - the object to translate (mesh, submesh, or group) + # @param thePoint - base point for scale + # @param theScaleFact - list of 1-3 scale factors for axises + # @param MakeGroups - forces the generation of new groups from existing ones + # @param NewMeshName - the name of the newly created mesh + # @return instance of Mesh class + def ScaleMakeMesh(self, theObject, thePoint, theScaleFact, MakeGroups=False, NewMeshName=""): + if (isinstance(theObject, Mesh)): + theObject = theObject.GetMesh() + if ( isinstance( theObject, list )): + theObject = self.editor.MakeIDSource(theObject,SMESH.ALL) + + mesh = self.editor.ScaleMakeMesh(theObject, thePoint, theScaleFact, + MakeGroups, NewMeshName) + #mesh.SetParameters(Parameters) + return Mesh( self.smeshpyD, self.geompyD, mesh ) + + + ## Rotates the elements # @param IDsOfElements list of elements ids # @param Axis the axis of rotation (AxisStruct or geom line) @@ -3343,10 +3846,17 @@ class Mesh: ## Finds groups of ajacent nodes within Tolerance. # @param Tolerance the value of tolerance # @param SubMeshOrGroup SubMesh or Group + # @param exceptNodes list of either SubMeshes, Groups or node IDs to exclude from search # @return the list of groups of nodes # @ingroup l2_modif_trsf - def FindCoincidentNodesOnPart (self, SubMeshOrGroup, Tolerance): - return self.editor.FindCoincidentNodesOnPart(SubMeshOrGroup, Tolerance) + def FindCoincidentNodesOnPart (self, SubMeshOrGroup, Tolerance, exceptNodes=[]): + if (isinstance( SubMeshOrGroup, Mesh )): + SubMeshOrGroup = SubMeshOrGroup.GetMesh() + if not isinstance( exceptNodes, list): + exceptNodes = [ exceptNodes ] + if exceptNodes and isinstance( exceptNodes[0], int): + exceptNodes = [ self.editor.MakeIDSource( exceptNodes, SMESH.NODE)] + return self.editor.FindCoincidentNodesOnPartBut(SubMeshOrGroup, Tolerance,exceptNodes) ## Merges nodes # @param GroupsOfNodes the list of groups of nodes @@ -3451,7 +3961,7 @@ class Mesh: ## Creates a hole in a mesh by doubling the nodes of some particular elements # This method provided for convenience works as DoubleNodes() described above. - # @param theNodes identifiers of node to be doubled + # @param theNodeId identifiers of node to be doubled # @param theModifiedElems identifiers of elements to be updated # @return TRUE if operation has been completed successfully, FALSE otherwise # @ingroup l2_modif_edit @@ -3462,11 +3972,15 @@ class Mesh: # This method provided for convenience works as DoubleNodes() described above. # @param theNodes group of nodes to be doubled # @param theModifiedElems group of elements to be updated. - # @return TRUE if operation has been completed successfully, FALSE otherwise + # @param theMakeGroup forces the generation of a group containing new nodes. + # @return TRUE or a created group if operation has been completed successfully, + # FALSE or None otherwise # @ingroup l2_modif_edit - def DoubleNodeGroup(self, theNodes, theModifiedElems): + def DoubleNodeGroup(self, theNodes, theModifiedElems, theMakeGroup=False): + if theMakeGroup: + return self.editor.DoubleNodeGroupNew(theNodes, theModifiedElems) return self.editor.DoubleNodeGroup(theNodes, theModifiedElems) - + ## Creates a hole in a mesh by doubling the nodes of some particular elements # This method provided for convenience works as DoubleNodes() described above. # @param theNodes list of groups of nodes to be doubled @@ -3505,10 +4019,13 @@ class Mesh: # @param theNodesNot - group of nodes not to replicated # @param theAffectedElems - group of elements to which the replicated nodes # should be associated to. + # @param theMakeGroup forces the generation of a group containing new elements. # @ingroup l2_modif_edit - def DoubleNodeElemGroup(self, theElems, theNodesNot, theAffectedElems): + def DoubleNodeElemGroup(self, theElems, theNodesNot, theAffectedElems, theMakeGroup=False): + if theMakeGroup: + return self.editor.DoubleNodeElemGroupNew(theElems, theNodesNot, theAffectedElems) return self.editor.DoubleNodeElemGroup(theElems, theNodesNot, theAffectedElems) - + ## Creates a hole in a mesh by doubling the nodes of some particular elements # This method provided for convenience works as DoubleNodes() described above. # @param theElems - group of of elements (edges or faces) to be replicated @@ -3518,7 +4035,7 @@ class Mesh: # The replicated nodes should be associated to affected elements. # @ingroup l2_modif_edit def DoubleNodeElemGroupInRegion(self, theElems, theNodesNot, theShape): - return self.editor.DoubleNodeElemGroup(theElems, theNodesNot, theShape) + return self.editor.DoubleNodeElemGroupInRegion(theElems, theNodesNot, theShape) ## Creates a hole in a mesh by doubling the nodes of some particular elements # This method provided for convenience works as DoubleNodes() described above. @@ -3543,6 +4060,86 @@ class Mesh: def DoubleNodeElemGroupsInRegion(self, theElems, theNodesNot, theShape): return self.editor.DoubleNodeElemGroupsInRegion(theElems, theNodesNot, theShape) + def _valueFromFunctor(self, funcType, elemId): + fn = self.smeshpyD.GetFunctor(funcType) + fn.SetMesh(self.mesh) + if fn.GetElementType() == self.GetElementType(elemId, True): + val = fn.GetValue(elemId) + else: + val = 0 + return val + + ## Get length of 1D element. + # @param elemId mesh element ID + # @return element's length value + # @ingroup l1_measurements + def GetLength(self, elemId): + return self._valueFromFunctor(SMESH.FT_Length, elemId) + + ## Get area of 2D element. + # @param elemId mesh element ID + # @return element's area value + # @ingroup l1_measurements + def GetArea(self, elemId): + return self._valueFromFunctor(SMESH.FT_Area, elemId) + + ## Get volume of 3D element. + # @param elemId mesh element ID + # @return element's volume value + # @ingroup l1_measurements + def GetVolume(self, elemId): + return self._valueFromFunctor(SMESH.FT_Volume3D, elemId) + + ## Get maximum element length. + # @param elemId mesh element ID + # @return element's maximum length value + # @ingroup l1_measurements + def GetMaxElementLength(self, elemId): + if self.GetElementType(elemId, True) == SMESH.VOLUME: + ftype = SMESH.FT_MaxElementLength3D + else: + ftype = SMESH.FT_MaxElementLength2D + return self._valueFromFunctor(ftype, elemId) + + ## Get aspect ratio of 2D or 3D element. + # @param elemId mesh element ID + # @return element's aspect ratio value + # @ingroup l1_measurements + def GetAspectRatio(self, elemId): + if self.GetElementType(elemId, True) == SMESH.VOLUME: + ftype = SMESH.FT_AspectRatio3D + else: + ftype = SMESH.FT_AspectRatio + return self._valueFromFunctor(ftype, elemId) + + ## Get warping angle of 2D element. + # @param elemId mesh element ID + # @return element's warping angle value + # @ingroup l1_measurements + def GetWarping(self, elemId): + return self._valueFromFunctor(SMESH.FT_Warping, elemId) + + ## Get minimum angle of 2D element. + # @param elemId mesh element ID + # @return element's minimum angle value + # @ingroup l1_measurements + def GetMinimumAngle(self, elemId): + return self._valueFromFunctor(SMESH.FT_MinimumAngle, elemId) + + ## Get taper of 2D element. + # @param elemId mesh element ID + # @return element's taper value + # @ingroup l1_measurements + def GetTaper(self, elemId): + return self._valueFromFunctor(SMESH.FT_Taper, elemId) + + ## Get skew of 2D element. + # @param elemId mesh element ID + # @return element's skew value + # @ingroup l1_measurements + def GetSkew(self, elemId): + return self._valueFromFunctor(SMESH.FT_Skew, elemId) + ## The mother class to define algorithm, it is not recommended to use it directly. # # More details. @@ -3685,19 +4282,24 @@ class Mesh_Algorithm: raise RuntimeError, "Attemp to create " + algo + " algoritm on None shape" self.mesh = mesh piece = mesh.geom + name = "" if not geom: self.geom = piece else: self.geom = geom - name = GetName(geom) - if name==NO_NAME: + try: + name = GetName(geom) + pass + except: name = mesh.geompyD.SubShapeName(geom, piece) - mesh.geompyD.addToStudyInFather(piece, geom, name) + if not name: + name = "%s_%s"%(geom.GetShapeType(), id(geom%1000)) + pass self.subm = mesh.mesh.GetSubMesh(geom, algo.GetName()) self.algo = algo status = mesh.mesh.AddHypothesis(self.geom, self.algo) - TreatHypoStatus( status, algo.GetName(), GetName(self.geom), True ) + TreatHypoStatus( status, algo.GetName(), name, True ) def CompareHyp (self, hyp, args): print "CompareHyp is not implemented for ", self.__class__.__name__, ":", hyp.GetName() @@ -3824,6 +4426,8 @@ class Mesh_Segment(Mesh_Algorithm): if not isinstance(reversedEdges,list): #old version script, before adding reversedEdges reversedEdges, UseExisting = [], reversedEdges entry = self.MainShapeEntry() + if reversedEdges and isinstance(reversedEdges[0],geompyDC.GEOM._objref_GEOM_Object): + reversedEdges = [ self.mesh.geompyD.GetSubShapeID(self.mesh.geom, e) for e in reversedEdges ] if s == []: hyp = self.Hypothesis("NumberOfSegments", [n, reversedEdges, entry], UseExisting=UseExisting, @@ -3866,6 +4470,8 @@ class Mesh_Segment(Mesh_Algorithm): def Arithmetic1D(self, start, end, reversedEdges=[], UseExisting=0): if not isinstance(reversedEdges,list): #old version script, before adding reversedEdges reversedEdges, UseExisting = [], reversedEdges + if reversedEdges and isinstance(reversedEdges[0],geompyDC.GEOM._objref_GEOM_Object): + reversedEdges = [ self.mesh.geompyD.GetSubShapeID(self.mesh.geom, e) for e in reversedEdges ] entry = self.MainShapeEntry() hyp = self.Hypothesis("Arithmetic1D", [start, end, reversedEdges, entry], UseExisting=UseExisting, @@ -3902,10 +4508,12 @@ class Mesh_Segment(Mesh_Algorithm): def FixedPoints1D(self, points, nbSegs=[1], reversedEdges=[], UseExisting=0): if not isinstance(reversedEdges,list): #old version script, before adding reversedEdges reversedEdges, UseExisting = [], reversedEdges + if reversedEdges and isinstance(reversedEdges[0],geompyDC.GEOM._objref_GEOM_Object): + reversedEdges = [ self.mesh.geompyD.GetSubShapeID(self.mesh.geom, e) for e in reversedEdges ] entry = self.MainShapeEntry() hyp = self.Hypothesis("FixedPoints1D", [points, nbSegs, reversedEdges, entry], UseExisting=UseExisting, - CompareMethod=self.CompareArithmetic1D) + CompareMethod=self.CompareFixedPoints1D) hyp.SetPoints(points) hyp.SetNbSegments(nbSegs) hyp.SetReversedEdges(reversedEdges) @@ -3936,6 +4544,8 @@ class Mesh_Segment(Mesh_Algorithm): def StartEndLength(self, start, end, reversedEdges=[], UseExisting=0): if not isinstance(reversedEdges,list): #old version script, before adding reversedEdges reversedEdges, UseExisting = [], reversedEdges + if reversedEdges and isinstance(reversedEdges[0],geompyDC.GEOM._objref_GEOM_Object): + reversedEdges = [ self.mesh.geompyD.GetSubShapeID(self.mesh.geom, e) for e in reversedEdges ] entry = self.MainShapeEntry() hyp = self.Hypothesis("StartEndLength", [start, end, reversedEdges, entry], UseExisting=UseExisting, @@ -4014,11 +4624,14 @@ class Mesh_Segment(Mesh_Algorithm): ### 0D algorithm if self.geom is None: raise RuntimeError, "Attemp to create SegmentAroundVertex_0D algoritm on None shape" - name = GetName(self.geom) - if name == NO_NAME: + try: + name = GetName(self.geom) + pass + except: piece = self.mesh.geom name = self.mesh.geompyD.SubShapeName(self.geom, piece) self.mesh.geompyD.addToStudyInFather(piece, self.geom, name) + pass algo = self.FindAlgorithm("SegmentAroundVertex_0D", self.mesh.smeshpyD) if algo is None: algo = self.mesh.smeshpyD.CreateHypothesis("SegmentAroundVertex_0D", "libStdMeshersEngine.so") @@ -4192,7 +4805,7 @@ class Mesh_Triangle(Mesh_Algorithm): self.Parameters().SetPhyMax(theVal) ## Sets a way to define maximum angular deflection of mesh from CAD model. - # @param theGeometricMesh is: DefaultGeom or Custom + # @param theGeometricMesh is: 0 (None) or 1 (Custom) # @ingroup l3_hypos_blsurf def SetGeometricMesh(self, theGeometricMesh=0): # Parameter of BLSURF algo @@ -4390,30 +5003,97 @@ class Mesh_Triangle(Mesh_Algorithm): # @ingroup l3_algos_basic class Mesh_Quadrangle(Mesh_Algorithm): + params=0 + ## Private constructor. def __init__(self, mesh, geom=0): Mesh_Algorithm.__init__(self) self.Create(mesh, geom, "Quadrangle_2D") + return - ## Defines "QuadranglePreference" hypothesis, forcing construction - # of quadrangles if the number of nodes on the opposite edges is not the same - # while the total number of nodes on edges is even - # - # @ingroup l3_hypos_additi - def QuadranglePreference(self): - hyp = self.Hypothesis("QuadranglePreference", UseExisting=1, - CompareMethod=self.CompareEqualHyp) - return hyp + ## Defines "QuadrangleParameters" hypothesis + # @param quadType defines the algorithm of transition between differently descretized + # sides of a geometrical face: + # - QUAD_STANDARD - both triangles and quadrangles are possible in the transition + # area along the finer meshed sides. + # - QUAD_TRIANGLE_PREF - only triangles are built in the transition area along the + # finer meshed sides. + # - QUAD_QUADRANGLE_PREF - only quadrangles are built in the transition area along + # the finer meshed sides, iff the total quantity of segments on + # all four sides of the face is even (divisible by 2). + # - QUAD_QUADRANGLE_PREF_REVERSED - same as QUAD_QUADRANGLE_PREF but the transition + # area is located along the coarser meshed sides. + # - QUAD_REDUCED - only quadrangles are built and the transition between the sides + # is made gradually, layer by layer. This type has a limitation on + # the number of segments: one pair of opposite sides must have the + # same number of segments, the other pair must have an even difference + # between the numbers of segments on the sides. + # @param triangleVertex: vertex of a trilateral geometrical face, around which triangles + # will be created while other elements will be quadrangles. + # Vertex can be either a GEOM_Object or a vertex ID within the + # shape to mesh + # @param UseExisting: if ==true - searches for the existing hypothesis created with + # the same parameters, else (default) - creates a new one + # @ingroup l3_hypos_quad + def QuadrangleParameters(self, quadType=StdMeshers.QUAD_STANDARD, triangleVertex=0, UseExisting=0): + vertexID = triangleVertex + if isinstance( triangleVertex, geompyDC.GEOM._objref_GEOM_Object ): + vertexID = self.mesh.geompyD.GetSubShapeID( self.mesh.geom, triangleVertex ) + if not self.params: + compFun = lambda hyp,args: \ + hyp.GetQuadType() == args[0] and \ + ( hyp.GetTriaVertex()==args[1] or ( hyp.GetTriaVertex()<1 and args[1]<1)) + self.params = self.Hypothesis("QuadrangleParams", [quadType,vertexID], + UseExisting = UseExisting, CompareMethod=compFun) + pass + if self.params.GetQuadType() != quadType: + self.params.SetQuadType(quadType) + if vertexID > 0: + self.params.SetTriaVertex( vertexID ) + return self.params + + ## Defines "QuadrangleParams" hypothesis with a type of quadrangulation that only + # quadrangles are built in the transition area along the finer meshed sides, + # iff the total quantity of segments on all four sides of the face is even. + # @param reversed if True, transition area is located along the coarser meshed sides. + # @param UseExisting: if ==true - searches for the existing hypothesis created with + # the same parameters, else (default) - creates a new one + # @ingroup l3_hypos_quad + def QuadranglePreference(self, reversed=False, UseExisting=0): + if reversed: + return self.QuadrangleParameters(QUAD_QUADRANGLE_PREF_REVERSED,UseExisting=UseExisting) + return self.QuadrangleParameters(QUAD_QUADRANGLE_PREF,UseExisting=UseExisting) + + ## Defines "QuadrangleParams" hypothesis with a type of quadrangulation that only + # triangles are built in the transition area along the finer meshed sides. + # @param UseExisting: if ==true - searches for the existing hypothesis created with + # the same parameters, else (default) - creates a new one + # @ingroup l3_hypos_quad + def TrianglePreference(self, UseExisting=0): + return self.QuadrangleParameters(QUAD_TRIANGLE_PREF,UseExisting=UseExisting) + + ## Defines "QuadrangleParams" hypothesis with a type of quadrangulation that only + # quadrangles are built and the transition between the sides is made gradually, + # layer by layer. This type has a limitation on the number of segments: one pair + # of opposite sides must have the same number of segments, the other pair must + # have an even difference between the numbers of segments on the sides. + # @param UseExisting: if ==true - searches for the existing hypothesis created with + # the same parameters, else (default) - creates a new one + # @ingroup l3_hypos_quad + def Reduced(self, UseExisting=0): + return self.QuadrangleParameters(QUAD_REDUCED,UseExisting=UseExisting) + + ## Defines "QuadrangleParams" hypothesis with QUAD_STANDARD type of quadrangulation + # @param vertex: vertex of a trilateral geometrical face, around which triangles + # will be created while other elements will be quadrangles. + # Vertex can be either a GEOM_Object or a vertex ID within the + # shape to mesh + # @param UseExisting: if ==true - searches for the existing hypothesis created with + # the same parameters, else (default) - creates a new one + # @ingroup l3_hypos_quad + def TriangleVertex(self, vertex, UseExisting=0): + return self.QuadrangleParameters(QUAD_STANDARD,vertex,UseExisting) - ## Defines "TrianglePreference" hypothesis, forcing construction - # of triangles in the refinement area if the number of nodes - # on the opposite edges is not the same - # - # @ingroup l3_hypos_additi - def TrianglePreference(self): - hyp = self.Hypothesis("TrianglePreference", UseExisting=1, - CompareMethod=self.CompareEqualHyp) - return hyp # Public class: Mesh_Tetrahedron # ------------------------------ @@ -4912,6 +5592,7 @@ class Mesh_RadialPrism3D(Mesh_Algorithm): self.mesh.GetMesh().RemoveHypothesis( self.geom, self.nbLayers ) self.mesh.GetMesh().AddHypothesis( self.geom, self.distribHyp ) study = self.mesh.smeshpyD.GetCurrentStudy() # prevents publishing own 1D hypothesis + self.mesh.smeshpyD.SetCurrentStudy( None ) hyp = self.mesh.smeshpyD.CreateHypothesis(hypType, so) self.mesh.smeshpyD.SetCurrentStudy( study ) # enables publishing self.distribHyp.SetLayerDistribution( hyp ) @@ -4998,7 +5679,7 @@ class Mesh_RadialQuadrangle1D2D(Mesh_Algorithm): Mesh_Algorithm.__init__(self) self.Create(mesh, geom, "RadialQuadrangle_1D2D") - self.distribHyp = self.Hypothesis("LayerDistribution2D", UseExisting=0) + self.distribHyp = None #self.Hypothesis("LayerDistribution2D", UseExisting=0) self.nbLayers = None ## Return 2D hypothesis holding the 1D one @@ -5009,21 +5690,26 @@ class Mesh_RadialQuadrangle1D2D(Mesh_Algorithm): # hypothesis. Returns the created hypothesis def OwnHypothesis(self, hypType, args=[], so="libStdMeshersEngine.so"): #print "OwnHypothesis",hypType - if not self.nbLayers is None: + if self.nbLayers: self.mesh.GetMesh().RemoveHypothesis( self.geom, self.nbLayers ) + if self.distribHyp is None: + self.distribHyp = self.Hypothesis("LayerDistribution2D", UseExisting=0) + else: self.mesh.GetMesh().AddHypothesis( self.geom, self.distribHyp ) study = self.mesh.smeshpyD.GetCurrentStudy() # prevents publishing own 1D hypothesis + self.mesh.smeshpyD.SetCurrentStudy( None ) hyp = self.mesh.smeshpyD.CreateHypothesis(hypType, so) self.mesh.smeshpyD.SetCurrentStudy( study ) # enables publishing self.distribHyp.SetLayerDistribution( hyp ) return hyp - ## Defines "NumberOfLayers2D" hypothesis, specifying the number of layers + ## Defines "NumberOfLayers" hypothesis, specifying the number of layers # @param n number of layers # @param UseExisting if ==true - searches for the existing hypothesis created with # the same parameters, else (default) - creates a new one - def NumberOfLayers2D(self, n, UseExisting=0): - self.mesh.GetMesh().RemoveHypothesis( self.geom, self.distribHyp ) + def NumberOfLayers(self, n, UseExisting=0): + if self.distribHyp: + self.mesh.GetMesh().RemoveHypothesis( self.geom, self.distribHyp ) self.nbLayers = self.Hypothesis("NumberOfLayers2D", [n], UseExisting=UseExisting, CompareMethod=self.CompareNumberOfLayers) self.nbLayers.SetNumberOfLayers( n ) @@ -5083,6 +5769,73 @@ class Mesh_RadialQuadrangle1D2D(Mesh_Algorithm): return hyp +# Public class: Mesh_UseExistingElements +# -------------------------------------- +## Defines a Radial Quadrangle 1D2D algorithm +# @ingroup l3_algos_basic +# +class Mesh_UseExistingElements(Mesh_Algorithm): + + def __init__(self, dim, mesh, geom=0): + if dim == 1: + self.Create(mesh, geom, "Import_1D") + else: + self.Create(mesh, geom, "Import_1D2D") + return + + ## Defines "Source edges" hypothesis, specifying groups of edges to import + # @param groups list of groups of edges + # @param toCopyMesh if True, the whole mesh \a groups belong to is imported + # @param toCopyGroups if True, all groups of the mesh \a groups belong to are imported + # @param UseExisting if ==true - searches for the existing hypothesis created with + # the same parameters, else (default) - creates a new one + def SourceEdges(self, groups, toCopyMesh=False, toCopyGroups=False, UseExisting=False): + if self.algo.GetName() == "Import_2D": + raise ValueError, "algoritm dimension mismatch" + hyp = self.Hypothesis("ImportSource1D", [groups, toCopyMesh, toCopyGroups], + UseExisting=UseExisting, CompareMethod=self._compareHyp) + hyp.SetSourceEdges(groups) + hyp.SetCopySourceMesh(toCopyMesh, toCopyGroups) + return hyp + + ## Defines "Source faces" hypothesis, specifying groups of faces to import + # @param groups list of groups of faces + # @param toCopyMesh if True, the whole mesh \a groups belong to is imported + # @param toCopyGroups if True, all groups of the mesh \a groups belong to are imported + # @param UseExisting if ==true - searches for the existing hypothesis created with + # the same parameters, else (default) - creates a new one + def SourceFaces(self, groups, toCopyMesh=False, toCopyGroups=False, UseExisting=False): + if self.algo.GetName() == "Import_1D": + raise ValueError, "algoritm dimension mismatch" + hyp = self.Hypothesis("ImportSource2D", [groups, toCopyMesh, toCopyGroups], + UseExisting=UseExisting, CompareMethod=self._compareHyp) + hyp.SetSourceFaces(groups) + hyp.SetCopySourceMesh(toCopyMesh, toCopyGroups) + return hyp + + def _compareHyp(self,hyp,args): + if hasattr( hyp, "GetSourceEdges"): + entries = hyp.GetSourceEdges() + else: + entries = hyp.GetSourceFaces() + groups = args[0] + toCopyMesh,toCopyGroups = hyp.GetCopySourceMesh() + if len(entries)==len(groups) and toCopyMesh==args[1] and toCopyGroups==args[2]: + entries2 = [] + study = self.mesh.smeshpyD.GetCurrentStudy() + if study: + for g in groups: + ior = salome.orb.object_to_string(g) + sobj = study.FindObjectIOR(ior) + if sobj: entries2.append( sobj.GetID() ) + pass + pass + entries.sort() + entries2.sort() + return entries == entries2 + return False + + # Private class: Mesh_UseExisting # ------------------------------- class Mesh_UseExisting(Mesh_Algorithm):