changeset 4649:8f745c353784 stree-experiment

Finished first version of conversion tool.
author Sascha L. Teichmann <sascha.teichmann@intevation.de>
date Sun, 13 Oct 2019 22:15:55 +0200
parents 66fcd898efd9
children f5fce22184da
files cmd/oct2str/main.go pkg/octree/tree.go
diffstat 2 files changed, 144 insertions(+), 5 deletions(-) [+]
line wrap: on
line diff
--- a/cmd/oct2str/main.go	Sun Oct 13 19:22:36 2019 +0200
+++ b/cmd/oct2str/main.go	Sun Oct 13 22:15:55 2019 +0200
@@ -15,20 +15,114 @@
 
 import (
 	"context"
+	"crypto/sha1"
 	"database/sql"
+	"encoding/hex"
 	"flag"
 	"log"
 
+	"gemma.intevation.de/gemma/pkg/octree"
 	"github.com/jackc/pgx"
 	"github.com/jackc/pgx/stdlib"
 )
 
-func process(ctx context.Context, conn *sql.Conn) error {
-	// TODO: Implement me!
+const (
+	fetchOneOctreeSQL = `
+SELECT
+  id,
+  octree_index
+FROM waterway.sounding_results
+WHERE mesh_index IS NULL
+LIMIT 1`
+
+	storeSTRTreeSQL = `
+UPDATE waterway.sounding_results
+SET mesh_index = $1, mesh_checksum = $2
+WHERE id = $3`
+)
+
+func process(ctx context.Context, conn *sql.Conn, count int) error {
+
+	fetch, err := conn.PrepareContext(ctx, fetchOneOctreeSQL)
+	if err != nil {
+		return err
+	}
+	defer fetch.Close()
+
+	store, err := conn.PrepareContext(ctx, storeSTRTreeSQL)
+	if err != nil {
+		return err
+	}
+	defer store.Close()
+
+	var next func() bool
+	if count < 0 {
+		next = func() bool { return true }
+	} else {
+		var c int
+		next = func() bool {
+			if c < count {
+				c++
+				return true
+			}
+			return false
+		}
+	}
+
+loop:
+	for next() {
+		switch err := func() error {
+			tx, err := conn.BeginTx(ctx, nil)
+			if err != nil {
+				return err
+			}
+			defer tx.Rollback()
+
+			var id int64
+			var data []byte
+
+			if err = tx.Stmt(fetch).QueryRowContext(ctx).Scan(&id, &data); err != nil {
+				return err
+			}
+
+			otree, err := octree.Deserialize(data)
+			if err != nil {
+				return err
+			}
+
+			unused := otree.FindUnused()
+
+			log.Printf("unused: %d\n", len(unused))
+
+			str := octree.STRTree{Entries: 16}
+			str.BuildWithout(otree.Tin(), unused)
+
+			out, err := str.Bytes()
+			if err != nil {
+				return err
+			}
+			h := sha1.New()
+			h.Write(out)
+			checksum := hex.EncodeToString(h.Sum(nil))
+			log.Printf("hash: %s\n", checksum)
+
+			if _, err := tx.Stmt(store).ExecContext(ctx, out, checksum, id); err != nil {
+				return err
+			}
+
+			return tx.Commit()
+		}(); {
+		case err == sql.ErrNoRows:
+			break loop
+		case err != nil:
+			return err
+		}
+	}
+
 	return nil
 }
 
-func connect(cc pgx.ConnConfig) error {
+func connect(cc pgx.ConnConfig, count int) error {
 	db := stdlib.OpenDB(cc)
 	defer db.Close()
 
@@ -40,7 +134,7 @@
 	}
 	defer conn.Close()
 
-	return process(ctx, conn)
+	return process(ctx, conn, count)
 }
 
 func main() {
@@ -51,6 +145,7 @@
 		password = flag.String("password", "so2Phie4", "database password")
 		port     = flag.Uint("port", 5432, "database port")
 		ssl      = flag.String("ssl", "prefer", "SSL mode")
+		count    = flag.Int("count", -1, "how many sounding results to convert")
 	)
 
 	flag.Parse()
@@ -66,7 +161,7 @@
 	cc.Password = *password
 	cc.Database = *db
 
-	if err := connect(cc); err != nil {
+	if err := connect(cc, *count); err != nil {
 		log.Fatalf("error: %v\n", err)
 	}
 }
--- a/pkg/octree/tree.go	Sun Oct 13 19:22:36 2019 +0200
+++ b/pkg/octree/tree.go	Sun Oct 13 22:15:55 2019 +0200
@@ -52,6 +52,50 @@
 	{0.5, 0.5, 1.0, 1.0},
 }
 
+func (ot *Tree) Tin() *Tin {
+	return &Tin{
+		EPSG:      ot.EPSG,
+		Vertices:  ot.vertices,
+		Triangles: ot.triangles,
+		Min:       ot.Min,
+		Max:       ot.Max,
+	}
+}
+
+func (ot *Tree) FindUnused() map[int32]struct{} {
+
+	used := make(map[int32]struct{}, len(ot.triangles))
+	for i := int32(0); i < int32(len(ot.triangles)); i++ {
+		used[i] = struct{}{}
+	}
+
+	stack := []int32{1}
+
+	for len(stack) > 0 {
+		top := stack[len(stack)-1]
+		stack = stack[:len(stack)-1]
+
+		if top > 0 { // node
+			if index := ot.index[top:]; len(index) > 7 {
+				for _, idx := range index[:8] {
+					if idx != 0 {
+						stack = append(stack, idx)
+					}
+				}
+			}
+		} else { // leaf
+			pos := -top - 1
+			n := ot.index[pos]
+			indices := ot.index[pos+1 : pos+1+n]
+			for _, idx := range indices {
+				delete(used, idx)
+			}
+		}
+	}
+
+	return used
+}
+
 func (ot *Tree) Value(x, y float64) (float64, bool) {
 
 	// out of bounding box