Documentation ¶
Overview ¶
Package stl implements functions to read, write, and transform files in the Stereolithography/Surface Tesselation Language (.stl) file format used in 3D modelling.
The format specification was taken from http://www.ennex.com/~fabbers/StL.asp, found at http://en.wikipedia.org/wiki/STL_%28file_format%29.
While STL stores the data in single precision 32 bit floating point numbers, the stl package does all calculations beyond simple addition in double precision 64 bit (float64).
Usage Example
// Read STL file solid, errRead := stl.ReadFile(inputFilename) if errRead != nil { fmt.Fprintln(os.Stderr, errRead) os.Exit(1) } // Convert from Inches to mm solid.Scale(25.4) // Write STL file errWrite := solid.WriteFile(outputFilename) if errWrite != nil { fmt.Fprintln(os.Stderr, errWrite) os.Exit(2) }
Everything that operates on a model is defined as a method of Solid.
Note that The STL format has two variants, a human-readable ASCII variant, and a more compact and precise binary variant which is preferrable.
ASCII Format Specialities ¶
The Solid.BinaryHeader field and the Triangle.Attributes fields will be empty, after reading, as these are not part of the ASCII format. The Solid.Name field is read from the first line after "solid ". It is not checked against the name at the end of the file after "endsolid ". The stl package will also not cope with Unicode byte order marks, which some text editors might automatically place at the beginning of a file.
Binary Format Specialities ¶
The Solid.BinaryHeader field is filled with all 80 bytes of header data. Then, ReadFile will try to fill solid.Name with an ASCII string read from the header data from the first byte until a \0 or a non-ASCII character is detected.
Numerical Errors ¶
As always when you do linear transformations on floating point numbers, you get numerical errors. So you should expect a vertex being rotated for 360° not to end up at exactly the original coordinates, but instead just very close to them. As the error is usually far smaller than the available precision of 3D printing applications, this is not an issue in most cases.
Stream Processing ¶
You can implement the Writer interface to directly write into your own data structures. This way you can use the CopyFile and CopyAll functions.
var ownData ownDataStructure // implements stl.Writer err := stl.CopyFile("somefile.stl", &ownData)
Index ¶
- Constants
- Variables
- func CopyAll(r io.ReadSeeker, sw Writer) (err error)
- func CopyFile(filename string, sw Writer) (err error)
- func RotationMatrix(pos Vec3, dir Vec3, angle float64, rotationMatrix *Mat4)
- type EdgeError
- type Mat4
- type Solid
- func (s *Solid) AppendTriangle(t Triangle)
- func (s *Solid) IsInPositive() bool
- func (s *Solid) Measure() SolidMeasure
- func (s *Solid) MoveToPositive()
- func (s *Solid) RecalculateNormals()
- func (s *Solid) Rotate(pos, dir Vec3, angle float64)
- func (s *Solid) Scale(factor float64)
- func (s *Solid) ScaleLinearDowntoSizeBox(sizeBox Vec3)
- func (s *Solid) SetASCII(isASCII bool)
- func (s *Solid) SetBinaryHeader(header []byte)
- func (s *Solid) SetName(name string)
- func (s *Solid) SetTriangleCount(n uint32)
- func (s *Solid) Stretch(vec Vec3)
- func (s *Solid) Transform(transformationMatrix *Mat4)
- func (s *Solid) TransformNR(transformationMatrix *Mat4)
- func (s *Solid) Translate(vec Vec3)
- func (s *Solid) Validate() map[int]*TriangleErrors
- func (s *Solid) WriteAll(w io.Writer) error
- func (s *Solid) WriteFile(filename string) (err error)
- type SolidMeasure
- type Triangle
- type TriangleErrors
- type Vec3
- func (vec Vec3) Add(o Vec3) Vec3
- func (vec Vec3) AlmostEqual(o Vec3, tol float32) bool
- func (vec Vec3) Angle(o Vec3) float64
- func (vec Vec3) Cross(o Vec3) Vec3
- func (vec Vec3) Diff(o Vec3) Vec3
- func (vec Vec3) Dot(o Vec3) float64
- func (vec Vec3) MultScalar(scalar float64) Vec3
- func (vec Vec3) UnitVec3() Vec3
- type Vec4
- type Writer
Constants ¶
const HalfPi = math.Pi * 0.5
HalfPi is math.Pi * 0.5
const Pi = math.Pi
Pi is just math.Pi
const QuarterPi = math.Pi * 0.25
QuarterPi is math.Pi * 0.25
const TwoPi = math.Pi * 2
TwoPi is math.Pi * 2
Variables ¶
var ErrIncompleteBinaryHeader = errors.New("incomplete STL binary header, 84 bytes expected")
ErrIncompleteBinaryHeader is used when reading binary STL files with incomplete header.
var ErrUnexpectedEOF = errors.New("unexpected end of file")
ErrUnexpectedEOF is used by ReadFile and ReadAll to signify an incomplete file.
var Mat4Identity = Mat4{ Vec4{1, 0, 0, 0}, Vec4{0, 1, 0, 0}, Vec4{0, 0, 1, 0}, Vec4{0, 0, 0, 1}, }
Mat4Identity is the identity matrix
Functions ¶
func RotationMatrix ¶
RotationMatrix calculates a 4x4 rotation matrix for a rotation of Angle in radians around a rotation axis defined by a point on it (pos) and its direction (dir). The result is written into *rotationMatrix.
Types ¶
type EdgeError ¶
type EdgeError struct { // SameEdgeTriangles are indexes in Solid.Triangles of triangles that contain exactly the same edge. SameEdgeTriangles []int // CounterEdgeTriangles are indexes in Solid.Triangles of triangles that contain the edge in the // opposite direction. If there is exactly one other triangle, this is no // error. CounterEdgeTriangles []int }
EdgeError describes the errors found for a single edge within a triangle using Solid.Validate().
func (*EdgeError) HasMultipleCounterEdges ¶
HasMultipleCounterEdges is true if there is more than one other triangle with this edge in the opposite direction
func (*EdgeError) HasNoCounterEdge ¶
HasNoCounterEdge is true if there is no other triangle with this edge in the opposite direction, meaning that there is no neighboring triangle
func (*EdgeError) IsUsedInOtherTriangles ¶
IsUsedInOtherTriangles is true if this edge is also used in another triangle, meaning that there is probably something wrong with this or the other triangle's orientation.
type Mat4 ¶
type Mat4 [4]Vec4
Mat4 represents a 4x4 Matrix of float64 used for 3D transformations. The 4th column can be used for moving the solid on the axes. Accessing matrix elements goes like this:
matrix[row][column]
type Solid ¶
type Solid struct { // only used in binary format BinaryHeader []byte // Name is the solid's name Name string // Triangles represent the solid's shape. Triangles []Triangle // IsAscii is true, if this Solid was read from an ASCII file, and false, if read // from a binary file. Also used to determine the format when writing // to a file. IsAscii bool }
Solid is a 3D model made out of triangles, called solid in STL, representing an STL file
func ReadAll ¶
func ReadAll(r io.ReadSeeker) (solid *Solid, err error)
ReadAll reads the contents of a file into a new Solid object. The file can be either in STL ASCII format, beginning with "solid ", or in STL binary format, beginning with a 84 byte header. Because of this, the file pointer has to be at the beginning of the file.
func ReadFile ¶
ReadFile reads the contents of a file into a new Solid object. The file can be either in STL ASCII format, beginning with "solid ", or in STL binary format, beginning with a 84 byte header. Shorthand for os.Open and ReadAll
func (*Solid) AppendTriangle ¶
AppendTriangle appends the given triangle to s.Triangles
func (*Solid) IsInPositive ¶
IsInPositive is true if every vertex in this solid is within the positive octant, i.e. all coordinate values are positive or 0.
func (*Solid) Measure ¶
func (s *Solid) Measure() SolidMeasure
Measure the dimensions of a solid in its own units
func (*Solid) MoveToPositive ¶
func (s *Solid) MoveToPositive()
MoveToPositive moves the solid into the positive octant if necessary, as prescribed by the original STL format spec. Some applications tolerate negative coordinates. This also makes sense, as the origin is a perfect reference point for rotations.
func (*Solid) RecalculateNormals ¶
func (s *Solid) RecalculateNormals()
RecalculateNormals recalculates all triangle normal vectors from the vertices. Can be used after multiple transformations using the TransformNR method that does not recalculate the normal vectors.
func (*Solid) Rotate ¶
Rotate the solid by Angle radians around a rotation axis defined by a point pos on the axis and a direction vector dir. This example would rotate the solid by 90 degree around the z-axis:
stl.Rotate(stl.Vec3{0,0,0}, stl.Vec3{0,0,1}, stl.HalfPi)
func (*Solid) ScaleLinearDowntoSizeBox ¶
ScaleLinearDowntoSizeBox works like this: if the solid does not fit into size box defined by sizeBox, it is scaled down accordingly. It is not scaled up, if it is smaller than sizeBox. All sizes have to be > 0.
func (*Solid) SetASCII ¶
SetASCII sets the IsAscii flag that indicates whether the solid was read from ASCII STL
func (*Solid) SetBinaryHeader ¶
SetName sets the binary header optionally used when writing to binary STL
func (*Solid) SetTriangleCount ¶
SetTriangleCount ensures that cap(s.Triangles) >= n, and len(s.Triangles) <= n, possibly deleting triangles starting at index n
func (*Solid) Transform ¶
Transform applies a 4x4 transformation matrix to every vertex and recalculates the normal for every triangle
func (*Solid) TransformNR ¶
TransformNR applies a 4x4 transformation matrix to every vertex and does not recalculate the normal vector for every triangle. This could be used to speed things up when multiple transformations are applied successively to a solid, and the transformation matrix is not calculated beforehand. Before writing this solid to disk then, RecalculateNormals() should be called.
func (*Solid) Validate ¶
func (s *Solid) Validate() map[int]*TriangleErrors
Validate looks for triangles that are really lines or dots, and for edges that violate the vertex-to-vertex rule. Returns a map of errors by triangle index that could be used to print out an error report.
type SolidMeasure ¶
type SolidMeasure struct { // Minimum values for axes Min Vec3 // Maximum values for axes Max Vec3 // Max - Min Len Vec3 }
SolidMeasure is used to store the result of Solid.Measure()
type Triangle ¶
type Triangle struct { // Normal vector of triangle, should be normalized... Normal Vec3 // Vertices of triangle in right hand order. // I.e. from the front the triangle's vertices are ordered counterclockwise // and the normal vector is orthogonal to the front pointing outside. Vertices [3]Vec3 // 16 bits of attributes. Not available in ASCII format. Could be used // for color selection, texture selection, refraction etc. Some tools ignore // this field completely, always writing 0 on export. Attributes uint16 }
Triangle represents single triangles used in Solid.Triangles. The vertices have to be ordered counter-clockwise when looking at their outside surface. The vector Normal is orthogonal to the triangle, pointing outside, and has length 1. This is redundant but included in the STL format in order to avoid recalculation.
type TriangleErrors ¶
type TriangleErrors struct { // HasEqualVertices is true if some vertices are identical, meaning we are having // a line, or even a point, as opposed to a triangle. HasEqualVertices bool // NormalDoesNotMatch istrue if the normal vector does not match a normal calculated from the // vertices in the right hand order, even allowing for an angular difference // of < 90 degree. NormalDoesNotMatch bool // EdgeErrors by edge. The edge is indexed by it's first vertex, i.e. // 0: V0 -> V1 // 1: V1 -> V2 // 2: V2 -> V0 // If the edge has no error its value is nil. EdgeErrors [3]*EdgeError }
TriangleErrors represent the errors found in a single triangle.
type Vec3 ¶
type Vec3 [3]float32
Vec3 represents a 3D vector, used in Triangle for normal vector and vertices.
func (Vec3) AlmostEqual ¶
AlmostEqual returns true if vec and o are equal allowing for numerical error tol.
func (Vec3) Angle ¶
Angle between vec and o in radians, without sign, between 0 and Pi. If vec or o is the origin, this returns 0.
func (Vec3) MultScalar ¶
MultScalar multiplies vec by scalar.
type Writer ¶
type Writer interface { // SetName sets the solid's name SetName(name string) // SetBinaryHeader explicitly sets a binary header used in binary STL SetBinaryHeader(header []byte) // SetASCII sets the IsAscii flag that indicates whether the solid was read from ASCII STL SetASCII(isASCII bool) // SetTriangleCount can optionally be used to set the triangle count if it is known, so // the underlying implementation can use it to allocate a data structure, or similar. SetTriangleCount(n uint32) // AppendTriangle adds a triangle to the solid AppendTriangle(t Triangle) }
Writer processes an STL solid as a stream.