Skip to content

Commit

Permalink
PointLocation() is a generic function
Browse files Browse the repository at this point in the history
  • Loading branch information
arl committed Oct 21, 2016
1 parent 267a755 commit 109059f
Show file tree
Hide file tree
Showing 6 changed files with 46 additions and 60 deletions.
23 changes: 0 additions & 23 deletions basic.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,26 +133,3 @@ func (q *BasicTree) subdivide(n *basicNode) {
func (q *BasicTree) Root() Node {
return q.root
}

// PointLocation returns the quadtree node containing the given point.
func (q *BasicTree) PointLocation(pt image.Point) Node {
var query func(n *basicNode) Node
query = func(n *basicNode) Node {
if !pt.In(n.bounds) {
return nil
}
if n.color != Gray {
return n
}

if pt.In(n.c[Northwest].bounds) {
return query(n.c[Northwest])
} else if pt.In(n.c[Northeast].bounds) {
return query(n.c[Northeast])
} else if pt.In(n.c[Southwest].bounds) {
return query(n.c[Southwest])
}
return query(n.c[Southeast])
}
return query(q.root)
}
4 changes: 2 additions & 2 deletions basic_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,14 +80,14 @@ func TestBasicTreeQuery(t *testing.T) {
check(t, err)

for _, tt := range testTbl {
node := q.PointLocation(tt.pt)
node := PointLocation(q, tt.pt)
exists := node != nil
if exists != tt.exists {
t.Fatalf("resolution %d, expected exists to be %t for point %v, got %t instead",
res, tt.exists, tt.pt, exists)
}
// obtain the refNode
refNode := q.PointLocation(refPt)
refNode := PointLocation(q, refPt)
if refNode == nil {
t.Fatalf("reference node should exist")
}
Expand Down
25 changes: 0 additions & 25 deletions cntree.go
Original file line number Diff line number Diff line change
Expand Up @@ -194,28 +194,3 @@ func (q *CNTree) ForEachLeaf(color Color, fn func(Node)) {
}
}
}

// PointLocation returns the quadtree node containing the given point.
// TODO: PointLocation should be as Neighbours, generic if the Quadtree doesn't
// implement PointLocation
func (q *CNTree) PointLocation(pt image.Point) Node {
var query func(n *cnNode) Node
query = func(n *cnNode) Node {
if !pt.In(n.bounds) {
return nil
}
if n.color != Gray {
return n
}

if pt.In(n.c[Northwest].bounds) {
return query(n.c[Northwest])
} else if pt.In(n.c[Northeast].bounds) {
return query(n.c[Northeast])
} else if pt.In(n.c[Southwest].bounds) {
return query(n.c[Southwest])
}
return query(n.c[Southeast])
}
return query(q.root)
}
43 changes: 43 additions & 0 deletions location.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package rquad

import "image"

// PointLocator is the interface implemented by objects that, given a point in
// 2D space, can return the leaf node that contains it.
type PointLocator interface {
// PointLocation returns the Node that contains the given point, or nil.
PointLocation(image.Point) Node
}

// PointLocation returns the quadtree node containing the given point.
//
// The standard method to search for the Node that contains a given point is a
// recursively search, starting from the root node, returning the Node that
// contains the point is a leaf. If q implements the PointLocator interfacen
// then the specific and more efficient implementation of PointLocation is
// called
func PointLocation(q Quadtree, pt image.Point) Node {
if locator, ok := q.(PointLocator); ok {
// use the specific point location implementation
return locator.PointLocation(pt)
}
return pointLocation(q.Root(), pt)
}

func pointLocation(n Node, pt image.Point) Node {
if !pt.In(n.Bounds()) {
return nil
}
if n.Color() != Gray {
return n
}

if pt.In(n.Child(Northwest).Bounds()) {
return pointLocation(n.Child(Northwest), pt)
} else if pt.In(n.Child(Northeast).Bounds()) {
return pointLocation(n.Child(Northeast), pt)
} else if pt.In(n.Child(Southwest).Bounds()) {
return pointLocation(n.Child(Southwest), pt)
}
return pointLocation(n.Child(Southeast), pt)
}
2 changes: 1 addition & 1 deletion neighbours_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ func testQuadtreeNeighbours(t *testing.T, fn newQuadtreeFunc) {
q, err := fn(scanner, tt.res)
check(t, err)

node := q.(PointLocator).PointLocation(tt.pt)
node := PointLocation(q, tt.pt)
exists := node != nil
if !exists {
t.Fatalf("%s, resolution %d, expected exists to be true for point %v, got false instead",
Expand Down
9 changes: 0 additions & 9 deletions quadtree.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@

package rquad

import "image"

// Quadtree defines the interface for a quadtree type.
type Quadtree interface {
// ForEachLeaf calls the given function for each leaf node of the quadtree.
Expand All @@ -36,10 +34,3 @@ type Quadtree interface {
// Root returns the quadtree root node.
Root() Node
}

// PointLocator is the interface implemented by objects that, given a point in
// 2D space, can return the leaf node it contains.
type PointLocator interface {
// PointLocation returns the quadtree node containing the given point.
PointLocation(image.Point) Node
}

0 comments on commit 109059f

Please sign in to comment.