view pkg/mesh/meshserialize_v1.go @ 5692:d920f0fa2f04 sr-v2

User generic serializer for serialization, too.
author Sascha L. Teichmann <sascha.teichmann@intevation.de>
date Mon, 12 Feb 2024 13:53:32 +0100
parents 9d2e74225104
children ef80748ae4f3
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).serializeV1,
		(*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
}