Mercurial > gemma
comparison pkg/octree/tin.go @ 968:a4fe07a21ba7
Moved octree builder into octree package to be reusable by the sounding result import job.
author | Sascha L. Teichmann <sascha.teichmann@intevation.de> |
---|---|
date | Wed, 17 Oct 2018 16:00:49 +0200 |
parents | |
children | f9fb6c399f3f |
comparison
equal
deleted
inserted
replaced
967:2025074ad835 | 968:a4fe07a21ba7 |
---|---|
1 package octree | |
2 | |
3 import ( | |
4 "bytes" | |
5 "encoding/binary" | |
6 "errors" | |
7 "fmt" | |
8 "io" | |
9 "log" | |
10 "math" | |
11 ) | |
12 | |
13 var ( | |
14 errNoByteSlice = errors.New("Not a byte slice") | |
15 errTooLessPoints = errors.New("Too less points") | |
16 ) | |
17 | |
18 const wgs84 = 4326 | |
19 | |
20 type Tin struct { | |
21 EPSG uint32 | |
22 Vertices []Vertex | |
23 Triangles [][]int32 | |
24 | |
25 Min Vertex | |
26 Max Vertex | |
27 } | |
28 | |
29 func (t *Tin) FromWKB(data []byte) error { | |
30 log.Printf("data length %d\n", len(data)) | |
31 | |
32 r := bytes.NewReader(data) | |
33 | |
34 endian, err := r.ReadByte() | |
35 | |
36 var order binary.ByteOrder | |
37 | |
38 switch { | |
39 case err != nil: | |
40 return err | |
41 case endian == wkbNDR: | |
42 order = binary.LittleEndian | |
43 case endian == wkbXDR: | |
44 order = binary.BigEndian | |
45 default: | |
46 return fmt.Errorf("unknown byte order %x", endian) | |
47 } | |
48 | |
49 var geomType uint32 | |
50 err = binary.Read(r, order, &geomType) | |
51 | |
52 switch { | |
53 case err != nil: | |
54 return err | |
55 case geomType != wkbTinZ: | |
56 return fmt.Errorf("unknown geometry type %x", geomType) | |
57 } | |
58 | |
59 var num uint32 | |
60 if err = binary.Read(r, order, &num); err != nil { | |
61 return err | |
62 } | |
63 | |
64 vertices := make([]Vertex, 0, 100000) | |
65 | |
66 var v Vertex | |
67 | |
68 v2i := make(map[Vertex]int32, 100000) | |
69 | |
70 var indexPool []int32 | |
71 | |
72 allocIndices := func() []int32 { | |
73 if len(indexPool) == 0 { | |
74 indexPool = make([]int32, 3*8*1024) | |
75 } | |
76 ids := indexPool[:3] | |
77 indexPool = indexPool[3:] | |
78 return ids | |
79 } | |
80 | |
81 var triangles [][]int32 | |
82 | |
83 min := Vertex{math.MaxFloat64, math.MaxFloat64, math.MaxFloat64} | |
84 max := Vertex{-math.MaxFloat64, -math.MaxFloat64, -math.MaxFloat64} | |
85 | |
86 for i := uint32(0); i < num; i++ { | |
87 | |
88 endian, err = r.ReadByte() | |
89 switch { | |
90 case err != nil: | |
91 return err | |
92 case endian == wkbNDR: | |
93 order = binary.LittleEndian | |
94 case endian == wkbXDR: | |
95 order = binary.BigEndian | |
96 default: | |
97 return fmt.Errorf("unknown byte order %x", endian) | |
98 } | |
99 | |
100 err = binary.Read(r, order, &geomType) | |
101 switch { | |
102 case err != nil: | |
103 return err | |
104 case geomType != wkbTriangleZ: | |
105 return fmt.Errorf("unknown geometry type %d", geomType) | |
106 } | |
107 | |
108 var rings uint32 | |
109 if err = binary.Read(r, order, &rings); err != nil { | |
110 return err | |
111 } | |
112 triangle := allocIndices() | |
113 | |
114 for ring := uint32(0); ring < rings; ring++ { | |
115 var npoints uint32 | |
116 if err = binary.Read(r, order, &npoints); err != nil { | |
117 return err | |
118 } | |
119 | |
120 if npoints < 3 { | |
121 return errTooLessPoints | |
122 } | |
123 | |
124 for p := uint32(0); p < npoints; p++ { | |
125 var x, y, z uint64 | |
126 for _, addr := range []*uint64{&x, &y, &z} { | |
127 if err = binary.Read(r, order, addr); err != nil { | |
128 return err | |
129 } | |
130 } | |
131 if p >= 3 || ring >= 1 { | |
132 // Don't store the forth point. | |
133 continue | |
134 } | |
135 // Do this conversion later to spare reflect calls | |
136 // and allocs in binary.Read. | |
137 v.X = math.Float64frombits(x) | |
138 v.Y = math.Float64frombits(y) | |
139 v.Z = math.Float64frombits(z) | |
140 idx, found := v2i[v] | |
141 if !found { | |
142 idx = int32(len(vertices)) | |
143 v2i[v] = idx | |
144 vertices = append(vertices, v) | |
145 min.Minimize(v) | |
146 max.Maximize(v) | |
147 } | |
148 triangle[p] = idx | |
149 } | |
150 } | |
151 triangles = append(triangles, triangle) | |
152 } | |
153 | |
154 log.Printf("bbox: [[%f, %f], [%f, %f]]\n", | |
155 min.X, min.Y, max.X, max.Y) | |
156 | |
157 *t = Tin{ | |
158 EPSG: wgs84, | |
159 Vertices: vertices, | |
160 Triangles: triangles, | |
161 Min: min, | |
162 Max: max, | |
163 } | |
164 | |
165 return nil | |
166 } | |
167 | |
168 func (t *Tin) Scan(raw interface{}) error { | |
169 | |
170 data, ok := raw.([]byte) | |
171 if !ok { | |
172 return errNoByteSlice | |
173 } | |
174 return t.FromWKB(data) | |
175 } | |
176 | |
177 func (t *Tin) Serialize(w io.Writer) error { | |
178 | |
179 if err := binary.Write(w, binary.LittleEndian, t.EPSG); err != nil { | |
180 return err | |
181 } | |
182 | |
183 if err := t.Min.Write(w); err != nil { | |
184 return err | |
185 } | |
186 if err := t.Max.Write(w); err != nil { | |
187 return err | |
188 } | |
189 | |
190 if err := binary.Write( | |
191 w, binary.LittleEndian, uint32(len(t.Vertices))); err != nil { | |
192 return err | |
193 } | |
194 | |
195 for _, v := range t.Vertices { | |
196 if err := v.Write(w); err != nil { | |
197 return err | |
198 } | |
199 } | |
200 log.Printf("vertices %d (%d)\n", len(t.Vertices), len(t.Vertices)*3*8) | |
201 | |
202 if err := binary.Write( | |
203 w, binary.LittleEndian, uint32(len(t.Triangles))); err != nil { | |
204 return err | |
205 } | |
206 | |
207 var buf [binary.MaxVarintLen32]byte | |
208 var written int | |
209 var last int32 | |
210 for _, triangle := range t.Triangles { | |
211 for _, idx := range triangle { | |
212 value := idx - last | |
213 n := binary.PutVarint(buf[:], int64(value)) | |
214 for p := buf[:n]; len(p) > 0; p = p[n:] { | |
215 var err error | |
216 if n, err = w.Write(p); err != nil { | |
217 return err | |
218 } | |
219 written += n | |
220 } | |
221 last = idx | |
222 } | |
223 } | |
224 log.Printf("compressed tin indices in bytes: %d (%d)\n", | |
225 written, 3*4*len(t.Triangles)) | |
226 | |
227 return nil | |
228 } |