changeset 976:c397fdd8c327

Generate the contour lines of the sounding result during the import, too.
author Sascha L. Teichmann <sascha.teichmann@intevation.de>
date Thu, 18 Oct 2018 17:05:54 +0200
parents 3da707172772
children 4a2ca0e20006
files pkg/imports/sr.go pkg/octree/contours.go
diffstat 2 files changed, 123 insertions(+), 4 deletions(-) [+]
line wrap: on
line diff
--- a/pkg/imports/sr.go	Thu Oct 18 16:47:17 2018 +0200
+++ b/pkg/imports/sr.go	Thu Oct 18 17:05:54 2018 +0200
@@ -342,12 +342,15 @@
 		return err
 	}
 
-	index := builder.Tree()
+	tree := builder.Tree()
 	builder = nil // not needed from now on
 
-	// TODO: Generate iso-lines
-
-	_ = index
+	start = time.Now()
+	err = generateContours(tree, tx, id)
+	log.Printf("generating and storing contour lines took %s\n", time.Since(start))
+	if err != nil {
+		return err
+	}
 
 	return tx.Commit()
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pkg/octree/contours.go	Thu Oct 18 17:05:54 2018 +0200
@@ -0,0 +1,116 @@
+package octree
+
+import (
+	"database/sql"
+	"runtime"
+	"sync"
+)
+
+const (
+	contourStepWidth = 0.5
+	contourTolerance = 0.1
+)
+
+type contourResult struct {
+	height float64
+	lines  MultiLineStringZ
+}
+
+const (
+	insertContourSQL = `
+INSERT INTO waterway.sounding_results_contour_lines (
+  sounding_result_id,
+  height,
+  lines
+)
+SELECT
+  $1,
+  $2,
+  ST_Transform(
+    ST_Multi(
+      ST_CollectionExtract(
+        ST_Intersection(
+          ST_Transform(sr.area::geometry, $3::integer),
+          ST_SimplifyPreserveTopology(
+            ST_GeomFromWKB($4, $3::integer),
+            $5
+          )
+        ),
+        2
+      )
+    ),
+    4326
+  )
+FROM waterway.sounding_results sr
+WHERE id = $1
+`
+)
+
+func generateContours(tree *Tree, tx *sql.Tx, id int64) error {
+	stmt, err := tx.Prepare(insertContourSQL)
+	if err != nil {
+		return err
+	}
+	defer stmt.Close()
+
+	doContours(tree, contourStepWidth, func(res *contourResult) {
+		if err == nil {
+			_, err = stmt.Exec(
+				id, res.height, tree.EPSG,
+				res.lines.AsWKB2D(),
+				contourTolerance)
+		}
+	})
+
+	return err
+}
+
+func doContours(tree *Tree, step float64, store func(*contourResult)) {
+
+	results := make(chan *contourResult)
+	done := make(chan struct{})
+	jobs := make(chan float64)
+
+	go func() {
+		for {
+			select {
+			case r := <-results:
+				store(r)
+			case <-done:
+				return
+			}
+		}
+	}()
+
+	var wg sync.WaitGroup
+	for i, n := 0, runtime.NumCPU(); i < n; i++ {
+		wg.Add(1)
+		go processLevels(tree, jobs, results, &wg)
+	}
+	for h := tree.Min.Z; h <= tree.Max.Z; h += step {
+		jobs <- h
+	}
+	close(jobs)
+	wg.Wait()
+	done <- struct{}{}
+}
+
+func processLevels(
+	tree *Tree,
+	jobs <-chan float64,
+	results chan<- *contourResult,
+	wg *sync.WaitGroup,
+) {
+	defer wg.Done()
+	for h := range jobs {
+		var lines MultiLineStringZ
+		tree.Horizontal(h, func(t *Triangle) {
+			line := t.IntersectHorizontal(h)
+			if len(line) > 1 {
+				lines = append(lines, line)
+			}
+		})
+		lines = lines.Merge()
+		results <- &contourResult{h, lines}
+	}
+}