func (m triangleErrorsMap) item(triangleIdx int) *TriangleErrors {
	if _, found := m[triangleIdx]; !found {
		m[triangleIdx] = new(TriangleErrors)
	}
	return m[triangleIdx]
}
item is a convenient map accessor that creates the entry on first use.
package stl
type Solid struct {
	BinaryHeader []byte
	Name string
	Triangles []Triangle
	IsAscii bool
}
func (s *Solid) SetName(name string) {
	s.Name = name
}
func (s *Solid) SetBinaryHeader(header []byte) {
	s.BinaryHeader = header
}
func (s *Solid) SetASCII(isASCII bool) {
	s.IsAscii = isASCII
}
func (s *Solid) SetTriangleCount(n uint32) {
	l := uint32(len(s.Triangles))
	c := uint32(cap(s.Triangles))
	if n < l {
		s.Triangles = s.Triangles[:n]
		return
	}
	if n <= c {
		return
	}
	oldTriangles := s.Triangles
	s.Triangles = make([]Triangle, l, n)
	if l > 0 {
		copy(s.Triangles[:l], oldTriangles)
	}
}
func (s *Solid) AppendTriangle(t Triangle) {
	s.Triangles = append(s.Triangles, t)
}
type SolidMeasure struct {
	Min Vec3
	Max Vec3
	Len Vec3
}
func (s *Solid) Measure() SolidMeasure {
	var measure SolidMeasure
	if len(s.Triangles) == 0 {
		return measure
	}
	a := &s.Triangles[0].Vertices[0]
	measure.Min = *a
	measure.Max = *a
	for _, triangle := range s.Triangles {
		for d := 0; d < 3; d++ {
			measure.Min[d] = min4(measure.Min[d], triangle.Vertices[0][d], triangle.Vertices[1][d], triangle.Vertices[2][d])
			measure.Max[d] = max4(measure.Max[d], triangle.Vertices[0][d], triangle.Vertices[1][d], triangle.Vertices[2][d])
		}
	}
	measure.Len = measure.Max.diff(measure.Min)
	return measure
}
func (s *Solid) Transform(transformationMatrix *Mat4) {
	l := len(s.Triangles)
	for i := 0; i < l; i++ {
		s.Triangles[i].transform(transformationMatrix)
	}
}
func (s *Solid) TransformNR(transformationMatrix *Mat4) {
	l := len(s.Triangles)
	for i := 0; i < l; i++ {
		s.Triangles[i].transformNR(transformationMatrix)
	}
}
func (s *Solid) RecalculateNormals() {
	for i := 0; i < len(s.Triangles); i++ {
		s.Triangles[i].recalculateNormal()
	}
}
func (s *Solid) Scale(factor float64) {
	for i := 0; i < len(s.Triangles); i++ {
		t := &s.Triangles[i]
		for v := 0; v < 3; v++ {
			for d := 0; d < 3; d++ {
				t.Vertices[v][d] = float32(factor * float64(t.Vertices[v][d]))
			}
		}
	}
}
func (s *Solid) Stretch(vec Vec3) {
	for i := 0; i < len(s.Triangles); i++ {
		t := &s.Triangles[i]
		for v := 0; v < 3; v++ {
			for d := 0; d < 3; d++ {
				t.Vertices[v][d] = float32(float64(vec[d]) * float64(t.Vertices[v][d]))
			}
		}
		t.recalculateNormal()
	}
}
func (s *Solid) ScaleLinearDowntoSizeBox(sizeBox Vec3) {
	if sizeBox[0] <= 0 || sizeBox[1] <= 0 || sizeBox[2] <= 0 {
		panic("Not all values in sizeBox are > 0!")
	}
	measure := s.Measure()
	factor := float64(1)
	for d := 0; d < 3; d++ {
		if measure.Len[d] > sizeBox[d] {
			scale := float64(sizeBox[d]) / float64(measure.Len[d])
			if scale < factor {
				factor = scale
			}
		}
	}
	if factor != float64(1) {
		s.Scale(factor)
	}
}
func (s *Solid) Translate(vec Vec3) {
	for i := 0; i < len(s.Triangles); i++ {
		t := &s.Triangles[i]
		for v := 0; v < 3; v++ {
			for d := 0; d < 3; d++ {
				t.Vertices[v][d] += vec[d]
			}
		}
	}
}
func (s *Solid) IsInPositive() bool {
	measure := s.Measure()
	for dim := 0; dim < 3; dim++ {
		if measure.Min[dim] < 0 {
			return false
		}
	}
	return true
}
func (s *Solid) MoveToPositive() {
	measure := s.Measure()
	var translationVector Vec3
	for dim := 0; dim < 3; dim++ {
		if measure.Min[dim] < 0 {
			translationVector[dim] = -measure.Min[dim]  
		}
	}
	if translationVector != vec3Zero {
		s.Translate(translationVector)
	}
}
func (s *Solid) scaleDim(factor float64, dim int) {
	for i := 0; i < len(s.Triangles); i++ {
		for v := 0; v < 3; v++ {
			s.Triangles[i].Vertices[v][dim] = float32(factor * float64(s.Triangles[i].Vertices[v][dim]))
		}
	}
}
func (s *Solid) Rotate(pos, dir Vec3, angle float64) {
	var rotationMatrix Mat4
	RotationMatrix(pos, dir, angle, &rotationMatrix)
	s.Transform(&rotationMatrix)
}
type TriangleErrors struct {
	HasEqualVertices bool
	NormalDoesNotMatch bool
	EdgeErrors [3]*EdgeError
}
func (te *TriangleErrors) edge(e int) *EdgeError {
	if te.EdgeErrors[e] == nil {
		te.EdgeErrors[e] = new(EdgeError)
	}
	return te.EdgeErrors[e]
}
type EdgeError struct {
	SameEdgeTriangles []int
	CounterEdgeTriangles []int
}
func (eer *EdgeError) IsUsedInOtherTriangles() bool {
	return len(eer.SameEdgeTriangles) != 0
}
func (eer *EdgeError) HasMultipleCounterEdges() bool {
	return len(eer.CounterEdgeTriangles) > 1
}
func (eer *EdgeError) HasNoCounterEdge() bool {
	return len(eer.CounterEdgeTriangles) == 0
}
type edgeLookup struct {
	edgeToTriangles map[[2]Vec3]map[int]bool
}
func newEdgeLookup() *edgeLookup {
	var l edgeLookup
	l.edgeToTriangles = make(map[[2]Vec3]map[int]bool)
	return &l
}
func (l *edgeLookup) OtherTrianglesWithEdge(v, w Vec3, i int) []int {
	triangleSet, found := l.edgeToTriangles[[2]Vec3{v, w}]
	if !found {
		return nil
	}
	r := make([]int, 0, len(triangleSet))
	for t := range triangleSet {
		if t != i {
			r = append(r, t)
		}
	}
	return r
}
func (l *edgeLookup) InsertEdge(triangleIndex int, v, w Vec3) {
	key := [2]Vec3{v, w}
	triangleSet, found := l.edgeToTriangles[key]
	if !found {
		l.edgeToTriangles[key] = make(map[int]bool)
		triangleSet = l.edgeToTriangles[key]
	}
	triangleSet[triangleIndex] = true
}
type triangleErrorsMap map[int]*TriangleErrors