Mercurial > gemma
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)) |