From 10273687bf1905209cee0b868c5aeeaf585cfa9c Mon Sep 17 00:00:00 2001 From: Bernd Hahnebach Date: Fri, 25 Nov 2016 22:59:18 +0100 Subject: [PATCH] FEM: FEMMesh2Mesh, add the module to convert the surface of a FEMMesh into a Mesh --- src/Mod/Fem/App/CMakeLists.txt | 1 + src/Mod/Fem/CMakeLists.txt | 2 + src/Mod/Fem/FemMesh2Mesh.py | 222 +++++++++++++++++++++++++++++++++ 3 files changed, 225 insertions(+) create mode 100644 src/Mod/Fem/FemMesh2Mesh.py diff --git a/src/Mod/Fem/App/CMakeLists.txt b/src/Mod/Fem/App/CMakeLists.txt index f84b4a9966..3420595e74 100755 --- a/src/Mod/Fem/App/CMakeLists.txt +++ b/src/Mod/Fem/App/CMakeLists.txt @@ -116,6 +116,7 @@ SET(FemScripts_SRCS FemInputWriterCcx.py FemInputWriterZ88.py FemMaterialMechanicalNonlinear.py + FemMesh2Mesh.py FemMeshGmsh.py FemMeshTools.py FemShellThickness.py diff --git a/src/Mod/Fem/CMakeLists.txt b/src/Mod/Fem/CMakeLists.txt index 1d5636a81a..1c2bd922a1 100755 --- a/src/Mod/Fem/CMakeLists.txt +++ b/src/Mod/Fem/CMakeLists.txt @@ -45,6 +45,8 @@ INSTALL( FemGmshTools.py + FemMesh2Mesh.py + FemBeamSection.py _FemBeamSection.py _ViewProviderFemBeamSection.py diff --git a/src/Mod/Fem/FemMesh2Mesh.py b/src/Mod/Fem/FemMesh2Mesh.py new file mode 100644 index 0000000000..c8fe4ebe5f --- /dev/null +++ b/src/Mod/Fem/FemMesh2Mesh.py @@ -0,0 +1,222 @@ +# *************************************************************************** +# * * +# * Copyright (c) 2016 - Frantisek Loeffelmann * +# * * +# * This program is free software; you can redistribute it and/or modify * +# * it under the terms of the GNU Lesser General Public License (LGPL) * +# * as published by the Free Software Foundation; either version 2 of * +# * the License, or (at your option) any later version. * +# * for detail see the LICENCE text file. * +# * * +# * This program is distributed in the hope that it will be useful, * +# * but WITHOUT ANY WARRANTY; without even the implied warranty of * +# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +# * GNU Library General Public License for more details. * +# * * +# * You should have received a copy of the GNU Library General Public * +# * License along with this program; if not, write to the Free Software * +# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * +# * USA * +# * * +# *************************************************************************** + +__title__ = "FemMesh to Mesh converter" +__author__ = "Frantisek Loeffelmann, Ulrich Brammer" +__url__ = "http://www.freecadweb.org" + +## @package FwmMesh2Mesh +# \ingroup FEM + +import FreeCADGui +from PySide import QtGui +import Mesh +import time + + +# These dictionaries list the nodes, that define faces of an element. +# The key is the face number, used internally by FreeCAD. +# The list contains the nodes in the element for each face. +tetFaces = { + 1: [0, 1, 2], + 2: [0, 3, 1], + 3: [1, 3, 2], + 4: [2, 3, 0]} + +pentaFaces = { + 1: [0, 1, 2], + 2: [3, 5, 4], + 3: [0, 3, 4, 1], + 4: [1, 4, 5, 2], + 5: [0, 2, 5, 3]} + +hexaFaces = { # hexa8 or hexa20 (ignoring mid-nodes) + 1: [0, 1, 2, 3], + 2: [4, 7, 6, 5], + 3: [0, 4, 5, 1], + 4: [1, 5, 6, 2], + 5: [2, 6, 7, 3], + 6: [3, 7, 4, 0]} + +pyraFaces = { # pyra5 or pyra13 (ignoring mid-nodes) + 1: [0, 1, 2, 3], + 2: [0, 4, 1], + 3: [1, 4, 2], + 4: [2, 4, 3], + 5: [3, 4, 0]} + +face_dicts = { + 4: tetFaces, + 5: pyraFaces, + 6: pentaFaces, + 8: hexaFaces, + 10: tetFaces, + 13: pyraFaces, + 15: pentaFaces, + 20: hexaFaces} + + +def makeSimpleMesh(myFemMesh, myResults=None): + shiftBits = 20 # allows a million nodes, needs to be higher for more nodes in a FemMesh + + # This code generates a dict and a faceCode for each face of all elements + # All faceCodes are than sorted. + + start_time = time.clock() + faceCodeList = [] + faceCodeDict = {} + + for ele in myFemMesh.Volumes: + element_nodes = myFemMesh.getElementNodes(ele) + # print 'element_node: ', element_nodes + faceDef = face_dicts[len(element_nodes)] + + for key in faceDef: + nodeList = [] + codeList = [] + faceCode = 0 + shifter = 0 + for nodeIdx in faceDef[key]: + nodeList.append(element_nodes[nodeIdx]) + codeList.append(element_nodes[nodeIdx]) + codeList.sort() + for node in codeList: + faceCode += (node << shifter) + # x << n: x shifted left by n bits = Multiplication + shifter += shiftBits + # print 'codeList: ', codeList + faceCodeDict[faceCode] = nodeList + faceCodeList.append(faceCode) + + faceCodeList.sort() + allFaces = len(faceCodeList) + actFaceIdx = 0 + singleFaces = [] + # Here we search for faces, which do not have a counterpart. + # These are the faces on the surface of the mesh. + while actFaceIdx < allFaces: + if actFaceIdx < (allFaces - 1): + if faceCodeList[actFaceIdx] == faceCodeList[actFaceIdx + 1]: + actFaceIdx += 2 + else: + # print 'found a single Face: ', faceCodeList[actFaceIdx] + singleFaces.append(faceCodeList[actFaceIdx]) + actFaceIdx += 1 + else: + print 'found a last Face: ', faceCodeList[actFaceIdx] + singleFaces.append(faceCodeList[actFaceIdx]) + actFaceIdx += 1 + + output_mesh = [] + if myResults: + for myFace in singleFaces: + face_nodes = faceCodeDict[myFace] + dispVec0 = myResults.DisplacementVectors[myResults.NodeNumbers.index(face_nodes[0])] + dispVec1 = myResults.DisplacementVectors[myResults.NodeNumbers.index(face_nodes[1])] + dispVec2 = myResults.DisplacementVectors[myResults.NodeNumbers.index(face_nodes[2])] + triangle = [myFemMesh.getNodeById(face_nodes[0]) + dispVec0, + myFemMesh.getNodeById(face_nodes[1]) + dispVec1, + myFemMesh.getNodeById(face_nodes[2]) + dispVec2] + output_mesh.extend(triangle) + # print 'my triangle: ', triangle + if len(face_nodes) == 4: + dispVec3 = myResults.DisplacementVectors[myResults.NodeNumbers.index(face_nodes[3])] + triangle = [myFemMesh.getNodeById(face_nodes[2]) + dispVec2, + myFemMesh.getNodeById(face_nodes[3]) + dispVec3, + myFemMesh.getNodeById(face_nodes[0]) + dispVec0] + output_mesh.extend(triangle) + # print 'my 2. triangle: ', triangle + + else: + for myFace in singleFaces: + face_nodes = faceCodeDict[myFace] + triangle = [myFemMesh.getNodeById(face_nodes[0]), + myFemMesh.getNodeById(face_nodes[1]), + myFemMesh.getNodeById(face_nodes[2])] + output_mesh.extend(triangle) + # print 'my triangle: ', triangle + if len(face_nodes) == 4: + triangle = [myFemMesh.getNodeById(face_nodes[2]), + myFemMesh.getNodeById(face_nodes[3]), + myFemMesh.getNodeById(face_nodes[0])] + output_mesh.extend(triangle) + # print 'my 2. triangle: ', triangle + + if output_mesh: + obj = Mesh.Mesh(output_mesh) + Mesh.show(obj) + end_time = time.clock() + print 'Mesh by surface search method: ', end_time - start_time + + ''' + if output_mesh: + obj = Mesh.Mesh(output_mesh) + Mesh.show(obj) + end_time = time.clock() + print 'Faces by surface time: ', end_time - start_time + # This creates a mesh from all faces defined in the mesh structure + # Some meshes from Gmsh or Netgen seems to contain the surface as a list + # of faces. + + start_time = time.clock() + output_mesh = [] + for myFace in myFemMesh.Faces: + element_nodes = myFemMesh.getElementNodes(myFace) + triangle = [myFemMesh.getNodeById(element_nodes[0]), + myFemMesh.getNodeById(element_nodes[1]), + myFemMesh.getNodeById(element_nodes[2])] + output_mesh.extend(triangle) + + if output_mesh: + obj = Mesh.Mesh(output_mesh) + Mesh.show(obj) + end_time = time.clock() + print 'Faces by face already in mesh time: ', end_time - start_time + ''' + + +def main(): + selection = FreeCADGui.Selection.getSelection() + femResult = None + input_mesh = None + + for theObject in selection: + if hasattr(theObject, "TypeId"): + print 'The TypeId: ', theObject.TypeId + if hasattr(theObject, "Name"): + print 'The Name: ', theObject.Name + if hasattr(theObject, "FemMesh"): + input_mesh = theObject.FemMesh + if theObject.TypeId == 'Fem::FemResultObject': + femResult = theObject # .DisplacementVectors + + if not input_mesh: + QtGui.QMessageBox.critical(None, "femmesh2mesh", "FemMesh object has to be selected!") + assert selection, "FemMesh object has to be selected!" + if input_mesh: + makeSimpleMesh(input_mesh, femResult) + + return 0 + + +if __name__ == '__main__': + main()