Mercurial > gemma
diff pkg/controllers/diff.go @ 4768:a2f16bbcc846 direct-diff
Morph differences: Directly raster A and subtract B as a raster.
author | Sascha L. Teichmann <sascha.teichmann@intevation.de> |
---|---|
date | Mon, 21 Oct 2019 02:01:56 +0200 |
parents | c93c8a837af8 |
children | f4abfd0ee8ad |
line wrap: on
line diff
--- a/pkg/controllers/diff.go Sat Oct 19 23:07:59 2019 +0200 +++ b/pkg/controllers/diff.go Mon Oct 21 02:01:56 2019 +0200 @@ -21,7 +21,6 @@ "log" "net/http" "runtime" - "sync" "time" "gemma.intevation.de/gemma/pkg/auth" @@ -92,6 +91,22 @@ 4326 ) ` + commonDiffBBoxSQL = ` +WITH joined AS ( + SELECT + sr.area AS area, + sr.date_info AS date_info + FROM waterway.sounding_results sr + WHERE sr.bottleneck_id = $1 +), +bbox AS ( + SELECT ST_Extent(ST_intersection( + (SELECT ST_Transform(area::geometry, $2::int) FROM joined WHERE date_info = $3::date), + (SELECT ST_Transform(area::geometry, $2::int) FROM joined WHERE date_info = $4::date) + )) AS area +) +SELECT ST_XMin(area), ST_YMin(area), ST_XMax(area), ST_YMax(area) FROM bbox +` ) type ( @@ -162,6 +177,38 @@ dci.Minuend.Format(common.DateFormat)) } + epsg := minuendTree.EPSG() + + var box octree.Box2D + + switch err := conn.QueryRowContext( + ctx, + commonDiffBBoxSQL, + dci.Bottleneck, + epsg, + dci.Minuend.Time, + dci.Subtrahend.Time, + ).Scan(&box.X1, &box.Y1, &box.X2, &box.Y2); { + case err == sql.ErrNoRows: + return 0, errors.New("No such intersection") + case err != nil: + return 0, err + } + + if box.Empty() { + return 0, errors.New("Intersection is empty") + } + + log.Printf("info: bbox of intersection: (%.2f, %.2f) - (%.2f, %.2f)\n", + box.X1, box.Y1, box.X2, box.Y2) + + start = time.Now() + raster := octree.NewRaster(box, isoCellSize) + raster.Rasterize(minuendTree.Value) + log.Printf("info: rasterizing minuend took %v\n", time.Since(start)) + + minuendTree = nil + start = time.Now() subtrahendTree, err := octree.FromCache( @@ -180,85 +227,15 @@ } // We need a slow path implementation for this. - epsg := minuendTree.EPSG() if epsg != subtrahendTree.EPSG() { return 0, errors.New("Calculating differences between two different " + "EPSG code meshes are not supported, yet.") } start = time.Now() - points := minuendTree.Diff(subtrahendTree) + raster.Diff(subtrahendTree.Value) log.Printf("info: A - B took %v\n", time.Since(start)) - - minuendTree, subtrahendTree = nil, nil - - // 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, - 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: - return 0, fmt.Errorf("%v %v", triErr, clipErr) - case triErr != nil: - return 0, triErr - case clipErr != nil: - return 0, clipErr - } - - start = time.Now() - tin := tri.Tin() - removed := tin.Clip(clip) - clip = nil - log.Printf("info: clipping TIN took %v\n", time.Since(start)) - - log.Printf("info: Number of triangles to clip: %d\n", len(removed)) - - start = time.Now() - var tree octree.STRTree - - tree.BuildWithout(tin, removed) - - log.Printf("info: Building final mesh took: %v\n", time.Since(start)) - - start = time.Now() + subtrahendTree = nil // XXX: Maybe we should start this transaction earlier!? var tx *sql.Tx @@ -267,6 +244,13 @@ } defer tx.Rollback() + zMin, zMax, ok := raster.ZExtent() + if !ok { + return 0, errors.New("Scans do not have common points") + } + + log.Printf("info: z range: %.3f - %.3f\n", zMin, zMax) + var heights []float64 heights, err = octree.LoadClassBreaks( @@ -275,12 +259,12 @@ if err != nil { log.Printf("warn: Loading class breaks failed: %v\n", err) err = nil - heights = octree.SampleDiffHeights(tin.Min.Z, tin.Max.Z, contourStep) + heights = octree.SampleDiffHeights(zMin, zMax, contourStep) } else { - heights = octree.ExtrapolateClassBreaks(heights, tin.Min.Z, tin.Max.Z) + heights = octree.ExtrapolateClassBreaks(heights, zMin, zMax) } - log.Printf("info: z range: %.3f - %.3f\n", tin.Min.Z, tin.Max.Z) + heights = common.DedupFloat64s(heights) log.Printf("info: num heights: %d\n", len(heights)) @@ -302,9 +286,9 @@ return 0, err } - heights = common.DedupFloat64s(heights) + areas := raster.Trace(heights) - areas := octree.TraceAreas(heights, isoCellSize, tin.Min, tin.Max, tree.Value) + raster = nil var size int @@ -327,7 +311,7 @@ log.Printf("info: Transferred WKB size: %.2fMB.\n", float64(size)/(1024*1024)) - log.Printf("info: calculating and storing iso lines took %v\n", + log.Printf("info: calculating and storing iso areas took %v\n", time.Since(start)) if err = tx.Commit(); err != nil {