Skip to content

Commit

Permalink
Use array of 3 axial event lists
Browse files Browse the repository at this point in the history
  • Loading branch information
Daniel Oom committed Aug 30, 2024
1 parent ef3fd9c commit a5dcd9e
Show file tree
Hide file tree
Showing 2 changed files with 111 additions and 75 deletions.
101 changes: 75 additions & 26 deletions kdtree/src/event.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::cmp::Ordering;

use geometry::{aabb::Aabb, axis::Axis};
use glam::Vec3;
use std::cmp::Ordering;

#[derive(Debug, PartialEq, PartialOrd, Eq, Ord)]
pub(crate) enum EventKind {
Expand Down Expand Up @@ -38,27 +38,41 @@ impl Event {
}

fn total_cmp(&self, other: &Self) -> Ordering {
f32::total_cmp(&self.distance, &other.distance).then(self.kind.cmp(&other.kind))
let cmp_distance = f32::total_cmp(&self.distance, &other.distance);
let cmp_kind = self.kind.cmp(&other.kind);
cmp_distance.then(cmp_kind)
}
}

pub(crate) fn generate_event_list(clipped: &[(u32, Aabb)], axis: Axis) -> Vec<Event> {
let mut events: Vec<Event> = Vec::with_capacity(clipped.len() * 2);
for c in clipped {
if c.1.min()[axis] == c.1.max()[axis] {
events.push(Event::new_planar(c.1.min()[axis]));
} else {
events.push(Event::new_end(c.1.max()[axis]));
events.push(Event::new_start(c.1.min()[axis]));
}
fn extend_vec_with_events(vec: &mut Vec<Event>, min: &Vec3, max: &Vec3, axis: Axis) {
if min[axis] == max[axis] {
vec.push(Event::new_planar(min[axis]));
} else {
vec.push(Event::new_start(min[axis]));
vec.push(Event::new_end(max[axis]));
}
}

pub(crate) fn generate_event_list(clipped: &[(u32, Aabb)]) -> [(Axis, Vec<Event>); 3] {
let mut events = [
(Axis::X, Vec::with_capacity(clipped.len() * 2)),
(Axis::Y, Vec::with_capacity(clipped.len() * 2)),
(Axis::Z, Vec::with_capacity(clipped.len() * 2)),
];
for (_, boundary) in clipped {
let (min, max) = (&boundary.min(), &boundary.max());
extend_vec_with_events(&mut events[0].1, min, max, Axis::X);
extend_vec_with_events(&mut events[1].1, min, max, Axis::Y);
extend_vec_with_events(&mut events[2].1, min, max, Axis::Z);
}
events.sort_unstable_by(Event::total_cmp);
events[0].1.sort_unstable_by(Event::total_cmp);
events[1].1.sort_unstable_by(Event::total_cmp);
events[2].1.sort_unstable_by(Event::total_cmp);
events
}

#[cfg(test)]
mod tests {
use crate::event::Event;
use glam::Vec3;

use super::*;
Expand All @@ -68,9 +82,13 @@ mod tests {
let triangle = Aabb::from_extents(Vec3::ZERO, Vec3::ONE);
let clipped = [(0, triangle)];

let actual = generate_event_list(&clipped, Axis::X);
let actual = generate_event_list(&clipped);

let expected = vec![Event::new_start(0.0), Event::new_end(1.0)];
let expected = [
(Axis::X, vec![Event::new_start(0.0), Event::new_end(1.0)]),
(Axis::Y, vec![Event::new_start(0.0), Event::new_end(1.0)]),
(Axis::Z, vec![Event::new_start(0.0), Event::new_end(1.0)]),
];
assert_eq!(actual, expected);
}

Expand All @@ -79,9 +97,13 @@ mod tests {
let triangle = Aabb::from_extents(Vec3::ZERO, Vec3::new(0.0, 1.0, 1.0));
let clipped = [(0, triangle)];

let actual = generate_event_list(&clipped, Axis::X);
let actual = generate_event_list(&clipped);

let expected = vec![Event::new_planar(0.0)];
let expected = [
(Axis::X, vec![Event::new_planar(0.0)]),
(Axis::Y, vec![Event::new_start(0.0), Event::new_end(1.0)]),
(Axis::Z, vec![Event::new_start(0.0), Event::new_end(1.0)]),
];
assert_eq!(actual, expected);
}

Expand All @@ -92,14 +114,41 @@ mod tests {
let triangle3 = Aabb::from_extents(Vec3::ONE, Vec3::new(1.0, 2.0, 2.0));
let clipped = [(0, triangle1), (1, triangle2), (2, triangle3)];

let actual = generate_event_list(&clipped, Axis::X);

let expected = vec![
Event::new_start(0.0),
Event::new_end(1.0),
Event::new_planar(1.0),
Event::new_start(1.0),
Event::new_end(2.0),
let actual = generate_event_list(&clipped);

let expected = [
(
Axis::X,
vec![
Event::new_start(0.0),
Event::new_end(1.0),
Event::new_planar(1.0),
Event::new_start(1.0),
Event::new_end(2.0),
],
),
(
Axis::Y,
vec![
Event::new_start(0.0),
Event::new_end(1.0),
Event::new_start(1.0),
Event::new_start(1.0),
Event::new_end(2.0),
Event::new_end(2.0),
],
),
(
Axis::Z,
vec![
Event::new_start(0.0),
Event::new_end(1.0),
Event::new_start(1.0),
Event::new_start(1.0),
Event::new_end(2.0),
Event::new_end(2.0),
],
),
];
assert_eq!(actual, expected);
}
Expand Down
85 changes: 36 additions & 49 deletions kdtree/src/sah.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use crate::{
cell::KdCell,
event::{generate_event_list, EventKind},
};
use geometry::{aabb::Aabb, aap::Aap, axis::Axis, geometry::Geometry};
use geometry::{aabb::Aabb, aap::Aap, geometry::Geometry};

#[derive(Debug, PartialEq)]
enum Side {
Expand Down Expand Up @@ -139,59 +139,46 @@ pub(crate) struct KdSplit {
pub(crate) right: KdCell,
}

fn sweep_plane_axis(
sah: &SahCost,
cell: &KdCell,
clipped: &[(u32, Aabb)],
axis: Axis,
) -> Option<SahSplit> {
let events = generate_event_list(clipped, axis);
fn sweep_plane(sah: &SahCost, cell: &KdCell, clipped: &[(u32, Aabb)]) -> Option<SahSplit> {
let events = generate_event_list(clipped);
let mut best_cost: Option<SahSplit> = None;
let mut n_left = 0;
let mut n_right = clipped.len();
let mut i = 0;
while i < events.len() {
let p = Aap {
axis,
distance: events[i].distance,
};

let p_end = events[i..]
.iter()
.take_while(|e| e.distance == p.distance && e.kind == EventKind::End)
.count();
i += p_end;
let p_planar = events[i..]
.iter()
.take_while(|e| e.distance == p.distance && e.kind == EventKind::Planar)
.count();
i += p_planar;
let p_start = events[i..]
.iter()
.take_while(|e| e.distance == p.distance && e.kind == EventKind::Start)
.count();
i += p_start;

n_right -= p_planar;
n_right -= p_end;
let cost = sah.split_cost_with_planar(&cell.boundary, p, (n_left, p_planar, n_right));
best_cost = SahSplit::zip_min(best_cost, cost);
n_left += p_start;
n_left += p_planar;
for (axis, events) in events {
let mut n_left = 0;
let mut n_right = clipped.len();
let mut i = 0;
while i < events.len() {
let p = Aap {
axis,
distance: events[i].distance,
};

let p_end = events[i..]
.iter()
.take_while(|e| e.distance == p.distance && e.kind == EventKind::End)
.count();
i += p_end;
let p_planar = events[i..]
.iter()
.take_while(|e| e.distance == p.distance && e.kind == EventKind::Planar)
.count();
i += p_planar;
let p_start = events[i..]
.iter()
.take_while(|e| e.distance == p.distance && e.kind == EventKind::Start)
.count();
i += p_start;

n_right -= p_planar;
n_right -= p_end;
let cost = sah.split_cost_with_planar(&cell.boundary, p, (n_left, p_planar, n_right));
best_cost = SahSplit::zip_min(best_cost, cost);
n_left += p_start;
n_left += p_planar;
}
}
best_cost
}

fn sweep_plane(sah: &SahCost, cell: &KdCell, clipped: &[(u32, Aabb)]) -> Option<SahSplit> {
SahSplit::zip_min(
sweep_plane_axis(sah, cell, clipped, Axis::X),
SahSplit::zip_min(
sweep_plane_axis(sah, cell, clipped, Axis::Y),
sweep_plane_axis(sah, cell, clipped, Axis::Z),
),
)
}

fn repartition(cell: &KdCell, clipped: &[(u32, Aabb)], best: SahSplit) -> KdSplit {
let plane = best.plane;
let mut left_indices: Vec<u32> = Vec::with_capacity(clipped.len());
Expand Down

0 comments on commit a5dcd9e

Please sign in to comment.