Address MR 2439 review comments.

- Round properly.
- Fix calculation of the x coordinate bounds.
- Use LineSegment2 in the signature.
- Use `in_swept_circle` for voxel colliders too.
This commit is contained in:
Avi Weinstock 2021-06-14 00:13:59 -04:00
parent 7f093c2a5d
commit 0f8493bf60
2 changed files with 29 additions and 19 deletions

View File

@ -101,29 +101,33 @@ impl SpatialGrid {
} }
/// Get an iterator over the entities in cells that overlap with a circle of /// Get an iterator over the entities in cells that overlap with a circle of
/// the given radius whose center is swept across the line from p0 to p1 /// the given radius whose center is swept across the given line segment
/// NOTE: for best optimization of the iterator use `for_each` /// NOTE: for best optimization of the iterator use `for_each`
/// rather than a for loop /// rather than a for loop
pub fn in_swept_circle<'a>( pub fn in_swept_circle<'a>(
&'a self, &'a self,
p0: Vec2<f32>, line: LineSegment2<f32>,
p1: Vec2<f32>,
radius: f32, radius: f32,
) -> impl Iterator<Item = specs::Entity> + 'a { ) -> impl Iterator<Item = specs::Entity> + 'a {
let iter = |max_entity_radius, grid: &'a hashbrown::HashMap<_, _>, lg2_cell_size| { let iter = |max_entity_radius: f32, grid: &'a hashbrown::HashMap<_, _>, lg2_cell_size| {
let min = line.start.map2(line.end, f32::min);
let max = line.start.map2(line.end, f32::max);
// Add buffer for other entity radius // Add buffer for other entity radius
let ylo = (p0.y.min(p1.y) - radius - max_entity_radius) as i32; let ylo = (min.y - radius - max_entity_radius).floor() as i32;
let yhi = (p0.y.max(p1.y) + radius + max_entity_radius) as i32; let yhi = (max.y + radius + max_entity_radius).ceil() as i32;
// Convert to cells // Convert to cells
let ylo = ylo >> lg2_cell_size; let ylo = ylo >> lg2_cell_size;
let yhi = (yhi + (1 << lg2_cell_size) - 1) >> lg2_cell_size; let yhi = (yhi + (1 << lg2_cell_size) - 1) >> lg2_cell_size;
(ylo..=yhi) (ylo..=yhi)
.flat_map(move |y| { .flat_map(move |y| {
let mid = LineSegment2 { start: p0, end: p1 } // 1. project points from outside the line onto the line
.projected_point(Vec2::new(p0.x, y as f32)); let xlo = line.projected_point(Vec2::new(min.x, y as f32)).x;
let xlo = (mid.x - radius - max_entity_radius) as i32; let xhi = line.projected_point(Vec2::new(max.x, y as f32)).x;
let xhi = (mid.x + radius + max_entity_radius) as i32; // 2. subtract/add the radius to create a gap around the line
let xlo = (xlo - radius - max_entity_radius).floor() as i32;
let xhi = (xhi + radius + max_entity_radius).ceil() as i32;
// 3. convert from voxel coordinates to cell coordinates
let xlo = xlo >> lg2_cell_size; let xlo = xlo >> lg2_cell_size;
let xhi = (xhi + (1 << lg2_cell_size) - 1) >> lg2_cell_size; let xhi = (xhi + (1 << lg2_cell_size) - 1) >> lg2_cell_size;
(xlo..=xhi).map(move |x| Vec2::new(x, y)) (xlo..=xhi).map(move |x| Vec2::new(x, y))

View File

@ -342,12 +342,14 @@ impl<'a> PhysicsData<'a> {
let mut vel_delta = Vec3::zero(); let mut vel_delta = Vec3::zero();
let query_p0 = pos.0.xy(); let query_line = LineSegment2 {
let query_p1 = (pos.0 + previous_cache.velocity_dt).xy(); start: pos.0.xy(),
end: (pos.0 + previous_cache.velocity_dt).xy(),
};
let query_radius = previous_cache.scaled_radius; let query_radius = previous_cache.scaled_radius;
spatial_grid spatial_grid
.in_swept_circle(query_p0, query_p1, query_radius) .in_swept_circle(query_line, query_radius)
.filter_map(|entity| { .filter_map(|entity| {
read.uids read.uids
.get(entity) .get(entity)
@ -920,7 +922,7 @@ impl<'a> PhysicsData<'a> {
// Compute center and radius of tick path bounding sphere for the entity // Compute center and radius of tick path bounding sphere for the entity
// for broad checks of whether it will collide with a voxel collider // for broad checks of whether it will collide with a voxel collider
let path_sphere = { let (path_sphere, query_line, query_radius) = {
// TODO: duplicated with maintain_pushback_cache, make a common function // TODO: duplicated with maintain_pushback_cache, make a common function
// to call to compute all this info? // to call to compute all this info?
let z_limits = calc_z_limit(character_state, Some(collider)); let z_limits = calc_z_limit(character_state, Some(collider));
@ -934,16 +936,20 @@ impl<'a> PhysicsData<'a> {
let radius = (flat_radius.powi(2) + half_height.powi(2)).sqrt(); let radius = (flat_radius.powi(2) + half_height.powi(2)).sqrt();
let path_bounding_radius = radius + (pos_delta / 2.0).magnitude(); let path_bounding_radius = radius + (pos_delta / 2.0).magnitude();
Sphere { let path_sphere = Sphere {
center: path_center, center: path_center,
radius: path_bounding_radius, radius: path_bounding_radius,
} };
let query_line = LineSegment2 {
start: pos.0.xy(),
end: (pos.0 + pos_delta).xy(),
};
let query_radius = flat_radius;
(path_sphere, query_line, query_radius)
}; };
// Collide with terrain-like entities // Collide with terrain-like entities
let query_center = path_sphere.center.xy();
let query_radius = path_sphere.radius;
voxel_collider_spatial_grid voxel_collider_spatial_grid
.in_circle_aabr(query_center, query_radius) .in_swept_circle(query_line, query_radius)
.filter_map(|entity| { .filter_map(|entity| {
positions positions
.get(entity) .get(entity)