File: STLWriter.py

package info (click to toggle)
uranium 3.3.0-1
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 5,876 kB
  • sloc: python: 22,349; sh: 111; makefile: 11
file content (115 lines) | stat: -rw-r--r-- 5,189 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# Copyright (c) 2016 Ultimaker B.V.
# Copyright (c) 2013 David Braam
# Uranium is released under the terms of the LGPLv3 or higher.

from UM.Mesh.MeshWriter import MeshWriter
from UM.Logger import Logger

import time
import struct

class STLWriter(MeshWriter):
    ##  Write the specified sequence of nodes to a stream in the STL format.
    #
    #   \param stream The output stream to write to.
    #   \param nodes A sequence of scene nodes to write to the output stream.
    #   \param mode The output mode to use for writing scene nodes. Text mode
    #   causes the writer to write in STL's ASCII format. Binary mode causes the
    #   writer to write in STL's binary format. Any other mode is invalid.
    def write(self, stream, nodes, mode = MeshWriter.OutputMode.TextMode):
        try:
            MeshWriter._meshNodes(nodes).__next__()
        except:
            Logger.log("e", "There is no mesh to write.")
            return False #Don't try to write a file if there is no mesh.

        if mode == MeshWriter.OutputMode.TextMode:
            self._writeAscii(stream, MeshWriter._meshNodes(nodes))
        elif mode == MeshWriter.OutputMode.BinaryMode:
            self._writeBinary(stream, MeshWriter._meshNodes(nodes))
        else:
            Logger.log("e", "Unsupported output mode writing STL to stream")
            return False

        return True

    def _writeAscii(self, stream, nodes):
        name = "Uranium STLWriter {0}".format(time.strftime("%a %d %b %Y %H:%M:%S"))
        stream.write("solid {0}\n".format(name))

        for node in nodes:
            mesh_data = node.getMeshData().getTransformed(node.getWorldTransformation())
            verts = mesh_data.getVertices()
            if verts is None:
                continue  # No mesh data, nothing to do.

            if mesh_data.hasIndices():
                for face in mesh_data.getIndices():
                    stream.write("facet normal 0.0 0.0 0.0\n")
                    stream.write("  outer loop\n")

                    v1 = verts[face[0]]
                    v2 = verts[face[1]]
                    v3 = verts[face[2]]
                    stream.write("    vertex {0} {1} {2}\n".format(v1[0], -v1[2], v1[1]))
                    stream.write("    vertex {0} {1} {2}\n".format(v2[0], -v2[2], v2[1]))
                    stream.write("    vertex {0} {1} {2}\n".format(v3[0], -v3[2], v3[1]))

                    stream.write("  endloop\n")
                    stream.write("endfacet\n")
            else:
                num_verts = mesh_data.getVertexCount()
                for index in range(0, num_verts - 2, 3):
                    stream.write("facet normal 0.0 0.0 0.0\n")
                    stream.write("  outer loop\n")
                    v1 = verts[index]
                    v2 = verts[index + 1]
                    v3 = verts[index + 2]
                    stream.write("    vertex {0} {1} {2}\n".format(v1[0], -v1[2], v1[1]))
                    stream.write("    vertex {0} {1} {2}\n".format(v2[0], -v2[2], v2[1]))
                    stream.write("    vertex {0} {1} {2}\n".format(v3[0], -v3[2], v3[1]))

                    stream.write("  endloop\n")
                    stream.write("endfacet\n")

        stream.write("endsolid {0}\n".format(name))

    def _writeBinary(self, stream, nodes):
        stream.write("Uranium STLWriter {0}".format(time.strftime("%a %d %b %Y %H:%M:%S")).encode().ljust(80, b"\000"))

        face_count = 0
        nodes = list(nodes)
        for node in nodes:
            if node.getMeshData().hasIndices():
                face_count += node.getMeshData().getFaceCount()
            else:
                face_count += node.getMeshData().getVertexCount() / 3

        stream.write(struct.pack("<I", int(face_count))) #Write number of faces to STL

        for node in nodes:
            mesh_data = node.getMeshData().getTransformed(node.getWorldTransformation())

            if mesh_data.hasIndices():
                verts = mesh_data.getVertices()
                for face in mesh_data.getIndices():
                    v1 = verts[face[0]]
                    v2 = verts[face[1]]
                    v3 = verts[face[2]]
                    stream.write(struct.pack("<fff", 0.0, 0.0, 0.0))
                    stream.write(struct.pack("<fff", v1[0], -v1[2], v1[1]))
                    stream.write(struct.pack("<fff", v2[0], -v2[2], v2[1]))
                    stream.write(struct.pack("<fff", v3[0], -v3[2], v3[1]))
                    stream.write(struct.pack("<H", 0))
            else:
                num_verts = mesh_data.getVertexCount()
                verts = mesh_data.getVertices()
                for index in range(0, num_verts - 1, 3):
                    v1 = verts[index]
                    v2 = verts[index + 1]
                    v3 = verts[index + 2]
                    stream.write(struct.pack("<fff", 0.0, 0.0, 0.0))
                    stream.write(struct.pack("<fff", v1[0], -v1[2], v1[1]))
                    stream.write(struct.pack("<fff", v2[0], -v2[2], v2[1]))
                    stream.write(struct.pack("<fff", v3[0], -v3[2], v3[1]))
                    stream.write(struct.pack("<H", 0))