#[cfg(feature = "rayon")]
use rayon::iter::{IndexedParallelIterator, IntoParallelIterator, ParallelIterator};
use crate::indices::MutableIndices;
use crate::r#type::IndexableNum;
use crate::rtree::sort::{Sort, SortParams};
#[derive(Debug, Clone, Copy)]
pub struct STRSort;
impl<N: IndexableNum> Sort<N> for STRSort {
fn sort(params: &mut SortParams<N>, boxes: &mut [N], indices: &mut MutableIndices) {
let mut center_values: Vec<N> = Vec::with_capacity(params.num_items);
let two = N::from(2).unwrap();
for i in 0..params.num_items {
let min_x = boxes[i * 4];
let max_x = boxes[(i * 4) + 2];
center_values.push((min_x + max_x) / two);
}
sort(
&mut center_values,
boxes,
indices,
0,
params.num_items - 1,
params.node_size,
);
center_values.clear();
for i in 0..params.num_items {
let min_y = boxes[(i * 4) + 1];
let max_y = boxes[(i * 4) + 3];
center_values.push((min_y + max_y) / two);
}
let num_leaf_nodes = (params.num_items as f64 / params.node_size as f64).ceil();
let num_vertical_slices = num_leaf_nodes.sqrt().ceil() as usize;
let num_items_per_slice = num_vertical_slices * params.node_size;
#[cfg(feature = "rayon")]
{
let center_slices = center_values
.chunks_mut(num_items_per_slice)
.collect::<Vec<_>>();
let boxes_slices = boxes
.chunks_mut(num_items_per_slice * 4)
.collect::<Vec<_>>();
let indices_slices = indices.chunks_mut(num_items_per_slice);
center_slices
.into_par_iter()
.zip(boxes_slices)
.zip(indices_slices)
.for_each(|((center_chunk, boxes_chunk), mut indices_chunk)| {
let chunk_len = center_chunk.len();
sort(
center_chunk,
boxes_chunk,
&mut indices_chunk,
0,
num_items_per_slice.min(chunk_len) - 1,
params.node_size,
);
})
}
#[cfg(not(feature = "rayon"))]
{
for i in 0..num_vertical_slices {
let partition_start = i * num_items_per_slice;
let partition_end = (i + 1) * num_items_per_slice;
sort(
&mut center_values,
boxes,
indices,
partition_start,
partition_end.min(params.num_items) - 1,
params.node_size,
);
}
}
}
}
fn sort<N: IndexableNum>(
values: &mut [N],
boxes: &mut [N],
indices: &mut MutableIndices,
left: usize,
right: usize,
node_size: usize,
) {
debug_assert!(left <= right);
if left / node_size >= right / node_size {
return;
}
let midpoint = (left + right) / 2;
let pivot = values[midpoint];
let mut i = left.wrapping_sub(1);
let mut j = right.wrapping_add(1);
loop {
loop {
i = i.wrapping_add(1);
if values[i] >= pivot {
break;
}
}
loop {
j = j.wrapping_sub(1);
if values[j] <= pivot {
break;
}
}
if i >= j {
break;
}
swap(values, boxes, indices, i, j);
}
sort(values, boxes, indices, left, j, node_size);
sort(values, boxes, indices, j.wrapping_add(1), right, node_size);
}
#[inline]
fn swap<N: IndexableNum>(
values: &mut [N],
boxes: &mut [N],
indices: &mut MutableIndices,
i: usize,
j: usize,
) {
values.swap(i, j);
let k = 4 * i;
let m = 4 * j;
boxes.swap(k, m);
boxes.swap(k + 1, m + 1);
boxes.swap(k + 2, m + 2);
boxes.swap(k + 3, m + 3);
indices.swap(i, j);
}