#points #nearest-neighbor

k_nearest

K-nearest neighbors search for points with maximal search radius

2 unstable releases

0.2.0 Jun 7, 2023
0.1.0 Jun 7, 2023

#2188 in Algorithms


Used in pcl_rs

Custom license

11KB
217 lines

k_nearest

Find k-nearest neighbors for a list of points with arbitrary dimensions

Code example

const MAX_NEIGHBORS: usize = 16;
const MAX_DISTANCE: f32 = 1.0;

fn example(points: &[Point]) {
	let kd_tree = k_nearest::KDTree::<
		3,       // dimensions
		f32,     // type of a value for a dimension
		Point,   // point type
		Adapter, // adapter to allow any point type
		Metric,  // metric to calculate distances
	>::new(points);

	// iterate all points to calculate something
	for point in points.iter() {
		// space to insert result
		//   can be part of a larger memory location
		//   every entry contains the distance and the point index
		//   initial values are never read
		let mut neighbors = [(0.0, 0); MAX_NEIGHBORS];

		// calculate nearest points
		//   result at offset 0 is the original point
		//   result at offset 1 is the nearest neighbor in the search radius
		let count = kd_tree.k_nearest(point, &mut neighbors, MAX_DISTANCE);

		// create a subslice so neighbors only contains valid entries
		let neighbors = &neighbors[0..count];

		// start the calculations
		...
	}
}

For a Point with values as members

struct Point {
	x: f32,
	y: f32,
	z: f32,
}

struct Adapter;
impl k_nearest::Adapter<3, f32, Point> for Adapter {

	fn get(point: &Point, dimension: usize) -> f32 {
		match dimension {
			0 => point.x,
			1 => point.y,
			2 => point.z,
			_ => unreachable!(),
		}
	}
}

For a point with values as array

struct Point([f32; 3]);

struct Adapter;
impl k_nearest::Adapter<3, f32, Point> for Adapter {
	fn get(point: &Point, dimension: usize) -> f32 {
		point.0[dimension]
	}

	// get all values in one call
	//  default implementation calls Adapter::get N times
	fn get_all(point: &Point) -> [f32; 3] {
		point.0
	}
}

Metric

// use euclidean distance
type Metric = k_nearest::EuclideanDistanceSquared;

// or define own metric
struct ManhattenDistance;

impl<const N: usize> Metric<N, f32> for ManhattenDistance {
	fn distance(left: &[f32; N], right: &[f32; N]) -> f32 {
		(0..N)
			.map(|d| left[d] - right[d])
			.map(|v| v.abs())
			.fold(0.0, |sum, v| sum + v)
	}
	fn distance_plane(position: &[f32; N], plane: f32, dimension: usize) -> f32 {
		let diff = position[dimension] - plane;
		diff.abs()
	}
}

No runtime deps