Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions clusters/dbscan/kdtree.go
Original file line number Diff line number Diff line change
Expand Up @@ -253,3 +253,39 @@ func (n *nodeSorter) Less(i, j int) bool {
}
return a < b
}

// NearestNeighbor returns the index and distance of the closest point in the KDTree to the given point.
func (tree *KDTree) NearestNeighbor(pt space.Point) (nearestIdx int, minDist float64) {
nearestIdx = -1
minDist = 1e20 // sufficiently large
var search func(t *T)
search = func(t *T) {
if t == nil {
return
}
dist := DistanceSphericalFast(tree.Points[t.PointID], pt)
if dist < minDist {
nearestIdx = t.PointID
minDist = dist
}
// Check equal points
for _, eqID := range t.EqualIDs {
eqDist := DistanceSphericalFast(tree.Points[eqID], pt)
if eqDist < minDist {
nearestIdx = eqID
minDist = eqDist
}
}
diff := pt[t.split] - tree.Points[t.PointID][t.split]
first, second := t.left, t.right
if diff > 0 {
first, second = t.right, t.left
}
search(first)
if diff*diff < minDist*minDist {
search(second)
}
}
search(tree.Root)
return
}
26 changes: 26 additions & 0 deletions clusters/dbscan/kdtree_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -206,3 +206,29 @@ func isSortedOnDim(dim int, nodes []int, pts pointSlice) bool {
}
return true
}

func TestNearestNeighbor(t *testing.T) {
// Sabit bir nokta kümesi
pts := clusters.PointList{
space.Point{0, 0},
space.Point{1, 1},
space.Point{2, 2},
space.Point{5, 5},
}
tree := NewKDTree(pts)
tests := []struct {
query space.Point
expected int
}{
{space.Point{0.1, 0.1}, 0},
{space.Point{1.2, 1.1}, 1},
{space.Point{2.1, 2.2}, 2},
{space.Point{4.9, 5.1}, 3},
}
for _, tc := range tests {
idx, _ := tree.NearestNeighbor(tc.query)
if idx != tc.expected {
t.Errorf("NearestNeighbor(%v) = %d, want %d", tc.query, idx, tc.expected)
}
}
}
3 changes: 2 additions & 1 deletion index/quadtree/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ import (
)

// Node Represents a node of a Quadtree. Nodes contain
// items which have a spatial extent corresponding to the node's position in the quadtree.
//
// items which have a spatial extent corresponding to the node's position in the quadtree.
type Node struct {
Items []interface{}
Subnode [4]*Node
Expand Down
15 changes: 9 additions & 6 deletions index/quadtree/quadtree.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// Package quadtree A Quadtree is a spatial index structure for efficient range querying
// of items bounded by 2D rectangles.
//
// of items bounded by 2D rectangles.
package quadtree

import (
Expand All @@ -11,17 +12,19 @@ import (
)

// Quadtree A Quadtree is a spatial index structure for efficient range querying
// of items bounded by 2D rectangles.
// Geometries can be indexed by using their Envelopes.
// Any type of Object can also be indexed as
// long as it has an extent that can be represented by an Envelope.
//
// of items bounded by 2D rectangles.
// Geometries can be indexed by using their Envelopes.
// Any type of Object can also be indexed as
// long as it has an extent that can be represented by an Envelope.
type Quadtree struct {
Root *Root
MinExtent float64
}

// EnsureExtent Ensure that the envelope for the inserted item has non-zero extents.
// Use the current minExtent to pad the envelope, if necessary
//
// Use the current minExtent to pad the envelope, if necessary
func EnsureExtent(itemEnv *envelope.Envelope, minExtent float64) *envelope.Envelope {

minx := itemEnv.MinX
Expand Down
3 changes: 2 additions & 1 deletion index/quadtree/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ func (r *Root) Insert(itemEnv *envelope.Envelope, item interface{}) {
}

// InsertContained insert an item which is known to be contained in the tree rooted at
// the given QuadNode root. Lower levels of the tree will be created if necessary to hold the item.
//
// the given QuadNode root. Lower levels of the tree will be created if necessary to hold the item.
func (r *Root) InsertContained(tree *Node, itemEnv *envelope.Envelope, item interface{}) {
isZeroX := IsZeroWidth(itemEnv.MinX, itemEnv.MaxX)
isZeroY := IsZeroWidth(itemEnv.MinY, itemEnv.MaxY)
Expand Down
9 changes: 5 additions & 4 deletions index/spatial_index.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@ import (

// SpatialIndex The basic operations supported
// implementing spatial index algorithms.
// A spatial index typically provides a primary filter for range rectangle queries.
// A secondary filter is required to test for exact intersection.
// The secondary filter may consist of other kinds of tests,
// such as testing other spatial relationships.
//
// A spatial index typically provides a primary filter for range rectangle queries.
// A secondary filter is required to test for exact intersection.
// The secondary filter may consist of other kinds of tests,
// such as testing other spatial relationships.
type SpatialIndex interface {
// Insert Adds a spatial item with an extent specified by the given Envelope to the index
Insert(itemEnv *envelope.Envelope, item interface{}) error
Expand Down