diff pkg/octree/builder.go @ 968:a4fe07a21ba7

Moved octree builder into octree package to be reusable by the sounding result import job.
author Sascha L. Teichmann <sascha.teichmann@intevation.de>
date Wed, 17 Oct 2018 16:00:49 +0200
parents
children b6fec8f85599
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pkg/octree/builder.go	Wed Oct 17 16:00:49 2018 +0200
@@ -0,0 +1,171 @@
+package octree
+
+import (
+	"encoding/binary"
+	"io"
+	"log"
+
+	"github.com/golang/snappy"
+)
+
+type Builder struct {
+	t      *Tin
+	nodes  int
+	leaves int
+	index  []int32
+}
+
+var cubes = [8][2]Vertex{
+	makeCube(0),
+	makeCube(1),
+	makeCube(2),
+	makeCube(3),
+	makeCube(4),
+	makeCube(5),
+	makeCube(6),
+	makeCube(7),
+}
+
+func makeCube(i int) [2]Vertex {
+	var d Vertex
+	if i&1 == 1 {
+		d.X = 0.5
+	}
+	if i&2 == 2 {
+		d.Y = 0.5
+	}
+	if i&4 == 4 {
+		d.Z = 0.5
+	}
+	return [2]Vertex{
+		Vertex{0.0, 0.0, 0.0}.Add(d),
+		Vertex{0.5, 0.5, 0.5}.Add(d),
+	}
+}
+
+func NewBuilder(t *Tin) *Builder {
+	return &Builder{t: t}
+}
+
+func (tb *Builder) Build() {
+
+	triangles := make([]int32, len(tb.t.Triangles))
+	for i := range triangles {
+		triangles[i] = int32(i)
+	}
+
+	tb.index = append(tb.index, 0)
+
+	tb.buildRecursive(triangles, tb.t.Min, tb.t.Max, 0)
+	tb.index[0] = int32(len(tb.index))
+	log.Printf("num nodes: %d\n", tb.index[0])
+
+	log.Printf("nodes: %d leaves: %d index %d\n",
+		tb.nodes, tb.leaves, tb.index[0])
+}
+
+func (tb *Builder) buildRecursive(
+	triangles []int32,
+	min, max Vertex,
+	depth int,
+) int32 {
+	if len(triangles) <= 16 || depth > 8 {
+		pos := len(tb.index)
+		tb.index = append(tb.index, int32(len(triangles)))
+		tb.index = append(tb.index, triangles...)
+		//log.Printf("leaf entries: %d (%d)\n", len(triangles), depth)
+		tb.leaves++
+		return int32(-(pos + 1))
+	}
+
+	pos := len(tb.index)
+	tb.index = append(tb.index,
+		0, 0, 0, 0,
+		0, 0, 0, 0)
+
+	bbox := Interpolate(min, max)
+
+	bboxes := make([][2]Vertex, len(cubes))
+
+	for i := range cubes {
+		bboxes[i] = [2]Vertex{
+			bbox(cubes[i][0]),
+			bbox(cubes[i][1]),
+		}
+	}
+
+	var quandrants [8][]int32
+
+	for _, tri := range triangles {
+		triangle := tb.t.Triangles[tri]
+		v0 := tb.t.Vertices[triangle[0]]
+		v1 := tb.t.Vertices[triangle[1]]
+		v2 := tb.t.Vertices[triangle[2]]
+
+		l := v0
+		l.Minimize(v1)
+		l.Minimize(v2)
+
+		h := v0
+		h.Maximize(v1)
+		h.Maximize(v2)
+
+		for i := range bboxes {
+			if !(h.Less(bboxes[i][0]) || bboxes[i][1].Less(l)) {
+				quandrants[i] = append(quandrants[i], tri)
+			}
+		}
+	}
+
+	for i := range quandrants {
+		if len(quandrants[i]) > 0 {
+			child := tb.buildRecursive(
+				quandrants[i],
+				bboxes[i][0], bboxes[i][1],
+				depth+1)
+			tb.index[pos+i] = child
+		}
+	}
+	tb.nodes++
+	return int32(pos)
+}
+
+func (tb *Builder) Serialize(w io.Writer) error {
+	var buf [binary.MaxVarintLen32]byte
+
+	if err := binary.Write(w, binary.LittleEndian, tb.index[0]); err != nil {
+		return err
+	}
+
+	var last int32
+	var written int
+
+	for _, x := range tb.index[1:] {
+		delta := x - last
+		n := binary.PutVarint(buf[:], int64(delta))
+		for p := buf[:n]; len(p) > 0; p = p[n:] {
+			var err error
+			if n, err = w.Write(p); err != nil {
+				return err
+			}
+			written += n
+		}
+
+		last = x
+	}
+	log.Printf("compressed octree index in bytes: %d (%d)\n",
+		written, 4*len(tb.index))
+
+	return nil
+}
+
+func (tb *Builder) WriteTo(w io.Writer) error {
+	out := snappy.NewBufferedWriter(w)
+	if err := tb.t.Serialize(out); err != nil {
+		return err
+	}
+	if err := tb.Serialize(out); err != nil {
+		return err
+	}
+	return out.Flush()
+}