changeset 5428:b8d5f1cd15fb marking-single-beam

Simplified classification. Needs testing.
author Sascha L. Teichmann <sascha.teichmann@intevation.de>
date Sun, 11 Jul 2021 13:08:49 +0200
parents 235cfce555b5
children 02a5da2f03b4
files pkg/imports/isr.go pkg/imports/sr.go pkg/mesh/classbreaks.go pkg/mesh/vertex.go
diffstat 4 files changed, 81 insertions(+), 127 deletions(-) [+]
line wrap: on
line diff
--- a/pkg/imports/isr.go	Sat Jul 10 01:09:57 2021 +0200
+++ b/pkg/imports/isr.go	Sun Jul 11 13:08:49 2021 +0200
@@ -148,6 +148,7 @@
 	if err != nil {
 		return nil, err
 	}
+	heights = heights.Dedup()
 
 	bns, err := fetchBottleneckResults(ctx, conn)
 	if err != nil {
@@ -246,15 +247,7 @@
 			}
 
 			// Re-classify points.
-			classes := heights.Classify(points.All())
-
-			// Should not happen ... Z values over the top.
-			if n := len(classes) - 1; n > 1 && len(classes[n]) > 0 {
-				// Place the over the top values to the class below.
-				classes[n-1] = append(classes[n-1], classes[n]...)
-				classes[n] = nil
-				classes = classes[:n]
-			}
+			classes := heights.Classify(points)
 
 			// Re-insert points
 			for i, class := range classes {
--- a/pkg/imports/sr.go	Sat Jul 10 01:09:57 2021 +0200
+++ b/pkg/imports/sr.go	Sun Jul 11 13:08:49 2021 +0200
@@ -24,7 +24,6 @@
 	"errors"
 	"fmt"
 	"io"
-	"log"
 	"math"
 	"os"
 	"path"
@@ -645,12 +644,10 @@
 	} else {
 		start = time.Now()
 		clippingPolygonBuffered.Indexify()
-		removed = make(map[int32]struct{})
-		for i, v := range xyz {
-			if clippingPolygonBuffered.IntersectionBox2D(v.Box2D()) == mesh.IntersectionOutSide {
-				removed[int32(i)] = struct{}{}
-			}
-		}
+		xyz = xyz.Filter(func(v mesh.Vertex) bool {
+			return clippingPolygonBuffered.IntersectionBox2D(v.Box2D()) ==
+				mesh.IntersectionOutSide
+		})
 		feedback.Info("Clipping took %v.", time.Since(start))
 		feedback.Info("Number of points to clip %d.", len(removed))
 	}
@@ -707,17 +704,19 @@
 			return nil, err
 		}
 		feedback.Info("Storing mesh index took %s.", time.Since(start))
-		if err := generateIsos(ctx, tx, feedback, &final, id); err != nil {
-			return nil, err
-		}
-	} else { // SurveyTypeMarking
-		if err := generateMarkingPoints(
+		err = generateIsoAreas(
 			ctx, tx, feedback,
-			xyz, removed, epsg,
-			id,
-		); err != nil {
-			return nil, err
-		}
+			&final,
+			loadClassBreaks(ctx, tx, feedback, final.Min().Z, final.Max().Z),
+			id)
+	} else { // SurveyTypeMarking
+		err = generateMarkingPoints(
+			ctx, tx, feedback,
+			xyz, epsg,
+			id)
+	}
+	if err != nil {
+		return nil, err
 	}
 
 	// Store for potential later removal.
@@ -937,6 +936,50 @@
 	return heights
 }
 
+func generateMarkingPoints(
+	ctx context.Context,
+	tx *sql.Tx,
+	feedback Feedback,
+	xyz mesh.MultiPointZ,
+	epsg uint32,
+	id int64,
+) error {
+	heights, err := mesh.LoadClassBreaks(
+		ctx, tx,
+		"morphology_classbreaks")
+
+	if err != nil {
+		feedback.Warn("Loading class breaks failed: %v", err)
+		feedback.Info("Using default class breaks")
+		min, max := xyz.MinMax()
+		heights = defaultClassBreaks(min.Z, max.Z)
+	}
+
+	heights = heights.Dedup()
+
+	classes := heights.Classify(xyz)
+
+	stmt, err := tx.PrepareContext(ctx, insertMarkingPointsSQL)
+	if err != nil {
+		return err
+	}
+	defer stmt.Close()
+
+	for i, class := range classes {
+		// Ignore empty classes
+		if len(class) == 0 {
+			continue
+		}
+		if _, err := stmt.ExecContext(
+			ctx, id, heights[i], epsg, class.AsWKB(),
+		); err != nil {
+			return err
+		}
+	}
+
+	return nil
+}
+
 func loadClassBreaks(
 	ctx context.Context,
 	tx *sql.Tx,
@@ -959,68 +1002,6 @@
 	return heights.Dedup()
 }
 
-func generateMarkingPoints(
-	ctx context.Context,
-	tx *sql.Tx,
-	feedback Feedback,
-	xyz mesh.MultiPointZ,
-	removed map[int32]struct{},
-	epsg uint32,
-	id int64,
-) error {
-	log.Printf("debug: generateMarkingPoints")
-
-	min, max := mesh.MinMaxVertex(xyz.FilterRemoved(removed))
-
-	log.Printf("debug: min/max %.2f/%.2f\n", min.Z, max.Z)
-
-	heights := loadClassBreaks(ctx, tx, feedback, min.Z, max.Z)
-
-	classes := heights.Classify(xyz.FilterRemoved(removed))
-
-	// Should not happen ... Z values over the top.
-	if n := len(classes) - 1; n > 1 && len(classes[n]) > 0 {
-		// Place the over the top values to the class below.
-		classes[n-1] = append(classes[n-1], classes[n]...)
-		classes[n] = nil
-		classes = classes[:n]
-	}
-
-	stmt, err := tx.PrepareContext(ctx, insertMarkingPointsSQL)
-	if err != nil {
-		return err
-	}
-	defer stmt.Close()
-
-	for i, class := range classes {
-		// Ignore empty classes
-		if len(class) == 0 {
-			continue
-		}
-		log.Printf("debug: class %d: %d\n", i, len(class))
-		if _, err := stmt.ExecContext(
-			ctx, id, heights[i], epsg, class.AsWKB(),
-		); err != nil {
-			return err
-		}
-	}
-
-	return nil
-}
-
-func generateIsos(
-	ctx context.Context,
-	tx *sql.Tx,
-	feedback Feedback,
-	tree *mesh.STRTree,
-	id int64,
-) error {
-
-	heights := loadClassBreaks(ctx, tx, feedback, tree.Min().Z, tree.Max().Z)
-
-	return generateIsoAreas(ctx, tx, feedback, tree, heights, id)
-}
-
 func generateIsoAreas(
 	ctx context.Context,
 	tx *sql.Tx,
--- a/pkg/mesh/classbreaks.go	Sat Jul 10 01:09:57 2021 +0200
+++ b/pkg/mesh/classbreaks.go	Sun Jul 11 13:08:49 2021 +0200
@@ -157,10 +157,14 @@
 	return ClassBreaks(common.DedupFloat64s(cbs))
 }
 
-func (cbs ClassBreaks) Classify(points func() (Vertex, bool)) []MultiPointZ {
-	classes := make([]MultiPointZ, len(cbs)+1)
-	for v, ok := points(); ok; v, ok = points() {
-		idx := len(cbs)
+func (cbs ClassBreaks) Classify(points MultiPointZ) []MultiPointZ {
+	if len(cbs) == 0 {
+		return nil
+	}
+	classes := make([]MultiPointZ, len(cbs))
+	for _, v := range points {
+		// Place in last class if greater than all.
+		idx := len(cbs) - 1
 		for i, cb := range cbs {
 			if v.Z <= cb {
 				idx = i
--- a/pkg/mesh/vertex.go	Sat Jul 10 01:09:57 2021 +0200
+++ b/pkg/mesh/vertex.go	Sun Jul 11 13:08:49 2021 +0200
@@ -1144,47 +1144,23 @@
 	return out
 }
 
-// All returns all points as an iterator.
-func (mpz MultiPointZ) All() func() (Vertex, bool) {
-	var idx int
-	return func() (v Vertex, ok bool) {
-		if idx >= len(mpz) {
-			ok = false
-			return
+// Filter returns a copy removed the vertices which
+// don't pass the filter test.
+func (mpz MultiPointZ) Filter(filter func(Vertex) bool) MultiPointZ {
+	n := make(MultiPointZ, 0, len(mpz))
+	for _, v := range mpz {
+		if filter(v) {
+			n = append(n, v)
 		}
-		v, ok = mpz[idx], true
-		idx++
-		return
 	}
+	return n
 }
 
-// FilterRemoved returns an iterator that only delivers the vertices
-// which indices are not marked as removed.
-func (mpz MultiPointZ) FilterRemoved(removed map[int32]struct{}) func() (Vertex, bool) {
-	var idx int32
-	return func() (v Vertex, ok bool) {
-		for {
-			if idx >= int32(len(mpz)) {
-				ok = false
-				return
-			}
-			if _, rm := removed[idx]; rm {
-				idx++
-				continue
-			}
-			break
-		}
-		v, ok = mpz[idx], true
-		idx++
-		return
-	}
-}
-
-// MinMaxVertex runs over a point iterator and figures out its boundary.
-func MinMaxVertex(points func() (Vertex, bool)) (Vertex, Vertex) {
+// MinMaxVertex returns the extend of the point set.
+func (mpz MultiPointZ) MinMax() (Vertex, Vertex) {
 	min := Vertex{math.MaxFloat64, math.MaxFloat64, math.MaxFloat64}
 	max := Vertex{-math.MaxFloat64, -math.MaxFloat64, -math.MaxFloat64}
-	for v, ok := points(); ok; v, ok = points() {
+	for _, v := range mpz {
 		min.Minimize(v)
 		max.Maximize(v)
 	}