From faec3d5d46c88e2949179dd2789899e5cf26ed48 Mon Sep 17 00:00:00 2001 From: Crozet Sébastien Date: Mon, 12 Oct 2020 18:33:58 +0200 Subject: Start adding cylinders. --- src/geometry/collider.rs | 48 +++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 43 insertions(+), 5 deletions(-) (limited to 'src/geometry/collider.rs') diff --git a/src/geometry/collider.rs b/src/geometry/collider.rs index 7c293b6..fe42bd7 100644 --- a/src/geometry/collider.rs +++ b/src/geometry/collider.rs @@ -1,7 +1,9 @@ use crate::dynamics::{MassProperties, RigidBodyHandle, RigidBodySet}; +#[cfg(feature = "dim3")] +use crate::geometry::PolygonalFeatureMap; use crate::geometry::{ - Ball, Capsule, ColliderGraphIndex, Contact, Cuboid, HeightField, InteractionGraph, Polygon, - Proximity, Ray, RayIntersection, Triangle, Trimesh, + Ball, Capsule, ColliderGraphIndex, Contact, Cuboid, Cylinder, HeightField, InteractionGraph, + Polygon, Proximity, Ray, RayIntersection, Triangle, Trimesh, }; use crate::math::{AngVector, Isometry, Point, Rotation, Vector}; use na::Point3; @@ -27,6 +29,9 @@ pub enum Shape { Trimesh(Trimesh), /// A heightfield shape. HeightField(HeightField), + #[cfg(feature = "dim3")] + /// A cylindrical shape. + Cylinder(Cylinder), } impl Shape { @@ -86,6 +91,25 @@ impl Shape { } } + /// Gets a reference to the underlying cylindrical shape, if `self` is one. + pub fn as_cylinder(&self) -> Option<&Cylinder> { + match self { + Shape::Cylinder(c) => Some(c), + _ => None, + } + } + + /// gets a reference to this shape seen as a PolygonalFeatureMap. + #[cfg(feature = "dim3")] + pub fn as_polygonal_feature_map(&self) -> Option<&dyn PolygonalFeatureMap> { + match self { + Shape::Triangle(t) => Some(t), + Shape::Cuboid(c) => Some(c), + Shape::Cylinder(c) => Some(c), + _ => None, + } + } + /// Computes the axis-aligned bounding box of this shape. pub fn compute_aabb(&self, position: &Isometry) -> AABB { match self { @@ -96,6 +120,7 @@ impl Shape { Shape::Triangle(triangle) => triangle.bounding_volume(position), Shape::Trimesh(trimesh) => trimesh.aabb(position), Shape::HeightField(heightfield) => heightfield.bounding_volume(position), + Shape::Cylinder(cylinder) => cylinder.bounding_volume(position), } } @@ -139,6 +164,10 @@ impl Shape { Shape::HeightField(heightfield) => { heightfield.toi_and_normal_with_ray(position, ray, max_toi, true) } + #[cfg(feature = "dim3")] + Shape::Cylinder(cylinder) => { + cylinder.toi_and_normal_with_ray(position, ray, max_toi, true) + } } } } @@ -242,9 +271,12 @@ impl Collider { Shape::Capsule(caps) => { MassProperties::from_capsule(self.density, caps.a, caps.b, caps.radius) } - Shape::Triangle(_) => MassProperties::zero(), - Shape::Trimesh(_) => MassProperties::zero(), - Shape::HeightField(_) => MassProperties::zero(), + Shape::Triangle(_) | Shape::Trimesh(_) | Shape::HeightField(_) => { + MassProperties::zero() + } + Shape::Cylinder(c) => { + MassProperties::from_cylinder(self.density, c.half_height, c.radius) + } } } } @@ -291,6 +323,12 @@ impl ColliderBuilder { Self::new(Shape::Ball(Ball::new(radius))) } + /// Initialize a new collider builder with a cylindrical shape defined by its half-height + /// (along along the y axis) and its radius. + pub fn cylinder(half_height: f32, radius: f32) -> Self { + Self::new(Shape::Cylinder(Cylinder::new(half_height, radius))) + } + /// Initialize a new collider builder with a cuboid shape defined by its half-extents. #[cfg(feature = "dim2")] pub fn cuboid(hx: f32, hy: f32) -> Self { -- cgit From 865ce8a8e5301b23ca474adaaffe8b43e725803e Mon Sep 17 00:00:00 2001 From: Crozet Sébastien Date: Tue, 20 Oct 2020 11:55:33 +0200 Subject: Collider shape: use a trait-object instead of an enum. --- src/geometry/collider.rs | 367 ++++++++++++++++++++++------------------------- 1 file changed, 172 insertions(+), 195 deletions(-) (limited to 'src/geometry/collider.rs') diff --git a/src/geometry/collider.rs b/src/geometry/collider.rs index fe42bd7..c6cf6d0 100644 --- a/src/geometry/collider.rs +++ b/src/geometry/collider.rs @@ -3,172 +3,186 @@ use crate::dynamics::{MassProperties, RigidBodyHandle, RigidBodySet}; use crate::geometry::PolygonalFeatureMap; use crate::geometry::{ Ball, Capsule, ColliderGraphIndex, Contact, Cuboid, Cylinder, HeightField, InteractionGraph, - Polygon, Proximity, Ray, RayIntersection, Triangle, Trimesh, + Polygon, Proximity, Ray, RayIntersection, Shape, ShapeType, Triangle, Trimesh, }; use crate::math::{AngVector, Isometry, Point, Rotation, Vector}; +use downcast_rs::{impl_downcast, DowncastSync}; +use erased_serde::Serialize; use na::Point3; use ncollide::bounding_volume::{HasBoundingVolume, AABB}; use ncollide::query::RayCast; use num::Zero; +use std::any::Any; +use std::ops::Deref; +use std::sync::Arc; +/// The shape of a collider. #[derive(Clone)] -#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] -/// An enum grouping all the possible shape of a collider. -pub enum Shape { - /// A ball shape. - Ball(Ball), - /// A convex polygon shape. - Polygon(Polygon), - /// A cuboid shape. - Cuboid(Cuboid), - /// A capsule shape. - Capsule(Capsule), - /// A triangle shape. - Triangle(Triangle), - /// A triangle mesh shape. - Trimesh(Trimesh), - /// A heightfield shape. - HeightField(HeightField), - #[cfg(feature = "dim3")] - /// A cylindrical shape. - Cylinder(Cylinder), -} +pub struct ColliderShape(pub Arc); -impl Shape { - /// Gets a reference to the underlying ball shape, if `self` is one. - pub fn as_ball(&self) -> Option<&Ball> { - match self { - Shape::Ball(b) => Some(b), - _ => None, - } +impl Deref for ColliderShape { + type Target = Shape; + fn deref(&self) -> &Shape { + &*self.0 } +} - /// Gets a reference to the underlying polygon shape, if `self` is one. - pub fn as_polygon(&self) -> Option<&Polygon> { - match self { - Shape::Polygon(p) => Some(p), - _ => None, - } +impl ColliderShape { + /// Initialize a ball shape defined by its radius. + pub fn ball(radius: f32) -> Self { + ColliderShape(Arc::new(Ball::new(radius))) } - /// Gets a reference to the underlying cuboid shape, if `self` is one. - pub fn as_cuboid(&self) -> Option<&Cuboid> { - match self { - Shape::Cuboid(c) => Some(c), - _ => None, - } + /// Initialize a cylindrical shape defined by its half-height + /// (along along the y axis) and its radius. + #[cfg(feature = "dim3")] + pub fn cylinder(half_height: f32, radius: f32) -> Self { + ColliderShape(Arc::new(Cylinder::new(half_height, radius))) } - /// Gets a reference to the underlying capsule shape, if `self` is one. - pub fn as_capsule(&self) -> Option<&Capsule> { - match self { - Shape::Capsule(c) => Some(c), - _ => None, - } + /// Initialize a cuboid shape defined by its half-extents. + pub fn cuboid(half_extents: Vector) -> Self { + ColliderShape(Arc::new(Cuboid::new(half_extents))) } - /// Gets a reference to the underlying triangle mesh shape, if `self` is one. - pub fn as_trimesh(&self) -> Option<&Trimesh> { - match self { - Shape::Trimesh(c) => Some(c), - _ => None, - } + /// Initialize a capsule shape aligned with the `y` axis. + pub fn capsule(half_height: f32, radius: f32) -> Self { + ColliderShape(Arc::new(Capsule::new(half_height, radius))) } - /// Gets a reference to the underlying heightfield shape, if `self` is one. - pub fn as_heightfield(&self) -> Option<&HeightField> { - match self { - Shape::HeightField(h) => Some(h), - _ => None, - } + /// Initializes a triangle shape. + pub fn triangle(a: Point, b: Point, c: Point) -> Self { + ColliderShape(Arc::new(Triangle::new(a, b, c))) } - /// Gets a reference to the underlying triangle shape, if `self` is one. - pub fn as_triangle(&self) -> Option<&Triangle> { - match self { - Shape::Triangle(c) => Some(c), - _ => None, - } + /// Initializes a triangle mesh shape defined by its vertex and index buffers. + pub fn trimesh(vertices: Vec>, indices: Vec>) -> Self { + ColliderShape(Arc::new(Trimesh::new(vertices, indices))) } - /// Gets a reference to the underlying cylindrical shape, if `self` is one. - pub fn as_cylinder(&self) -> Option<&Cylinder> { - match self { - Shape::Cylinder(c) => Some(c), - _ => None, - } + /// Initializes an heightfield shape defined by its set of height and a scale + /// factor along each coordinate axis. + #[cfg(feature = "dim2")] + pub fn heightfield(heights: na::DVector, scale: Vector) -> Self { + ColliderShape(Arc::new(HeightField::new(heights, scale))) } - /// gets a reference to this shape seen as a PolygonalFeatureMap. + /// Initializes an heightfield shape on the x-z plane defined by its set of height and a scale + /// factor along each coordinate axis. #[cfg(feature = "dim3")] - pub fn as_polygonal_feature_map(&self) -> Option<&dyn PolygonalFeatureMap> { - match self { - Shape::Triangle(t) => Some(t), - Shape::Cuboid(c) => Some(c), - Shape::Cylinder(c) => Some(c), - _ => None, - } + pub fn heightfield(heights: na::DMatrix, scale: Vector) -> Self { + ColliderShape(Arc::new(HeightField::new(heights, scale))) } +} - /// Computes the axis-aligned bounding box of this shape. - pub fn compute_aabb(&self, position: &Isometry) -> AABB { - match self { - Shape::Ball(ball) => ball.bounding_volume(position), - Shape::Polygon(poly) => poly.aabb(position), - Shape::Capsule(caps) => caps.aabb(position), - Shape::Cuboid(cuboid) => cuboid.bounding_volume(position), - Shape::Triangle(triangle) => triangle.bounding_volume(position), - Shape::Trimesh(trimesh) => trimesh.aabb(position), - Shape::HeightField(heightfield) => heightfield.bounding_volume(position), - Shape::Cylinder(cylinder) => cylinder.bounding_volume(position), +#[cfg(feature = "serde-serialize")] +impl serde::Serialize for ColliderShape { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + use crate::serde::ser::SerializeStruct; + + if let Some(ser) = self.0.as_serialize() { + let typ = self.0.shape_type(); + let mut state = serializer.serialize_struct("ColliderShape", 2)?; + state.serialize_field("tag", &(typ as i32))?; + state.serialize_field("inner", ser)?; + state.end() + } else { + Err(serde::ser::Error::custom( + "Found a non-serializable custom shape.", + )) } } +} - /// Computes the first intersection point between a ray in this collider. - /// - /// Some shapes are not supported yet and will always return `None`. - /// - /// # Parameters - /// - `position`: the position of this shape. - /// - `ray`: the ray to cast. - /// - `max_toi`: the maximum time-of-impact that can be reported by this cast. This effectively - /// limits the length of the ray to `ray.dir.norm() * max_toi`. Use `f32::MAX` for an unbounded ray. - pub fn cast_ray( - &self, - position: &Isometry, - ray: &Ray, - max_toi: f32, - ) -> Option { - match self { - Shape::Ball(ball) => ball.toi_and_normal_with_ray(position, ray, max_toi, true), - Shape::Polygon(_poly) => None, - Shape::Capsule(caps) => { - let pos = position * caps.transform_wrt_y(); - let caps = ncollide::shape::Capsule::new(caps.half_height(), caps.radius); - caps.toi_and_normal_with_ray(&pos, ray, max_toi, true) +#[cfg(feature = "serde-serialize")] +impl<'de> serde::Deserialize<'de> for ColliderShape { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + struct Visitor {}; + impl<'de> serde::de::Visitor<'de> for Visitor { + type Value = ColliderShape; + fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(formatter, "one shape type tag and the inner shape data") } - Shape::Cuboid(cuboid) => cuboid.toi_and_normal_with_ray(position, ray, max_toi, true), - #[cfg(feature = "dim2")] - Shape::Triangle(_) | Shape::Trimesh(_) => { - // This is not implemented yet in 2D. - None - } - #[cfg(feature = "dim3")] - Shape::Triangle(triangle) => { - triangle.toi_and_normal_with_ray(position, ray, max_toi, true) - } - #[cfg(feature = "dim3")] - Shape::Trimesh(trimesh) => { - trimesh.toi_and_normal_with_ray(position, ray, max_toi, true) - } - Shape::HeightField(heightfield) => { - heightfield.toi_and_normal_with_ray(position, ray, max_toi, true) - } - #[cfg(feature = "dim3")] - Shape::Cylinder(cylinder) => { - cylinder.toi_and_normal_with_ray(position, ray, max_toi, true) + + fn visit_seq(self, mut seq: A) -> Result + where + A: serde::de::SeqAccess<'de>, + { + use num::cast::FromPrimitive; + + let tag: i32 = seq + .next_element()? + .ok_or_else(|| serde::de::Error::invalid_length(0, &self))?; + + let shape = match ShapeType::from_i32(tag) { + Some(ShapeType::Ball) => { + let shape: Ball = seq + .next_element()? + .ok_or_else(|| serde::de::Error::invalid_length(0, &self))?; + Arc::new(shape) as Arc + } + Some(ShapeType::Polygon) => { + unimplemented!() + // let shape: Polygon = seq + // .next_element()? + // .ok_or_else(|| serde::de::Error::invalid_length(0, &self))?; + // Arc::new(shape) as Arc + } + Some(ShapeType::Cuboid) => { + let shape: Cuboid = seq + .next_element()? + .ok_or_else(|| serde::de::Error::invalid_length(0, &self))?; + Arc::new(shape) as Arc + } + Some(ShapeType::Capsule) => { + let shape: Capsule = seq + .next_element()? + .ok_or_else(|| serde::de::Error::invalid_length(0, &self))?; + Arc::new(shape) as Arc + } + Some(ShapeType::Triangle) => { + let shape: Triangle = seq + .next_element()? + .ok_or_else(|| serde::de::Error::invalid_length(0, &self))?; + Arc::new(shape) as Arc + } + Some(ShapeType::Trimesh) => { + let shape: Trimesh = seq + .next_element()? + .ok_or_else(|| serde::de::Error::invalid_length(0, &self))?; + Arc::new(shape) as Arc + } + Some(ShapeType::HeightField) => { + let shape: HeightField = seq + .next_element()? + .ok_or_else(|| serde::de::Error::invalid_length(0, &self))?; + Arc::new(shape) as Arc + } + #[cfg(feature = "dim3")] + Some(ShapeType::Cylinder) => { + let shape: Cylinder = seq + .next_element()? + .ok_or_else(|| serde::de::Error::invalid_length(0, &self))?; + Arc::new(shape) as Arc + } + None => { + return Err(serde::de::Error::custom( + "found invalid shape type to deserialize", + )) + } + }; + + Ok(ColliderShape(shape)) } } + + deserializer.deserialize_struct("ColliderShape", &["tag", "inner"], Visitor {}) } } @@ -177,7 +191,7 @@ impl Shape { /// /// To build a new collider, use the `ColliderBuilder` structure. pub struct Collider { - shape: Shape, + shape: ColliderShape, density: f32, is_sensor: bool, pub(crate) parent: RigidBodyHandle, @@ -245,7 +259,7 @@ impl Collider { /// The geometric shape of this collider. pub fn shape(&self) -> &Shape { - &self.shape + &*self.shape.0 } /// Compute the axis-aligned bounding box of this collider. @@ -261,23 +275,7 @@ impl Collider { /// Compute the local-space mass properties of this collider. pub fn mass_properties(&self) -> MassProperties { - match &self.shape { - Shape::Ball(ball) => MassProperties::from_ball(self.density, ball.radius), - #[cfg(feature = "dim2")] - Shape::Polygon(p) => MassProperties::from_polygon(self.density, p.vertices()), - #[cfg(feature = "dim3")] - Shape::Polygon(_p) => unimplemented!(), - Shape::Cuboid(c) => MassProperties::from_cuboid(self.density, c.half_extents), - Shape::Capsule(caps) => { - MassProperties::from_capsule(self.density, caps.a, caps.b, caps.radius) - } - Shape::Triangle(_) | Shape::Trimesh(_) | Shape::HeightField(_) => { - MassProperties::zero() - } - Shape::Cylinder(c) => { - MassProperties::from_cylinder(self.density, c.half_height, c.radius) - } - } + self.shape.mass_properties(self.density) } } @@ -286,7 +284,7 @@ impl Collider { #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] pub struct ColliderBuilder { /// The shape of the collider to be built. - pub shape: Shape, + pub shape: ColliderShape, /// The density of the collider to be built. density: Option, /// The friction coefficient of the collider to be built. @@ -301,7 +299,7 @@ pub struct ColliderBuilder { impl ColliderBuilder { /// Initialize a new collider builder with the given shape. - pub fn new(shape: Shape) -> Self { + pub fn new(shape: ColliderShape) -> Self { Self { shape, density: None, @@ -320,102 +318,81 @@ impl ColliderBuilder { /// Initialize a new collider builder with a ball shape defined by its radius. pub fn ball(radius: f32) -> Self { - Self::new(Shape::Ball(Ball::new(radius))) + Self::new(ColliderShape::ball(radius)) } /// Initialize a new collider builder with a cylindrical shape defined by its half-height /// (along along the y axis) and its radius. + #[cfg(feature = "dim3")] pub fn cylinder(half_height: f32, radius: f32) -> Self { - Self::new(Shape::Cylinder(Cylinder::new(half_height, radius))) + Self::new(ColliderShape::cylinder(half_height, radius)) } /// Initialize a new collider builder with a cuboid shape defined by its half-extents. #[cfg(feature = "dim2")] pub fn cuboid(hx: f32, hy: f32) -> Self { - let cuboid = Cuboid { - half_extents: Vector::new(hx, hy), - }; - - Self::new(Shape::Cuboid(cuboid)) - - /* - use crate::math::Point; - let vertices = vec![ - Point::new(hx, -hy), - Point::new(hx, hy), - Point::new(-hx, hy), - Point::new(-hx, -hy), - ]; - let normals = vec![Vector::x(), Vector::y(), -Vector::x(), -Vector::y()]; - let polygon = Polygon::new(vertices, normals); - - Self::new(Shape::Polygon(polygon)) - */ + Self::new(ColliderShape::cuboid(Vector::new(hx, hy))) } /// Initialize a new collider builder with a capsule shape aligned with the `x` axis. pub fn capsule_x(half_height: f32, radius: f32) -> Self { - let capsule = Capsule::new_x(half_height, radius); - Self::new(Shape::Capsule(capsule)) + #[cfg(feature = "dim2")] + let rot = -std::f32::consts::FRAC_PI_2; + #[cfg(feature = "dim3")] + let rot = Vector::z() * -std::f32::consts::FRAC_PI_2; + Self::new(ColliderShape::capsule(half_height, radius)) + .position(Isometry::new(na::zero(), rot)) } /// Initialize a new collider builder with a capsule shape aligned with the `y` axis. pub fn capsule_y(half_height: f32, radius: f32) -> Self { - let capsule = Capsule::new_y(half_height, radius); - Self::new(Shape::Capsule(capsule)) + Self::new(ColliderShape::capsule(half_height, radius)) } /// Initialize a new collider builder with a capsule shape aligned with the `z` axis. #[cfg(feature = "dim3")] pub fn capsule_z(half_height: f32, radius: f32) -> Self { - let capsule = Capsule::new_z(half_height, radius); - Self::new(Shape::Capsule(capsule)) + let rot = Vector::x() * std::f32::consts::FRAC_PI_2; + Self::new(ColliderShape::capsule(half_height, radius)) + .position(Isometry::new(na::zero(), rot)) } /// Initialize a new collider builder with a cuboid shape defined by its half-extents. #[cfg(feature = "dim3")] pub fn cuboid(hx: f32, hy: f32, hz: f32) -> Self { - let cuboid = Cuboid { - half_extents: Vector::new(hx, hy, hz), - }; - - Self::new(Shape::Cuboid(cuboid)) + Self::new(ColliderShape::cuboid(Vector::new(hx, hy, hz))) } /// Initializes a collider builder with a segment shape. /// /// A segment shape is modeled by a capsule with a 0 radius. pub fn segment(a: Point, b: Point) -> Self { - let capsule = Capsule::new(a, b, 0.0); - Self::new(Shape::Capsule(capsule)) + let (pos, half_height) = crate::utils::segment_to_capsule(&a, &b); + Self::new(ColliderShape::capsule(half_height, 0.0)).position(pos) } /// Initializes a collider builder with a triangle shape. pub fn triangle(a: Point, b: Point, c: Point) -> Self { - let triangle = Triangle::new(a, b, c); - Self::new(Shape::Triangle(triangle)) + Self::new(ColliderShape::triangle(a, b, c)) } /// Initializes a collider builder with a triangle mesh shape defined by its vertex and index buffers. pub fn trimesh(vertices: Vec>, indices: Vec>) -> Self { - let trimesh = Trimesh::new(vertices, indices); - Self::new(Shape::Trimesh(trimesh)) + Self::new(ColliderShape::trimesh(vertices, indices)) } /// Initializes a collider builder with a heightfield shape defined by its set of height and a scale /// factor along each coordinate axis. #[cfg(feature = "dim2")] pub fn heightfield(heights: na::DVector, scale: Vector) -> Self { - let heightfield = HeightField::new(heights, scale); - Self::new(Shape::HeightField(heightfield)) + Self::new(ColliderShape::heightfield(heights, scale)) } /// Initializes a collider builder with a heightfield shape defined by its set of height and a scale /// factor along each coordinate axis. #[cfg(feature = "dim3")] pub fn heightfield(heights: na::DMatrix, scale: Vector) -> Self { - let heightfield = HeightField::new(heights, scale); - Self::new(Shape::HeightField(heightfield)) + Self::new(ColliderShape::heightfield(heights, scale)) } /// The default friction coefficient used by the collider builder. -- cgit From d513c22d33ab44b0048355bcfd1db4173b3f7ece Mon Sep 17 00:00:00 2001 From: Crozet Sébastien Date: Tue, 20 Oct 2020 14:16:01 +0200 Subject: Add cone support. --- src/geometry/collider.rs | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) (limited to 'src/geometry/collider.rs') diff --git a/src/geometry/collider.rs b/src/geometry/collider.rs index c6cf6d0..f952b15 100644 --- a/src/geometry/collider.rs +++ b/src/geometry/collider.rs @@ -1,10 +1,10 @@ use crate::dynamics::{MassProperties, RigidBodyHandle, RigidBodySet}; -#[cfg(feature = "dim3")] -use crate::geometry::PolygonalFeatureMap; use crate::geometry::{ - Ball, Capsule, ColliderGraphIndex, Contact, Cuboid, Cylinder, HeightField, InteractionGraph, - Polygon, Proximity, Ray, RayIntersection, Shape, ShapeType, Triangle, Trimesh, + Ball, Capsule, ColliderGraphIndex, Contact, Cuboid, HeightField, InteractionGraph, Polygon, + Proximity, Ray, RayIntersection, Shape, ShapeType, Triangle, Trimesh, }; +#[cfg(feature = "dim3")] +use crate::geometry::{Cone, Cylinder, PolygonalFeatureMap}; use crate::math::{AngVector, Isometry, Point, Rotation, Vector}; use downcast_rs::{impl_downcast, DowncastSync}; use erased_serde::Serialize; @@ -40,6 +40,13 @@ impl ColliderShape { ColliderShape(Arc::new(Cylinder::new(half_height, radius))) } + /// Initialize a cone shape defined by its half-height + /// (along along the y axis) and its basis radius. + #[cfg(feature = "dim3")] + pub fn cone(half_height: f32, radius: f32) -> Self { + ColliderShape(Arc::new(Cone::new(half_height, radius))) + } + /// Initialize a cuboid shape defined by its half-extents. pub fn cuboid(half_extents: Vector) -> Self { ColliderShape(Arc::new(Cuboid::new(half_extents))) @@ -171,6 +178,13 @@ impl<'de> serde::Deserialize<'de> for ColliderShape { .ok_or_else(|| serde::de::Error::invalid_length(0, &self))?; Arc::new(shape) as Arc } + #[cfg(feature = "dim3")] + Some(ShapeType::Cone) => { + let shape: Cone = seq + .next_element()? + .ok_or_else(|| serde::de::Error::invalid_length(0, &self))?; + Arc::new(shape) as Arc + } None => { return Err(serde::de::Error::custom( "found invalid shape type to deserialize", @@ -328,6 +342,13 @@ impl ColliderBuilder { Self::new(ColliderShape::cylinder(half_height, radius)) } + /// Initialize a new collider builder with a cone shape defined by its half-height + /// (along along the y axis) and its basis radius. + #[cfg(feature = "dim3")] + pub fn cone(half_height: f32, radius: f32) -> Self { + Self::new(ColliderShape::cone(half_height, radius)) + } + /// Initialize a new collider builder with a cuboid shape defined by its half-extents. #[cfg(feature = "dim2")] pub fn cuboid(hx: f32, hy: f32) -> Self { -- cgit From 64958470950cd9832a669b1bd5d70a2aeb6a85ef Mon Sep 17 00:00:00 2001 From: Crozet Sébastien Date: Tue, 20 Oct 2020 15:57:54 +0200 Subject: Add rounded cylinder. --- src/geometry/collider.rs | 95 +++++++++++++++++++++++------------------------- 1 file changed, 46 insertions(+), 49 deletions(-) (limited to 'src/geometry/collider.rs') diff --git a/src/geometry/collider.rs b/src/geometry/collider.rs index f952b15..4b3b115 100644 --- a/src/geometry/collider.rs +++ b/src/geometry/collider.rs @@ -1,7 +1,7 @@ use crate::dynamics::{MassProperties, RigidBodyHandle, RigidBodySet}; use crate::geometry::{ Ball, Capsule, ColliderGraphIndex, Contact, Cuboid, HeightField, InteractionGraph, Polygon, - Proximity, Ray, RayIntersection, Shape, ShapeType, Triangle, Trimesh, + Proximity, Ray, RayIntersection, Rounded, Shape, ShapeType, Triangle, Trimesh, }; #[cfg(feature = "dim3")] use crate::geometry::{Cone, Cylinder, PolygonalFeatureMap}; @@ -40,6 +40,17 @@ impl ColliderShape { ColliderShape(Arc::new(Cylinder::new(half_height, radius))) } + /// Initialize a rounded cylindrical shape defined by its half-height + /// (along along the y axis), its radius, and its roundedness (the + /// radius of the sphere used for dilating the cylinder). + #[cfg(feature = "dim3")] + pub fn rounded_cylinder(half_height: f32, radius: f32, rounding_radius: f32) -> Self { + ColliderShape(Arc::new(Rounded::new( + Cylinder::new(half_height, radius), + rounding_radius, + ))) + } + /// Initialize a cone shape defined by its half-height /// (along along the y axis) and its basis radius. #[cfg(feature = "dim3")] @@ -127,13 +138,20 @@ impl<'de> serde::Deserialize<'de> for ColliderShape { .next_element()? .ok_or_else(|| serde::de::Error::invalid_length(0, &self))?; + fn deser<'de, A, S: Shape + serde::Deserialize<'de>>( + seq: &mut A, + ) -> Result, A::Error> + where + A: serde::de::SeqAccess<'de>, + { + let shape: S = seq.next_element()?.ok_or_else(|| { + serde::de::Error::custom("Failed to deserialize builtin shape.") + })?; + Ok(Arc::new(shape) as Arc) + } + let shape = match ShapeType::from_i32(tag) { - Some(ShapeType::Ball) => { - let shape: Ball = seq - .next_element()? - .ok_or_else(|| serde::de::Error::invalid_length(0, &self))?; - Arc::new(shape) as Arc - } + Some(ShapeType::Ball) => deser::(&mut seq)?, Some(ShapeType::Polygon) => { unimplemented!() // let shape: Polygon = seq @@ -141,50 +159,17 @@ impl<'de> serde::Deserialize<'de> for ColliderShape { // .ok_or_else(|| serde::de::Error::invalid_length(0, &self))?; // Arc::new(shape) as Arc } - Some(ShapeType::Cuboid) => { - let shape: Cuboid = seq - .next_element()? - .ok_or_else(|| serde::de::Error::invalid_length(0, &self))?; - Arc::new(shape) as Arc - } - Some(ShapeType::Capsule) => { - let shape: Capsule = seq - .next_element()? - .ok_or_else(|| serde::de::Error::invalid_length(0, &self))?; - Arc::new(shape) as Arc - } - Some(ShapeType::Triangle) => { - let shape: Triangle = seq - .next_element()? - .ok_or_else(|| serde::de::Error::invalid_length(0, &self))?; - Arc::new(shape) as Arc - } - Some(ShapeType::Trimesh) => { - let shape: Trimesh = seq - .next_element()? - .ok_or_else(|| serde::de::Error::invalid_length(0, &self))?; - Arc::new(shape) as Arc - } - Some(ShapeType::HeightField) => { - let shape: HeightField = seq - .next_element()? - .ok_or_else(|| serde::de::Error::invalid_length(0, &self))?; - Arc::new(shape) as Arc - } + Some(ShapeType::Cuboid) => deser::(&mut seq)?, + Some(ShapeType::Capsule) => deser::(&mut seq)?, + Some(ShapeType::Triangle) => deser::(&mut seq)?, + Some(ShapeType::Trimesh) => deser::(&mut seq)?, + Some(ShapeType::HeightField) => deser::(&mut seq)?, #[cfg(feature = "dim3")] - Some(ShapeType::Cylinder) => { - let shape: Cylinder = seq - .next_element()? - .ok_or_else(|| serde::de::Error::invalid_length(0, &self))?; - Arc::new(shape) as Arc - } + Some(ShapeType::Cylinder) => deser::(&mut seq)?, #[cfg(feature = "dim3")] - Some(ShapeType::Cone) => { - let shape: Cone = seq - .next_element()? - .ok_or_else(|| serde::de::Error::invalid_length(0, &self))?; - Arc::new(shape) as Arc - } + Some(ShapeType::Cone) => deser::(&mut seq)?, + #[cfg(feature = "dim3")] + Some(ShapeType::RoundedCylinder) => deser::>(&mut seq)?, None => { return Err(serde::de::Error::custom( "found invalid shape type to deserialize", @@ -342,6 +327,18 @@ impl ColliderBuilder { Self::new(ColliderShape::cylinder(half_height, radius)) } + /// Initialize a new collider builder with a rounded cylindrical shape defined by its half-height + /// (along along the y axis), its radius, and its roundedness (the + /// radius of the sphere used for dilating the cylinder). + #[cfg(feature = "dim3")] + pub fn rounded_cylinder(half_height: f32, radius: f32, rounding_radius: f32) -> Self { + Self::new(ColliderShape::rounded_cylinder( + half_height, + radius, + rounding_radius, + )) + } + /// Initialize a new collider builder with a cone shape defined by its half-height /// (along along the y axis) and its basis radius. #[cfg(feature = "dim3")] -- cgit From 949e3f5384a366c3bff5415c5db4635e811a580e Mon Sep 17 00:00:00 2001 From: Crozet Sébastien Date: Tue, 20 Oct 2020 16:22:53 +0200 Subject: Fix many warnings. --- src/geometry/collider.rs | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) (limited to 'src/geometry/collider.rs') diff --git a/src/geometry/collider.rs b/src/geometry/collider.rs index 4b3b115..4785d62 100644 --- a/src/geometry/collider.rs +++ b/src/geometry/collider.rs @@ -1,18 +1,13 @@ use crate::dynamics::{MassProperties, RigidBodyHandle, RigidBodySet}; use crate::geometry::{ - Ball, Capsule, ColliderGraphIndex, Contact, Cuboid, HeightField, InteractionGraph, Polygon, - Proximity, Ray, RayIntersection, Rounded, Shape, ShapeType, Triangle, Trimesh, + Ball, Capsule, ColliderGraphIndex, Contact, Cuboid, HeightField, InteractionGraph, Proximity, + Shape, ShapeType, Triangle, Trimesh, }; #[cfg(feature = "dim3")] -use crate::geometry::{Cone, Cylinder, PolygonalFeatureMap}; +use crate::geometry::{Cone, Cylinder, PolygonalFeatureMap, Rounded}; use crate::math::{AngVector, Isometry, Point, Rotation, Vector}; -use downcast_rs::{impl_downcast, DowncastSync}; -use erased_serde::Serialize; use na::Point3; -use ncollide::bounding_volume::{HasBoundingVolume, AABB}; -use ncollide::query::RayCast; -use num::Zero; -use std::any::Any; +use ncollide::bounding_volume::AABB; use std::ops::Deref; use std::sync::Arc; @@ -21,8 +16,8 @@ use std::sync::Arc; pub struct ColliderShape(pub Arc); impl Deref for ColliderShape { - type Target = Shape; - fn deref(&self) -> &Shape { + type Target = dyn Shape; + fn deref(&self) -> &dyn Shape { &*self.0 } } @@ -257,7 +252,7 @@ impl Collider { } /// The geometric shape of this collider. - pub fn shape(&self) -> &Shape { + pub fn shape(&self) -> &dyn Shape { &*self.shape.0 } -- cgit From f7a6f433d62ea427f6e2233365a6f534ca7e1c63 Mon Sep 17 00:00:00 2001 From: Crozet Sébastien Date: Tue, 20 Oct 2020 18:14:20 +0200 Subject: Rename rounded -> round. --- src/geometry/collider.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/geometry/collider.rs') diff --git a/src/geometry/collider.rs b/src/geometry/collider.rs index 4785d62..755ae5a 100644 --- a/src/geometry/collider.rs +++ b/src/geometry/collider.rs @@ -39,7 +39,7 @@ impl ColliderShape { /// (along along the y axis), its radius, and its roundedness (the /// radius of the sphere used for dilating the cylinder). #[cfg(feature = "dim3")] - pub fn rounded_cylinder(half_height: f32, radius: f32, rounding_radius: f32) -> Self { + pub fn round_cylinder(half_height: f32, radius: f32, rounding_radius: f32) -> Self { ColliderShape(Arc::new(Rounded::new( Cylinder::new(half_height, radius), rounding_radius, @@ -164,7 +164,7 @@ impl<'de> serde::Deserialize<'de> for ColliderShape { #[cfg(feature = "dim3")] Some(ShapeType::Cone) => deser::(&mut seq)?, #[cfg(feature = "dim3")] - Some(ShapeType::RoundedCylinder) => deser::>(&mut seq)?, + Some(ShapeType::RoundCylinder) => deser::>(&mut seq)?, None => { return Err(serde::de::Error::custom( "found invalid shape type to deserialize", @@ -326,8 +326,8 @@ impl ColliderBuilder { /// (along along the y axis), its radius, and its roundedness (the /// radius of the sphere used for dilating the cylinder). #[cfg(feature = "dim3")] - pub fn rounded_cylinder(half_height: f32, radius: f32, rounding_radius: f32) -> Self { - Self::new(ColliderShape::rounded_cylinder( + pub fn round_cylinder(half_height: f32, radius: f32, rounding_radius: f32) -> Self { + Self::new(ColliderShape::round_cylinder( half_height, radius, rounding_radius, -- cgit From b9156302d331a1eaf9f40b84d8c1ffd68b9040ed Mon Sep 17 00:00:00 2001 From: Crozet Sébastien Date: Tue, 20 Oct 2020 18:57:53 +0200 Subject: Replace rounding -> round. --- src/geometry/collider.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/geometry/collider.rs') diff --git a/src/geometry/collider.rs b/src/geometry/collider.rs index 755ae5a..838dda2 100644 --- a/src/geometry/collider.rs +++ b/src/geometry/collider.rs @@ -39,10 +39,10 @@ impl ColliderShape { /// (along along the y axis), its radius, and its roundedness (the /// radius of the sphere used for dilating the cylinder). #[cfg(feature = "dim3")] - pub fn round_cylinder(half_height: f32, radius: f32, rounding_radius: f32) -> Self { + pub fn round_cylinder(half_height: f32, radius: f32, round_radius: f32) -> Self { ColliderShape(Arc::new(Rounded::new( Cylinder::new(half_height, radius), - rounding_radius, + round_radius, ))) } @@ -326,11 +326,11 @@ impl ColliderBuilder { /// (along along the y axis), its radius, and its roundedness (the /// radius of the sphere used for dilating the cylinder). #[cfg(feature = "dim3")] - pub fn round_cylinder(half_height: f32, radius: f32, rounding_radius: f32) -> Self { + pub fn round_cylinder(half_height: f32, radius: f32, round_radius: f32) -> Self { Self::new(ColliderShape::round_cylinder( half_height, radius, - rounding_radius, + round_radius, )) } -- cgit From 2b628f9580a826722346983ef42672d4e8dd8053 Mon Sep 17 00:00:00 2001 From: Crozet Sébastien Date: Mon, 26 Oct 2020 15:58:30 +0100 Subject: Redefine capsules as a segment with a radius, allowing us to reuse the pfm_pfm_contact generator for it. --- src/geometry/collider.rs | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-) (limited to 'src/geometry/collider.rs') diff --git a/src/geometry/collider.rs b/src/geometry/collider.rs index 838dda2..ae5cc73 100644 --- a/src/geometry/collider.rs +++ b/src/geometry/collider.rs @@ -1,7 +1,7 @@ use crate::dynamics::{MassProperties, RigidBodyHandle, RigidBodySet}; use crate::geometry::{ Ball, Capsule, ColliderGraphIndex, Contact, Cuboid, HeightField, InteractionGraph, Proximity, - Shape, ShapeType, Triangle, Trimesh, + Segment, Shape, ShapeType, Triangle, Trimesh, }; #[cfg(feature = "dim3")] use crate::geometry::{Cone, Cylinder, PolygonalFeatureMap, Rounded}; @@ -58,9 +58,14 @@ impl ColliderShape { ColliderShape(Arc::new(Cuboid::new(half_extents))) } - /// Initialize a capsule shape aligned with the `y` axis. - pub fn capsule(half_height: f32, radius: f32) -> Self { - ColliderShape(Arc::new(Capsule::new(half_height, radius))) + /// Initialize a capsule shape from its endpoints and radius. + pub fn capsule(a: Point, b: Point, radius: f32) -> Self { + ColliderShape(Arc::new(Capsule::new(a, b, radius))) + } + + /// Initialize a segment shape from its endpoints. + pub fn segment(a: Point, b: Point) -> Self { + ColliderShape(Arc::new(Segment::new(a, b))) } /// Initializes a triangle shape. @@ -157,6 +162,7 @@ impl<'de> serde::Deserialize<'de> for ColliderShape { Some(ShapeType::Cuboid) => deser::(&mut seq)?, Some(ShapeType::Capsule) => deser::(&mut seq)?, Some(ShapeType::Triangle) => deser::(&mut seq)?, + Some(ShapeType::Segment) => deser::(&mut seq)?, Some(ShapeType::Trimesh) => deser::(&mut seq)?, Some(ShapeType::HeightField) => deser::(&mut seq)?, #[cfg(feature = "dim3")] @@ -349,25 +355,21 @@ impl ColliderBuilder { /// Initialize a new collider builder with a capsule shape aligned with the `x` axis. pub fn capsule_x(half_height: f32, radius: f32) -> Self { - #[cfg(feature = "dim2")] - let rot = -std::f32::consts::FRAC_PI_2; - #[cfg(feature = "dim3")] - let rot = Vector::z() * -std::f32::consts::FRAC_PI_2; - Self::new(ColliderShape::capsule(half_height, radius)) - .position(Isometry::new(na::zero(), rot)) + let p = Point::from(Vector::x() * half_height); + Self::new(ColliderShape::capsule(-p, p, radius)) } /// Initialize a new collider builder with a capsule shape aligned with the `y` axis. pub fn capsule_y(half_height: f32, radius: f32) -> Self { - Self::new(ColliderShape::capsule(half_height, radius)) + let p = Point::from(Vector::y() * half_height); + Self::new(ColliderShape::capsule(-p, p, radius)) } /// Initialize a new collider builder with a capsule shape aligned with the `z` axis. #[cfg(feature = "dim3")] pub fn capsule_z(half_height: f32, radius: f32) -> Self { - let rot = Vector::x() * std::f32::consts::FRAC_PI_2; - Self::new(ColliderShape::capsule(half_height, radius)) - .position(Isometry::new(na::zero(), rot)) + let p = Point::from(Vector::z() * half_height); + Self::new(ColliderShape::capsule(-p, p, radius)) } /// Initialize a new collider builder with a cuboid shape defined by its half-extents. @@ -377,11 +379,8 @@ impl ColliderBuilder { } /// Initializes a collider builder with a segment shape. - /// - /// A segment shape is modeled by a capsule with a 0 radius. pub fn segment(a: Point, b: Point) -> Self { - let (pos, half_height) = crate::utils::segment_to_capsule(&a, &b); - Self::new(ColliderShape::capsule(half_height, 0.0)).position(pos) + Self::new(ColliderShape::segment(a, b)) } /// Initializes a collider builder with a triangle shape. -- cgit From 08930b1238c90bec16db84c50ac4ea7c9a1e0a5b Mon Sep 17 00:00:00 2001 From: Crozet Sébastien Date: Mon, 26 Oct 2020 16:36:07 +0100 Subject: Fix multiple warnings. --- src/geometry/collider.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/geometry/collider.rs') diff --git a/src/geometry/collider.rs b/src/geometry/collider.rs index ae5cc73..d4f685c 100644 --- a/src/geometry/collider.rs +++ b/src/geometry/collider.rs @@ -4,7 +4,7 @@ use crate::geometry::{ Segment, Shape, ShapeType, Triangle, Trimesh, }; #[cfg(feature = "dim3")] -use crate::geometry::{Cone, Cylinder, PolygonalFeatureMap, Rounded}; +use crate::geometry::{Cone, Cylinder, Rounded}; use crate::math::{AngVector, Isometry, Point, Rotation, Vector}; use na::Point3; use ncollide::bounding_volume::AABB; -- cgit From 8c872dc0af9ece127a87b4adb112b0e1ed6ab249 Mon Sep 17 00:00:00 2001 From: Crozet Sébastien Date: Tue, 27 Oct 2020 09:20:40 +0100 Subject: Replace the Rounded type by a non-generic RoundCylinder type. --- src/geometry/collider.rs | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) (limited to 'src/geometry/collider.rs') diff --git a/src/geometry/collider.rs b/src/geometry/collider.rs index d4f685c..522f002 100644 --- a/src/geometry/collider.rs +++ b/src/geometry/collider.rs @@ -4,7 +4,7 @@ use crate::geometry::{ Segment, Shape, ShapeType, Triangle, Trimesh, }; #[cfg(feature = "dim3")] -use crate::geometry::{Cone, Cylinder, Rounded}; +use crate::geometry::{Cone, Cylinder, RoundCylinder}; use crate::math::{AngVector, Isometry, Point, Rotation, Vector}; use na::Point3; use ncollide::bounding_volume::AABB; @@ -39,10 +39,11 @@ impl ColliderShape { /// (along along the y axis), its radius, and its roundedness (the /// radius of the sphere used for dilating the cylinder). #[cfg(feature = "dim3")] - pub fn round_cylinder(half_height: f32, radius: f32, round_radius: f32) -> Self { - ColliderShape(Arc::new(Rounded::new( - Cylinder::new(half_height, radius), - round_radius, + pub fn round_cylinder(half_height: f32, radius: f32, border_radius: f32) -> Self { + ColliderShape(Arc::new(RoundCylinder::new( + half_height, + radius, + border_radius, ))) } @@ -170,7 +171,7 @@ impl<'de> serde::Deserialize<'de> for ColliderShape { #[cfg(feature = "dim3")] Some(ShapeType::Cone) => deser::(&mut seq)?, #[cfg(feature = "dim3")] - Some(ShapeType::RoundCylinder) => deser::>(&mut seq)?, + Some(ShapeType::RoundCylinder) => deser::(&mut seq)?, None => { return Err(serde::de::Error::custom( "found invalid shape type to deserialize", @@ -332,11 +333,11 @@ impl ColliderBuilder { /// (along along the y axis), its radius, and its roundedness (the /// radius of the sphere used for dilating the cylinder). #[cfg(feature = "dim3")] - pub fn round_cylinder(half_height: f32, radius: f32, round_radius: f32) -> Self { + pub fn round_cylinder(half_height: f32, radius: f32, border_radius: f32) -> Self { Self::new(ColliderShape::round_cylinder( half_height, radius, - round_radius, + border_radius, )) } -- cgit