diff cmd/tin2octree/tin.go @ 661:af1d4d44a88a octree

Experimental tin octree indexer.
author Sascha L. Teichmann <sascha.teichmann@intevation.de>
date Tue, 18 Sep 2018 00:11:32 +0200
parents
children a3d722e1f593
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cmd/tin2octree/tin.go	Tue Sep 18 00:11:32 2018 +0200
@@ -0,0 +1,234 @@
+package main
+
+import (
+	"bytes"
+	"encoding/binary"
+	"errors"
+	"fmt"
+	"io"
+	"log"
+	"math"
+)
+
+var (
+	errNoByteSlice   = errors.New("Not a byte slice")
+	errTooLessPoints = errors.New("Too less points")
+)
+
+const (
+	wkbXDR       byte   = 0
+	wkbNDR       byte   = 1
+	wkbTinZ      uint32 = 1000 + 16
+	wkbTriangleZ uint32 = 1000 + 17
+)
+
+type tin struct {
+	vertices  []vertex
+	triangles [][]int32
+
+	min vertex
+	max vertex
+}
+
+func (t *tin) FromWKB(data []byte) error {
+	log.Printf("data length %d\n", len(data))
+
+	r := bytes.NewReader(data)
+
+	endian, err := r.ReadByte()
+
+	var order binary.ByteOrder
+
+	switch {
+	case err != nil:
+		return err
+	case endian == wkbNDR:
+		order = binary.LittleEndian
+	case endian == wkbXDR:
+		order = binary.BigEndian
+	default:
+		return fmt.Errorf("unknown byte order %x", endian)
+	}
+
+	var geomType uint32
+	err = binary.Read(r, order, &geomType)
+
+	switch {
+	case err != nil:
+		return err
+	case geomType != wkbTinZ:
+		return fmt.Errorf("unknown geometry type %x", geomType)
+	}
+
+	var num uint32
+	if err = binary.Read(r, order, &num); err != nil {
+		return err
+	}
+
+	vertices := make([]vertex, 0, 100000)
+
+	var v vertex
+
+	v2i := make(map[vertex]int32, 100000)
+
+	var indexPool []int32
+
+	allocIndices := func() []int32 {
+		if len(indexPool) == 0 {
+			indexPool = make([]int32, 3*8*1024)
+		}
+		ids := indexPool[:3]
+		indexPool = indexPool[3:]
+		return ids
+	}
+
+	var triangles [][]int32
+
+	min := vertex{math.MaxFloat64, math.MaxFloat64, math.MaxFloat64}
+	max := vertex{-math.MaxFloat64, -math.MaxFloat64, -math.MaxFloat64}
+
+	for i := uint32(0); i < num; i++ {
+
+		endian, err = r.ReadByte()
+		switch {
+		case err != nil:
+			return err
+		case endian == wkbNDR:
+			order = binary.LittleEndian
+		case endian == wkbXDR:
+			order = binary.BigEndian
+		default:
+			return fmt.Errorf("unknown byte order %x", endian)
+		}
+
+		err = binary.Read(r, order, &geomType)
+		switch {
+		case err != nil:
+			return err
+		case geomType != wkbTriangleZ:
+			return fmt.Errorf("unknown geometry type %d", geomType)
+		}
+
+		var rings uint32
+		if err = binary.Read(r, order, &rings); err != nil {
+			return err
+		}
+		triangle := allocIndices()
+
+		for ring := uint32(0); ring < rings; ring++ {
+			var npoints uint32
+			if err = binary.Read(r, order, &npoints); err != nil {
+				return err
+			}
+
+			if npoints < 3 {
+				return errTooLessPoints
+			}
+
+			for p := uint32(0); p < npoints; p++ {
+				var x, y, z uint64
+				for _, addr := range []*uint64{&x, &y, &z} {
+					if err = binary.Read(r, order, addr); err != nil {
+						return err
+					}
+				}
+				if p >= 3 || ring >= 1 {
+					// Don't store the forth point.
+					continue
+				}
+				// Do this conversion later to spare reflect calls
+				// and allocs in binary.Read.
+				v.x = math.Float64frombits(x)
+				v.y = math.Float64frombits(y)
+				v.z = math.Float64frombits(z)
+				idx, found := v2i[v]
+				if !found {
+					idx = int32(len(vertices))
+					v2i[v] = idx
+					vertices = append(vertices, v)
+					min.minimize(v)
+					max.maximize(v)
+				}
+				triangle[p] = idx
+			}
+		}
+		triangles = append(triangles, triangle)
+	}
+
+	*t = tin{
+		vertices:  vertices,
+		triangles: triangles,
+		min:       min,
+		max:       max,
+	}
+
+	return nil
+}
+
+func (t *tin) Scan(raw interface{}) error {
+
+	data, ok := raw.([]byte)
+	if !ok {
+		return errNoByteSlice
+	}
+	return t.FromWKB(data)
+}
+
+func (v *vertex) write(w io.Writer) error {
+	for _, addr := range []*float64{&v.x, &v.y, &v.z} {
+		if err := binary.Write(
+			w, binary.LittleEndian, math.Float64bits(*addr)); err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+func (t *tin) Serialize(w io.Writer) error {
+
+	if err := t.min.write(w); err != nil {
+		return err
+	}
+	if err := t.max.write(w); err != nil {
+		return err
+	}
+
+	if err := binary.Write(
+		w, binary.LittleEndian, uint32(len(t.vertices))); err != nil {
+		return err
+	}
+
+	for _, v := range t.vertices {
+		if err := v.write(w); err != nil {
+			return err
+		}
+	}
+	log.Printf("vertices %d (%d)\n", len(t.vertices), len(t.vertices)*3*8)
+
+	if err := binary.Write(
+		w, binary.LittleEndian, uint32(len(t.triangles))); err != nil {
+		return err
+	}
+
+	var buf [binary.MaxVarintLen32]byte
+	var written int
+	var last int32
+	for _, triangle := range t.triangles {
+		for _, idx := range triangle {
+			value := idx - last
+			n := binary.PutVarint(buf[:], int64(value))
+			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 = idx
+		}
+	}
+	log.Printf("compressed tin indices in bytes: %d (%d)\n",
+		written, 3*4*len(t.triangles))
+
+	return nil
+}