changeset 1134:0420761c1c3f

Store contour lines in deterministic order.
author Sascha L. Teichmann <sascha.teichmann@intevation.de>
date Wed, 07 Nov 2018 21:45:10 +0100
parents dd4071019676
children 19a04b150b6c
files pkg/octree/contours.go
diffstat 1 files changed, 56 insertions(+), 22 deletions(-) [+]
line wrap: on
line diff
--- a/pkg/octree/contours.go	Wed Nov 07 18:13:02 2018 +0100
+++ b/pkg/octree/contours.go	Wed Nov 07 21:45:10 2018 +0100
@@ -21,54 +21,88 @@
 type ContourResult struct {
 	Height float64
 	Lines  MultiLineStringZ
+
+	done bool
+	mu   sync.Mutex
+	cond *sync.Cond
+}
+
+func NewContorResult(height float64) *ContourResult {
+	cr := ContourResult{Height: height}
+	cr.cond = sync.NewCond(&cr.mu)
+	return &cr
+}
+
+func (cr *ContourResult) wait() {
+	cr.cond.L.Lock()
+	for !cr.done {
+		cr.cond.Wait()
+	}
+	cr.cond.L.Unlock()
+}
+
+func (cr *ContourResult) get() float64 {
+	cr.cond.L.Lock()
+	defer cr.cond.L.Unlock()
+	return cr.Height
+}
+
+func (cr *ContourResult) set(lines MultiLineStringZ) {
+	cr.cond.L.Lock()
+	defer cr.cond.L.Unlock()
+	cr.Lines = lines
+	cr.done = true
+	cr.cond.Signal()
 }
 
 func DoContours(tree *Tree, step float64, store func(*ContourResult)) {
 
-	results := make(chan *ContourResult)
-	done := make(chan struct{})
-	jobs := make(chan float64)
+	var contours []*ContourResult
+	for h := tree.Min.Z; h <= tree.Max.Z; h += step {
+		contours = append(contours, NewContorResult(h))
+	}
 
-	go func() {
-		for {
-			select {
-			case r := <-results:
-				store(r)
-			case <-done:
-				return
-			}
-		}
-	}()
+	jobs := make(chan *ContourResult)
 
 	var wg sync.WaitGroup
 	for i, n := 0, runtime.NumCPU(); i < n; i++ {
 		wg.Add(1)
-		go processLevels(tree, jobs, results, &wg)
+		go processLevels(tree, jobs, &wg)
 	}
-	for h := tree.Min.Z; h <= tree.Max.Z; h += step {
-		jobs <- h
+
+	done := make(chan struct{})
+	go func() {
+		defer close(done)
+		for _, cr := range contours {
+			cr.wait()
+			store(cr)
+		}
+	}()
+
+	for _, cr := range contours {
+		jobs <- cr
 	}
 	close(jobs)
+
 	wg.Wait()
-	done <- struct{}{}
+	<-done
 }
 
 func processLevels(
 	tree *Tree,
-	jobs <-chan float64,
-	results chan<- *ContourResult,
+	jobs <-chan *ContourResult,
 	wg *sync.WaitGroup,
 ) {
 	defer wg.Done()
-	for h := range jobs {
+	for cr := range jobs {
 		var lines MultiLineStringZ
+		h := cr.get()
 		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}
+		cr.set(lines.Merge())
 	}
 }