changeset 2492:10681749371d octree-diff

Implemented the BBox/clipping polygon test. TODO: triangle/clipping polygon test.
author Sascha L. Teichmann <sascha.teichmann@intevation.de>
date Mon, 04 Mar 2019 11:55:29 +0100
parents c9164ff98871
children e3487fa9284d
files pkg/octree/polygon.go pkg/octree/vertex.go
diffstat 2 files changed, 178 insertions(+), 7 deletions(-) [+]
line wrap: on
line diff
--- a/pkg/octree/polygon.go	Sun Mar 03 21:10:07 2019 +0100
+++ b/pkg/octree/polygon.go	Mon Mar 04 11:55:29 2019 +0100
@@ -19,17 +19,25 @@
 	"fmt"
 	"math"
 
+	"github.com/tidwall/rtree"
+
 	"gemma.intevation.de/gemma/pkg/wkb"
 )
 
-type ring []float64
+type (
+	ring []float64
+
+	Polygon struct {
+		// TODO: Implement me!
+		rings []ring
 
-type Polygon struct {
-	// TODO: Implement me!
-	rings []ring
-}
+		indices []*rtree.RTree
+	}
 
-type IntersectionType byte
+	IntersectionType byte
+
+	lineSegment []float64
+)
 
 const (
 	IntersectionInside IntersectionType = iota
@@ -37,8 +45,167 @@
 	IntersectionOverlaps
 )
 
+func (ls lineSegment) Rect(interface{}) ([]float64, []float64) {
+
+	var min, max [2]float64
+
+	if ls[0] < ls[2] {
+		min[0] = ls[0]
+		max[0] = ls[2]
+	} else {
+		min[0] = ls[2]
+		max[0] = ls[0]
+	}
+
+	if ls[1] < ls[3] {
+		min[1] = ls[1]
+		max[1] = ls[3]
+	} else {
+		min[1] = ls[3]
+		max[1] = ls[1]
+	}
+
+	return min[:], max[:]
+}
+
+func (p *Polygon) Indexify() {
+	indices := make([]*rtree.RTree, len(p.rings))
+
+	for i := range indices {
+		index := rtree.New(nil)
+		indices[i] = index
+
+		rng := p.rings[i]
+
+		for i := 0; i < len(rng); i += 2 {
+			var ls lineSegment
+			if i+4 <= len(rng) {
+				ls = lineSegment(rng[i : i+4])
+			} else {
+				ls = []float64{rng[i], rng[i+1], rng[0], rng[1]}
+			}
+			index.Insert(ls)
+		}
+	}
+
+	p.indices = indices
+}
+
+func (a Box2D) InterectsSegment(ls lineSegment) bool {
+	p1x := ls[0]
+	p1y := ls[1]
+	p2x := ls[2]
+	p2y := ls[3]
+
+	left := a.X1
+	right := a.X2
+	top := a.Y1
+	bottom := a.Y2
+
+	// The direction of the ray
+	dx := p2x - p1x
+	dy := p2y - p1y
+
+	min, max := 0.0, 1.0
+
+	var t0, t1 float64
+
+	// Left and right sides.
+	// - If the line is parallel to the y axis.
+	if dx == 0 {
+		if p1x < left || p1x > right {
+			return false
+		}
+	} else {
+		// - Make sure t0 holds the smaller value by checking the direction of the line.
+		if dx > 0 {
+			t0 = (left - p1x) / dx
+			t1 = (right - p1x) / dx
+		} else {
+			t1 = (left - p1x) / dx
+			t0 = (right - p1x) / dx
+		}
+
+		if t0 > min {
+			min = t0
+		}
+		if t1 < max {
+			max = t1
+		}
+		if min > max || max < 0 {
+			return false
+		}
+	}
+
+	// The top and bottom side.
+	// - If the line is parallel to the x axis.
+	if dy == 0 {
+		if p1y < top || p1y > bottom {
+			return false
+		}
+	} else {
+		// - Make sure t0 holds the smaller value by checking the direction of the line.
+		if dy > 0 {
+			t0 = (top - p1y) / dy
+			t1 = (bottom - p1y) / dy
+		} else {
+			t1 = (top - p1y) / dy
+			t0 = (bottom - p1y) / dy
+		}
+
+		if t0 > min {
+			min = t0
+		}
+		if t1 < max {
+			max = t1
+		}
+		if min > max || max < 0 {
+			return false
+		}
+	}
+
+	// The point of intersection
+	// ix = p1x + dx*min
+	// iy = p1y + dy*min
+	return true
+}
+
 func (p *Polygon) IntersectionBox2D(box Box2D) IntersectionType {
-	// TODO: Implement me
+
+	if len(p.rings) == 0 {
+		return IntersectionOutSide
+	}
+
+	for _, index := range p.indices {
+		var intersects bool
+		index.Search(box, func(item rtree.Item) bool {
+			ls := item.(lineSegment)
+			if box.InterectsSegment(ls) {
+				intersects = true
+				return false
+			}
+			return true
+		})
+		if intersects {
+			return IntersectionOverlaps
+		}
+	}
+
+	// No intersection -> check inside or outside
+	// if an abritrary point  is inside or not.
+	point := []float64{box.X1, box.Y1}
+
+	// Check holes first: inside a hole means outside.
+	if len(p.rings) > 0 {
+		for _, hole := range p.rings[1:] {
+			if hole.contains(point) {
+				return IntersectionOutSide
+			}
+		}
+	}
+	if p.rings[0].contains(point) {
+		return IntersectionInside
+	}
 	return IntersectionOutSide
 }
 
--- a/pkg/octree/vertex.go	Sun Mar 03 21:10:07 2019 +0100
+++ b/pkg/octree/vertex.go	Mon Mar 04 11:55:29 2019 +0100
@@ -681,6 +681,10 @@
 	return out
 }
 
+func (a Box2D) Rect(interface{}) ([]float64, []float64) {
+	return []float64{a.X1, a.Y1}, []float64{a.X2, a.Y2}
+}
+
 // Intersects checks if two Box2Ds intersect.
 func (a Box2D) Intersects(b Box2D) bool {
 	return !(a.X2 < a.X1 || a.X2 < b.X1 ||