Source code for Muscat.IO.StlWriter

# -*- coding: utf-8 -*-
#
# This file is subject to the terms and conditions defined in
# file 'LICENSE.txt', which is part of this source code package.
#


from Muscat.IO.IOFactory import RegisterWriterClass
from typing import Optional, List, Union

import numpy as np

from Muscat.IO.WriterBase import WriterBase as WriterBase
import Muscat.Containers.ElementsDescription as ED
from Muscat.Containers.Mesh import Mesh


[docs]def WriteMeshToStl(filename: str, mesh: Mesh, normals: Optional[np.ndarray] = None) -> None: """Functional API for writing mesh in the stl format file. Parameters ---------- filename : str name with path to the file to be created (relative or absolute) mesh : Mesh the mesh to be exported normals : np.ndarray, optional containing the normal at each element of the surface, by default None """ OW = StlWriter() OW.Open(filename) OW.Write(mesh, normals=normals) OW.Close()
[docs]class StlWriter(WriterBase): """Class to write Unstructured surface mesh on disk in the stl format file """ def __init__(self) -> None: super().__init__() self.extractSkin = True self.canHandleBinaryChange = False def __str__(self) -> str: res = 'StlWriter : \n' res += ' FileName : '+str(self.fileName)+'\n' return res
[docs] def SetFileName(self, fileName: Union[str,None]) -> None: """Sets the name of the file to read Parameters ---------- fileName : str name of the file to read """ self.fileName = fileName
[docs] def Close(self) -> None: """Close the output file """ if self.isOpen(): super().Close()
[docs] def Write(self, mesh: Mesh, normals: Optional[np.ndarray] = None, Name: Optional[str] = None, PointFieldsNames: Optional[List[str]] = None, PointFields: Optional[List[np.ndarray]] = None, CellFieldsNames: Optional[List[str]] = None, CellFields: Optional[List[np.ndarray]] = None, GridFieldsNames: Optional[List[str]] = None, GridFields: Optional[List[np.ndarray]] = None) -> None: """Write mesh to file in stl format Parameters ---------- mesh : Mesh the mesh to be written normals : np.ndarray, optional containing the normal at each element of the surface, by default None Name : str, optional name of the surface to write, by default None PointFieldsNames : List[str] Not Used, by default None PointFields : None Not Used, by default None CellFieldsNames : List[str] Not Used, by default None CellFields : List[np.ndarray] Not Used, by default None GridFieldsNames : List[str] Not Used, by default None GridFields : List[Number] Not Used, by default None """ from Muscat.Containers.Mesh import ElementsContainer triangles = ElementsContainer(ED.Triangle_3) triangles.Merge(mesh.GetElementsOfType(ED.Triangle_3)) nodes = mesh.nodes if nodes.shape[1] < 3: nodes = np.hstack((nodes,)+(np.zeros((nodes.shape[0], 1)),)*(3-nodes.shape[1])) if self.extractSkin: from Muscat.Containers.MeshModificationTools import ComputeSkin skin = ComputeSkin(mesh) elements = skin.GetElementsOfType(ED.Triangle_3) triangles.Merge(elements) if Name is None: Name = "Solid" self.writeText("solid {}\n".format(Name)) for i in range(triangles.GetNumberOfElements()): if normals is not None: self.writeText(" facet normal {}\n".format(" ".join(map(str, normals[i, :])))) else: p0 = nodes[triangles.connectivity[i, 0], :] p1 = nodes[triangles.connectivity[i, 1], :] p2 = nodes[triangles.connectivity[i, 2], :] normal = np.cross(p1-p0, p2-p0) normal = normal/np.linalg.norm(normal) self.writeText(" facet normal {}\n".format(" ".join(map(str, normal)))) self.writeText(" outer loop\n") for p in range(3): self.writeText(" vertex {}\n".format(" ".join(map(str, nodes[triangles.connectivity[i, p], :])))) self.writeText(" endloop\n") self.writeText(" endfacet\n") self.writeText("endsolid\n")
RegisterWriterClass(".stl", StlWriter)
[docs]def CheckIntegrity() -> str: data = u""" solid cube_corner facet normal 0.0 -1.0 0.0 outer loop vertex 0.0 0.0 0.0 vertex 1.0 0.0 0.0 vertex 0.0 0.0 1.0 endloop endfacet facet normal 0.0 0.0 -1.0 outer loop vertex 0.0 0.0 0.0 vertex 0.0 1.0 0.0 vertex 1.0 0.0 0.0 endloop endfacet facet normal -1.0 0.0 0.0 outer loop vertex 0.0 0.0 0.0 vertex 0.0 0.0 1.0 vertex 0.0 1.0 0.0 endloop endfacet facet normal 0.577 0.577 0.577 outer loop vertex 1.0 0.0 0.0 vertex 0.0 1.0 0.0 vertex 0.0 0.0 1.0 endloop endfacet endsolid""" from Muscat.IO.StlReader import ReadStl as ReadStl from Muscat.Helpers.IO.TemporaryDirectory import TemporaryDirectory res = ReadStl(string=data) print(res) tempdir = TemporaryDirectory.GetTempPath() WriteMeshToStl(tempdir+"Test_StlWriter.stl", res) res.nodes = res.nodes[:, 0:2] WriteMeshToStl(tempdir+"Test_StlWriter_with_normals.stl", res, normals=res.elemFields["normals"]) ow = StlWriter() print(ow) return ("ok")
if __name__ == '__main__': print(CheckIntegrity()) # pragma: no cover