@@ -796,6 +796,104 @@ def generate_iges(self,
796796 display .DisplayShape (generated_tip , update = True )
797797 start_display ()
798798
799+ def generate_stl (self , min_length = None , max_length = None , outfile_stl = None ):
800+ """
801+ Generate and export the .STL surface mesh for the blade as a whole,
802+ including the upper face, lower face and tip. The method utilizes
803+ modules from OCC SMESH which is standalone mesh framework based on
804+ SALOME mesher project. Please refer to https://github.com/tpaviot
805+ and http://docs.salome-platform.org/7/gui/SMESH/index.html for
806+ further details.
807+
808+ This method requires PythonOCC and SMESH to be installed.
809+
810+ :param double min_length: smallest distance between two nodes. Default
811+ value is None
812+ :param double max_length: largest distance between two nodes. Default
813+ value is None
814+ :param string outfile_stl: if string is passed then the method exports
815+ the generated 2D surface mesh into .stl file holding the name
816+ <outfile_stl>.stl. Default value is None
817+
818+ We note that since the current implementation performs triangulation
819+ based on a topological compound that combines the blade 3 generated
820+ shapes without "fusion", it may happen that the generated triangulation
821+ of the upper and lower blade faces do not share the same exact nodes
822+ on the joint edge/wire resulting from the faces intersection. The
823+ current implementation can be enough for visualization purpose. However
824+ if the generated mesh is intended for computational analysis then a
825+ manual mesh healing is recommended by the user (e.g. see
826+ "Repair > Sewing" in SALOME GUI) for a proper mesh closure.
827+ """
828+ from OCC .SMESH import SMESH_Gen , SMESH_MeshVSLink
829+ from OCC .StdMeshers import (StdMeshers_Arithmetic1D , StdMeshers_TrianglePreference ,
830+ StdMeshers_Regular_1D , StdMeshers_Quadrangle_2D ,
831+ StdMeshers_MEFISTO_2D )
832+ from OCC .BRep import BRep_Builder
833+ from OCC .TopoDS import TopoDS_Shape , TopoDS_Compound
834+
835+ # First we check that blade shapes are generated, otherwise we generate
836+ # them. After that we combine the generated_upper_face,
837+ # generated_lower_face, and generated_tip into a topological compound
838+ # that we use to compute the surface mesh
839+ if (self .generated_upper_face is None ) or not isinstance (self .generated_upper_face , TopoDS_Shape ):
840+ # Upper face is generated with a maximal U degree = 1
841+ self ._generate_upper_face (maxDeg = 1 )
842+ if (self .generated_lower_face is None ) or not isinstance (self .generated_lower_face , TopoDS_Shape ):
843+ # Upper face is generated with a maximal U degree = 1
844+ self ._generate_lower_face (maxDeg = 1 )
845+ if (self .generated_tip is None ) or not isinstance (self .generated_tip , TopoDS_Shape ):
846+ # Upper face is generated with a maximal U degree = 1
847+ self ._generate_tip (maxDeg = 1 )
848+
849+ # Now we regroup all the shapes into a TopoDS_Compound
850+ aCompound = TopoDS_Compound ()
851+ aBuilder = BRep_Builder ()
852+ aBuilder .MakeCompound (aCompound )
853+ # Add shapes
854+ aBuilder .Add (aCompound ,self .generated_upper_face )
855+ aBuilder .Add (aCompound ,self .generated_lower_face )
856+ aBuilder .Add (aCompound ,self .generated_tip )
857+
858+ # In the following we build the surface mesh according to the given
859+ # hypotheses
860+ aMeshGen = SMESH_Gen ()
861+ aMesh = aMeshGen .CreateMesh (0 , True )
862+ # Adding 1D hypothesis and algorithms
863+ # Wire discretization. Nodes are distributed based on Arithmetic1D
864+ # hypothesis which allows to split edges into segments with a length
865+ # that changes in arithmetic progression (Lk = Lk-1 + d) beginning
866+ # from a given min length and up to a given max length. More about
867+ # 1D hypotheses can be viewed through:
868+ # http://docs.salome-platform.org/7/gui/SMESH/a1d_meshing_hypo_page.html
869+ an1DHypothesis = StdMeshers_Arithmetic1D (0 , 0 , aMeshGen )
870+ # Smallest distance between 2 points
871+ an1DHypothesis .SetLength (min_length , False )
872+ # Longest distance between 2 points
873+ an1DHypothesis .SetLength (max_length , True )
874+ # Regular Interpolation
875+ an1DAlgo = StdMeshers_Regular_1D (1 , 0 , aMeshGen )
876+ # Adding 2D hypothesis and algorithms
877+ # 2D surface mesh -- Triangulations
878+ a2dHypothseis = StdMeshers_TrianglePreference (2 , 0 , aMeshGen )
879+ a2dAlgo = StdMeshers_MEFISTO_2D (3 , 0 , aMeshGen )
880+
881+ #Calculate mesh for the topological compound containing the 3 shapes
882+ aMesh .ShapeToMesh (aCompound )
883+
884+ #Assign hyptothesis to mesh
885+ aMesh .AddHypothesis (aCompound , 0 )
886+ aMesh .AddHypothesis (aCompound , 1 )
887+ aMesh .AddHypothesis (aCompound , 2 )
888+ aMesh .AddHypothesis (aCompound , 3 )
889+
890+ #Compute the data
891+ aMeshGen .Compute (aMesh , aMesh .GetShapeToMesh ())
892+
893+ if outfile_stl is not None :
894+ assert isinstance (outfile_stl , str ), "outfile_stl must be a valid string."
895+ aMesh .ExportSTL (outfile_stl + '.stl' , False )
896+
799897 @staticmethod
800898 def _check_string (filename ):
801899 """
0 commit comments