diff pkg/mesh/meshserialize.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 ef80748ae4f3
children 1ea1d3ef2258
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pkg/mesh/meshserialize.go	Tue Feb 20 21:28:56 2024 +0100
@@ -0,0 +1,190 @@
+// 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 (
+	"bufio"
+	"bytes"
+	"compress/gzip"
+	"encoding/binary"
+	"fmt"
+	"io"
+
+	"gemma.intevation.de/gemma/pkg/log"
+)
+
+// Version is current version of the format the mesh index is stored in.
+const Version = 2
+
+// magicHeader is a magic header to tell if the data blob is a mesh index.
+const magicHeader = "SR3D"
+
+// coalesceVersion returns the most recent version if version is less or equal zero.
+func coalesceVersion(version int) int {
+	if version > 0 {
+		return version
+	}
+	return Version
+}
+
+// OptimizeForSerialization apply version specific storage optimizations
+// before serialization.
+func (s *STRTree) OptimizeForSerialization(version int) {
+	version = coalesceVersion(version)
+	if version == 2 {
+		s.optimizeForSerializationV2()
+	}
+}
+
+// Bytes serializes this tree to a byte slice.
+func (s *STRTree) Bytes(version int) ([]byte, int, error) {
+	var buf bytes.Buffer
+	w, err := gzip.NewWriterLevel(&buf, gzip.BestSpeed)
+	if err != nil {
+		return nil, 0, err
+	}
+	version = coalesceVersion(version)
+	if err := s.serializeVn(w, version); err != nil {
+		return nil, 0, err
+	}
+	if err := w.Close(); err != nil {
+		return nil, 0, err
+	}
+	return buf.Bytes(), version, nil
+}
+
+func (s *STRTree) serializeVn(w io.Writer, version int) error {
+	switch version {
+	case 1:
+		return s.serializeV1(w)
+	case 2:
+		return s.serializeV2(w)
+	default:
+		return fmt.Errorf("cannot serialize mesh version %d", version)
+	}
+}
+
+// FromBytes restores a STRTree from a binary representation.
+func (s *STRTree) FromBytes(data []byte, version int) error {
+	version = coalesceVersion(version)
+	r, err := gzip.NewReader(bytes.NewReader(data))
+	if err != nil {
+		return err
+	}
+	return s.deserialize(bufio.NewReader(r), version)
+}
+
+func (s *STRTree) deserialize(r *bufio.Reader, version int) error {
+	header, err := r.Peek(8)
+	if err != nil {
+		return err
+	}
+	if bytes.HasPrefix(header, []byte(magicHeader)) {
+		realVersion := int(binary.LittleEndian.Uint32(header[4:]))
+		if realVersion != version {
+			return fmt.Errorf("mesh version mismatch: Have %d expect %d",
+				realVersion, version)
+		}
+		// Skip the header
+		if _, err := r.Discard(8); err != nil {
+			return err
+		}
+		return s.deserializeVn(r, realVersion)
+	}
+	return s.deserializeV1(r)
+}
+
+func (s *STRTree) deserializeVn(r *bufio.Reader, version int) error {
+	switch version {
+	case 1:
+		return s.deserializeV1(r)
+	case 2:
+		return s.deserializeV2(r)
+	default:
+		return fmt.Errorf("cannot deserialize mesh version %d", version)
+	}
+}
+
+// serializer is a generic function to apply a chain of
+// serializer/deserializer functions to an object given a reader or writer.
+func serializer[T, S any](
+	s S,
+	t T,
+	fns ...func(T, S) error,
+) error {
+	for _, fn := range fns {
+		if err := fn(t, s); err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+func (s *STRTree) serializeEntries(w io.Writer) error {
+	return binary.Write(w, binary.LittleEndian, uint8(s.Entries))
+}
+
+func (s *STRTree) deserializeEntries(r *bufio.Reader) error {
+	var numEntries uint8
+	if err := binary.Read(r, binary.LittleEndian, &numEntries); err != nil {
+		return err
+	}
+	s.Entries = int(numEntries)
+	return nil
+}
+
+func (t *Tin) serializeExtent(w io.Writer) error {
+	if err := t.Min.Write(w); err != nil {
+		return err
+	}
+	return t.Max.Write(w)
+}
+
+func (t *Tin) deserializeExtent(r *bufio.Reader) error {
+	if err := t.Min.Read(r); err != nil {
+		return err
+	}
+	if err := t.Max.Read(r); err != nil {
+		return err
+	}
+	log.Infof("BBOX: [[%f, %f, %f], [%f, %f, %f]]\n",
+		t.Min.X, t.Min.Y, t.Min.Z,
+		t.Max.X, t.Max.Y, t.Max.Z)
+	return nil
+}
+
+func (t *Tin) serializeEPSG(w io.Writer) error {
+	return binary.Write(w, binary.LittleEndian, t.EPSG)
+}
+
+func (t *Tin) deserializeEPSG(r *bufio.Reader) error {
+	if err := binary.Read(r, binary.LittleEndian, &t.EPSG); err != nil {
+		return err
+	}
+	log.Infof("EPSG: %d\n", t.EPSG)
+	return nil
+}
+
+func serializeHeader() func(*STRTree, io.Writer) error {
+	return func(_ *STRTree, w io.Writer) error {
+		_, err := w.Write([]byte(magicHeader))
+		return err
+	}
+}
+
+func serializeVersion(version int) func(*STRTree, io.Writer) error {
+	return func(_ *STRTree, w io.Writer) error {
+		return binary.Write(w, binary.LittleEndian, uint32(version))
+	}
+}