Skip to content

Commit

Permalink
Merge pull request #300 from rustsim/ccd
Browse files Browse the repository at this point in the history
Implement nonlinear TOI + refactor the query and world modules.
  • Loading branch information
sebcrozet committed Aug 6, 2019
2 parents 3d1a93f + d00a0b9 commit 3cbcd08
Show file tree
Hide file tree
Showing 200 changed files with 4,571 additions and 3,635 deletions.
1 change: 1 addition & 0 deletions build/ncollide2d/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ downcast-rs = "1.0"
num-traits = { version = "0.2", default-features = false }
smallvec = "0.6"
slab = "0.4"
slotmap = "0.3"
petgraph = "0.4"
alga = "0.9"
nalgebra = "0.18"
Expand Down
62 changes: 31 additions & 31 deletions build/ncollide2d/examples/custom_collision_filter2d.rs
Original file line number Diff line number Diff line change
@@ -1,34 +1,34 @@
extern crate nalgebra as na;
extern crate ncollide2d;

use ncollide2d::broad_phase::BroadPhasePairFilter;
use ncollide2d::shape::{Ball, ShapeHandle};
use ncollide2d::world::{CollisionGroups, CollisionObject, CollisionWorld, GeometricQueryType};

struct ParityFilter;

impl BroadPhasePairFilter<f32, ()> for ParityFilter {
fn is_pair_valid(&self, b1: &CollisionObject<f32, ()>, b2: &CollisionObject<f32, ()>) -> bool {
b1.handle().uid() % 2 == b2.handle().uid() % 2
}
}
//extern crate nalgebra as na;
//extern crate ncollide2d;
//
//use ncollide2d::broad_phase::BroadPhasePairFilter;
//use ncollide2d::shape::{Ball, ShapeHandle};
//use ncollide2d::world::{CollisionGroups, CollisionObject, CollisionWorld, GeometricQueryType};
//
//struct ParityFilter;
//
//impl BroadPhasePairFilter<f32, ()> for ParityFilter {
// fn is_pair_valid(&self, b1: &CollisionObject<f32, ()>, b2: &CollisionObject<f32, ()>) -> bool {
// b1.handle().uid() % 2 == b2.handle().uid() % 2
// }
//}

fn main() {
let shape = ShapeHandle::new(Ball::new(0.5f32));
let groups = CollisionGroups::new();
let query = GeometricQueryType::Contacts(0.0, 0.0);

let mut world = CollisionWorld::new(0.02);

world.register_broad_phase_pair_filter("Parity filter", ParityFilter);

world.add(na::one(), shape.clone(), groups, query, ());
world.add(na::one(), shape.clone(), groups, query, ());
world.add(na::one(), shape.clone(), groups, query, ());
world.add(na::one(), shape.clone(), groups, query, ());

world.update();

// There will be only 2 contact pairs instead of 6.
assert!(world.contact_pairs(true).count() == 2);
// let shape = ShapeHandle::new(Ball::new(0.5f32));
// let groups = CollisionGroups::new();
// let query = GeometricQueryType::Contacts(0.0, 0.0);
//
// let mut world = CollisionWorld::new(0.02);
//
// world.register_broad_phase_pair_filter("Parity filter", ParityFilter);
//
// world.add(na::one(), shape.clone(), groups, query, ());
// world.add(na::one(), shape.clone(), groups, query, ());
// world.add(na::one(), shape.clone(), groups, query, ());
// world.add(na::one(), shape.clone(), groups, query, ());
//
// world.update();
//
// // There will be only 2 contact pairs instead of 6.
// assert!(world.contact_pairs(true).count() == 2);
}
8 changes: 4 additions & 4 deletions build/ncollide2d/examples/ray_bvt2d.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@ fn main() {
let cube2 = Cuboid::new(Vector2::new(1.0, 0.5));

let shapes = [
&ball1 as &Shape,
&ball2 as &Shape,
&cube1 as &Shape,
&cube2 as &Shape,
&ball1 as &dyn Shape,
&ball2 as &dyn Shape,
&cube1 as &dyn Shape,
&cube2 as &dyn Shape,
];

let poss = [
Expand Down
12 changes: 9 additions & 3 deletions build/ncollide2d/examples/time_of_impact_query2d.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ fn main() {
&cuboid_pos,
&box_vel1,
&cuboid,
std::f64::MAX,
0.0,
);
let toi_will_touch = query::time_of_impact(
&ball_pos_will_touch,
Expand All @@ -35,6 +37,8 @@ fn main() {
&cuboid_pos,
&box_vel2,
&cuboid,
std::f64::MAX,
0.0,
);
let toi_wont_touch = query::time_of_impact(
&ball_pos_wont_touch,
Expand All @@ -43,10 +47,12 @@ fn main() {
&cuboid_pos,
&box_vel1,
&cuboid,
std::f64::MAX,
0.0,
);

assert_eq!(toi_intersecting, Some(0.0));
assert_eq!(toi_intersecting.map(|toi| toi.toi), Some(0.0));
println!("Toi: {:?}", toi_will_touch);
assert!(toi_will_touch.is_some() && toi_will_touch.unwrap() > 0.0);
assert_eq!(toi_wont_touch, None);
assert!(toi_will_touch.is_some() && toi_will_touch.unwrap().toi > 0.0);
assert_eq!(toi_wont_touch.map(|toi| toi.toi), None);
}
4 changes: 2 additions & 2 deletions build/ncollide2d/tests/geometry/ball_ball_toi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ fn test_ball_ball_toi() {
let m1 = Isometry2::new(na::zero(), na::zero());
let m2 = Isometry2::new(Vector2::new(0.0, 10.0), na::zero());

let cast = query::time_of_impact(&m1, &Vector2::new(0.0, 10.0), &b, &m2, &na::zero(), &b);
let cast = query::time_of_impact(&m1, &Vector2::new(0.0, 10.0), &b, &m2, &na::zero(), &b,std::f64::MAX, 0.0);

assert_eq!(cast.unwrap(), 0.9);
assert_eq!(cast.unwrap().toi, 0.9);
}
10 changes: 3 additions & 7 deletions build/ncollide2d/tests/geometry/epa2.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
use na::{self, Isometry2, Vector2};
use ncollide2d::narrow_phase::{ContactDispatcher, DefaultContactDispatcher};
use ncollide2d::query::contacts_internal;
use ncollide2d::query::ContactPrediction;
use ncollide2d::query::{self, ContactPrediction};
use ncollide2d::shape::Cuboid;
use ncollide2d::utils::IdAllocator;

#[test]
#[allow(non_snake_case)]
Expand All @@ -12,13 +10,13 @@ fn cuboid_cuboid_EPA() {
let m1 = Isometry2::new(Vector2::new(3.5, 0.0), na::zero());
let m2 = Isometry2::identity();

let res = contacts_internal::support_map_against_support_map(&m1, &c, &m2, &c, 10.0)
let res = query::contact_support_map_support_map(&m1, &c, &m2, &c, 10.0)
.expect("Penetration not found.");
assert_eq!(res.depth, 0.5);
assert_eq!(res.normal, -Vector2::x_axis());

let m1 = Isometry2::new(Vector2::new(0.0, 0.2), na::zero());
let res = contacts_internal::support_map_against_support_map(&m1, &c, &m2, &c, 10.0)
let res = query::contact_support_map_support_map(&m1, &c, &m2, &c, 10.0)
.expect("Penetration not found.");
assert_eq!(res.depth, 1.8);
assert_eq!(res.normal, -Vector2::y_axis());
Expand All @@ -40,7 +38,6 @@ fn cuboids_large_size_ratio_issue_181() {

let mut p = Vector2::new(0.0, 0.0);
let mut angle = 0.0;
let mut id_alloc = IdAllocator::new();

// Used to panic at some point:
// thread 'main' panicked at 'assertion failed: neg_dist <= gjk::eps_tol()', ncollide_geometry/query/algorithms/EPA.rs:26:9
Expand All @@ -61,7 +58,6 @@ fn cuboids_large_size_ratio_issue_181() {
&cuboid_b,
None,
&prediction,
&mut id_alloc,
&mut manifold
);

Expand Down
16 changes: 9 additions & 7 deletions build/ncollide2d/tests/geometry/ray_cast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,35 +102,37 @@ fn perpendicular_raycast_starting_bellow_segment() {
/// Tests the accuracy of raycaster collision detection against a `ConvexPolygon`.
#[test]
fn convexpoly_raycast_fuzz() {
let vertices: Vec<Point2<f64>> = vec![[1, 1], [2, 1], [2, 2], [1, 2]]
let vertices: Vec<Point2<f64>> = vec![[2, 1], [2, 2], [1, 2], [1, 1]]
.into_iter()
.map(|[x, y]| Point2::new(x as f64, y as f64))
.collect();

let square = ConvexPolygon::try_new(vertices).unwrap();
let raycaster = square.as_ray_cast().unwrap();

let test_raycast = |ray_origin: Point2<f64>, ray_look_at: Point2<f64>| -> Option<f64> {
let ray_angle: Vector2<f64> = ray_look_at - ray_origin;
let ray_angle = ray_look_at - ray_origin;

raycaster.toi_with_ray(
&Isometry2::identity(),
&Ray::new(ray_origin, ray_angle.normalize()),
true,
)
};
for i in 8..10_000 {

for i in 0..10_000 {
let ray_origin = Point2::new(3., 1. + (i as f64 * 0.0001));
let ray_look_at = Point2::new(0., 2.);
let collision = test_raycast(ray_origin, ray_look_at);

match collision {
Some(distance) if distance >= 1.0 && distance < (2.0f64).sqrt() => (),
Some(distance) if distance >= 2.0 => panic!(
"Collided with back face instead of front face. Distance: {}",
distance
),
Some(distance) => panic!("Invalid collision distance: {}", distance),
None => panic!(
"Failed to collide with any face: {}, {}, {}",
i, ray_origin, ray_look_at
),
None => panic!("Failed to collide with any face"),
}
}
}
14 changes: 10 additions & 4 deletions build/ncollide2d/tests/geometry/time_of_impact2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ fn ball_cuboid_toi() {
&cuboid_pos,
&box_vel1,
&cuboid,
std::f64::MAX,
0.0,
);
let toi_will_touch = query::time_of_impact(
&ball_pos_will_touch,
Expand All @@ -33,6 +35,8 @@ fn ball_cuboid_toi() {
&cuboid_pos,
&box_vel2,
&cuboid,
std::f64::MAX,
0.0,
);
let toi_wont_touch = query::time_of_impact(
&ball_pos_wont_touch,
Expand All @@ -41,14 +45,16 @@ fn ball_cuboid_toi() {
&cuboid_pos,
&box_vel1,
&cuboid,
std::f64::MAX,
0.0,
);

assert_eq!(toi_intersecting, Some(0.0));
assert_eq!(toi_intersecting.map(|toi| toi.toi), Some(0.0));
assert!(relative_eq!(
toi_will_touch.unwrap(),
toi_will_touch.unwrap().toi,
(2.0f64.sqrt() - 1.0) / (ball_vel2 - box_vel2).norm()
));
assert_eq!(toi_wont_touch, None);
assert_eq!(toi_wont_touch.map(|toi| toi.toi), None);
}

#[test]
Expand All @@ -62,6 +68,6 @@ fn cuboid_cuboid_toi_issue_214() {
let vel1 = Vector2::new(1.0, 0.0);
let vel2 = Vector2::new(0.0, 0.0);

let toi = query::time_of_impact(&pos1, &vel1, &shape1, &pos2, &vel2, &shape2);
let toi = query::time_of_impact(&pos1, &vel1, &shape1, &pos2, &vel2, &shape2,std::f64::MAX, 0.0);
assert!(toi.is_some());
}
7 changes: 3 additions & 4 deletions build/ncollide2d/tests/pipeline/world_remove.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,19 @@
use na::{Isometry2, Vector2};
use ncollide2d::shape::{Ball, ShapeHandle};
use ncollide2d::world::GeometricQueryType;
use ncollide2d::world::{CollisionGroups, CollisionWorld};
use ncollide2d::pipeline::{GeometricQueryType, CollisionGroups, CollisionWorld};

#[test]
fn issue_57_object_remove() {
let mut world = CollisionWorld::new(0.1);
let shape = ShapeHandle::new(Ball::new(1.0));
let contact_query = GeometricQueryType::Contacts(0.0, 0.0);
let object1 = world.add(
let (object1, _) = world.add(
Isometry2::new(Vector2::new(1.0, 0.0), 0.0),
shape.clone(),
CollisionGroups::new(),
contact_query,
(),
).handle();
);
let _ = world.add(
Isometry2::new(Vector2::new(1.0, 1.0), 0.0),
shape.clone(),
Expand Down
1 change: 1 addition & 0 deletions build/ncollide3d/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ downcast-rs = "1.0"
num-traits = { version = "0.2", default-features = false }
smallvec = "0.6"
slab = "0.4"
slotmap = "0.3"
petgraph = "0.4"
alga = "0.9"
nalgebra = "0.18"
Expand Down
2 changes: 1 addition & 1 deletion build/ncollide3d/examples/collision_groups.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
extern crate ncollide3d;

use ncollide3d::world::CollisionGroups;
use ncollide3d::pipeline::CollisionGroups;

fn main() {
let a = CollisionGroups::new()
Expand Down
62 changes: 31 additions & 31 deletions build/ncollide3d/examples/custom_collision_filter3d.rs
Original file line number Diff line number Diff line change
@@ -1,34 +1,34 @@
extern crate nalgebra as na;
extern crate ncollide3d;

use ncollide3d::broad_phase::BroadPhasePairFilter;
use ncollide3d::shape::{Ball, ShapeHandle};
use ncollide3d::world::{CollisionGroups, CollisionObject, CollisionWorld, GeometricQueryType};

struct ParityFilter;

impl BroadPhasePairFilter<f32, ()> for ParityFilter {
fn is_pair_valid(&self, b1: &CollisionObject<f32, ()>, b2: &CollisionObject<f32, ()>) -> bool {
b1.handle().uid() % 2 == b2.handle().uid() % 2
}
}
//extern crate nalgebra as na;
//extern crate ncollide3d;
//
//use ncollide3d::broad_phase::BroadPhasePairFilter;
//use ncollide3d::shape::{Ball, ShapeHandle};
//use ncollide3d::pipeline::{CollisionGroups, CollisionObject, CollisionObjectSlabHandle, CollisionWorld, GeometricQueryType};
//
//struct ParityFilter;
//
//impl BroadPhasePairFilter<f32, CollisionObject<f32, ()>, CollisionObjectSlabHandle> for ParityFilter {
// fn is_pair_valid(&self, _: &CollisionObject<f32, ()>, _: &CollisionObject<f32, ()>, handle1: CollisionObjectSlabHandle, handle2: CollisionObjectSlabHandle) -> bool {
// handle1.uid() % 2 == handle2.uid() % 2
// }
//}

fn main() {
let shape = ShapeHandle::new(Ball::new(0.5f32));
let groups = CollisionGroups::new();
let query = GeometricQueryType::Contacts(0.0, 0.0);

let mut world = CollisionWorld::new(0.02);

world.register_broad_phase_pair_filter("Parity filter", ParityFilter);

world.add(na::one(), shape.clone(), groups, query, ());
world.add(na::one(), shape.clone(), groups, query, ());
world.add(na::one(), shape.clone(), groups, query, ());
world.add(na::one(), shape.clone(), groups, query, ());

world.update();

// There will be only 2 contacts instead of 6.
assert!(world.contact_pairs(true).count() == 2);
// let shape = ShapeHandle::new(Ball::new(0.5f32));
// let groups = CollisionGroups::new();
// let query = GeometricQueryType::Contacts(0.0, 0.0);
//
// let mut world = CollisionWorld::new(0.02);
//
// world.register_broad_phase_pair_filter("Parity filter", ParityFilter);
//
// world.add(na::one(), shape.clone(), groups, query, ());
// world.add(na::one(), shape.clone(), groups, query, ());
// world.add(na::one(), shape.clone(), groups, query, ());
// world.add(na::one(), shape.clone(), groups, query, ());
//
// world.update();
//
// // There will be only 2 contacts instead of 6.
// assert!(world.contact_pairs(true).count() == 2);
}
8 changes: 4 additions & 4 deletions build/ncollide3d/examples/ray_bvt3d.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@ fn main() {
let cube = Cuboid::new(Vector3::new(1.0, 0.5, 1.0));

let shapes = [
&ball as &Shape3,
&caps as &Shape3,
&cone as &Shape3,
&cube as &Shape3,
&ball as &dyn Shape3,
&caps as &dyn Shape3,
&cone as &dyn Shape3,
&cube as &dyn Shape3,
];

let poss = [
Expand Down
Loading

0 comments on commit 3cbcd08

Please sign in to comment.