Mercurial > gemma
comparison pkg/imports/sr.go @ 4654:3eda5a7215ab stree-experiment
Generate STRTrees instaead of Octree during sounding result imports.
author | Sascha L. Teichmann <sascha.teichmann@intevation.de> |
---|---|
date | Mon, 14 Oct 2019 13:12:38 +0200 |
parents | 89a72e0e2f9b |
children | 6eab3ac0e849 |
comparison
equal
deleted
inserted
replaced
4653:8efc6b3289f3 | 4654:3eda5a7215ab |
---|---|
22 "database/sql" | 22 "database/sql" |
23 "encoding/hex" | 23 "encoding/hex" |
24 "errors" | 24 "errors" |
25 "fmt" | 25 "fmt" |
26 "io" | 26 "io" |
27 "log" | |
28 "math" | 27 "math" |
29 "os" | 28 "os" |
30 "path" | 29 "path" |
31 "path/filepath" | 30 "path/filepath" |
32 "strconv" | 31 "strconv" |
154 ST_AsBinary(ST_Buffer(ST_Transform(ST_GeomFromWKB($1, $2::integer), $3::integer), 0.1)), | 153 ST_AsBinary(ST_Buffer(ST_Transform(ST_GeomFromWKB($1, $2::integer), $3::integer), 0.1)), |
155 ST_Area(ST_Transform(ST_GeomFromWKB($1, $2::integer), $3::integer))` | 154 ST_Area(ST_Transform(ST_GeomFromWKB($1, $2::integer), $3::integer))` |
156 | 155 |
157 insertOctreeSQL = ` | 156 insertOctreeSQL = ` |
158 UPDATE waterway.sounding_results SET | 157 UPDATE waterway.sounding_results SET |
159 octree_checksum = $2, octree_index = $3 | 158 mesh_checksum = $2, mesh_index = $3 |
160 WHERE id = $1` | 159 WHERE id = $1` |
161 | 160 |
162 repairBoundarySQL = ` | 161 repairBoundarySQL = ` |
163 SELECT | 162 SELECT |
164 ST_AsBinary(ST_Buffer(ST_MakeValid(ST_GeomFromWKB($1, $2::integer)), 0.0)), | 163 ST_AsBinary(ST_Buffer(ST_MakeValid(ST_GeomFromWKB($1, $2::integer)), 0.0)), |
496 | 495 |
497 feedback.Info("Build virtual DEM based on original XYZ data.") | 496 feedback.Info("Build virtual DEM based on original XYZ data.") |
498 | 497 |
499 start = time.Now() | 498 start = time.Now() |
500 | 499 |
501 var tree *octree.Tree | 500 tin := tri.Tin() |
502 { | 501 var virtual octree.STRTree |
503 builder := octree.NewBuilder(tri.Tin()) | 502 virtual.BuildWithout(tin, removed) |
504 builder.Build(removed) | |
505 tree = builder.Tree() | |
506 } | |
507 | 503 |
508 feedback.Info("Building took %v", time.Since(start)) | 504 feedback.Info("Building took %v", time.Since(start)) |
509 | 505 |
510 feedback.Info("Boundary area: %.2fm²", polygonArea) | 506 feedback.Info("Boundary area: %.2fm²", polygonArea) |
511 | 507 |
516 | 512 |
517 start = time.Now() | 513 start = time.Now() |
518 | 514 |
519 generated := make(octree.LineStringZ, 0, numPoints+clippingPolygon.NumVertices(0)) | 515 generated := make(octree.LineStringZ, 0, numPoints+clippingPolygon.NumVertices(0)) |
520 | 516 |
521 tree.GenerateRandomVertices(numPoints, func(vertices []octree.Vertex) { | 517 octree.GenerateRandomVertices( |
522 generated = append(generated, vertices...) | 518 numPoints, |
523 }) | 519 tin.Min, tin.Max, |
520 virtual.Value, | |
521 func(vertices []octree.Vertex) { | |
522 generated = append(generated, vertices...) | |
523 }) | |
524 | 524 |
525 feedback.Info("Generating %d points took %v.", len(generated), time.Since(start)) | 525 feedback.Info("Generating %d points took %v.", len(generated), time.Since(start)) |
526 | 526 |
527 // Add the boundary to new point cloud. | 527 // Add the boundary to new point cloud. |
528 dupes := map[[2]float64]struct{}{} | 528 dupes := map[[2]float64]struct{}{} |
530 key := [2]float64{x, y} | 530 key := [2]float64{x, y} |
531 if _, found := dupes[key]; found { | 531 if _, found := dupes[key]; found { |
532 return | 532 return |
533 } | 533 } |
534 dupes[key] = struct{}{} | 534 dupes[key] = struct{}{} |
535 if z, ok := tree.Value(x, y); ok { | 535 if z, ok := virtual.Value(x, y); ok { |
536 generated = append(generated, octree.Vertex{X: x, Y: y, Z: z}) | 536 generated = append(generated, octree.Vertex{X: x, Y: y, Z: z}) |
537 } | 537 } |
538 }) | 538 }) |
539 | 539 |
540 feedback.Info("Triangulate new point cloud.") | 540 feedback.Info("Triangulate new point cloud.") |
546 return nil, err | 546 return nil, err |
547 } | 547 } |
548 feedback.Info("Second triangulation took %v.", time.Since(start)) | 548 feedback.Info("Second triangulation took %v.", time.Since(start)) |
549 feedback.Info("Number triangles: %d.", len(tri.Triangles)/3) | 549 feedback.Info("Number triangles: %d.", len(tri.Triangles)/3) |
550 feedback.Info("Clipping triangles from new mesh.") | 550 feedback.Info("Clipping triangles from new mesh.") |
551 | |
552 } | 551 } |
553 | 552 |
554 start = time.Now() | 553 start = time.Now() |
555 tin = tri.Tin() | 554 tin = tri.Tin() |
556 tin.EPSG = epsg | 555 tin.EPSG = epsg |
565 removed = str.Clip(&clippingPolygonBuffered) | 564 removed = str.Clip(&clippingPolygonBuffered) |
566 feedback.Info("Clipping STR tree took %v.", time.Since(start)) | 565 feedback.Info("Clipping STR tree took %v.", time.Since(start)) |
567 feedback.Info("Number of triangles to clip %d.", len(removed)) | 566 feedback.Info("Number of triangles to clip %d.", len(removed)) |
568 | 567 |
569 start = time.Now() | 568 start = time.Now() |
570 s := octree.STRTree{Entries: 16} | 569 final := octree.STRTree{Entries: 16} |
571 s.BuildWithout(tin, removed) | 570 final.BuildWithout(tin, removed) |
572 if _, err2 := s.Bytes(); err2 != nil { | 571 |
573 log.Printf("serializing STRTree failed: %v\n", err2) | |
574 } | |
575 log.Printf("Building strtree took: %v.\n", time.Since(start)) | |
576 | |
577 // return nil, UnchangedError("nothing to do") | |
578 | |
579 feedback.Info("Build final octree index") | |
580 | |
581 builder := octree.NewBuilder(tin) | |
582 builder.Build(removed) | |
583 octreeIndex, err := builder.Bytes() | |
584 if err != nil { | |
585 return nil, err | |
586 } | |
587 feedback.Info("Building octree took %v.", time.Since(start)) | 572 feedback.Info("Building octree took %v.", time.Since(start)) |
588 feedback.Info("Store octree.") | 573 feedback.Info("Store octree.") |
589 | 574 |
590 start = time.Now() | 575 start = time.Now() |
591 | 576 |
621 "no matching bottleneck of given name or time available: %v", err) | 606 "no matching bottleneck of given name or time available: %v", err) |
622 case err != nil: | 607 case err != nil: |
623 return nil, err | 608 return nil, err |
624 } | 609 } |
625 | 610 |
611 index, err := final.Bytes() | |
612 if err != nil { | |
613 return nil, err | |
614 } | |
615 | |
626 h := sha1.New() | 616 h := sha1.New() |
627 h.Write(octreeIndex) | 617 h.Write(index) |
628 checksum := hex.EncodeToString(h.Sum(nil)) | 618 checksum := hex.EncodeToString(h.Sum(nil)) |
629 _, err = tx.ExecContext(ctx, insertOctreeSQL, id, checksum, octreeIndex) | 619 _, err = tx.ExecContext(ctx, insertOctreeSQL, id, checksum, index) |
630 if err != nil { | 620 if err != nil { |
631 return nil, err | 621 return nil, err |
632 } | 622 } |
633 feedback.Info("Storing octree index took %s.", time.Since(start)) | 623 feedback.Info("Storing octree index took %s.", time.Since(start)) |
634 err = generateIsos(ctx, tx, feedback, builder.Tree(), id) | 624 err = generateIsos(ctx, tx, feedback, &final, id) |
635 if err != nil { | 625 if err != nil { |
636 return nil, err | 626 return nil, err |
637 } | 627 } |
638 | 628 |
639 // Store for potential later removal. | 629 // Store for potential later removal. |
836 | 826 |
837 func generateIsos( | 827 func generateIsos( |
838 ctx context.Context, | 828 ctx context.Context, |
839 tx *sql.Tx, | 829 tx *sql.Tx, |
840 feedback Feedback, | 830 feedback Feedback, |
841 tree *octree.Tree, | 831 tree *octree.STRTree, |
842 id int64, | 832 id int64, |
843 ) error { | 833 ) error { |
844 | 834 |
845 heights, err := octree.LoadClassBreaks( | 835 heights, err := octree.LoadClassBreaks( |
846 ctx, tx, | 836 ctx, tx, |
847 "morphology_classbreaks", | 837 "morphology_classbreaks", |
848 ) | 838 ) |
849 | 839 |
840 minZ, maxZ := tree.Min().Z, tree.Max().Z | |
841 | |
850 if err != nil { | 842 if err != nil { |
851 feedback.Warn("Loading class breaks failed: %v", err) | 843 feedback.Warn("Loading class breaks failed: %v", err) |
852 feedback.Info("Using default class breaks") | 844 feedback.Info("Using default class breaks") |
853 heights = nil | 845 heights = nil |
854 h := contourStepWidth * math.Ceil(tree.Min.Z/contourStepWidth) | 846 h := contourStepWidth * math.Ceil(minZ/contourStepWidth) |
855 for ; h <= tree.Max.Z; h += contourStepWidth { | 847 for ; h <= maxZ; h += contourStepWidth { |
856 heights = append(heights, h) | 848 heights = append(heights, h) |
857 } | 849 } |
858 } else { | 850 } else { |
859 heights = octree.ExtrapolateClassBreaks(heights, tree.Min.Z, tree.Max.Z) | 851 heights = octree.ExtrapolateClassBreaks(heights, minZ, maxZ) |
860 // We set steps for InBetweenClassBreaks to 1, so it | 852 // We set steps for InBetweenClassBreaks to 1, so it |
861 // becomes a null operation. The extra class breaks | 853 // becomes a null operation. The extra class breaks |
862 // were considered unexpected and confusing by the | 854 // were considered unexpected and confusing by the |
863 // users. Once we get filled polygones the visual will | 855 // users. Once we get filled polygones the visual will |
864 // be considerably different anyway. -- sw | 856 // be considerably different anyway. -- sw |
879 | 871 |
880 func generateIsoAreas( | 872 func generateIsoAreas( |
881 ctx context.Context, | 873 ctx context.Context, |
882 tx *sql.Tx, | 874 tx *sql.Tx, |
883 feedback Feedback, | 875 feedback Feedback, |
884 tree *octree.Tree, | 876 tree *octree.STRTree, |
885 heights []float64, | 877 heights []float64, |
886 id int64, | 878 id int64, |
887 ) error { | 879 ) error { |
888 feedback.Info("Generate iso areas") | 880 feedback.Info("Generate iso areas") |
889 total := time.Now() | 881 total := time.Now() |
890 defer func() { | 882 defer func() { |
891 feedback.Info("Generating iso areas took %s.", | 883 feedback.Info("Generating iso areas took %s.", |
892 time.Since(total)) | 884 time.Since(total)) |
893 }() | 885 }() |
894 | 886 |
895 areas := octree.TraceAreas(heights, isoCellSize, tree.Min, tree.Max, tree.Value) | 887 areas := octree.TraceAreas(heights, isoCellSize, tree.Min(), tree.Max(), tree.Value) |
896 | 888 |
897 return storeAreas( | 889 return storeAreas( |
898 ctx, tx, feedback, | 890 ctx, tx, feedback, |
899 areas, tree.EPSG, heights, id) | 891 areas, tree.EPSG(), heights, id) |
900 } | 892 } |
901 | 893 |
902 func storeAreas( | 894 func storeAreas( |
903 ctx context.Context, | 895 ctx context.Context, |
904 tx *sql.Tx, | 896 tx *sql.Tx, |