Mercurial > gemma
changeset 2512:2768f74d54ab octree-diff
Added an STRTree for the triangulation. Should be better suited for filtering out the clipped triangles.
author | Sascha L. Teichmann <sascha.teichmann@intevation.de> |
---|---|
date | Tue, 05 Mar 2019 13:05:50 +0100 |
parents | 17538d937b8c |
children | 1534df518201 |
files | pkg/octree/strtree.go pkg/octree/vertex.go |
diffstat | 2 files changed, 203 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/pkg/octree/strtree.go Tue Mar 05 13:05:50 2019 +0100 @@ -0,0 +1,194 @@ +// This is Free Software under GNU Affero General Public License v >= 3.0 +// without warranty, see README.md and license for details. +// +// SPDX-License-Identifier: AGPL-3.0-or-later +// License-Filename: LICENSES/AGPL-3.0.txt +// +// Copyright (C) 2018 by via donau +// – Österreichische Wasserstraßen-Gesellschaft mbH +// Software engineering by Intevation GmbH +// +// Author(s): +// * Sascha L. Teichmann <sascha.teichmann@intevation.de> + +package octree + +import ( + "math" + "sort" +) + +const numEntries = 8 + +type STRTree struct { + tri *Triangulation + index []int32 + triangles [][]int32 + bboxes []Box2D +} + +func (s *STRTree) Build(t *Triangulation) { + + s.tri = t + + s.triangles = t.TriangleSlices() + + all := make([]int32, len(s.triangles)) + + for i := range all { + all[i] = int32(i) + } + + s.index = append(s.index, 0) + + root := s.build(all) + + s.index[0] = root +} + +func (s *STRTree) build(items []int32) int32 { + sort.Slice(items, func(i, j int) bool { + ti := s.triangles[items[i]] + tj := s.triangles[items[j]] + return s.tri.Points[ti[0]].X < s.tri.Points[tj[0]].X + }) + + P := int(math.Ceil(float64(len(items)) / float64(numEntries))) + S := int(math.Ceil(math.Sqrt(float64(P)))) + + sm := S * numEntries + + slices := make([][]int32, S) + for i := range slices { + end := (i + 1) * sm + if end > len(items) { + end = len(items) + } + slices[i] = items[i*sm : end] + } + + leaves := make([]int32, 0, S*S) + + for _, slice := range slices { + sort.Slice(slice, func(i, j int) bool { + ti := s.triangles[slice[i]] + tj := s.triangles[slice[j]] + return s.tri.Points[ti[0]].X < s.tri.Points[tj[0]].X + }) + + for len(slice) > 0 { + n := numEntries + if l := len(slice); l < numEntries { + n = l + } + leaves = append(leaves, s.allocLeaf(slice[:n])) + slice = slice[n:] + } + } + + return s.buildNodes(leaves) +} + +func bboxIndex(idx int32) int32 { + if idx < 0 { + return -idx - 1 + } + return idx +} + +func (s *STRTree) buildNodes(items []int32) int32 { + + if len(items) <= numEntries { + return s.allocNode(items) + } + + sort.Slice(items, func(i, j int) bool { + bi := s.bboxes[s.index[bboxIndex(items[i])]] + bj := s.bboxes[s.index[bboxIndex(items[j])]] + return bi.X1 < bj.X1 + }) + + P := int(math.Ceil(float64(len(items)) / float64(numEntries))) + S := int(math.Ceil(math.Sqrt(float64(P)))) + + sm := S * numEntries + + slices := make([][]int32, S) + for i := range slices { + end := (i + 1) * sm + if end > len(items) { + end = len(items) + } + slices[i] = items[i*sm : end] + } + + nodes := make([]int32, 0, S*S) + + for _, slice := range slices { + sort.Slice(slice, func(i, j int) bool { + bi := s.bboxes[s.index[bboxIndex(slice[i])]] + bj := s.bboxes[s.index[bboxIndex(slice[j])]] + return bi.X1 < bj.X1 + }) + + for len(slice) > 0 { + n := numEntries + if l := len(slice); l < numEntries { + n = l + } + nodes = append(nodes, s.allocNode(slice[:n])) + slice = slice[n:] + } + } + + return s.buildNodes(nodes) +} + +func (s *STRTree) allocNode(items []int32) int32 { + pos := len(s.index) + s.index = append(s.index, 0) + s.index = append(s.index, items...) + if len(items) > 0 { + box := s.bboxes[s.index[bboxIndex(items[0])]] + for i := 1; i < len(items); i++ { + it := items[i] + b := s.bboxes[s.index[bboxIndex(it)]] + box = box.Union(b) + } + s.index[pos] = int32(s.allocBBox(box)) + } + return int32(pos) +} + +func (s *STRTree) allocBBox(box Box2D) int { + pos := len(s.bboxes) + s.bboxes = append(s.bboxes, box) + return pos +} + +func (s *STRTree) allocLeaf(items []int32) int32 { + pos := len(s.index) + s.index = append(s.index, 0) + s.index = append(s.index, items...) + if len(items) > 0 { + ti := s.triangles[items[0]] + t := Triangle{ + s.tri.Points[ti[0]], + s.tri.Points[ti[1]], + s.tri.Points[ti[2]], + } + box := t.BBox() + for i := 1; i < len(items); i++ { + it := items[i] + ti := s.triangles[it] + t := Triangle{ + s.tri.Points[ti[0]], + s.tri.Points[ti[1]], + s.tri.Points[ti[2]], + } + box = box.Union(t.BBox()) + } + s.index[pos] = int32(s.allocBBox(box)) + } + return -int32(pos) - 1 +}
--- a/pkg/octree/vertex.go Mon Mar 04 18:16:13 2019 +0100 +++ b/pkg/octree/vertex.go Tue Mar 05 13:05:50 2019 +0100 @@ -723,6 +723,15 @@ return a.Y2 } +func (a Box2D) Union(b Box2D) Box2D { + return Box2D{ + X1: math.Min(a.X1, b.X1), + Y1: math.Min(a.Y1, b.Y1), + X2: math.Max(a.X2, b.X2), + Y2: math.Max(a.Y2, b.Y2), + } +} + // NewPlane2D creates a new Plane2D from two given points. func NewPlane2D(x1, y1, x2, y2 float64) Plane2D { b := x2 - x1