[orx-kdtree] Add support for range query in kd-tree (#201)

This commit is contained in:
Yann Le Gall
2021-10-19 02:57:23 -07:00
committed by GitHub
parent d4309cf2c7
commit dd750e58a0
2 changed files with 80 additions and 0 deletions

View File

@@ -0,0 +1,39 @@
import org.openrndr.application
import org.openrndr.color.ColorRGBa
import org.openrndr.extra.kdtree.buildKDTree
import org.openrndr.extra.kdtree.findAllInRange
import org.openrndr.extra.kdtree.vector2Mapper
import org.openrndr.math.Vector2
fun main() {
application {
configure {
width = 1080
height = 720
}
program {
val points = MutableList(1000) {
Vector2(Math.random() * width, Math.random() * height)
}
val tree = buildKDTree(points, 2, ::vector2Mapper)
val radius = 50.0
extend {
drawer.circles(points, 5.0)
val allInRange = findAllInRange(tree, mouse.position, maxDistance = radius, dimensions = 2, ::vector2Mapper)
drawer.fill = ColorRGBa.PINK
drawer.stroke = ColorRGBa.PINK
drawer.strokeWeight = 2.0
drawer.circles(allInRange, 7.0)
drawer.fill = null
drawer.strokeWeight = 1.0
drawer.circle(mouse.position, radius)
}
}
}
}

View File

@@ -268,6 +268,47 @@ fun <T> findNearest(root: KDTreeNode<T>, item: T, dimensions: Int, mapper: (T, I
return nearestArg?.item
}
fun <T> findAllInRange(
root: KDTreeNode<T>,
item: T,
maxDistance: Double,
dimensions: Int,
mapper: (T, Int) -> Double
) : List<T> {
val sqrMaxDist = maxDistance * maxDistance
val queue = kotlin.collections.ArrayDeque<KDTreeNode<T>?>()
queue.add(root)
val results = mutableListOf<T?>()
while (queue.isNotEmpty()) {
val node = queue.removeFirst()
if (node != null) {
val dimensionValue = mapper(item, node.dimension)
val distance = sqrDistance(item, node.item
?: throw IllegalStateException("item is null"), dimensions, mapper)
if (distance <= sqrMaxDist) {
results.add(node.item)
}
val route: Int = if (dimensionValue < node.median) {
queue.add(node.children[0])
0
} else {
queue.add(node.children[1])
1
}
val d = abs(node.median - dimensionValue)
if (d * d <= sqrMaxDist) {
queue.add(node.children[1 - route])
}
}
}
return results.filterNotNull()
}
fun <T> insert(root: KDTreeNode<T>, item: T, dimensions: Int, mapper: (T, Int) -> Double): KDTreeNode<T> {
val stack = Stack<KDTreeNode<T>>()
stack.push(root)