[orx-kdtree] Add generated and verified documentation
This commit is contained in:
51
orx-kdtree/src/commonMain/kotlin/IterableExtensions.kt
Normal file
51
orx-kdtree/src/commonMain/kotlin/IterableExtensions.kt
Normal file
@@ -0,0 +1,51 @@
|
||||
package org.openrndr.extra.kdtree
|
||||
|
||||
import org.openrndr.math.Vector2
|
||||
import org.openrndr.math.Vector3
|
||||
import org.openrndr.math.Vector4
|
||||
import kotlin.jvm.JvmName
|
||||
|
||||
|
||||
/**
|
||||
* Constructs a KD-Tree for a collection of 2D vectors.
|
||||
*
|
||||
* This function creates a KD-Tree from the given iterable collection of `Vector2` objects.
|
||||
* The KD-Tree is built in a way that organizes the points for efficient spatial operations,
|
||||
* such as nearest neighbor search or range queries, considering two dimensions (x and y).
|
||||
*
|
||||
* @return The root node of the KD-Tree representing the input collection of 2D vectors.
|
||||
*/
|
||||
@JvmName("kdTreeVector2")
|
||||
fun Iterable<Vector2>.kdTree(): KDTreeNode<Vector2> {
|
||||
val items = this.toMutableList()
|
||||
return buildKDTree(items, 2, ::vector2Mapper)
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a KD-Tree from an iterable collection of 3-dimensional `Vector3` objects.
|
||||
*
|
||||
* This function converts the input iterable into a mutable list and utilizes the `buildKDTree` method
|
||||
* to organize the `Vector3` objects into a spatial data structure for efficient querying.
|
||||
*
|
||||
* @return The root node of the constructed KD-Tree containing the `Vector3` objects.
|
||||
*/
|
||||
@JvmName("kdTreeVector3")
|
||||
fun Iterable<Vector3>.kdTree(): KDTreeNode<Vector3> {
|
||||
val items = this.toMutableList()
|
||||
return buildKDTree(items, 3, ::vector3Mapper)
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a KD-Tree from the iterable collection of 4-dimensional vectors.
|
||||
*
|
||||
* This method uses the components of each `Vector4` (x, y, z, w) as the coordinate axes
|
||||
* in a 4-dimensional space to build the KD-Tree.
|
||||
*
|
||||
* @receiver An iterable collection of `Vector4` objects to be organized in the KD-Tree.
|
||||
* @return The root node of the constructed KD-Tree containing the `Vector4` objects.
|
||||
*/
|
||||
@JvmName("kdTreeVector4")
|
||||
fun Iterable<Vector4>.kdTree(): KDTreeNode<Vector4> {
|
||||
val items = this.toMutableList()
|
||||
return buildKDTree(items, 4, ::vector4Mapper)
|
||||
}
|
||||
@@ -1,11 +1,15 @@
|
||||
package org.openrndr.extra.kdtree
|
||||
|
||||
|
||||
import org.openrndr.collections.PriorityQueue
|
||||
import kotlin.math.abs
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Represents a node in a KD-Tree, a data structure for organizing points in a k-dimensional space.
|
||||
*
|
||||
* @param T The type of the items stored in the KD-Tree.
|
||||
* @property dimensions The number of dimensions for the tree.
|
||||
* @property mapper A function that extracts a coordinate value for a specific dimension from a data item.
|
||||
*/
|
||||
class KDTreeNode<T>(val dimensions: Int, val mapper: (T, Int) -> Double) {
|
||||
var parent: KDTreeNode<T>? = null
|
||||
var median: Double = 0.0
|
||||
@@ -13,25 +17,89 @@ class KDTreeNode<T>(val dimensions: Int, val mapper: (T, Int) -> Double) {
|
||||
var children: Array<KDTreeNode<T>?> = arrayOfNulls(2)
|
||||
var item: T? = null
|
||||
|
||||
/**
|
||||
* Determines if the current node is a leaf node in the KD-Tree.
|
||||
*
|
||||
* A node is considered a leaf if both of its child nodes are null,
|
||||
* indicating that it does not have any children.
|
||||
*
|
||||
* @return `true` if the node has no children, otherwise `false`.
|
||||
*/
|
||||
internal val isLeaf: Boolean
|
||||
get() = children[0] == null && children[1] == null
|
||||
|
||||
|
||||
/**
|
||||
* Inserts an item into the KD-Tree.
|
||||
*
|
||||
* This method adds a new item to the KD-Tree, determining its appropriate position
|
||||
* based on the structure of the tree, the number of dimensions, and the provided
|
||||
* mapping function for extracting coordinate values.
|
||||
*
|
||||
* @param item The item to be inserted into the KD-Tree.
|
||||
* @return The newly created KDTreeNode containing the inserted item.
|
||||
*/
|
||||
fun insert(item: T): KDTreeNode<T> {
|
||||
return insert(this, item, dimensions, mapper)
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a specified KDTreeNode from the KD-Tree.
|
||||
*
|
||||
* The method removes the given node from the tree while preserving the tree's structure and properties.
|
||||
* If the node is a leaf, it will simply be removed; otherwise, rebalancing actions may be performed.
|
||||
*
|
||||
* @param node The KDTreeNode to be removed from the KD-Tree.
|
||||
* @return The KDTreeNode that replaces the removed node, or null if the node is a leaf or if no replacement occurs.
|
||||
*/
|
||||
fun remove(node: KDTreeNode<T>): KDTreeNode<T>? {
|
||||
return org.openrndr.extra.kdtree.remove(node, mapper)
|
||||
return remove(node, mapper)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Finds the nearest neighbor to the given query within the KD-Tree.
|
||||
*
|
||||
* This method searches the KD-Tree to identify the closest item to the provided query point,
|
||||
* based on the spatial arrangement of the tree and the dimensions defined in its construction.
|
||||
*
|
||||
* @param query The query point for which the nearest neighbor is to be found.
|
||||
* @param includeQuery If true, the query point itself can be returned as the nearest neighbor,
|
||||
* otherwise, it is excluded from the results. Default is false.
|
||||
* @return The item in the KD-Tree that is the closest to the query point, or null if the tree is empty.
|
||||
*/
|
||||
fun findNearest(query: T, includeQuery: Boolean = false): T? = findNearest(this, query, includeQuery)
|
||||
|
||||
/**
|
||||
* Finds the k-nearest neighbors to a given query point within the KD-Tree.
|
||||
*
|
||||
* This method performs a nearest-neighbor search in the KD-Tree structure to retrieve
|
||||
* a list of the `k` closest items to the provided query point. The search uses the tree's
|
||||
* spatial arrangement and allows for optional inclusion or exclusion of the query point itself.
|
||||
*
|
||||
* @param query The query point for which the k-nearest neighbors are to be found.
|
||||
* @param k The number of nearest neighbors to retrieve.
|
||||
* @param includeQuery If true, the query point itself can be included in the results.
|
||||
* If false, the query point is excluded. Default is false.
|
||||
* @return A list of the `k` nearest neighbors to the query point, ordered by proximity.
|
||||
*/
|
||||
fun findKNearest(query: T, k: Int, includeQuery: Boolean = false): List<T> {
|
||||
return findKNearest(this, query, k, includeQuery)
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves all items within a specified radius around a query point in the KD-Tree.
|
||||
*
|
||||
* This method searches the KD-Tree to find all items whose distance to the specified query point
|
||||
* does not exceed the given radius. Optionally, the query point itself may be included or excluded
|
||||
* from the results.
|
||||
*
|
||||
* @param query The query point around which items will be searched.
|
||||
* @param radius The maximum radius within which items will be included in the results.
|
||||
* @param includeQuery If true, the query point itself may be included in the results.
|
||||
* If false, the query point is excluded. Default is false.
|
||||
* @return A list of all items within the specified radius from the query point.
|
||||
*/
|
||||
fun findAllInRadius(query: T, radius: Double, includeQuery: Boolean = false): List<T> {
|
||||
return findAllInRadius(this, query, radius, includeQuery)
|
||||
}
|
||||
@@ -46,23 +114,17 @@ class KDTreeNode<T>(val dimensions: Int, val mapper: (T, Int) -> Double) {
|
||||
}
|
||||
}
|
||||
|
||||
private fun <T> insertItem(root: KDTreeNode<T>, item: T): KDTreeNode<T> {
|
||||
return if (root.isLeaf) {
|
||||
root.item = item
|
||||
root
|
||||
} else {
|
||||
if (root.mapper(item, root.dimension) < root.median) {
|
||||
insertItem(root.children[0] ?: throw IllegalStateException("left is null"), item)
|
||||
} else {
|
||||
insertItem(root.children[1] ?: throw IllegalStateException("right is null"), item)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a KD-Tree from a mutable list of items, using a mapper function to extract
|
||||
* coordinate values for the specified dimensions.
|
||||
*
|
||||
* @param items A mutable list of items to be included in the KD-Tree.
|
||||
* @param dimensions The number of dimensions to consider in the KD-Tree.
|
||||
* @param mapper A function that maps an item and a dimension index to a coordinate value.
|
||||
* @return The root node of the constructed KD-Tree.
|
||||
*/
|
||||
expect fun <T> buildKDTree(items: MutableList<T>, dimensions: Int, mapper: (T, Int) -> Double): KDTreeNode<T>
|
||||
|
||||
|
||||
|
||||
private fun <T> sqrDistance(left: T, right: T, dimensions: Int, mapper: (T, Int) -> Double): Double {
|
||||
var distance = 0.0
|
||||
|
||||
@@ -92,7 +154,7 @@ fun <T> findAllNodes(root: KDTreeNode<T>): List<KDTreeNode<T>> {
|
||||
}
|
||||
|
||||
|
||||
fun <T> findKNearest(
|
||||
private fun <T> findKNearest(
|
||||
root: KDTreeNode<T>,
|
||||
query: T,
|
||||
k: Int,
|
||||
|
||||
@@ -1,11 +1,19 @@
|
||||
package org.openrndr.extra.kdtree
|
||||
|
||||
import org.openrndr.math.Vector2
|
||||
import org.openrndr.math.IntVector2
|
||||
import org.openrndr.math.Vector3
|
||||
import org.openrndr.math.Vector4
|
||||
import kotlin.jvm.JvmName
|
||||
|
||||
/** built-in mapper for [Vector2] */
|
||||
|
||||
/**
|
||||
* Maps a 2D vector's dimension to its corresponding value.
|
||||
*
|
||||
* @param v The 2D vector whose dimension is to be mapped.
|
||||
* @param dimension The dimension index to map (0 for x, any other value for y).
|
||||
* @return The value of the specified dimension of the vector.
|
||||
*/
|
||||
fun vector2Mapper(v: Vector2, dimension: Int): Double {
|
||||
return when (dimension) {
|
||||
0 -> v.x
|
||||
@@ -13,6 +21,13 @@ fun vector2Mapper(v: Vector2, dimension: Int): Double {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps the specified dimension of an IntVector2 to a Double.
|
||||
*
|
||||
* @param v the IntVector2 instance containing integer components x and y.
|
||||
* @param dimension the dimension to map (0 for x, any other value for y).
|
||||
* @return the x or y component of the vector as a Double, depending on the specified dimension.
|
||||
*/
|
||||
fun intVector2Mapper(v: IntVector2, dimension: Int): Double {
|
||||
return when (dimension) {
|
||||
0 -> v.x.toDouble()
|
||||
@@ -20,8 +35,13 @@ fun intVector2Mapper(v: IntVector2, dimension: Int): Double {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** built-in mapper for [Vector3] */
|
||||
/**
|
||||
* Maps a Vector3 object to one of its components (x, y, or z) based on the specified dimension.
|
||||
*
|
||||
* @param v the Vector3 object whose component is to be retrieved
|
||||
* @param dimension the index representing the component to be retrieved (0 for x, 1 for y, others for z)
|
||||
* @return the component value corresponding to the specified dimension
|
||||
*/
|
||||
fun vector3Mapper(v: Vector3, dimension: Int): Double {
|
||||
return when (dimension) {
|
||||
0 -> v.x
|
||||
@@ -30,7 +50,13 @@ fun vector3Mapper(v: Vector3, dimension: Int): Double {
|
||||
}
|
||||
}
|
||||
|
||||
/** built-in mapper for [Vector4] */
|
||||
/**
|
||||
* Maps the components of a 4-dimensional vector based on the specified dimension index.
|
||||
*
|
||||
* @param v the 4-dimensional vector containing the components x, y, z, and w
|
||||
* @param dimension the index of the dimension to retrieve; 0 for x, 1 for y, 2 for z, and any other value for w
|
||||
* @return the value of the vector component corresponding to the specified dimension index
|
||||
*/
|
||||
fun vector4Mapper(v: Vector4, dimension: Int): Double {
|
||||
return when (dimension) {
|
||||
0 -> v.x
|
||||
@@ -40,22 +66,3 @@ fun vector4Mapper(v: Vector4, dimension: Int): Double {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@JvmName("kdTreeVector2")
|
||||
fun Iterable<Vector2>.kdTree(): KDTreeNode<Vector2> {
|
||||
val items = this.toMutableList()
|
||||
return buildKDTree(items, 2, ::vector2Mapper)
|
||||
}
|
||||
|
||||
@JvmName("kdTreeVector3")
|
||||
fun Iterable<Vector3>.kdTree(): KDTreeNode<Vector3> {
|
||||
val items = this.toMutableList()
|
||||
return buildKDTree(items, 3, ::vector3Mapper)
|
||||
}
|
||||
|
||||
@JvmName("kdTreeVector4")
|
||||
fun Iterable<Vector4>.kdTree(): KDTreeNode<Vector4> {
|
||||
val items = this.toMutableList()
|
||||
return buildKDTree(items, 4, ::vector4Mapper)
|
||||
}
|
||||
Reference in New Issue
Block a user