// 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.a = new(Point) // corner point a triangle.b = new(Point) // corner point b triangle.c = new(Point) // corner point c // parse x, y and z coordinate for corner point a triangle.a.x = math.Float32frombits(binary.LittleEndian.Uint32(data[12:16])) triangle.a.y = math.Float32frombits(binary.LittleEndian.Uint32(data[16:20])) triangle.a.z = math.Float32frombits(binary.LittleEndian.Uint32(data[20:24])) // parse x, y and z coordinate for corner point b triangle.b.x = math.Float32frombits(binary.LittleEndian.Uint32(data[24:28])) triangle.b.y = math.Float32frombits(binary.LittleEndian.Uint32(data[28:32])) triangle.b.z = math.Float32frombits(binary.LittleEndian.Uint32(data[32:36])) // parse x, y and z coordinate for corner point c triangle.c.x = math.Float32frombits(binary.LittleEndian.Uint32(data[36:40])) triangle.c.y = math.Float32frombits(binary.LittleEndian.Uint32(data[40:44])) triangle.c.z = math.Float32frombits(binary.LittleEndian.Uint32(data[44:48])) return triangle } func (stl StlModel) toVertices() []float32 { retval := make([]float32, stl.numberOfTriangles * 9) for index,triangle := range(stl.surface.triangles) { retval[index*9+0] = triangle.a.x retval[index*9+1] = triangle.a.y retval[index*9+2] = triangle.a.z retval[index*9+3] = triangle.b.x retval[index*9+4] = triangle.b.y retval[index*9+5] = triangle.b.z retval[index*9+6] = triangle.c.x retval[index*9+7] = triangle.c.y retval[index*9+8] = triangle.c.z } return retval }