# -*- 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