Mercurial > gemma
view pkg/octree/contours.go @ 3971:4eaa6bca367a
Added db migration for nee password reset mechanism.
author | Sascha L. Teichmann <sascha.teichmann@intevation.de> |
---|---|
date | Wed, 17 Jul 2019 10:47:11 +0200 |
parents | 631f5eaf29de |
children |
line wrap: on
line source
// This is Free Software under GNU Affero General Public License v >= 3.0 // without warranty, see README.md and license for details. // // SPDX-License-Identifier: AGPL-3.0-or-later // License-Filename: LICENSES/AGPL-3.0.txt // // Copyright (C) 2018 by via donau // – Österreichische Wasserstraßen-Gesellschaft mbH // Software engineering by Intevation GmbH // // Author(s): // * Sascha L. Teichmann <sascha.teichmann@intevation.de> // * Tom Gottfried <tom.gottfried@intevation.de> package octree import ( "runtime" "sync" ) // ContourResult stores an calculated iso line for a given height. // Is used as a future variable in the concurrent iso line calculation. type ContourResult struct { Height float64 Lines MultiLineStringZ done bool mu sync.Mutex cond *sync.Cond } // NewContourResult prepares a future variable to later hold // the result of the iso line calculation. func NewContourResult(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() } // DoContours calculates the iso line for the given heights. // This is done concurrently. // It is guaranteed that the results are given to the store // function in order of the original heights values. func DoContours(tree *Tree, heights []float64, store func(*ContourResult)) { if len(heights) == 0 { return } contours := make([]*ContourResult, len(heights)) for i, h := range heights { contours[i] = NewContourResult(h) } jobs := make(chan *ContourResult) var wg sync.WaitGroup for i, n := 0, runtime.NumCPU(); i < n; i++ { wg.Add(1) go processLevels(tree, jobs, &wg) } 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 } func processLevels( tree *Tree, jobs <-chan *ContourResult, wg *sync.WaitGroup, ) { defer wg.Done() 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) } }) cr.set(lines.Merge()) } }