summaryrefslogtreecommitdiff
path: root/stl.go
blob: 35e69eb78dda096aeef9e9d37a05b4c06280c42c (plain)
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
// 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
}

// 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() []float32 {

	retval := make([]float32, stl.numberOfTriangles * 9)

	for triangleIndex,triangle := range(stl.surface.triangles) {

		for pointIndex,point := range(triangle.points) {

			for scalarIndex,scalar := range(point.scalars) {

				retval[triangleIndex*9+pointIndex*3+scalarIndex] = scalar

			}

		}

	}

	return retval
}