-
-
Save xlab/f82f6f5cb6cb5d34b47b584e29a1e063 to your computer and use it in GitHub Desktop.
STL reader
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"bufio" | |
"bytes" | |
"encoding/binary" | |
"flag" | |
"fmt" | |
"github.com/spf13/nitro" | |
"io" | |
"io/ioutil" | |
"os" | |
) | |
type Model struct { | |
Header [80]byte | |
Length uint32 | |
Triangles []Triangle | |
} | |
// 50 bytes | |
type Triangle struct { | |
Normal [3]float32 | |
Vertex1 [3]float32 | |
Vertex2 [3]float32 | |
Vertex3 [3]float32 | |
Attribute uint16 `"_"` | |
} | |
var filename string | |
func init() { | |
flag.StringVar(&filename, "file", "", "Filename of the STL file to parse.") | |
flag.Parse() | |
} | |
func ParseBufferedSTL(filename string, size int) *Model { | |
file, err := os.Open(filename) | |
if err != nil { | |
panic(err) | |
} | |
defer file.Close() | |
m := new(Model) | |
b := bufio.NewReader(file) | |
data := make([]byte, 84) | |
b.Read(data) | |
// Parsing Header first 80 bytes. | |
err = binary.Read(bytes.NewBuffer(data[0:80]), binary.LittleEndian, &m.Header) | |
if err != nil { | |
panic(err) | |
} | |
// Parsing triangle count uint32 at byte 80 | |
err = binary.Read(bytes.NewBuffer(data[80:84]), binary.LittleEndian, &m.Length) | |
if err != nil { | |
panic(err) | |
} | |
// Allocating enough memory for all the triangles in the slice | |
m.Triangles = make([]Triangle, m.Length) | |
buf := make([]byte, 50*size) | |
tris := make([]Triangle, size) | |
rs := io.ReadSeeker(file) | |
rs.Seek(84,0) | |
b = bufio.NewReaderSize(rs, 50*size) | |
i := 0 | |
for { | |
n, err := b.Read(buf) | |
if err != nil { | |
if err == io.EOF { | |
break | |
} | |
panic(err) | |
} | |
offset := n/50 | |
if i > int(m.Length) { | |
break | |
} | |
err = binary.Read(bytes.NewBuffer(buf), binary.LittleEndian, &tris) | |
if err != nil { | |
panic(err) | |
} | |
copy(m.Triangles[i:i+offset],tris[:offset]) | |
i = i + offset | |
} | |
return m | |
} | |
func Compare(src, dst []Triangle) bool { | |
for i, _ := range src { | |
if src[i] != dst[i] { | |
return false | |
} | |
} | |
return true | |
} | |
func ParseSTL(filename string) *Model { | |
// Reading entire STL file into memory | |
data, err := ioutil.ReadFile(filename) | |
if err != nil { | |
panic(err) | |
} | |
m := new(Model) | |
// Parsing Header first 80 bytes. | |
err = binary.Read(bytes.NewBuffer(data[0:80]), binary.LittleEndian, &m.Header) | |
if err != nil { | |
panic(err) | |
} | |
// Parsing triangle count uint32 at byte 80 | |
err = binary.Read(bytes.NewBuffer(data[80:84]), binary.LittleEndian, &m.Length) | |
if err != nil { | |
panic(err) | |
} | |
// Allocating enough memory for all the triangles in the slice | |
m.Triangles = make([]Triangle, m.Length) | |
// Parsing the Triangle slice on byte 84 onwards, 50 bytes per triangle | |
err = binary.Read(bytes.NewBuffer(data[84:]), binary.LittleEndian, &m.Triangles) | |
if err != nil { | |
panic(err) | |
} | |
return m | |
} | |
func SaveASCII(name string, model *Model) { | |
fo, err := os.Create(name+".stl") | |
if err != nil { panic(err) } | |
// close fo on exit and check for its returned error | |
defer func() { | |
if err := fo.Close(); err != nil { | |
panic(err) | |
} | |
}() | |
fmt.Fprintf(fo, "solid %v\n", name) | |
for _, tri := range model.Triangles { | |
fmt.Fprintf(fo, " facet normal %E %E %E\n", tri.Normal[0], tri.Normal[1], tri.Normal[2]) | |
fmt.Fprintf(fo, " outer loop\n", ) | |
fmt.Fprintf(fo, " vertex %E %E %E\n", tri.Vertex1[0], tri.Vertex1[1], tri.Vertex1[2] ) | |
fmt.Fprintf(fo, " vertex %E %E %E\n", tri.Vertex2[0], tri.Vertex2[1], tri.Vertex2[2] ) | |
fmt.Fprintf(fo, " vertex %E %E %E\n", tri.Vertex3[0], tri.Vertex3[1], tri.Vertex3[2] ) | |
fmt.Fprintf(fo, " endloop\n" ) | |
fmt.Fprintf(fo, " endfacet\n" ) | |
} | |
fmt.Fprintf(fo, "endsolid %v", name) | |
} | |
func main() { | |
fmt.Println(filename) | |
timer := nitro.Initalize() | |
model := ParseSTL(filename) | |
timer.Step("Parsing STL") | |
fmt.Println("File has", model.Length, "triangles.") | |
model1 := ParseBufferedSTL(filename, 100) | |
timer.Step("Parsing STL (buffered) 100") | |
fmt.Println("File has", model1.Length, "triangles.") | |
model2 := ParseBufferedSTL(filename, 1000) | |
timer.Step("Parsing STL (buffered) 1000") | |
fmt.Println("File has", model2.Length, "triangles.") | |
model3 := ParseBufferedSTL(filename, 10000) | |
timer.Step("Parsing STL (buffered) 10000" ) | |
fmt.Println("File has", model3.Length, "triangles.") | |
SaveASCII(filename+"-ascii", model) | |
timer.Step("Saving ASCII") | |
SaveASCII(filename+"-ascii-1", model1) | |
timer.Step("Saving ASCII") | |
SaveASCII(filename+"-ascii-2", model2) | |
timer.Step("Saving ASCII") | |
SaveASCII(filename+"-ascii-3", model3) | |
timer.Step("Saving ASCII") | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment