| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| __title__ = "FreeCAD tetgen exporter" |
| __author__ = "Juergen Riegel" |
| __url__ = "https://www.freecad.org" |
|
|
| |
| |
|
|
| |
| import FreeCAD |
| from FreeCAD import Console |
| import Mesh |
|
|
| App = FreeCAD |
| if FreeCAD.GuiUp: |
| import FreeCADGui |
|
|
| Gui = FreeCADGui |
|
|
|
|
| def exportMeshToTetGenPoly(meshToExport, filePath, beVerbose=1): |
| """Export mesh to TetGen *.poly file format""" |
| |
| if beVerbose == 1: |
| Console.PrintMessage("\nExport of mesh to TetGen file ...") |
| (allVertices, allFacets) = meshToExport.Topology |
| f = open(filePath, "w") |
| f.write("# This file was generated from FreeCAD geometry\n") |
| f.write("# Part 1 - node list\n") |
| f.write( |
| "TotalNumOfPoints: {}, NumOfDimensions; {}, " |
| "NumOfProperties: {}, BoundaryMarkerExists: {}\n".format(len(allVertices), 3, 0, 0) |
| ) |
| for PointIndex in range(len(allVertices)): |
| f.write( |
| "%(PointIndex)5i %(x) e %(y) e %(z) e\n" |
| % { |
| "PointIndex": PointIndex, |
| "x": allVertices[PointIndex].x, |
| "y": allVertices[PointIndex].y, |
| "z": allVertices[PointIndex].z, |
| } |
| ) |
|
|
| |
| |
| BoundaryMarkerExists = 1 |
| PointList = [allFacets[0][1], allFacets[0][0]] |
| PointList.sort() |
| EdgeFacets = {(PointList[0], PointList[1]): {0}} |
| Edge = [] |
|
|
| |
| for FacetIndex in range(len(allFacets)): |
| Facet = allFacets[FacetIndex] |
| for i in range(0, -len(Facet), -1): |
| tmpEdge = [Facet[i], Facet[i + 1]] |
| tmpEdge.sort() |
| Edge.append(tmpEdge) |
| for i in range(len(Edge)): |
| EdgeIndex = (Edge[i][0], Edge[i][1]) |
| if EdgeIndex in EdgeFacets: |
| EdgeFacets[EdgeIndex].add(FacetIndex) |
| else: |
| EdgeFacets[EdgeIndex] = {FacetIndex} |
| Edge = [] |
|
|
| |
| BoundaryMarker = [] |
| for index in range(len(allFacets)): |
| BoundaryMarker.append(0) |
| MinMarker = -1 |
| InitialFacet = 0 |
| BoundaryMarker[InitialFacet] = MinMarker |
| EdgeKeys = EdgeFacets.keys() |
| |
| if beVerbose == 1: |
| Console.PrintMessage( |
| "\nBoundaryMarker:" + repr(BoundaryMarker) + " " + repr(len(EdgeFacets)) |
| ) |
| searchForPair = 1 |
|
|
| |
| |
| while len(EdgeFacets) > 0: |
| removeEdge = 0 |
| for EdgeIndex in EdgeKeys: |
| if len(EdgeFacets[EdgeIndex]) == 1: |
| removeEdge = 1 |
| break |
| if len(EdgeFacets[EdgeIndex]) == 2: |
| FacetPair = [] |
| for facet in EdgeFacets[EdgeIndex]: |
| FacetPair.append(facet) |
| if (BoundaryMarker[FacetPair[0]] == 0) and (BoundaryMarker[FacetPair[1]] == 0): |
| continue |
| if (BoundaryMarker[FacetPair[0]] != 0) and (BoundaryMarker[FacetPair[1]] != 0): |
| removeEdge = 1 |
| break |
| if BoundaryMarker[FacetPair[0]] != 0: |
| BoundaryMarker[FacetPair[1]] = BoundaryMarker[FacetPair[0]] |
| else: |
| BoundaryMarker[FacetPair[0]] = BoundaryMarker[FacetPair[1]] |
| removeEdge = 1 |
| break |
| if searchForPair == 1: |
| continue |
| FacetTree = [] |
| |
| MarkerSum = 0 |
| for facet in EdgeFacets[EdgeIndex]: |
| FacetTree.append(facet) |
| MarkerSum += BoundaryMarker[facet] |
| if MarkerSum == 0: |
| continue |
| for facet in EdgeFacets[EdgeIndex]: |
| if BoundaryMarker[facet] == 0: |
| MinMarker -= 1 |
| BoundaryMarker[facet] = MinMarker |
| searchForPair = 1 |
| removeEdge = 1 |
| break |
| if removeEdge == 1: |
| del EdgeFacets[EdgeIndex] |
| EdgeKeys = EdgeFacets.keys() |
| continue |
| searchForPair = 0 |
| |
| if beVerbose == 1: |
| Console.PrintMessage( |
| "\nNew BoundaryMarker:" + repr(BoundaryMarker) + " " + repr(len(EdgeFacets)) |
| ) |
|
|
| |
| f.write("# Part 2 - facet list\n") |
| f.write( |
| "%(TotalNumOfFacets)i %(BoundaryMarkerExists)i\n" |
| % {"TotalNumOfFacets": len(allFacets), "BoundaryMarkerExists": BoundaryMarkerExists} |
| ) |
| for FacetIndex in range(len(allFacets)): |
| f.write("# FacetIndex = %(Index)i\n" % {"Index": FacetIndex}) |
| f.write("%(NumOfPolygons)3i " % {"NumOfPolygons": 1}) |
| if BoundaryMarkerExists == 1: |
| f.write("0 %(BoundaryMarker)i" % {"BoundaryMarker": BoundaryMarker[FacetIndex]}) |
| f.write("\n%(NumOfConers)3i " % {"NumOfConers": len(allFacets[FacetIndex])}) |
| for PointIndex in range(len(allFacets[FacetIndex])): |
| |
| f.write("%(PointIndex)i " % {"PointIndex": allFacets[FacetIndex][PointIndex]}) |
| f.write("\n") |
| |
| f.write("# Part 3 - the hole list.\n# There is no hole in bar.\n0\n") |
| f.write("# Part 4 - the region list.\n# There is no region defined.\n0\n") |
| f.write("# This file was generated from FreeCAD geometry\n") |
| f.close() |
|
|
|
|
| def export(objectslist, filename): |
| """Called when freecad exports a mesh to poly format""" |
| for obj in objectslist: |
| if isinstance(obj, Mesh.Feature): |
| exportMeshToTetGenPoly(obj.Mesh, filename, False) |
| break |
|
|
|
|
| def createMesh(): |
| |
| beVerbose = 1 |
| if beVerbose == 1: |
| Console.PrintMessage("\n\n\n\n\n\n\n\nScript starts...") |
| |
| |
| PyDocumentName = "pnJunction" |
| PSideBoxName = "PSide" |
| NSideBoxName = "NSide" |
| DepletionBoxName = "Depletion" |
| SurfDepletionBoxName = "SurfDepletion" |
| OxideBoxName = "Oxide" |
| AdsorbtionBoxName = "Adsorbtion" |
| pnMeshName = "pnMesh" |
|
|
| |
| if beVerbose == 1: |
| Console.PrintMessage("\nInit Objects...") |
| |
| |
| AppPyDoc = App.newDocument(PyDocumentName) |
| NSideBox = AppPyDoc.addObject("Part::Box", NSideBoxName) |
| PSideBox = AppPyDoc.addObject("Part::Box", PSideBoxName) |
| DepletionBox = AppPyDoc.addObject("Part::Box", DepletionBoxName) |
| SurfDepletionBox = AppPyDoc.addObject("Part::Box", SurfDepletionBoxName) |
| OxideBox = AppPyDoc.addObject("Part::Box", OxideBoxName) |
| AdsorbtionBox = AppPyDoc.addObject("Part::Box", AdsorbtionBoxName) |
| pnMesh = AppPyDoc.addObject("Mesh::Feature", pnMeshName) |
|
|
| BoxList = [NSideBox, DepletionBox, PSideBox, OxideBox, AdsorbtionBox, SurfDepletionBox] |
| NSideBoxMesh = Mesh.Mesh() |
| PSideBoxMesh = Mesh.Mesh() |
| DepletionBoxMesh = Mesh.Mesh() |
| SurfDepletionBoxMesh = Mesh.Mesh() |
| OxideBoxMesh = Mesh.Mesh() |
| AdsorbtionBoxMesh = Mesh.Mesh() |
| BoxMeshList = [ |
| NSideBoxMesh, |
| DepletionBoxMesh, |
| PSideBoxMesh, |
| OxideBoxMesh, |
| AdsorbtionBoxMesh, |
| SurfDepletionBoxMesh, |
| ] |
| if beVerbose == 1: |
| if len(BoxList) != len(BoxMeshList): |
| Console.PrintMessage( |
| "\n ERROR! Input len() of BoxList and BoxMeshList is not the same! " |
| ) |
|
|
| |
| if beVerbose == 1: |
| Console.PrintMessage("\nSet sizes...") |
| tessellationTollerance = 0.05 |
| ModelWidth = 300 |
| BulkHeight = 300 |
| BulkLength = 300 |
| DepletionSize = 50 |
| OxideThickness = 5 |
| AdsorbtionThickness = 10 |
|
|
| |
| NSideBox.Height = BulkHeight |
| NSideBox.Width = ModelWidth |
| NSideBox.Length = BulkLength |
| PSideBox.Height = BulkHeight |
| PSideBox.Width = ModelWidth |
| PSideBox.Length = BulkLength |
| |
| DepletionBox.Height = BulkHeight |
| DepletionBox.Width = ModelWidth |
| DepletionBox.Length = DepletionSize * 2 |
| |
| SurfDepletionBox.Height = DepletionSize |
| SurfDepletionBox.Width = ModelWidth |
| SurfDepletionBox.Length = BulkLength * 2 + DepletionSize * 2 |
| |
| OxideBox.Height = OxideThickness |
| OxideBox.Width = ModelWidth |
| OxideBox.Length = BulkLength * 2 + DepletionSize * 2 |
| |
| AdsorbtionBox.Height = AdsorbtionThickness |
| AdsorbtionBox.Width = ModelWidth |
| AdsorbtionBox.Length = BulkLength * 2 + DepletionSize * 2 |
|
|
| |
| Rot = App.Rotation(0, 0, 0, 1) |
| NSideBox.Placement = App.Placement(App.Vector(0, 0, -BulkHeight), Rot) |
| PSideBox.Placement = App.Placement( |
| App.Vector(DepletionSize * 2 + BulkLength, 0, -BulkHeight), Rot |
| ) |
| DepletionBox.Placement = App.Placement(App.Vector(BulkLength, 0, -BulkHeight), Rot) |
| SurfDepletionBox.Placement = App.Placement(App.Vector(0, 0, 0), Rot) |
| OxideBox.Placement = App.Placement(App.Vector(0, 0, DepletionSize), Rot) |
| AdsorbtionBox.Placement = App.Placement(App.Vector(0, 0, DepletionSize + OxideThickness), Rot) |
|
|
| |
| if beVerbose == 1: |
| Console.PrintMessage("\nFuse objects...") |
| fuseShape = BoxList[0].Shape |
| for index in range(1, len(BoxList), 1): |
| fuseShape = fuseShape.fuse(BoxList[index].Shape) |
| nmesh = Mesh.Mesh() |
| nmesh.addFacets(fuseShape.tessellate(tessellationTollerance)) |
|
|
| |
| for index in range(len(BoxList) - 1): |
| BoxMeshList[index].addFacets(BoxList[index].Shape.tessellate(tessellationTollerance)) |
| nmesh.addMesh(BoxMeshList[index]) |
|
|
| nmesh.removeDuplicatedPoints() |
| nmesh.removeDuplicatedFacets() |
| pnMesh.Mesh = nmesh |
|
|
| if FreeCAD.GuiUp: |
| |
| for box in BoxList: |
| Gui.hideObject(box) |
|
|
| |
| |
| |
|
|
| |
| AppPyDoc.recompute() |
|
|
| |
| |
| |
|
|
| if FreeCAD.GuiUp: |
| pnMesh.ViewObject.Document.activeView().viewAxonometric() |
| pnMesh.ViewObject.Document.activeView().fitAll() |
|
|
| if beVerbose == 1: |
| Console.PrintMessage("\nScript finished without errors.") |
|
|
|
|
| |
|
|