Mercurial > gemma
comparison 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 |
comparison
equal
deleted
inserted
replaced
5672:b1a10654bf0f | 5710:37c8feeecb4d |
---|---|
1 // This is Free Software under GNU Affero General Public License v >= 3.0 | |
2 // without warranty, see README.md and license for details. | |
3 // | |
4 // SPDX-License-Identifier: AGPL-3.0-or-later | |
5 // License-Filename: LICENSES/AGPL-3.0.txt | |
6 // | |
7 // Copyright (C) 2018 by via donau | |
8 // – Österreichische Wasserstraßen-Gesellschaft mbH | |
9 // Software engineering by Intevation GmbH | |
10 // | |
11 // Author(s): | |
12 // * Sascha L. Teichmann <sascha.teichmann@intevation.de> | |
13 | |
14 package mesh | |
15 | |
16 import ( | |
17 "bufio" | |
18 "bytes" | |
19 "compress/gzip" | |
20 "encoding/binary" | |
21 "fmt" | |
22 "io" | |
23 | |
24 "gemma.intevation.de/gemma/pkg/log" | |
25 ) | |
26 | |
27 // Version is current version of the format the mesh index is stored in. | |
28 const Version = 2 | |
29 | |
30 // magicHeader is a magic header to tell if the data blob is a mesh index. | |
31 const magicHeader = "SR3D" | |
32 | |
33 // coalesceVersion returns the most recent version if version is less or equal zero. | |
34 func coalesceVersion(version int) int { | |
35 if version > 0 { | |
36 return version | |
37 } | |
38 return Version | |
39 } | |
40 | |
41 // OptimizeForSerialization apply version specific storage optimizations | |
42 // before serialization. | |
43 func (s *STRTree) OptimizeForSerialization(version int) { | |
44 version = coalesceVersion(version) | |
45 if version == 2 { | |
46 s.optimizeForSerializationV2() | |
47 } | |
48 } | |
49 | |
50 // Bytes serializes this tree to a byte slice. | |
51 func (s *STRTree) Bytes(version int) ([]byte, int, error) { | |
52 var buf bytes.Buffer | |
53 w, err := gzip.NewWriterLevel(&buf, gzip.BestSpeed) | |
54 if err != nil { | |
55 return nil, 0, err | |
56 } | |
57 version = coalesceVersion(version) | |
58 if err := s.serializeVn(w, version); err != nil { | |
59 return nil, 0, err | |
60 } | |
61 if err := w.Close(); err != nil { | |
62 return nil, 0, err | |
63 } | |
64 return buf.Bytes(), version, nil | |
65 } | |
66 | |
67 func (s *STRTree) serializeVn(w io.Writer, version int) error { | |
68 switch version { | |
69 case 1: | |
70 return s.serializeV1(w) | |
71 case 2: | |
72 return s.serializeV2(w) | |
73 default: | |
74 return fmt.Errorf("cannot serialize mesh version %d", version) | |
75 } | |
76 } | |
77 | |
78 // FromBytes restores a STRTree from a binary representation. | |
79 func (s *STRTree) FromBytes(data []byte, version int) error { | |
80 version = coalesceVersion(version) | |
81 r, err := gzip.NewReader(bytes.NewReader(data)) | |
82 if err != nil { | |
83 return err | |
84 } | |
85 return s.deserialize(bufio.NewReader(r), version) | |
86 } | |
87 | |
88 func (s *STRTree) deserialize(r *bufio.Reader, version int) error { | |
89 header, err := r.Peek(8) | |
90 if err != nil { | |
91 return err | |
92 } | |
93 if bytes.HasPrefix(header, []byte(magicHeader)) { | |
94 realVersion := int(binary.LittleEndian.Uint32(header[4:])) | |
95 if realVersion != version { | |
96 return fmt.Errorf("mesh version mismatch: Have %d expect %d", | |
97 realVersion, version) | |
98 } | |
99 // Skip the header | |
100 if _, err := r.Discard(8); err != nil { | |
101 return err | |
102 } | |
103 return s.deserializeVn(r, realVersion) | |
104 } | |
105 return s.deserializeV1(r) | |
106 } | |
107 | |
108 func (s *STRTree) deserializeVn(r *bufio.Reader, version int) error { | |
109 switch version { | |
110 case 1: | |
111 return s.deserializeV1(r) | |
112 case 2: | |
113 return s.deserializeV2(r) | |
114 default: | |
115 return fmt.Errorf("cannot deserialize mesh version %d", version) | |
116 } | |
117 } | |
118 | |
119 // serializer is a generic function to apply a chain of | |
120 // serializer/deserializer functions to an object given a reader or writer. | |
121 func serializer[T, S any]( | |
122 s S, | |
123 t T, | |
124 fns ...func(T, S) error, | |
125 ) error { | |
126 for _, fn := range fns { | |
127 if err := fn(t, s); err != nil { | |
128 return err | |
129 } | |
130 } | |
131 return nil | |
132 } | |
133 | |
134 func (s *STRTree) serializeEntries(w io.Writer) error { | |
135 return binary.Write(w, binary.LittleEndian, uint8(s.Entries)) | |
136 } | |
137 | |
138 func (s *STRTree) deserializeEntries(r *bufio.Reader) error { | |
139 var numEntries uint8 | |
140 if err := binary.Read(r, binary.LittleEndian, &numEntries); err != nil { | |
141 return err | |
142 } | |
143 s.Entries = int(numEntries) | |
144 return nil | |
145 } | |
146 | |
147 func (t *Tin) serializeExtent(w io.Writer) error { | |
148 if err := t.Min.Write(w); err != nil { | |
149 return err | |
150 } | |
151 return t.Max.Write(w) | |
152 } | |
153 | |
154 func (t *Tin) deserializeExtent(r *bufio.Reader) error { | |
155 if err := t.Min.Read(r); err != nil { | |
156 return err | |
157 } | |
158 if err := t.Max.Read(r); err != nil { | |
159 return err | |
160 } | |
161 log.Infof("BBOX: [[%f, %f, %f], [%f, %f, %f]]\n", | |
162 t.Min.X, t.Min.Y, t.Min.Z, | |
163 t.Max.X, t.Max.Y, t.Max.Z) | |
164 return nil | |
165 } | |
166 | |
167 func (t *Tin) serializeEPSG(w io.Writer) error { | |
168 return binary.Write(w, binary.LittleEndian, t.EPSG) | |
169 } | |
170 | |
171 func (t *Tin) deserializeEPSG(r *bufio.Reader) error { | |
172 if err := binary.Read(r, binary.LittleEndian, &t.EPSG); err != nil { | |
173 return err | |
174 } | |
175 log.Infof("EPSG: %d\n", t.EPSG) | |
176 return nil | |
177 } | |
178 | |
179 func serializeHeader() func(*STRTree, io.Writer) error { | |
180 return func(_ *STRTree, w io.Writer) error { | |
181 _, err := w.Write([]byte(magicHeader)) | |
182 return err | |
183 } | |
184 } | |
185 | |
186 func serializeVersion(version int) func(*STRTree, io.Writer) error { | |
187 return func(_ *STRTree, w io.Writer) error { | |
188 return binary.Write(w, binary.LittleEndian, uint32(version)) | |
189 } | |
190 } |