Mercurial > gemma
view pkg/controllers/diff.go @ 2576:647a58ee9ae9
Morphological differences: Centralized generation of height values for differences in octree package.
author | Sascha L. Teichmann <sascha.teichmann@intevation.de> |
---|---|
date | Mon, 11 Mar 2019 15:04:23 +0100 |
parents | 59e7a011d347 |
children | 5125db802b79 |
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, 2019 by via donau // – Österreichische Wasserstraßen-Gesellschaft mbH // Software engineering by Intevation GmbH // // Author(s): // * Sascha L. Teichmann <sascha.teichmann@intevation.de> package controllers import ( "database/sql" "fmt" "log" "net/http" "sync" "time" "golang.org/x/sync/semaphore" "gemma.intevation.de/gemma/pkg/common" "gemma.intevation.de/gemma/pkg/models" "gemma.intevation.de/gemma/pkg/octree" ) // Only allow three diffence calculation at once. // TODO: Make this configurable? var diffCalculationSemaphore = semaphore.NewWeighted(int64(3)) func diffCalculation( input interface{}, req *http.Request, conn *sql.Conn, ) (jr JSONResult, err error) { start := time.Now() ctx := req.Context() // DoS counter measure. if err = diffCalculationSemaphore.Acquire(ctx, 1); err != nil { return } defer diffCalculationSemaphore.Release(1) dci := input.(models.DiffCalculationInput) minuendTree, err := octree.FromCache( ctx, conn, dci.Bottleneck, dci.Minuend.Time) log.Printf("info: loading minuend octree took %s\n", time.Since(start)) if err != nil { return } if minuendTree == nil { err = JSONError{ Code: http.StatusNotFound, Message: fmt.Sprintf("Cannot find survey for %s/%s.", dci.Bottleneck, dci.Minuend.Format(common.DateFormat)), } return } start = time.Now() subtrahendTree, err := octree.FromCache( ctx, conn, dci.Bottleneck, dci.Subtrahend.Time) log.Printf("info: loading subtrahend octree took %s\n", time.Since(start)) if err != nil { return } if subtrahendTree == nil { err = JSONError{ Code: http.StatusNotFound, Message: fmt.Sprintf("Cannot find survey for %s/%s.", dci.Bottleneck, dci.Subtrahend.Format(common.DateFormat)), } return } // We need a slow path implementation for this. if minuendTree.EPSG != subtrahendTree.EPSG { err = JSONError{ Code: http.StatusInternalServerError, Message: "Calculating differences between two different " + "EPSG code octrees are not supported, yet.", } return } start = time.Now() points := minuendTree.Diff(subtrahendTree) log.Printf("info: A - B took %v\n", time.Since(start)) // The Triangulation and the loading of the clipping // polygon can be done concurrently. jobs := make(chan func()) wg := new(sync.WaitGroup) for i := 0; i < 2; i++ { wg.Add(1) go func() { defer wg.Done() for job := range jobs { job() } }() } var ( tri *octree.Triangulation triErr error clip *octree.Polygon clipErr error ) jobs <- func() { start := time.Now() tri, triErr = points.Triangulate() log.Printf("info: triangulation took %v\n", time.Since(start)) } jobs <- func() { start := time.Now() clip, clipErr = octree.LoadClippingPolygon( ctx, conn, minuendTree.EPSG, dci.Bottleneck, dci.Minuend.Time, dci.Subtrahend.Time) log.Printf("info: loading clipping polygon took %v\n", time.Since(start)) } close(jobs) wg.Wait() switch { case triErr != nil && clipErr != nil: err = fmt.Errorf("%v %v", triErr, clipErr) return case triErr != nil: err = triErr return case clipErr != nil: err = clipErr return } start = time.Now() tin := tri.Tin() removed := tin.Clip(clip) log.Printf("info: clipping TIN took %v\n", time.Since(start)) start = time.Now() log.Printf("info: Number of triangles to clip: %d\n", len(removed)) builder := octree.NewBuilder(tin) builder.Build(removed) log.Printf("info: building octree took %v\n", time.Since(start)) tree := builder.Tree() log.Printf("info: min/max: %f %f\n", tree.Min.Z, tree.Max.Z) heights := octree.SampleDiffHeights(tree.Min.Z, tree.Max.Z, 0.1) log.Printf("info: num heights: %d\n", len(heights)) // TODO: Implement me! return }