diff pkg/octree/triangulation.go @ 3604:6248a4bc10c7

Moved triangle elimination to triangulation code.
author Sascha L. Teichmann <sascha.teichmann@intevation.de>
date Wed, 05 Jun 2019 11:39:25 +0200
parents 4fa92d468164
children e1021fd60190
line wrap: on
line diff
--- a/pkg/octree/triangulation.go	Wed Jun 05 09:38:59 2019 +0200
+++ b/pkg/octree/triangulation.go	Wed Jun 05 11:39:25 2019 +0200
@@ -21,7 +21,11 @@
 
 import (
 	"fmt"
+	"log"
 	"math"
+	"sort"
+
+	"gonum.org/v1/gonum/stat"
 )
 
 type Triangulation struct {
@@ -38,6 +42,82 @@
 	return &Triangulation{points, t.convexHull(), t.triangles, t.halfedges}, err
 }
 
+func (t *Triangulation) ConcaveHull(quantile float64) []int32 {
+
+	numTris := len(t.Triangles) / 3
+
+	// Calculate the max edge lengths per triangle.
+	lengths := make([]float64, numTris)
+	for i := range lengths {
+		idx := i * 3
+		var max float64
+		vs := t.Triangles[idx : idx+3]
+		for j, vj := range vs {
+			k := (j + 1) % 3
+			if l := t.Points[vj].SquaredDistance2D(t.Points[vs[k]]); l > max {
+				max = l
+			}
+		}
+		lengths[i] = max
+	}
+
+	qs := make([]float64, len(lengths))
+	copy(qs, lengths)
+	sort.Float64s(qs)
+	q := stat.Quantile(quantile, stat.LinInterp, qs, nil)
+	log.Printf("info: %.2f%% quantile: %.2f\n", quantile, math.Sqrt(q))
+
+	removed := map[int32]bool{}
+
+	isBorder := func(n int32) bool {
+		n *= 3
+		for i := int32(0); i < 3; i++ {
+			e := n + i
+			if t.Halfedges[e] == -1 || removed[e] {
+				return true
+			}
+		}
+		return false
+	}
+
+	oldCandidates := make([]int32, 0, int(math.Ceil(float64(numTris)*(1.0-quantile))))
+	log.Printf("info: cap candidates: %d\n", cap(oldCandidates))
+
+	for i, length := range lengths {
+		if length >= q {
+			oldCandidates = append(oldCandidates, int32(i))
+		}
+	}
+
+	var newCandidates []int32
+
+	for len(oldCandidates) > 0 {
+		log.Printf("candidates: %d\n", len(oldCandidates))
+
+		oldRemoved := len(removed)
+
+		for _, i := range oldCandidates {
+
+			if isBorder(i) {
+				removed[i] = true
+			} else {
+				newCandidates = append(newCandidates, i)
+			}
+		}
+
+		if oldRemoved == len(removed) {
+			break
+		}
+
+		oldCandidates = newCandidates
+		newCandidates = newCandidates[:0]
+	}
+
+	log.Printf("info: triangles to remove: %d\n", len(removed))
+
+	return nil
+}
+
 func (t *Triangulation) TriangleSlices() [][]int32 {
 	sl := make([][]int32, len(t.Triangles)/3)
 	var j int