Mercurial > gemma
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)) + } +}