changeset 768:3219e7e34953

Join neighbored linestring segments in octree cross sections and sort them along the input line.
author Sascha L. Teichmann <sascha.teichmann@intevation.de>
date Tue, 25 Sep 2018 17:45:44 +0200
parents dedf252b3e01
children ba2007b746ef
files pkg/octree/vertex.go
diffstat 1 files changed, 81 insertions(+), 3 deletions(-) [+]
line wrap: on
line diff
--- a/pkg/octree/vertex.go	Tue Sep 25 17:39:00 2018 +0200
+++ b/pkg/octree/vertex.go	Tue Sep 25 17:45:44 2018 +0200
@@ -6,6 +6,7 @@
 	"io"
 	"log"
 	"math"
+	"sort"
 )
 
 type (
@@ -161,10 +162,87 @@
 	return nil
 }
 
+func linearScale(x1, y1, x2, y2 float64) func(Vertex) float64 {
+	dx := x2 - x1
+	dy := y2 - y1
+
+	switch {
+	case dx != 0:
+		return func(v Vertex) float64 {
+			return (v.X - x1) / dx
+		}
+	case dy != 0:
+		return func(v Vertex) float64 {
+			return (v.Y - y1) / dy
+		}
+	default:
+		return func(Vertex) float64 {
+			return 0
+		}
+	}
+}
+
+func (ls LineStringZ) order(position func(Vertex) float64) {
+	type posVertex struct {
+		pos float64
+		v   Vertex
+	}
+	positions := make([]posVertex, len(ls))
+	for i, v := range ls {
+		positions[i] = posVertex{position(v), v}
+	}
+	sort.Slice(positions, func(i, j int) bool {
+		return positions[i].pos < positions[j].pos
+	})
+	for i := range positions {
+		ls[i] = positions[i].v
+	}
+}
+
+func (v Vertex) EpsEquals(w Vertex) bool {
+	const eqs = 1e-5
+	return math.Abs(v.X-w.X) < eps &&
+		math.Abs(v.Y-w.Y) < eps && math.Abs(v.Z-w.Z) < eps
+}
+
 func (mls MultiLineStringZ) JoinOnLine(x1, y1, x2, y2 float64) MultiLineStringZ {
-	// TODO: Implement me!
-	log.Println("MultiLineStringZ.JoinOnLine is not implemented, yet!")
-	return mls
+
+	position := linearScale(x1, y1, x2, y2)
+
+	type posLineString struct {
+		pos  float64
+		line LineStringZ
+	}
+
+	positions := make([]posLineString, 0, len(mls))
+
+	for _, ls := range mls {
+		if len(ls) == 0 {
+			continue
+		}
+		// order the atoms first
+		ls.order(position)
+		positions = append(positions, posLineString{position(ls[0]), ls})
+	}
+
+	sort.Slice(positions, func(i, j int) bool {
+		return positions[i].pos < positions[j].pos
+	})
+
+	out := make(MultiLineStringZ, 0, len(positions))
+
+	for i := range positions {
+		curr := positions[i].line
+		if l := len(out); l > 0 {
+			if last := out[l-1]; last[len(last)-1].EpsEquals(curr[0]) {
+				out[l-1] = append(last[:len(last)-1], curr...)
+				continue
+			}
+		}
+		out = append(out, curr)
+	}
+
+	return out
 }
 
 func (v *Vertex) Write(w io.Writer) error {