Mercurial > gemma
comparison cmd/tin2octree/tin.go @ 661:af1d4d44a88a octree
Experimental tin octree indexer.
author | Sascha L. Teichmann <sascha.teichmann@intevation.de> |
---|---|
date | Tue, 18 Sep 2018 00:11:32 +0200 |
parents | |
children | a3d722e1f593 |
comparison
equal
deleted
inserted
replaced
660:79db27e3a999 | 661:af1d4d44a88a |
---|---|
1 package main | |
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 ( | |
19 wkbXDR byte = 0 | |
20 wkbNDR byte = 1 | |
21 wkbTinZ uint32 = 1000 + 16 | |
22 wkbTriangleZ uint32 = 1000 + 17 | |
23 ) | |
24 | |
25 type tin struct { | |
26 vertices []vertex | |
27 triangles [][]int32 | |
28 | |
29 min vertex | |
30 max vertex | |
31 } | |
32 | |
33 func (t *tin) FromWKB(data []byte) error { | |
34 log.Printf("data length %d\n", len(data)) | |
35 | |
36 r := bytes.NewReader(data) | |
37 | |
38 endian, err := r.ReadByte() | |
39 | |
40 var order binary.ByteOrder | |
41 | |
42 switch { | |
43 case err != nil: | |
44 return err | |
45 case endian == wkbNDR: | |
46 order = binary.LittleEndian | |
47 case endian == wkbXDR: | |
48 order = binary.BigEndian | |
49 default: | |
50 return fmt.Errorf("unknown byte order %x", endian) | |
51 } | |
52 | |
53 var geomType uint32 | |
54 err = binary.Read(r, order, &geomType) | |
55 | |
56 switch { | |
57 case err != nil: | |
58 return err | |
59 case geomType != wkbTinZ: | |
60 return fmt.Errorf("unknown geometry type %x", geomType) | |
61 } | |
62 | |
63 var num uint32 | |
64 if err = binary.Read(r, order, &num); err != nil { | |
65 return err | |
66 } | |
67 | |
68 vertices := make([]vertex, 0, 100000) | |
69 | |
70 var v vertex | |
71 | |
72 v2i := make(map[vertex]int32, 100000) | |
73 | |
74 var indexPool []int32 | |
75 | |
76 allocIndices := func() []int32 { | |
77 if len(indexPool) == 0 { | |
78 indexPool = make([]int32, 3*8*1024) | |
79 } | |
80 ids := indexPool[:3] | |
81 indexPool = indexPool[3:] | |
82 return ids | |
83 } | |
84 | |
85 var triangles [][]int32 | |
86 | |
87 min := vertex{math.MaxFloat64, math.MaxFloat64, math.MaxFloat64} | |
88 max := vertex{-math.MaxFloat64, -math.MaxFloat64, -math.MaxFloat64} | |
89 | |
90 for i := uint32(0); i < num; i++ { | |
91 | |
92 endian, err = r.ReadByte() | |
93 switch { | |
94 case err != nil: | |
95 return err | |
96 case endian == wkbNDR: | |
97 order = binary.LittleEndian | |
98 case endian == wkbXDR: | |
99 order = binary.BigEndian | |
100 default: | |
101 return fmt.Errorf("unknown byte order %x", endian) | |
102 } | |
103 | |
104 err = binary.Read(r, order, &geomType) | |
105 switch { | |
106 case err != nil: | |
107 return err | |
108 case geomType != wkbTriangleZ: | |
109 return fmt.Errorf("unknown geometry type %d", geomType) | |
110 } | |
111 | |
112 var rings uint32 | |
113 if err = binary.Read(r, order, &rings); err != nil { | |
114 return err | |
115 } | |
116 triangle := allocIndices() | |
117 | |
118 for ring := uint32(0); ring < rings; ring++ { | |
119 var npoints uint32 | |
120 if err = binary.Read(r, order, &npoints); err != nil { | |
121 return err | |
122 } | |
123 | |
124 if npoints < 3 { | |
125 return errTooLessPoints | |
126 } | |
127 | |
128 for p := uint32(0); p < npoints; p++ { | |
129 var x, y, z uint64 | |
130 for _, addr := range []*uint64{&x, &y, &z} { | |
131 if err = binary.Read(r, order, addr); err != nil { | |
132 return err | |
133 } | |
134 } | |
135 if p >= 3 || ring >= 1 { | |
136 // Don't store the forth point. | |
137 continue | |
138 } | |
139 // Do this conversion later to spare reflect calls | |
140 // and allocs in binary.Read. | |
141 v.x = math.Float64frombits(x) | |
142 v.y = math.Float64frombits(y) | |
143 v.z = math.Float64frombits(z) | |
144 idx, found := v2i[v] | |
145 if !found { | |
146 idx = int32(len(vertices)) | |
147 v2i[v] = idx | |
148 vertices = append(vertices, v) | |
149 min.minimize(v) | |
150 max.maximize(v) | |
151 } | |
152 triangle[p] = idx | |
153 } | |
154 } | |
155 triangles = append(triangles, triangle) | |
156 } | |
157 | |
158 *t = tin{ | |
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 (v *vertex) write(w io.Writer) error { | |
178 for _, addr := range []*float64{&v.x, &v.y, &v.z} { | |
179 if err := binary.Write( | |
180 w, binary.LittleEndian, math.Float64bits(*addr)); err != nil { | |
181 return err | |
182 } | |
183 } | |
184 return nil | |
185 } | |
186 | |
187 func (t *tin) Serialize(w io.Writer) error { | |
188 | |
189 if err := t.min.write(w); err != nil { | |
190 return err | |
191 } | |
192 if err := t.max.write(w); err != nil { | |
193 return err | |
194 } | |
195 | |
196 if err := binary.Write( | |
197 w, binary.LittleEndian, uint32(len(t.vertices))); err != nil { | |
198 return err | |
199 } | |
200 | |
201 for _, v := range t.vertices { | |
202 if err := v.write(w); err != nil { | |
203 return err | |
204 } | |
205 } | |
206 log.Printf("vertices %d (%d)\n", len(t.vertices), len(t.vertices)*3*8) | |
207 | |
208 if err := binary.Write( | |
209 w, binary.LittleEndian, uint32(len(t.triangles))); err != nil { | |
210 return err | |
211 } | |
212 | |
213 var buf [binary.MaxVarintLen32]byte | |
214 var written int | |
215 var last int32 | |
216 for _, triangle := range t.triangles { | |
217 for _, idx := range triangle { | |
218 value := idx - last | |
219 n := binary.PutVarint(buf[:], int64(value)) | |
220 for p := buf[:n]; len(p) > 0; p = p[n:] { | |
221 var err error | |
222 if n, err = w.Write(p); err != nil { | |
223 return err | |
224 } | |
225 written += n | |
226 } | |
227 last = idx | |
228 } | |
229 } | |
230 log.Printf("compressed tin indices in bytes: %d (%d)\n", | |
231 written, 3*4*len(t.triangles)) | |
232 | |
233 return nil | |
234 } |