Mercurial > gemma
comparison pkg/mesh/tin.go @ 4827:f4abfd0ee8ad remove-octree-debris
Renamed octree package to mesh as there is no octree any more.
author | Sascha L. Teichmann <sascha.teichmann@intevation.de> |
---|---|
date | Tue, 05 Nov 2019 14:30:22 +0100 |
parents | pkg/octree/tin.go@f5492fda097c |
children | 4847ac70103a |
comparison
equal
deleted
inserted
replaced
4826:ec5afada70ec | 4827:f4abfd0ee8ad |
---|---|
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 "bytes" | |
18 "encoding/binary" | |
19 "errors" | |
20 "fmt" | |
21 "io" | |
22 "log" | |
23 "math" | |
24 | |
25 "gemma.intevation.de/gemma/pkg/models" | |
26 "gemma.intevation.de/gemma/pkg/wkb" | |
27 ) | |
28 | |
29 var ( | |
30 errNoByteSlice = errors.New("Not a byte slice") | |
31 errTooLessPoints = errors.New("Too less points") | |
32 ) | |
33 | |
34 // Tin stores a mesh of triangles with common vertices. | |
35 type Tin struct { | |
36 // EPSG holds the projection. | |
37 EPSG uint32 | |
38 // Vertices are the shared vertices. | |
39 Vertices []Vertex | |
40 // Triangles are the triangles. | |
41 Triangles [][]int32 | |
42 | |
43 // Min is the lower left corner of the bbox. | |
44 Min Vertex | |
45 // Max is the upper right corner of the bbox. | |
46 Max Vertex | |
47 } | |
48 | |
49 func (t *Tin) Clip(polygon *Polygon) map[int32]struct{} { | |
50 var tree STRTree | |
51 tree.Build(t) | |
52 return tree.Clip(polygon) | |
53 } | |
54 | |
55 // FromWKB constructs the TIN from a WKB representation. | |
56 // Shared vertices are identified and referenced by the | |
57 // same index. | |
58 func (t *Tin) FromWKB(data []byte) error { | |
59 log.Printf("info: data length %d\n", len(data)) | |
60 | |
61 r := bytes.NewReader(data) | |
62 | |
63 endian, err := r.ReadByte() | |
64 | |
65 var order binary.ByteOrder | |
66 | |
67 switch { | |
68 case err != nil: | |
69 return err | |
70 case endian == wkb.NDR: | |
71 order = binary.LittleEndian | |
72 case endian == wkb.XDR: | |
73 order = binary.BigEndian | |
74 default: | |
75 return fmt.Errorf("unknown byte order %x", endian) | |
76 } | |
77 | |
78 var geomType uint32 | |
79 err = binary.Read(r, order, &geomType) | |
80 | |
81 switch { | |
82 case err != nil: | |
83 return err | |
84 case geomType != wkb.TinZ: | |
85 return fmt.Errorf("unknown geometry type %x", geomType) | |
86 } | |
87 | |
88 var num uint32 | |
89 if err = binary.Read(r, order, &num); err != nil { | |
90 return err | |
91 } | |
92 | |
93 vertices := make([]Vertex, 0, 100000) | |
94 | |
95 var v Vertex | |
96 | |
97 v2i := make(map[Vertex]int32, 100000) | |
98 | |
99 var indexPool []int32 | |
100 | |
101 allocIndices := func() []int32 { | |
102 if len(indexPool) == 0 { | |
103 indexPool = make([]int32, 3*8*1024) | |
104 } | |
105 ids := indexPool[:3] | |
106 indexPool = indexPool[3:] | |
107 return ids | |
108 } | |
109 | |
110 var triangles [][]int32 | |
111 | |
112 min := Vertex{math.MaxFloat64, math.MaxFloat64, math.MaxFloat64} | |
113 max := Vertex{-math.MaxFloat64, -math.MaxFloat64, -math.MaxFloat64} | |
114 | |
115 for i := uint32(0); i < num; i++ { | |
116 | |
117 endian, err = r.ReadByte() | |
118 switch { | |
119 case err != nil: | |
120 return err | |
121 case endian == wkb.NDR: | |
122 order = binary.LittleEndian | |
123 case endian == wkb.XDR: | |
124 order = binary.BigEndian | |
125 default: | |
126 return fmt.Errorf("unknown byte order %x", endian) | |
127 } | |
128 | |
129 err = binary.Read(r, order, &geomType) | |
130 switch { | |
131 case err != nil: | |
132 return err | |
133 case geomType != wkb.TriangleZ: | |
134 return fmt.Errorf("unknown geometry type %d", geomType) | |
135 } | |
136 | |
137 var rings uint32 | |
138 if err = binary.Read(r, order, &rings); err != nil { | |
139 return err | |
140 } | |
141 triangle := allocIndices() | |
142 | |
143 for ring := uint32(0); ring < rings; ring++ { | |
144 var npoints uint32 | |
145 if err = binary.Read(r, order, &npoints); err != nil { | |
146 return err | |
147 } | |
148 | |
149 if npoints < 3 { | |
150 return errTooLessPoints | |
151 } | |
152 | |
153 for p := uint32(0); p < npoints; p++ { | |
154 var x, y, z uint64 | |
155 for _, addr := range []*uint64{&x, &y, &z} { | |
156 if err = binary.Read(r, order, addr); err != nil { | |
157 return err | |
158 } | |
159 } | |
160 if p >= 3 || ring >= 1 { | |
161 // Don't store the forth point. | |
162 continue | |
163 } | |
164 // Do this conversion later to spare reflect calls | |
165 // and allocs in binary.Read. | |
166 v.X = math.Float64frombits(x) | |
167 v.Y = math.Float64frombits(y) | |
168 v.Z = math.Float64frombits(z) | |
169 idx, found := v2i[v] | |
170 if !found { | |
171 idx = int32(len(vertices)) | |
172 v2i[v] = idx | |
173 vertices = append(vertices, v) | |
174 min.Minimize(v) | |
175 max.Maximize(v) | |
176 } | |
177 triangle[p] = idx | |
178 } | |
179 } | |
180 triangles = append(triangles, triangle) | |
181 } | |
182 | |
183 log.Printf("info: bbox: [[%f, %f], [%f, %f]]\n", | |
184 min.X, min.Y, max.X, max.Y) | |
185 | |
186 *t = Tin{ | |
187 EPSG: models.WGS84, | |
188 Vertices: vertices, | |
189 Triangles: triangles, | |
190 Min: min, | |
191 Max: max, | |
192 } | |
193 | |
194 return nil | |
195 } | |
196 | |
197 // Scan implements the sql.Scanner interface. | |
198 func (t *Tin) Scan(raw interface{}) error { | |
199 if raw == nil { | |
200 return nil | |
201 } | |
202 data, ok := raw.([]byte) | |
203 if !ok { | |
204 return errNoByteSlice | |
205 } | |
206 return t.FromWKB(data) | |
207 } | |
208 | |
209 func (t *Tin) serialize(w io.Writer) error { | |
210 | |
211 if err := binary.Write(w, binary.LittleEndian, t.EPSG); err != nil { | |
212 return err | |
213 } | |
214 | |
215 if err := t.Min.Write(w); err != nil { | |
216 return err | |
217 } | |
218 if err := t.Max.Write(w); err != nil { | |
219 return err | |
220 } | |
221 | |
222 if err := binary.Write( | |
223 w, binary.LittleEndian, uint32(len(t.Vertices))); err != nil { | |
224 return err | |
225 } | |
226 | |
227 var err error | |
228 vwrite := func(v float64) { | |
229 if err == nil { | |
230 err = binary.Write(w, binary.LittleEndian, math.Float64bits(v)) | |
231 } | |
232 } | |
233 | |
234 for _, v := range t.Vertices { | |
235 vwrite(v.X) | |
236 vwrite(v.Y) | |
237 vwrite(v.Z) | |
238 } | |
239 | |
240 if err != nil { | |
241 return err | |
242 } | |
243 log.Printf("info: vertices %d (%d)\n", len(t.Vertices), len(t.Vertices)*3*8) | |
244 | |
245 if err := binary.Write( | |
246 w, binary.LittleEndian, uint32(len(t.Triangles))); err != nil { | |
247 return err | |
248 } | |
249 | |
250 var buf [binary.MaxVarintLen32]byte | |
251 var written int | |
252 var last int32 | |
253 for _, triangle := range t.Triangles { | |
254 for _, idx := range triangle { | |
255 value := idx - last | |
256 n := binary.PutVarint(buf[:], int64(value)) | |
257 for p := buf[:n]; len(p) > 0; p = p[n:] { | |
258 var err error | |
259 if n, err = w.Write(p); err != nil { | |
260 return err | |
261 } | |
262 written += n | |
263 } | |
264 last = idx | |
265 } | |
266 } | |
267 log.Printf("info: compressed tin indices in bytes: %d (%d)\n", | |
268 written, 3*4*len(t.Triangles)) | |
269 | |
270 return nil | |
271 } |