view cmd/soundingresults/points.go @ 904:e4b72a199258

New default bottleneck colors Mainly to make the stroke color one actually selectable in the ui. In addition the pink does better match the collors used on the ECDIS layer.
author Sascha Wilde <wilde@intevation.de>
date Tue, 02 Oct 2018 13:34:59 +0200
parents bc2b7da07d60
children
line wrap: on
line source

package main

import (
	"bufio"
	"bytes"
	"compress/bzip2"
	"compress/gzip"
	"encoding/binary"
	"io"
	"log"
	"math"
	"os"
	"path/filepath"
	"strconv"
	"strings"
)

type point3d struct {
	x float64
	y float64
	z float64
}

type points3d []*point3d

func parseXYZ(fname string) (points3d, error) {
	f, err := os.Open(fname)
	if err != nil {
		return nil, err
	}
	defer f.Close()

	r, err := wrap(fname, f)
	if err != nil {
		return nil, err
	}
	return readXYZ(r)
}

func wrap(fname string, f io.Reader) (io.Reader, error) {

	switch strings.ToLower(filepath.Ext(fname)) {
	case ".gz":
		return gzip.NewReader(f)
	case ".bz2":
		return bzip2.NewReader(f), nil
	}

	return bufio.NewReader(f), nil
}

func readXYZ(r io.Reader) (points3d, error) {

	// Alloc in larger chunks to reduce pressure on memory management.
	var chunk []point3d
	alloc := func() *point3d {
		if len(chunk) == 0 {
			chunk = make([]point3d, 8*1024)
		}
		p := &chunk[0]
		chunk = chunk[1:]
		return p
	}

	var points points3d

	s := bufio.NewScanner(r)
	if s.Scan() { // Skip header line.
		for line := 2; s.Scan(); line++ {
			p := alloc()
			text := s.Text()
			// fmt.Sscanf(text, "%f,%f,%f") is 4 times slower.
			idx := strings.IndexByte(text, ',')
			if idx == -1 {
				log.Printf("format error in line %d\n", line)
				continue
			}
			var err error
			if p.x, err = strconv.ParseFloat(text[:idx], 64); err != nil {
				log.Printf("format error in line %d: %v\n", line, err)
				continue
			}
			text = text[idx+1:]
			if idx = strings.IndexByte(text, ','); idx == -1 {
				log.Printf("format error in line %d\n", line)
				continue
			}
			if p.y, err = strconv.ParseFloat(text[:idx], 64); err != nil {
				log.Printf("format error in line %d: %v\n", line, err)
				continue
			}
			text = text[idx+1:]
			if p.z, err = strconv.ParseFloat(text, 64); err != nil {
				log.Printf("format error in line %d: %v\n", line, err)
				continue
			}
			points = append(points, p)
		}
	}

	return points, s.Err()
}

const (
	wkbNDR         byte   = 1
	wkbPointZ      uint32 = 1 + 1000
	wkbMultiPointZ uint32 = 4 + 1000
)

func (ps points3d) asWKB() string {

	size := 1 + 4 + 4 + len(ps)*(1+4+3*8)

	buf := bytes.NewBuffer(make([]byte, 0, size))

	binary.Write(buf, binary.LittleEndian, wkbNDR)
	binary.Write(buf, binary.LittleEndian, wkbMultiPointZ)
	binary.Write(buf, binary.LittleEndian, uint32(len(ps)))

	for _, p := range ps {
		binary.Write(buf, binary.LittleEndian, wkbNDR)
		binary.Write(buf, binary.LittleEndian, wkbPointZ)
		binary.Write(buf, binary.LittleEndian, math.Float64bits(p.x))
		binary.Write(buf, binary.LittleEndian, math.Float64bits(p.y))
		binary.Write(buf, binary.LittleEndian, math.Float64bits(p.z))
	}

	return buf.String()
}