view pkg/mesh/meshserialize_v1.go @ 5718:3d497077f888 uploadwg

Implemented direct file upload as alternative import method for WG. For testing and data corrections it is useful to be able to import waterway gauges data directly by uploading a xml file.
author Sascha Wilde <wilde@sha-bang.de>
date Thu, 18 Apr 2024 19:23:19 +0200
parents ef80748ae4f3
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) 2024 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 (
	"bufio"
	"encoding/binary"
	"io"
	"math"

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

func (s *STRTree) serializeV1(w io.Writer) error {
	return serializer(w, s,
		(*STRTree).serializeTinV1,
		(*STRTree).serializeEntries,
		(*STRTree).serializeIndexV1,
		(*STRTree).serializeBBoxesV1,
	)
}

func (s *STRTree) serializeTinV1(w io.Writer) error {
	return s.tin.serializeV1(w)
}

func (s *STRTree) serializeBBoxesV1(w io.Writer) error {
	if err := binary.Write(w, binary.LittleEndian, int32(len(s.bboxes))); err != nil {
		return err
	}
	var err error
	write := func(v float64) {
		if err == nil {
			err = binary.Write(w, binary.LittleEndian, math.Float64bits(v))
		}
	}
	for _, box := range s.bboxes {
		write(box.X1)
		write(box.Y1)
		write(box.X2)
		write(box.Y2)
	}
	return err
}

func (s *STRTree) serializeIndexV1(w io.Writer) error {
	if err := binary.Write(w, binary.LittleEndian, int32(len(s.index))); err != nil {
		return err
	}
	var buf [binary.MaxVarintLen32]byte
	var last int32
	var written int
	for _, x := range s.index {
		delta := x - last
		n := binary.PutVarint(buf[:], int64(delta))
		for p := buf[:n]; len(p) > 0; p = p[n:] {
			var err error
			if n, err = w.Write(p); err != nil {
				return err
			}
			written += n
		}
		last = x
	}
	log.Infof("compressed index in bytes: %d %.2f (%d %.2f)\n",
		written,
		float64(written)/(1024*1024),
		4*len(s.index),
		float64(4*len(s.index))/(1024*1024),
	)
	return nil
}

func (t *Tin) serializeV1(w io.Writer) error {
	return serializer(w, t,
		(*Tin).serializeEPSG,
		(*Tin).serializeExtent,
		(*Tin).serializeVerticesV1,
		(*Tin).serializeTrianglesV1,
	)
}

func (t *Tin) serializeTrianglesV1(w io.Writer) error {
	if err := binary.Write(
		w, binary.LittleEndian, uint32(len(t.Triangles))); err != nil {
		return err
	}
	var buf [binary.MaxVarintLen32]byte
	var written int
	var last int32
	for _, triangle := range t.Triangles {
		for _, idx := range triangle {
			value := idx - last
			n := binary.PutVarint(buf[:], int64(value))
			for p := buf[:n]; len(p) > 0; p = p[n:] {
				var err error
				if n, err = w.Write(p); err != nil {
					return err
				}
				written += n
			}
			last = idx
		}
	}
	log.Infof("compressed tin indices in bytes: %d (%d)\n",
		written, 3*4*len(t.Triangles))
	return nil
}

func (t *Tin) serializeVerticesV1(w io.Writer) error {
	if err := binary.Write(
		w, binary.LittleEndian, uint32(len(t.Vertices))); err != nil {
		return err
	}
	var err error
	vwrite := func(v float64) {
		if err == nil {
			err = binary.Write(w, binary.LittleEndian, math.Float64bits(v))
		}
	}
	for _, v := range t.Vertices {
		vwrite(v.X)
		vwrite(v.Y)
		vwrite(v.Z)
	}
	if err != nil {
		return err
	}
	log.Infof("vertices %d (%d)\n", len(t.Vertices), len(t.Vertices)*3*8)
	return nil
}

func (s *STRTree) deserializeV1(r *bufio.Reader) error {
	return serializer(r, s,
		(*STRTree).deserializeTinV1,
		(*STRTree).deserializeEntries,
		(*STRTree).deserializeIndexV1,
		(*STRTree).deserializeBBoxesV1,
	)
}

func (s *STRTree) deserializeBBoxesV1(r *bufio.Reader) error {
	var numBBoxes int32
	if err := binary.Read(r, binary.LittleEndian, &numBBoxes); err != nil {
		return err
	}
	bboxes := make([]Box2D, numBBoxes)
	s.bboxes = bboxes
	var err error
	read := func(v *float64) {
		if err == nil {
			err = binary.Read(r, binary.LittleEndian, v)
		}
	}
	for i := range bboxes {
		read(&bboxes[i].X1)
		read(&bboxes[i].Y1)
		read(&bboxes[i].X2)
		read(&bboxes[i].Y2)
	}
	return err
}

func (s *STRTree) deserializeIndexV1(r *bufio.Reader) error {
	var numIndex int32
	if err := binary.Read(r, binary.LittleEndian, &numIndex); err != nil {
		return err
	}
	index := make([]int32, numIndex)
	s.index = index
	var last int32
	for i := range index {
		v, err := binary.ReadVarint(r)
		if err != nil {
			return err
		}
		value := int32(v) + last
		index[i] = value
		last = value
	}
	return nil
}

func (s *STRTree) deserializeTinV1(r *bufio.Reader) error {
	s.tin = new(Tin)
	return s.tin.deserializeV1(r)
}

// deserializeV1 restores a TIN from a binary representation.
func (t *Tin) deserializeV1(r *bufio.Reader) error {
	return serializer(r, t,
		(*Tin).deserializeEPSG,
		(*Tin).deserializeExtent,
		(*Tin).deserializeVerticesV1,
		(*Tin).deserializeTrianglesV1,
	)
}

func (t *Tin) deserializeVerticesV1(r *bufio.Reader) error {
	var numVertices uint32
	if err := binary.Read(r, binary.LittleEndian, &numVertices); err != nil {
		return err
	}
	log.Infof("vertices: %d\n", numVertices)
	vertices := make([]Vertex, numVertices)
	t.Vertices = vertices
	for i := range vertices {
		if err := vertices[i].Read(r); err != nil {
			return err
		}
	}
	return nil
}

func (t *Tin) deserializeTrianglesV1(r *bufio.Reader) error {
	var numTriangles uint32
	if err := binary.Read(r, binary.LittleEndian, &numTriangles); err != nil {
		return err
	}
	log.Infof("triangles: %d\n", numTriangles)
	indices := make([]int32, 3*numTriangles)
	triangles := make([][]int32, numTriangles)
	t.Triangles = triangles
	var last int32
	for i := range triangles {
		tri := indices[:3]
		indices = indices[3:]
		triangles[i] = tri
		for j := range tri {
			v, err := binary.ReadVarint(r)
			if err != nil {
				return err
			}
			value := int32(v) + last
			tri[j] = value
			last = value
		}
	}
	return nil
}