From 3073e8887521485329113b8f17fbdb316bb3c65d Mon Sep 17 00:00:00 2001 From: Edwin Jakobs Date: Fri, 24 Jan 2025 20:26:22 +0100 Subject: [PATCH] [orx-kdtree] Add generated and verified documentation --- .../commonMain/kotlin/IterableExtensions.kt | 51 +++++++++ orx-kdtree/src/commonMain/kotlin/KDTree.kt | 102 ++++++++++++++---- orx-kdtree/src/commonMain/kotlin/Mappers.kt | 53 +++++---- 3 files changed, 163 insertions(+), 43 deletions(-) create mode 100644 orx-kdtree/src/commonMain/kotlin/IterableExtensions.kt diff --git a/orx-kdtree/src/commonMain/kotlin/IterableExtensions.kt b/orx-kdtree/src/commonMain/kotlin/IterableExtensions.kt new file mode 100644 index 00000000..55e36326 --- /dev/null +++ b/orx-kdtree/src/commonMain/kotlin/IterableExtensions.kt @@ -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.kdTree(): KDTreeNode { + 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.kdTree(): KDTreeNode { + 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.kdTree(): KDTreeNode { + val items = this.toMutableList() + return buildKDTree(items, 4, ::vector4Mapper) +} \ No newline at end of file diff --git a/orx-kdtree/src/commonMain/kotlin/KDTree.kt b/orx-kdtree/src/commonMain/kotlin/KDTree.kt index a8304937..9b846864 100644 --- a/orx-kdtree/src/commonMain/kotlin/KDTree.kt +++ b/orx-kdtree/src/commonMain/kotlin/KDTree.kt @@ -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(val dimensions: Int, val mapper: (T, Int) -> Double) { var parent: KDTreeNode? = null var median: Double = 0.0 @@ -13,25 +17,89 @@ class KDTreeNode(val dimensions: Int, val mapper: (T, Int) -> Double) { var children: Array?> = 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 { 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): KDTreeNode? { - 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 { 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 { return findAllInRadius(this, query, radius, includeQuery) } @@ -46,23 +114,17 @@ class KDTreeNode(val dimensions: Int, val mapper: (T, Int) -> Double) { } } -private fun insertItem(root: KDTreeNode, item: T): KDTreeNode { - 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 buildKDTree(items: MutableList, dimensions: Int, mapper: (T, Int) -> Double): KDTreeNode - - private fun sqrDistance(left: T, right: T, dimensions: Int, mapper: (T, Int) -> Double): Double { var distance = 0.0 @@ -92,7 +154,7 @@ fun findAllNodes(root: KDTreeNode): List> { } -fun findKNearest( +private fun findKNearest( root: KDTreeNode, query: T, k: Int, diff --git a/orx-kdtree/src/commonMain/kotlin/Mappers.kt b/orx-kdtree/src/commonMain/kotlin/Mappers.kt index 5371e5a2..0ecbbf5b 100644 --- a/orx-kdtree/src/commonMain/kotlin/Mappers.kt +++ b/orx-kdtree/src/commonMain/kotlin/Mappers.kt @@ -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.kdTree(): KDTreeNode { - val items = this.toMutableList() - return buildKDTree(items, 2, ::vector2Mapper) -} - -@JvmName("kdTreeVector3") -fun Iterable.kdTree(): KDTreeNode { - val items = this.toMutableList() - return buildKDTree(items, 3, ::vector3Mapper) -} - -@JvmName("kdTreeVector4") -fun Iterable.kdTree(): KDTreeNode { - val items = this.toMutableList() - return buildKDTree(items, 4, ::vector4Mapper) -} \ No newline at end of file