comparison pkg/imports/sr.go @ 3646:810b28f59b8b single-beam

Generate random points for second mesh.
author Sascha L. Teichmann <sascha.teichmann@intevation.de>
date Wed, 12 Jun 2019 17:30:20 +0200
parents e1021fd60190
children 01ce3ba9b0d0
comparison
equal deleted inserted replaced
3640:10471aa73ad8 3646:810b28f59b8b
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"
27 "math" 28 "math"
28 "os" 29 "os"
29 "path" 30 "path"
30 "path/filepath" 31 "path/filepath"
32 "runtime"
31 "strconv" 33 "strconv"
32 "strings" 34 "strings"
35 "sync"
33 "time" 36 "time"
34 37
35 shp "github.com/jonas-p/go-shp" 38 shp "github.com/jonas-p/go-shp"
36 39
37 "gemma.intevation.de/gemma/pkg/common" 40 "gemma.intevation.de/gemma/pkg/common"
63 } 66 }
64 67
65 const ( 68 const (
66 contourStepWidth = 0.1 69 contourStepWidth = 0.1
67 contourTolerance = 0.1 70 contourTolerance = 0.1
71 )
72
73 const (
74 tooLongEdge = 50.0
75 pointsPerSquareMeter = 5
68 ) 76 )
69 77
70 // SRJobKind is the unique name of a SoundingResult import job. 78 // SRJobKind is the unique name of a SoundingResult import job.
71 const SRJobKind JobKind = "sr" 79 const SRJobKind JobKind = "sr"
72 80
358 return nil, err 366 return nil, err
359 } 367 }
360 feedback.Info("Triangulation took %v.", time.Since(start)) 368 feedback.Info("Triangulation took %v.", time.Since(start))
361 feedback.Info("Number triangles: %d.", len(tri.Triangles)/3) 369 feedback.Info("Number triangles: %d.", len(tri.Triangles)/3)
362 370
371 var clippingPolygon octree.Polygon
372
363 if boundary == nil { 373 if boundary == nil {
364 feedback.Info("No boundary given.") 374 feedback.Info("No boundary given.")
365 feedback.Info("Eliminate triangles with long edges.") 375
366 376 polygon, removed := tri.ConcaveHull(tooLongEdge)
367 tri.ConcaveHull(50.0) 377
378 polygonArea := polygon.Area()
379 if polygonArea < 0.0 { // counter clockwise
380 polygonArea = -polygonArea
381 polygon.Reverse()
382 }
383
384 firstTin := tri.Tin()
385 builder := octree.NewBuilder(firstTin)
386 builder.Build(removed)
387
388 firstTree := builder.Tree()
389
390 bbox := polygon.BBox()
391 bboxArea := bbox.Area()
392
393 log.Printf("bbox area: %.2f\n", bboxArea)
394 log.Printf("polygon area: %.2f\n", polygonArea)
395
396 numPoints := int(math.Ceil(polygonArea * pointsPerSquareMeter))
397
398 log.Printf("random points for density of ~%d points/m²: %d\n",
399 pointsPerSquareMeter, numPoints)
400
401 start := time.Now()
402
403 var wg sync.WaitGroup
404
405 jobs := make(chan int)
406 out := make(chan []octree.Vertex)
407 done := make(chan struct{})
408
409 cpus := runtime.NumCPU()
410
411 free := make(chan []octree.Vertex, cpus)
412
413 for i, n := 0, cpus; i < n; i++ {
414 wg.Add(1)
415 go func() {
416 defer wg.Done()
417 xRange := common.Random(bbox.X1, bbox.X2)
418 yRange := common.Random(bbox.Y1, bbox.Y2)
419
420 for size := range jobs {
421 var vertices []octree.Vertex
422 select {
423 case vertices = <-free:
424 default:
425 vertices = make([]octree.Vertex, 0, 1000)
426 }
427 for len(vertices) < size {
428 x, y := xRange(), yRange()
429 if z, ok := firstTree.Value(x, y); ok {
430 vertices = append(vertices, octree.Vertex{X: x, Y: y, Z: z})
431 }
432 }
433 out <- vertices
434 }
435 }()
436 }
437
438 generated := make(octree.LineStringZ, 0, numPoints+len(polygon)-1)
439
440 go func() {
441 defer close(done)
442 for vertices := range out {
443 generated = append(generated, vertices...)
444 select {
445 case free <- vertices[:0]:
446 default:
447 }
448 }
449 }()
450
451 for remain := numPoints; remain > 0; {
452 if remain > 1000 {
453 jobs <- 1000
454 remain -= 1000
455 } else {
456 jobs <- remain
457 remain = 0
458 }
459 }
460 close(jobs)
461 wg.Wait()
462 close(out)
463 <-done
464
465 log.Printf("Generating %d points took %v\n", len(generated), time.Since(start))
466
467 // Add the boundary to new point cloud.
468 generated = append(generated, polygon[:len(polygon)-1]...)
469
470 xyz = octree.MultiPointZ(generated)
471
472 } else {
473 var hull []byte
474 if err = tx.QueryRowContext(
475 ctx,
476 reprojectPointsSQL,
477 boundary.asWKB(),
478 m.EPSG,
479 epsg,
480 ).Scan(&hull); err != nil {
481 return nil, err
482 }
483 if err := clippingPolygon.FromWKB(hull); err != nil {
484 return nil, err
485 }
486 clippingPolygon.Indexify()
368 } 487 }
369 488
370 // TODO: Implement me! 489 // TODO: Implement me!
371 return nil, errors.New("Not implemented, yet!") 490 return nil, errors.New("Not implemented, yet!")
372 } 491 }
417 feedback.Info("Best suited UTM EPSG: %d", epsg) 536 feedback.Info("Best suited UTM EPSG: %d", epsg)
418 537
419 start = time.Now() 538 start = time.Now()
420 539
421 var clippingPolygon octree.Polygon 540 var clippingPolygon octree.Polygon
541
422 if err := clippingPolygon.FromWKB(hull); err != nil { 542 if err := clippingPolygon.FromWKB(hull); err != nil {
423 return nil, err 543 return nil, err
424 } 544 }
425 clippingPolygon.Indexify() 545 clippingPolygon.Indexify()
426 feedback.Info("Building clipping polygon took %v.", time.Since(start)) 546 feedback.Info("Building clipping polygon took %v.", time.Since(start))