view cmd/octree2contour/main.go @ 932:ae1531e00344

Merged line merging from geo-style branch into default (where it belongs).
author Sascha L. Teichmann <sascha.teichmann@intevation.de>
date Mon, 08 Oct 2018 14:52:37 +0200
parents 52cb0b82b490
children
line wrap: on
line source

package main

import (
	"flag"
	"log"
	"runtime"
	"sort"
	"sync"
	"time"

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

var (
	one        = flag.Bool("o", false, "create only a single contour")
	step       = flag.Float64("s", 0.5, "step width")
	tol        = flag.Float64("t", 0.1, "tolerance for simplification")
	max        = flag.Float64("m", 10, "max height from lowest point")
	bottleneck = flag.String("bottleneck", "", "bottleneck id")
	date       = flag.String("date", "", "date info")
)

func processLevels(
	tree *octree.Tree,
	jobs <-chan float64,
	results chan<- result,
	wg *sync.WaitGroup,
) {
	defer wg.Done()
	for h := range jobs {
		var lines octree.MultiLineStringZ
		tree.Horizontal(h, func(t *octree.Triangle) {
			line := t.IntersectHorizontal(h)
			if len(line) > 1 {
				lines = append(lines, line)
			}
		})
		lines = lines.Merge()
		results <- result{h, lines}
	}
}

func process(tree *octree.Tree) []result {

	if *one {
		var lines octree.MultiLineStringZ
		tree.Horizontal(*step, func(t *octree.Triangle) {
			line := t.IntersectHorizontal(*step)
			if len(line) > 0 {
				lines = append(lines, line)
			}
		})
		lines = lines.Merge()
		return []result{{*step, lines}}
	}

	results := make(chan result)
	done := make(chan struct{})

	var all []result
	go func() {
		for {
			select {
			case r := <-results:
				all = append(all, r)
			case <-done:
				return
			}
		}
	}()

	var wg sync.WaitGroup
	jobs := make(chan float64)
	for i, n := 0, runtime.NumCPU(); i < n; i++ {
		wg.Add(1)
		go processLevels(tree, jobs, results, &wg)
	}
	for h := tree.Min.Z; h <= tree.Max.Z; h += *step {
		jobs <- h
	}
	close(jobs)
	wg.Wait()
	done <- struct{}{}

	sort.Slice(all, func(i, j int) bool {
		return all[i].h < all[j].h
	})

	return all
}

func main() {
	flag.Parse()

	if *bottleneck == "" || *date == "" {
		log.Fatalln("missing bottleneck or date option.")
	}

	dateInfo, err := time.Parse("2006-01-02", *date)
	if err != nil {
		log.Fatalf("error: %v\n", err)
	}

	for _, fname := range flag.Args() {
		log.Printf("processing %s\n", fname)
		start := time.Now()
		tree, err := octree.LoadTree(fname)
		if err != nil {
			log.Printf("error: %v\n", err)
			continue
		}
		log.Printf("loading took: %v\n", time.Since(start))
		start = time.Now()
		all := process(tree)
		log.Printf("processing took: %v\n", time.Since(start))
		start = time.Now()
		if err = store(all, tree.EPSG, *bottleneck, dateInfo, *tol); err != nil {
			log.Printf("error: %v\n", err)
		}
		log.Printf("storing took: %v\n", time.Since(start))
	}
}