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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
|
// vim: shiftwidth=4 tabstop=4 noexpandtab
/*
Wikipedia about STL file format: https://en.wikipedia.org/wiki/STL_(file_format)
*/
package main
import (
"io/ioutil"
"log"
"encoding/binary"
"math"
)
// representation of binary STL file content
type StlModel struct {
header []byte
numberOfTriangles uint32
surface Surface
}
type Vector3 [3]float32
// read and parse a given binary STL file
func ReadBinaryStlFile(filePath string) (StlModel, error) {
fileContent, err := ioutil.ReadFile(filePath)
if err != nil {
return StlModel{}, err
}
model := StlModel{}
model.surface = Surface{}
model.header = fileContent[0:80]
log.Printf("STL header: '%s'\n", string(model.header))
model.numberOfTriangles = binary.LittleEndian.Uint32(fileContent[80:84])
log.Printf("STL model has %d triangles\n", model.numberOfTriangles)
var i uint32
for i = 0; i < model.numberOfTriangles; i++ { // for each expected triangle
start := 84 + i*50 // 50 bytes is length of one triangle
end := 84 + (i+1)*50
model.surface.triangles = append(model.surface.triangles,
ParseBinaryStlTriangle(fileContent[start:end]))
}
return model,nil
}
// parse the 50 bytes of the STL file representing a triangle (surface normal is ignored)
func ParseBinaryStlTriangle(data []byte) *Triangle { // FIXME: This function should only accept 50 byte slices/arrays
// allocate a new triangle and three corner points on the heap
triangle := new(Triangle)
triangle.points[0] = new(Point)
triangle.points[1] = new(Point)
triangle.points[2] = new(Point)
// parse x, y and z coordinate for corner point a
triangle.points[0].scalars[0] = math.Float32frombits(binary.LittleEndian.Uint32(data[12:16]))
triangle.points[0].scalars[1] = math.Float32frombits(binary.LittleEndian.Uint32(data[16:20]))
triangle.points[0].scalars[2] = math.Float32frombits(binary.LittleEndian.Uint32(data[20:24]))
// parse x, y and z coordinate for corner point b
triangle.points[1].scalars[0] = math.Float32frombits(binary.LittleEndian.Uint32(data[24:28]))
triangle.points[1].scalars[1] = math.Float32frombits(binary.LittleEndian.Uint32(data[28:32]))
triangle.points[1].scalars[2] = math.Float32frombits(binary.LittleEndian.Uint32(data[32:36]))
// parse x, y and z coordinate for corner point c
triangle.points[2].scalars[0] = math.Float32frombits(binary.LittleEndian.Uint32(data[36:40]))
triangle.points[2].scalars[1] = math.Float32frombits(binary.LittleEndian.Uint32(data[40:44]))
triangle.points[2].scalars[2] = math.Float32frombits(binary.LittleEndian.Uint32(data[44:48]))
return triangle
}
func (stl StlModel) toVertices() (vertex_position []float32, vertex_normal []float32) {
vertex_position = make([]float32, stl.numberOfTriangles * 9)
vertex_normal = make([]float32, stl.numberOfTriangles * 9)
var point0,point1,point2,edge0,edge1,normal Vector3;
for triangleIndex,triangle := range(stl.surface.triangles) {
for pointIndex,point := range(triangle.points) {
for scalarIndex,scalar := range(point.scalars) {
vertex_position[triangleIndex*9+pointIndex*3+scalarIndex] = scalar
}
}
// calculate normal
point0 = Vector3{triangle.points[0].scalars[0], triangle.points[0].scalars[1], triangle.points[0].scalars[2]}
point1 = Vector3{triangle.points[1].scalars[0], triangle.points[1].scalars[1], triangle.points[1].scalars[2]}
point2 = Vector3{triangle.points[2].scalars[0], triangle.points[2].scalars[1], triangle.points[2].scalars[2]}
edge0 = point1.subtract(point0)
edge1 = point2.subtract(point1)
normal = edge0.crossProduct(edge1)
normal.divideScalar(2.0) // length of normal vector corresponds to triangle area
// save normal to each vertex of the triangle
for i := 0; i<3; i++ {
vertex_normal[triangleIndex*9+i*3+0] = normal[0]
vertex_normal[triangleIndex*9+i*3+1] = normal[1]
vertex_normal[triangleIndex*9+i*3+2] = normal[2]
}
}
return vertex_position, vertex_normal
}
func (vector *Vector3) divideScalar(scalar float32) {
vector[0] = vector[0] / scalar
vector[1] = vector[1] / scalar
vector[2] = vector[2] / scalar
}
func (vectorA Vector3) subtract(vectorB Vector3) (vectorC Vector3) {
vectorC[0] = vectorA[0] - vectorB[0]
vectorC[1] = vectorA[1] - vectorB[1]
vectorC[2] = vectorA[2] - vectorB[2]
return vectorC
}
func (vectorA Vector3) crossProduct(vectorB Vector3) (vectorC Vector3) {
vectorC[0] = vectorA[1] * vectorB[2] - vectorA[2] * vectorB[1]
vectorC[1] = vectorA[2] * vectorB[0] - vectorA[0] * vectorB[2]
vectorC[2] = vectorA[0] * vectorB[1] - vectorA[1] * vectorB[0]
return vectorC
}
|