view pkg/mesh/areas.go @ 5710:37c8feeecb4d

Merged branch sr-v2 into default.
author Sascha L. Teichmann <sascha.teichmann@intevation.de>
date Tue, 20 Feb 2024 21:28:56 +0100
parents 181c2c05b12a
children
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 by via donau
//   – Österreichische Wasserstraßen-Gesellschaft mbH
// Software engineering by Intevation GmbH
//
// Author(s):
//  * Sascha L. Teichmann <sascha.teichmann@intevation.de>

package mesh

import (
	"runtime"
	"sync"

	"gemma.intevation.de/gemma/pkg/common"
)

// GenerateRandomVertices generates n random vertices.
// X/Y values are diced between the X/Y components of min and max.
// eval is called to find out the corresponding Z value.
// The random vertices are are transfered in chunks to
// the callback function.
func GenerateRandomVertices(
	n int,
	min, max Vertex,
	eval func(float64, float64) (float64, bool),
	callback func([]Vertex),
) {
	var wg sync.WaitGroup

	jobs := make(chan int)
	out := make(chan []Vertex)
	done := make(chan struct{})

	cpus := runtime.NumCPU()

	free := make(chan []Vertex, cpus)

	for i := 0; i < cpus; i++ {
		wg.Add(1)
		go func() {
			defer wg.Done()
			xRange := common.Random(min.X, max.X)
			yRange := common.Random(min.Y, max.Y)

			for size := range jobs {
				var vertices []Vertex
				select {
				case vertices = <-free:
				default:
					vertices = make([]Vertex, 0, 1000)
				}
				for len(vertices) < size {
					x, y := xRange(), yRange()
					if z, ok := eval(x, y); ok {
						vertices = append(vertices, Vertex{X: x, Y: y, Z: z})
					}
				}
				out <- vertices
			}
		}()
	}

	go func() {
		defer close(done)
		for vertices := range out {
			callback(vertices)
			select {
			case free <- vertices[:0]:
			default:
			}
		}
	}()

	for remain := n; remain > 0; {
		if remain > 1000 {
			jobs <- 1000
			remain -= 1000
		} else {
			jobs <- remain
			remain = 0
		}
	}
	close(jobs)
	wg.Wait()
	close(out)
	<-done
}