comparison pkg/octree/tree.go @ 2516:1ec4c5633eb6 octree-diff

Clip STR tree and not Octree.
author Sascha L. Teichmann <sascha.teichmann@intevation.de>
date Tue, 05 Mar 2019 17:08:16 +0100
parents e0a7571ac13a
children 7686c7c23506
comparison
equal deleted inserted replaced
2515:6bcaa8bf2603 2516:1ec4c5633eb6
12 // * Sascha L. Teichmann <sascha.teichmann@intevation.de> 12 // * Sascha L. Teichmann <sascha.teichmann@intevation.de>
13 13
14 package octree 14 package octree
15 15
16 import ( 16 import (
17 "fmt"
18 "log"
19 "math" 17 "math"
20 "os"
21 ) 18 )
22 19
23 // Tree is an Octree holding triangles. 20 // Tree is an Octree holding triangles.
24 type Tree struct { 21 type Tree struct {
25 // EPSG is the projection. 22 // EPSG is the projection.
47 var scale = [4][4]float64{ 44 var scale = [4][4]float64{
48 {0.0, 0.0, 0.5, 0.5}, 45 {0.0, 0.0, 0.5, 0.5},
49 {0.5, 0.0, 1.0, 0.5}, 46 {0.5, 0.0, 1.0, 0.5},
50 {0.0, 0.5, 0.5, 1.0}, 47 {0.0, 0.5, 0.5, 1.0},
51 {0.5, 0.5, 1.0, 1.0}, 48 {0.5, 0.5, 1.0, 1.0},
52 }
53
54 func (ot *Tree) Dump() error {
55 fake, err := os.Create("/tmp/dump.geojson")
56 if err != nil {
57 return err
58 }
59 defer fake.Close()
60
61 fmt.Fprintln(fake,
62 `{
63 "crs": {
64 "type": "name",
65 "properties": {
66 "name": "urn:ogc:def:crs:EPSG::32633"
67 }
68 },
69
70 "type": "FeatureCollection",
71 "features": [`)
72
73 first := true
74
75 already := make(map[int32]struct{})
76
77 stack := []int32{1}
78 for len(stack) > 0 {
79 pos := stack[len(stack)-1]
80 stack = stack[:len(stack)-1]
81
82 if pos > 0 { // node
83 index := ot.index[pos:]
84 if len(index) > 8 {
85 index = index[:8]
86 }
87 for i := range index {
88 if index[i] != 0 {
89 stack = append(stack, index[i])
90 }
91 }
92 } else {
93 pos = -pos - 1
94 n := ot.index[pos]
95 indices := ot.index[pos+1 : pos+1+n]
96 for _, index := range indices {
97 if _, found := already[index]; found {
98 continue
99 }
100 already[index] = struct{}{}
101 tri := ot.triangles[index]
102 t := Triangle{
103 ot.vertices[tri[0]],
104 ot.vertices[tri[1]],
105 ot.vertices[tri[2]],
106 }
107 if first {
108 first = false
109 } else {
110 fmt.Fprintln(fake, ",")
111 }
112 fmt.Fprintf(fake,
113 `{ "type": "Feature",
114 "properties": {
115 "id": %d
116 },
117 "geometry": {
118 "type": "Polygon",
119 "coordinates": [[
120 [ %.6f, %.6f ],
121 [ %.6f, %.6f ],
122 [ %.6f, %.6f ],
123 [ %.6f, %.6f ]]
124 ]
125 }
126 }`, index,
127 t[0].X, t[0].Y,
128 t[1].X, t[1].Y,
129 t[2].X, t[2].Y,
130 t[0].X, t[0].Y)
131 }
132 }
133 }
134
135 fmt.Fprintln(fake,
136 `]
137 }`)
138 return nil
139 }
140
141 func (ot *Tree) eliminate(removed map[int32]IntersectionType) {
142
143 var bad int
144
145 stack := []int32{1}
146 for len(stack) > 0 {
147 pos := stack[len(stack)-1]
148 stack = stack[:len(stack)-1]
149
150 if pos > 0 { // node
151 index := ot.index[pos:]
152 if len(index) > 8 {
153 index = index[:8]
154 }
155 for i := range index {
156 if index[i] != 0 {
157 stack = append(stack, index[i])
158 }
159 }
160 } else {
161 pos = -pos - 1
162 n := ot.index[pos]
163 indices := ot.index[pos+1 : pos+1+n]
164
165 for i := len(indices) - 1; i >= 0; i-- {
166 index := indices[i]
167 if t, found := removed[index]; found && t != IntersectionInside {
168 if i < len(indices)-1 {
169 copy(indices[i:], indices[i+1:])
170 }
171 indices[len(indices)-1] = 0
172 indices = indices[:len(indices)-1]
173 bad++
174 }
175 }
176 ot.index[pos] = int32(len(indices))
177 }
178 }
179
180 log.Printf("bad triangles: %d\n", bad)
181 }
182
183 func (ot *Tree) Clip(p *Polygon) {
184
185 /*
186 fake, _ := os.Create("/tmp/removed.geojson")
187 defer fake.Close()
188
189 fmt.Fprintln(fake,
190 `{
191 "crs": {
192 "type": "name",
193 "properties": {
194 "name": "urn:ogc:def:crs:EPSG::32633"
195 }
196 },
197
198 "type": "FeatureCollection",
199 "features": [`)
200
201 first := true
202 */
203
204 log.Printf("info: num triangles: %d\n", len(ot.triangles))
205
206 all := Box2D{ot.Min.X, ot.Min.Y, ot.Max.X, ot.Max.Y}
207
208 stack := []boxFrame{{1, all}}
209
210 triChecks := make(map[int32]IntersectionType)
211
212 var nodeTests int
213 var nodesClipped int
214 var trianglesClipped int
215 var nodesAllInside int
216
217 frames:
218 for len(stack) > 0 {
219 top := stack[len(stack)-1]
220 stack = stack[:len(stack)-1]
221
222 if top.pos > 0 { // node
223 nodeTests++
224 switch p.IntersectionBox2D(top.Box2D) {
225 case IntersectionInside:
226 // all inside so nothing to clip.
227 nodesAllInside++
228 continue frames
229 case IntersectionOutSide:
230 // all outside -> clip from tree.
231 index := ot.index[top.pos:]
232 if len(index) > 8 {
233 index = index[:8]
234 }
235 for i := range index {
236 if index[i] != 0 {
237 index[i] = 0
238 nodesClipped++
239 }
240 }
241 continue frames
242 default: // Overlaps
243 if index := ot.index[top.pos:]; len(index) > 7 {
244 children:
245 for i := 0; i < 4; i++ {
246 a := index[i]
247 b := index[i+4]
248 if a == 0 && b == 0 {
249 continue
250 }
251 dx := top.X2 - top.X1
252 dy := top.Y2 - top.Y1
253 nbox := Box2D{
254 dx*scale[i][0] + top.X1,
255 dy*scale[i][1] + top.Y1,
256 dx*scale[i][2] + top.X1,
257 dy*scale[i][3] + top.Y1,
258 }
259 switch p.IntersectionBox2D(nbox) {
260 case IntersectionInside:
261 // all inside so nothing to clip.
262 nodesAllInside++
263 continue children
264 case IntersectionOutSide:
265 // all are ouside -> clip from tree.
266 if a != 0 {
267 index[i] = 0
268 nodesClipped++
269 }
270 if b != 0 {
271 index[i+4] = 0
272 nodesClipped++
273 }
274 continue children
275 default: // Overlaps
276 if a != 0 {
277 stack = append(stack, boxFrame{a, nbox})
278 }
279 if b != 0 {
280 stack = append(stack, boxFrame{b, nbox})
281 }
282 }
283 }
284 }
285 }
286 } else { // leaf
287 pos := -top.pos - 1
288 n := ot.index[pos]
289 indices := ot.index[pos+1 : pos+1+n]
290 tris:
291 for i := len(indices) - 1; i >= 0; i-- {
292 triIndex := indices[i]
293 what, found := triChecks[triIndex]
294 if !found {
295 tri := ot.triangles[triIndex]
296 t := Triangle{
297 ot.vertices[tri[0]],
298 ot.vertices[tri[1]],
299 ot.vertices[tri[2]],
300 }
301 what = p.IntersectionWithTriangle(&t)
302 triChecks[triIndex] = what
303
304 /*
305
306 if what != IntersectionInside {
307 if first {
308 first = false
309 } else {
310 fmt.Fprintln(fake, ",")
311 }
312 fmt.Fprintf(fake,
313 `{ "type": "Feature",
314 "properties": {
315 "id": %d
316 },
317 "geometry": {
318 "type": "Polygon",
319 "coordinates": [[
320 [ %.6f, %.6f ],
321 [ %.6f, %.6f ],
322 [ %.6f, %.6f ],
323 [ %.6f, %.6f ]]
324 ]
325 }
326 }`, triIndex,
327 t[0].X, t[0].Y,
328 t[1].X, t[1].Y,
329 t[2].X, t[2].Y,
330 t[0].X, t[0].Y)
331 }
332 */
333 }
334 switch what {
335 case IntersectionInside:
336 // triangle inside -> stay.
337 continue tris
338 default:
339 trianglesClipped++
340 // outside or not fully covered -> remove.
341 if i < len(indices)-1 {
342 copy(indices[i:], indices[i+1:])
343 }
344 indices[len(indices)-1] = 0
345 indices = indices[:len(indices)-1]
346 }
347 }
348 ot.index[pos] = int32(len(indices))
349 }
350 }
351 /*
352 fmt.Fprintln(fake,
353 `]
354 }`)
355 */
356 log.Printf("info: node tests: %d\n", nodeTests)
357 log.Printf("info: nodes clipped: %d\n", nodesClipped)
358 log.Printf("info: nodes all inside: %d\n", nodesAllInside)
359 log.Printf("info: triangle clipped: %d\n", trianglesClipped)
360 log.Printf("info: tested triangles: %d\n", len(triChecks))
361
362 ot.eliminate(triChecks)
363 } 49 }
364 50
365 func (ot *Tree) Value(x, y float64) (float64, bool) { 51 func (ot *Tree) Value(x, y float64) (float64, bool) {
366 52
367 // out of bounding box 53 // out of bounding box