use crate::bounding_volume::{Aabb, BoundingSphere, BoundingVolume};
use crate::mass_properties::MassProperties;
use crate::math::{Isometry, Point, Real, Vector};
use crate::query::{PointQuery, RayCast};
#[cfg(feature = "serde-serialize")]
use crate::shape::SharedShape;
#[cfg(feature = "std")]
use crate::shape::{composite_shape::SimdCompositeShape, Compound, HeightField, Polyline, TriMesh};
use crate::shape::{
    Ball, Capsule, Cuboid, FeatureId, HalfSpace, PolygonalFeatureMap, RoundCuboid, RoundShape,
    RoundTriangle, Segment, SupportMap, Triangle,
};
#[cfg(feature = "dim3")]
use crate::shape::{Cone, Cylinder, RoundCone, RoundCylinder};
#[cfg(feature = "dim3")]
#[cfg(feature = "std")]
use crate::shape::{ConvexPolyhedron, RoundConvexPolyhedron};
#[cfg(feature = "dim2")]
#[cfg(feature = "std")]
use crate::shape::{ConvexPolygon, RoundConvexPolygon};
use downcast_rs::{impl_downcast, DowncastSync};
use na::{RealField, Unit};
use num::Zero;
use num_derive::FromPrimitive;
#[derive(Copy, Clone, Debug, FromPrimitive, PartialEq, Eq, Hash)]
pub enum ShapeType {
    Ball = 0,
    Cuboid,
    Capsule,
    Segment,
    Triangle,
    TriMesh,
    Polyline,
    HalfSpace,
    HeightField,
    Compound,
    #[cfg(feature = "dim2")]
    ConvexPolygon,
    #[cfg(feature = "dim3")]
    ConvexPolyhedron,
    #[cfg(feature = "dim3")]
    Cylinder,
    #[cfg(feature = "dim3")]
    Cone,
    RoundCuboid,
    RoundTriangle,
    #[cfg(feature = "dim3")]
    RoundCylinder,
    #[cfg(feature = "dim3")]
    RoundCone,
    #[cfg(feature = "dim3")]
    RoundConvexPolyhedron,
    #[cfg(feature = "dim2")]
    RoundConvexPolygon,
    Custom,
}
#[derive(Copy, Clone, Debug)]
#[cfg_attr(feature = "serde-serialize", derive(Serialize))]
pub enum TypedShape<'a> {
    Ball(&'a Ball),
    Cuboid(&'a Cuboid),
    Capsule(&'a Capsule),
    Segment(&'a Segment),
    Triangle(&'a Triangle),
    #[cfg(feature = "std")]
    TriMesh(&'a TriMesh),
    #[cfg(feature = "std")]
    Polyline(&'a Polyline),
    HalfSpace(&'a HalfSpace),
    #[cfg(feature = "std")]
    HeightField(&'a HeightField),
    #[cfg(feature = "std")]
    Compound(&'a Compound),
    #[cfg(feature = "dim2")]
    #[cfg(feature = "std")]
    ConvexPolygon(&'a ConvexPolygon),
    #[cfg(feature = "dim3")]
    #[cfg(feature = "std")]
    ConvexPolyhedron(&'a ConvexPolyhedron),
    #[cfg(feature = "dim3")]
    Cylinder(&'a Cylinder),
    #[cfg(feature = "dim3")]
    Cone(&'a Cone),
    RoundCuboid(&'a RoundCuboid),
    RoundTriangle(&'a RoundTriangle),
    #[cfg(feature = "dim3")]
    RoundCylinder(&'a RoundCylinder),
    #[cfg(feature = "dim3")]
    RoundCone(&'a RoundCone),
    #[cfg(feature = "dim3")]
    #[cfg(feature = "std")]
    RoundConvexPolyhedron(&'a RoundConvexPolyhedron),
    #[cfg(feature = "dim2")]
    #[cfg(feature = "std")]
    RoundConvexPolygon(&'a RoundConvexPolygon),
    Custom(u32),
}
#[cfg(feature = "serde-serialize")]
#[derive(Deserialize)]
pub(crate) enum DeserializableTypedShape {
    Ball(Ball),
    Cuboid(Cuboid),
    Capsule(Capsule),
    Segment(Segment),
    Triangle(Triangle),
    #[cfg(feature = "std")]
    TriMesh(TriMesh),
    #[cfg(feature = "std")]
    Polyline(Polyline),
    HalfSpace(HalfSpace),
    #[cfg(feature = "std")]
    HeightField(HeightField),
    #[cfg(feature = "std")]
    Compound(Compound),
    #[cfg(feature = "dim2")]
    #[cfg(feature = "std")]
    ConvexPolygon(ConvexPolygon),
    #[cfg(feature = "dim3")]
    #[cfg(feature = "std")]
    ConvexPolyhedron(ConvexPolyhedron),
    #[cfg(feature = "dim3")]
    Cylinder(Cylinder),
    #[cfg(feature = "dim3")]
    Cone(Cone),
    RoundCuboid(RoundCuboid),
    RoundTriangle(RoundTriangle),
    #[cfg(feature = "dim3")]
    RoundCylinder(RoundCylinder),
    #[cfg(feature = "dim3")]
    RoundCone(RoundCone),
    #[cfg(feature = "dim3")]
    #[cfg(feature = "std")]
    RoundConvexPolyhedron(RoundConvexPolyhedron),
    #[cfg(feature = "dim2")]
    #[cfg(feature = "std")]
    RoundConvexPolygon(RoundConvexPolygon),
    Custom(u32),
}
#[cfg(feature = "serde-serialize")]
impl DeserializableTypedShape {
    pub fn into_shared_shape(self) -> Option<SharedShape> {
        match self {
            DeserializableTypedShape::Ball(s) => Some(SharedShape::new(s)),
            DeserializableTypedShape::Cuboid(s) => Some(SharedShape::new(s)),
            DeserializableTypedShape::Capsule(s) => Some(SharedShape::new(s)),
            DeserializableTypedShape::Segment(s) => Some(SharedShape::new(s)),
            DeserializableTypedShape::Triangle(s) => Some(SharedShape::new(s)),
            #[cfg(feature = "std")]
            DeserializableTypedShape::TriMesh(s) => Some(SharedShape::new(s)),
            #[cfg(feature = "std")]
            DeserializableTypedShape::Polyline(s) => Some(SharedShape::new(s)),
            DeserializableTypedShape::HalfSpace(s) => Some(SharedShape::new(s)),
            #[cfg(feature = "std")]
            DeserializableTypedShape::HeightField(s) => Some(SharedShape::new(s)),
            #[cfg(feature = "std")]
            DeserializableTypedShape::Compound(s) => Some(SharedShape::new(s)),
            #[cfg(feature = "dim2")]
            #[cfg(feature = "std")]
            DeserializableTypedShape::ConvexPolygon(s) => Some(SharedShape::new(s)),
            #[cfg(feature = "dim3")]
            #[cfg(feature = "std")]
            DeserializableTypedShape::ConvexPolyhedron(s) => Some(SharedShape::new(s)),
            #[cfg(feature = "dim3")]
            DeserializableTypedShape::Cylinder(s) => Some(SharedShape::new(s)),
            #[cfg(feature = "dim3")]
            DeserializableTypedShape::Cone(s) => Some(SharedShape::new(s)),
            DeserializableTypedShape::RoundCuboid(s) => Some(SharedShape::new(s)),
            DeserializableTypedShape::RoundTriangle(s) => Some(SharedShape::new(s)),
            #[cfg(feature = "dim3")]
            DeserializableTypedShape::RoundCylinder(s) => Some(SharedShape::new(s)),
            #[cfg(feature = "dim3")]
            DeserializableTypedShape::RoundCone(s) => Some(SharedShape::new(s)),
            #[cfg(feature = "dim3")]
            #[cfg(feature = "std")]
            DeserializableTypedShape::RoundConvexPolyhedron(s) => Some(SharedShape::new(s)),
            #[cfg(feature = "dim2")]
            #[cfg(feature = "std")]
            DeserializableTypedShape::RoundConvexPolygon(s) => Some(SharedShape::new(s)),
            DeserializableTypedShape::Custom(_) => None,
        }
    }
}
pub trait Shape: RayCast + PointQuery + DowncastSync {
    fn compute_local_aabb(&self) -> Aabb;
    fn compute_local_bounding_sphere(&self) -> BoundingSphere;
    #[cfg(feature = "std")]
    fn clone_box(&self) -> Box<dyn Shape>;
    fn compute_aabb(&self, position: &Isometry<Real>) -> Aabb {
        self.compute_local_aabb().transform_by(position)
    }
    fn compute_bounding_sphere(&self, position: &Isometry<Real>) -> BoundingSphere {
        self.compute_local_bounding_sphere().transform_by(position)
    }
    fn mass_properties(&self, density: Real) -> MassProperties;
    fn shape_type(&self) -> ShapeType;
    fn as_typed_shape(&self) -> TypedShape;
    fn ccd_thickness(&self) -> Real;
    fn ccd_angular_thickness(&self) -> Real;
    fn is_convex(&self) -> bool {
        false
    }
    fn as_support_map(&self) -> Option<&dyn SupportMap> {
        None
    }
    #[cfg(feature = "std")]
    fn as_composite_shape(&self) -> Option<&dyn SimdCompositeShape> {
        None
    }
    fn as_polygonal_feature_map(&self) -> Option<(&dyn PolygonalFeatureMap, Real)> {
        None
    }
    fn feature_normal_at_point(
        &self,
        _feature: FeatureId,
        _point: &Point<Real>,
    ) -> Option<Unit<Vector<Real>>> {
        None
    }
    fn compute_swept_aabb(&self, start_pos: &Isometry<Real>, end_pos: &Isometry<Real>) -> Aabb {
        let aabb1 = self.compute_aabb(start_pos);
        let aabb2 = self.compute_aabb(end_pos);
        aabb1.merged(&aabb2)
    }
}
impl_downcast!(sync Shape);
impl dyn Shape {
    pub fn as_shape<T: Shape>(&self) -> Option<&T> {
        self.downcast_ref()
    }
    pub fn as_shape_mut<T: Shape>(&mut self) -> Option<&mut T> {
        self.downcast_mut()
    }
    pub fn as_ball(&self) -> Option<&Ball> {
        self.downcast_ref()
    }
    pub fn as_ball_mut(&mut self) -> Option<&mut Ball> {
        self.downcast_mut()
    }
    pub fn as_cuboid(&self) -> Option<&Cuboid> {
        self.downcast_ref()
    }
    pub fn as_cuboid_mut(&mut self) -> Option<&mut Cuboid> {
        self.downcast_mut()
    }
    pub fn as_halfspace(&self) -> Option<&HalfSpace> {
        self.downcast_ref()
    }
    pub fn as_halfspace_mut(&mut self) -> Option<&mut HalfSpace> {
        self.downcast_mut()
    }
    pub fn as_segment(&self) -> Option<&Segment> {
        self.downcast_ref()
    }
    pub fn as_segment_mut(&mut self) -> Option<&mut Segment> {
        self.downcast_mut()
    }
    pub fn as_capsule(&self) -> Option<&Capsule> {
        self.downcast_ref()
    }
    pub fn as_capsule_mut(&mut self) -> Option<&mut Capsule> {
        self.downcast_mut()
    }
    pub fn as_triangle(&self) -> Option<&Triangle> {
        self.downcast_ref()
    }
    pub fn as_triangle_mut(&mut self) -> Option<&mut Triangle> {
        self.downcast_mut()
    }
    #[cfg(feature = "std")]
    pub fn as_compound(&self) -> Option<&Compound> {
        self.downcast_ref()
    }
    #[cfg(feature = "std")]
    pub fn as_compound_mut(&mut self) -> Option<&mut Compound> {
        self.downcast_mut()
    }
    #[cfg(feature = "std")]
    pub fn as_trimesh(&self) -> Option<&TriMesh> {
        self.downcast_ref()
    }
    #[cfg(feature = "std")]
    pub fn as_trimesh_mut(&mut self) -> Option<&mut TriMesh> {
        self.downcast_mut()
    }
    #[cfg(feature = "std")]
    pub fn as_polyline(&self) -> Option<&Polyline> {
        self.downcast_ref()
    }
    #[cfg(feature = "std")]
    pub fn as_polyline_mut(&mut self) -> Option<&mut Polyline> {
        self.downcast_mut()
    }
    #[cfg(feature = "std")]
    pub fn as_heightfield(&self) -> Option<&HeightField> {
        self.downcast_ref()
    }
    #[cfg(feature = "std")]
    pub fn as_heightfield_mut(&mut self) -> Option<&mut HeightField> {
        self.downcast_mut()
    }
    pub fn as_round_cuboid(&self) -> Option<&RoundCuboid> {
        self.downcast_ref()
    }
    pub fn as_round_cuboid_mut(&mut self) -> Option<&mut RoundCuboid> {
        self.downcast_mut()
    }
    pub fn as_round_triangle(&self) -> Option<&RoundTriangle> {
        self.downcast_ref()
    }
    pub fn as_round_triangle_mut(&mut self) -> Option<&mut RoundTriangle> {
        self.downcast_mut()
    }
    #[cfg(feature = "dim2")]
    #[cfg(feature = "std")]
    pub fn as_convex_polygon(&self) -> Option<&ConvexPolygon> {
        self.downcast_ref()
    }
    #[cfg(feature = "dim2")]
    #[cfg(feature = "std")]
    pub fn as_convex_polygon_mut(&mut self) -> Option<&mut ConvexPolygon> {
        self.downcast_mut()
    }
    #[cfg(feature = "dim2")]
    #[cfg(feature = "std")]
    pub fn as_round_convex_polygon(&self) -> Option<&RoundConvexPolygon> {
        self.downcast_ref()
    }
    #[cfg(feature = "dim2")]
    #[cfg(feature = "std")]
    pub fn as_round_convex_polygon_mut(&mut self) -> Option<&mut RoundConvexPolygon> {
        self.downcast_mut()
    }
    #[cfg(feature = "dim3")]
    #[cfg(feature = "std")]
    pub fn as_convex_polyhedron(&self) -> Option<&ConvexPolyhedron> {
        self.downcast_ref()
    }
    #[cfg(feature = "dim3")]
    #[cfg(feature = "std")]
    pub fn as_convex_polyhedron_mut(&mut self) -> Option<&mut ConvexPolyhedron> {
        self.downcast_mut()
    }
    #[cfg(feature = "dim3")]
    pub fn as_cylinder(&self) -> Option<&Cylinder> {
        self.downcast_ref()
    }
    #[cfg(feature = "dim3")]
    pub fn as_cylinder_mut(&mut self) -> Option<&mut Cylinder> {
        self.downcast_mut()
    }
    #[cfg(feature = "dim3")]
    pub fn as_cone(&self) -> Option<&Cone> {
        self.downcast_ref()
    }
    #[cfg(feature = "dim3")]
    pub fn as_cone_mut(&mut self) -> Option<&mut Cone> {
        self.downcast_mut()
    }
    #[cfg(feature = "dim3")]
    pub fn as_round_cylinder(&self) -> Option<&RoundCylinder> {
        self.downcast_ref()
    }
    #[cfg(feature = "dim3")]
    pub fn as_round_cylinder_mut(&mut self) -> Option<&mut RoundCylinder> {
        self.downcast_mut()
    }
    #[cfg(feature = "dim3")]
    pub fn as_round_cone(&self) -> Option<&RoundCone> {
        self.downcast_ref()
    }
    #[cfg(feature = "dim3")]
    pub fn as_round_cone_mut(&mut self) -> Option<&mut RoundCone> {
        self.downcast_mut()
    }
    #[cfg(feature = "dim3")]
    #[cfg(feature = "std")]
    pub fn as_round_convex_polyhedron(&self) -> Option<&RoundConvexPolyhedron> {
        self.downcast_ref()
    }
    #[cfg(feature = "dim3")]
    #[cfg(feature = "std")]
    pub fn as_round_convex_polyhedron_mut(&mut self) -> Option<&mut RoundConvexPolyhedron> {
        self.downcast_mut()
    }
}
impl Shape for Ball {
    #[cfg(feature = "std")]
    fn clone_box(&self) -> Box<dyn Shape> {
        Box::new(*self)
    }
    fn compute_local_aabb(&self) -> Aabb {
        self.local_aabb()
    }
    fn compute_local_bounding_sphere(&self) -> BoundingSphere {
        self.local_bounding_sphere()
    }
    fn compute_aabb(&self, position: &Isometry<Real>) -> Aabb {
        self.aabb(position)
    }
    fn mass_properties(&self, density: Real) -> MassProperties {
        MassProperties::from_ball(density, self.radius)
    }
    fn ccd_thickness(&self) -> Real {
        self.radius
    }
    fn ccd_angular_thickness(&self) -> Real {
        Real::pi()
    }
    fn is_convex(&self) -> bool {
        true
    }
    fn shape_type(&self) -> ShapeType {
        ShapeType::Ball
    }
    fn as_typed_shape(&self) -> TypedShape {
        TypedShape::Ball(self)
    }
    fn as_support_map(&self) -> Option<&dyn SupportMap> {
        Some(self as &dyn SupportMap)
    }
    #[inline]
    fn feature_normal_at_point(
        &self,
        _: FeatureId,
        point: &Point<Real>,
    ) -> Option<Unit<Vector<Real>>> {
        Unit::try_new(point.coords, crate::math::DEFAULT_EPSILON)
    }
}
impl Shape for Cuboid {
    #[cfg(feature = "std")]
    fn clone_box(&self) -> Box<dyn Shape> {
        Box::new(*self)
    }
    fn compute_local_aabb(&self) -> Aabb {
        self.local_aabb()
    }
    fn compute_local_bounding_sphere(&self) -> BoundingSphere {
        self.local_bounding_sphere()
    }
    fn compute_aabb(&self, position: &Isometry<Real>) -> Aabb {
        self.aabb(position)
    }
    fn mass_properties(&self, density: Real) -> MassProperties {
        MassProperties::from_cuboid(density, self.half_extents)
    }
    fn is_convex(&self) -> bool {
        true
    }
    fn shape_type(&self) -> ShapeType {
        ShapeType::Cuboid
    }
    fn as_typed_shape(&self) -> TypedShape {
        TypedShape::Cuboid(self)
    }
    fn ccd_thickness(&self) -> Real {
        self.half_extents.min()
    }
    fn ccd_angular_thickness(&self) -> Real {
        Real::frac_pi_2()
    }
    fn as_support_map(&self) -> Option<&dyn SupportMap> {
        Some(self as &dyn SupportMap)
    }
    fn as_polygonal_feature_map(&self) -> Option<(&dyn PolygonalFeatureMap, Real)> {
        Some((self as &dyn PolygonalFeatureMap, 0.0))
    }
    fn feature_normal_at_point(
        &self,
        feature: FeatureId,
        _point: &Point<Real>,
    ) -> Option<Unit<Vector<Real>>> {
        self.feature_normal(feature)
    }
}
impl Shape for Capsule {
    #[cfg(feature = "std")]
    fn clone_box(&self) -> Box<dyn Shape> {
        Box::new(*self)
    }
    fn compute_local_aabb(&self) -> Aabb {
        self.local_aabb()
    }
    fn compute_local_bounding_sphere(&self) -> BoundingSphere {
        self.local_bounding_sphere()
    }
    fn compute_aabb(&self, position: &Isometry<Real>) -> Aabb {
        self.aabb(position)
    }
    fn mass_properties(&self, density: Real) -> MassProperties {
        MassProperties::from_capsule(density, self.segment.a, self.segment.b, self.radius)
    }
    fn is_convex(&self) -> bool {
        true
    }
    fn shape_type(&self) -> ShapeType {
        ShapeType::Capsule
    }
    fn as_typed_shape(&self) -> TypedShape {
        TypedShape::Capsule(self)
    }
    fn ccd_thickness(&self) -> Real {
        self.radius
    }
    fn ccd_angular_thickness(&self) -> Real {
        Real::frac_pi_2()
    }
    fn as_support_map(&self) -> Option<&dyn SupportMap> {
        Some(self as &dyn SupportMap)
    }
    fn as_polygonal_feature_map(&self) -> Option<(&dyn PolygonalFeatureMap, Real)> {
        Some((&self.segment as &dyn PolygonalFeatureMap, self.radius))
    }
}
impl Shape for Triangle {
    #[cfg(feature = "std")]
    fn clone_box(&self) -> Box<dyn Shape> {
        Box::new(*self)
    }
    fn compute_local_aabb(&self) -> Aabb {
        self.local_aabb()
    }
    fn compute_local_bounding_sphere(&self) -> BoundingSphere {
        self.local_bounding_sphere()
    }
    fn compute_aabb(&self, position: &Isometry<Real>) -> Aabb {
        self.aabb(position)
    }
    fn mass_properties(&self, _density: Real) -> MassProperties {
        #[cfg(feature = "dim2")]
        return MassProperties::from_triangle(_density, &self.a, &self.b, &self.c);
        #[cfg(feature = "dim3")]
        return MassProperties::zero();
    }
    fn is_convex(&self) -> bool {
        true
    }
    fn shape_type(&self) -> ShapeType {
        ShapeType::Triangle
    }
    fn as_typed_shape(&self) -> TypedShape {
        TypedShape::Triangle(self)
    }
    fn ccd_thickness(&self) -> Real {
        0.0
    }
    fn ccd_angular_thickness(&self) -> Real {
        Real::frac_pi_2()
    }
    fn as_support_map(&self) -> Option<&dyn SupportMap> {
        Some(self as &dyn SupportMap)
    }
    fn as_polygonal_feature_map(&self) -> Option<(&dyn PolygonalFeatureMap, Real)> {
        Some((self as &dyn PolygonalFeatureMap, 0.0))
    }
    fn feature_normal_at_point(
        &self,
        feature: FeatureId,
        _point: &Point<Real>,
    ) -> Option<Unit<Vector<Real>>> {
        self.feature_normal(feature)
    }
}
impl Shape for Segment {
    #[cfg(feature = "std")]
    fn clone_box(&self) -> Box<dyn Shape> {
        Box::new(*self)
    }
    fn compute_local_aabb(&self) -> Aabb {
        self.local_aabb()
    }
    fn compute_local_bounding_sphere(&self) -> BoundingSphere {
        self.local_bounding_sphere()
    }
    fn compute_aabb(&self, position: &Isometry<Real>) -> Aabb {
        self.aabb(position)
    }
    fn mass_properties(&self, _density: Real) -> MassProperties {
        MassProperties::zero()
    }
    fn is_convex(&self) -> bool {
        true
    }
    fn ccd_thickness(&self) -> Real {
        0.0
    }
    fn ccd_angular_thickness(&self) -> Real {
        Real::frac_pi_2()
    }
    fn shape_type(&self) -> ShapeType {
        ShapeType::Segment
    }
    fn as_typed_shape(&self) -> TypedShape {
        TypedShape::Segment(self)
    }
    fn as_support_map(&self) -> Option<&dyn SupportMap> {
        Some(self as &dyn SupportMap)
    }
    fn as_polygonal_feature_map(&self) -> Option<(&dyn PolygonalFeatureMap, Real)> {
        Some((self as &dyn PolygonalFeatureMap, 0.0))
    }
    fn feature_normal_at_point(
        &self,
        feature: FeatureId,
        _point: &Point<Real>,
    ) -> Option<Unit<Vector<Real>>> {
        self.feature_normal(feature)
    }
}
#[cfg(feature = "std")]
impl Shape for Compound {
    fn clone_box(&self) -> Box<dyn Shape> {
        Box::new(self.clone())
    }
    fn compute_local_aabb(&self) -> Aabb {
        *self.local_aabb()
    }
    fn compute_local_bounding_sphere(&self) -> BoundingSphere {
        self.local_bounding_sphere()
    }
    fn compute_aabb(&self, position: &Isometry<Real>) -> Aabb {
        self.local_aabb().transform_by(position)
    }
    fn mass_properties(&self, density: Real) -> MassProperties {
        MassProperties::from_compound(density, self.shapes())
    }
    fn shape_type(&self) -> ShapeType {
        ShapeType::Compound
    }
    fn as_typed_shape(&self) -> TypedShape {
        TypedShape::Compound(self)
    }
    fn ccd_thickness(&self) -> Real {
        self.shapes()
            .iter()
            .fold(Real::MAX, |curr, (_, s)| curr.min(s.ccd_thickness()))
    }
    fn ccd_angular_thickness(&self) -> Real {
        self.shapes().iter().fold(Real::MAX, |curr, (_, s)| {
            curr.max(s.ccd_angular_thickness())
        })
    }
    #[cfg(feature = "std")]
    fn as_composite_shape(&self) -> Option<&dyn SimdCompositeShape> {
        Some(self as &dyn SimdCompositeShape)
    }
}
#[cfg(feature = "std")]
impl Shape for Polyline {
    fn clone_box(&self) -> Box<dyn Shape> {
        Box::new(self.clone())
    }
    fn compute_local_aabb(&self) -> Aabb {
        *self.local_aabb()
    }
    fn compute_local_bounding_sphere(&self) -> BoundingSphere {
        self.local_bounding_sphere()
    }
    fn compute_aabb(&self, position: &Isometry<Real>) -> Aabb {
        self.aabb(position)
    }
    fn mass_properties(&self, _density: Real) -> MassProperties {
        MassProperties::zero()
    }
    fn shape_type(&self) -> ShapeType {
        ShapeType::Polyline
    }
    fn as_typed_shape(&self) -> TypedShape {
        TypedShape::Polyline(self)
    }
    fn ccd_thickness(&self) -> Real {
        0.0
    }
    fn ccd_angular_thickness(&self) -> Real {
        Real::frac_pi_4()
    }
    #[cfg(feature = "std")]
    fn as_composite_shape(&self) -> Option<&dyn SimdCompositeShape> {
        Some(self as &dyn SimdCompositeShape)
    }
}
#[cfg(feature = "std")]
impl Shape for TriMesh {
    fn clone_box(&self) -> Box<dyn Shape> {
        Box::new(self.clone())
    }
    fn compute_local_aabb(&self) -> Aabb {
        *self.local_aabb()
    }
    fn compute_local_bounding_sphere(&self) -> BoundingSphere {
        self.local_bounding_sphere()
    }
    fn compute_aabb(&self, position: &Isometry<Real>) -> Aabb {
        self.aabb(position)
    }
    fn mass_properties(&self, density: Real) -> MassProperties {
        MassProperties::from_trimesh(density, self.vertices(), self.indices())
    }
    fn shape_type(&self) -> ShapeType {
        ShapeType::TriMesh
    }
    fn as_typed_shape(&self) -> TypedShape {
        TypedShape::TriMesh(self)
    }
    fn ccd_thickness(&self) -> Real {
        0.0
    }
    fn ccd_angular_thickness(&self) -> Real {
        Real::frac_pi_4()
    }
    #[cfg(feature = "std")]
    fn as_composite_shape(&self) -> Option<&dyn SimdCompositeShape> {
        Some(self as &dyn SimdCompositeShape)
    }
}
#[cfg(feature = "std")]
impl Shape for HeightField {
    fn clone_box(&self) -> Box<dyn Shape> {
        Box::new(self.clone())
    }
    fn compute_local_aabb(&self) -> Aabb {
        self.local_aabb()
    }
    fn compute_local_bounding_sphere(&self) -> BoundingSphere {
        self.local_bounding_sphere()
    }
    fn compute_aabb(&self, position: &Isometry<Real>) -> Aabb {
        self.aabb(position)
    }
    fn mass_properties(&self, _density: Real) -> MassProperties {
        MassProperties::zero()
    }
    fn shape_type(&self) -> ShapeType {
        ShapeType::HeightField
    }
    fn as_typed_shape(&self) -> TypedShape {
        TypedShape::HeightField(self)
    }
    fn ccd_thickness(&self) -> Real {
        0.0
    }
    fn ccd_angular_thickness(&self) -> Real {
        Real::frac_pi_4()
    }
}
#[cfg(feature = "dim2")]
#[cfg(feature = "std")]
impl Shape for ConvexPolygon {
    fn clone_box(&self) -> Box<dyn Shape> {
        Box::new(self.clone())
    }
    fn compute_local_aabb(&self) -> Aabb {
        self.local_aabb()
    }
    fn compute_local_bounding_sphere(&self) -> BoundingSphere {
        self.local_bounding_sphere()
    }
    fn compute_aabb(&self, position: &Isometry<Real>) -> Aabb {
        self.aabb(position)
    }
    fn mass_properties(&self, density: Real) -> MassProperties {
        MassProperties::from_convex_polygon(density, self.points())
    }
    fn is_convex(&self) -> bool {
        true
    }
    fn shape_type(&self) -> ShapeType {
        ShapeType::ConvexPolygon
    }
    fn as_typed_shape(&self) -> TypedShape {
        TypedShape::ConvexPolygon(self)
    }
    fn ccd_thickness(&self) -> Real {
        self.compute_local_aabb().half_extents().min()
    }
    fn ccd_angular_thickness(&self) -> Real {
        Real::frac_pi_4()
    }
    fn as_support_map(&self) -> Option<&dyn SupportMap> {
        Some(self as &dyn SupportMap)
    }
    fn as_polygonal_feature_map(&self) -> Option<(&dyn PolygonalFeatureMap, Real)> {
        Some((self as &dyn PolygonalFeatureMap, 0.0))
    }
    fn feature_normal_at_point(
        &self,
        feature: FeatureId,
        _point: &Point<Real>,
    ) -> Option<Unit<Vector<Real>>> {
        self.feature_normal(feature)
    }
}
#[cfg(feature = "dim3")]
#[cfg(feature = "std")]
impl Shape for ConvexPolyhedron {
    fn clone_box(&self) -> Box<dyn Shape> {
        Box::new(self.clone())
    }
    fn compute_local_aabb(&self) -> Aabb {
        self.local_aabb()
    }
    fn compute_local_bounding_sphere(&self) -> BoundingSphere {
        self.local_bounding_sphere()
    }
    fn compute_aabb(&self, position: &Isometry<Real>) -> Aabb {
        self.aabb(position)
    }
    fn mass_properties(&self, density: Real) -> MassProperties {
        let (vertices, indices) = self.to_trimesh();
        MassProperties::from_convex_polyhedron(density, &vertices, &indices)
    }
    fn is_convex(&self) -> bool {
        true
    }
    fn shape_type(&self) -> ShapeType {
        ShapeType::ConvexPolyhedron
    }
    fn as_typed_shape(&self) -> TypedShape {
        TypedShape::ConvexPolyhedron(self)
    }
    fn ccd_thickness(&self) -> Real {
        self.compute_local_aabb().half_extents().min()
    }
    fn ccd_angular_thickness(&self) -> Real {
        Real::frac_pi_4()
    }
    fn as_support_map(&self) -> Option<&dyn SupportMap> {
        Some(self as &dyn SupportMap)
    }
    fn as_polygonal_feature_map(&self) -> Option<(&dyn PolygonalFeatureMap, Real)> {
        Some((self as &dyn PolygonalFeatureMap, 0.0))
    }
    fn feature_normal_at_point(
        &self,
        feature: FeatureId,
        _point: &Point<Real>,
    ) -> Option<Unit<Vector<Real>>> {
        self.feature_normal(feature)
    }
}
#[cfg(feature = "dim3")]
impl Shape for Cylinder {
    #[cfg(feature = "std")]
    fn clone_box(&self) -> Box<dyn Shape> {
        Box::new(*self)
    }
    fn compute_local_aabb(&self) -> Aabb {
        self.local_aabb()
    }
    fn compute_local_bounding_sphere(&self) -> BoundingSphere {
        self.local_bounding_sphere()
    }
    fn compute_aabb(&self, position: &Isometry<Real>) -> Aabb {
        self.aabb(position)
    }
    fn mass_properties(&self, density: Real) -> MassProperties {
        MassProperties::from_cylinder(density, self.half_height, self.radius)
    }
    fn is_convex(&self) -> bool {
        true
    }
    fn shape_type(&self) -> ShapeType {
        ShapeType::Cylinder
    }
    fn as_typed_shape(&self) -> TypedShape {
        TypedShape::Cylinder(self)
    }
    fn ccd_thickness(&self) -> Real {
        self.radius
    }
    fn ccd_angular_thickness(&self) -> Real {
        Real::frac_pi_2()
    }
    fn as_support_map(&self) -> Option<&dyn SupportMap> {
        Some(self as &dyn SupportMap)
    }
    fn as_polygonal_feature_map(&self) -> Option<(&dyn PolygonalFeatureMap, Real)> {
        Some((self as &dyn PolygonalFeatureMap, 0.0))
    }
}
#[cfg(feature = "dim3")]
impl Shape for Cone {
    #[cfg(feature = "std")]
    fn clone_box(&self) -> Box<dyn Shape> {
        Box::new(*self)
    }
    fn compute_local_aabb(&self) -> Aabb {
        self.local_aabb()
    }
    fn compute_local_bounding_sphere(&self) -> BoundingSphere {
        self.local_bounding_sphere()
    }
    fn compute_aabb(&self, position: &Isometry<Real>) -> Aabb {
        self.aabb(position)
    }
    fn mass_properties(&self, density: Real) -> MassProperties {
        MassProperties::from_cone(density, self.half_height, self.radius)
    }
    fn is_convex(&self) -> bool {
        true
    }
    fn shape_type(&self) -> ShapeType {
        ShapeType::Cone
    }
    fn as_typed_shape(&self) -> TypedShape {
        TypedShape::Cone(self)
    }
    fn ccd_thickness(&self) -> Real {
        self.radius
    }
    fn ccd_angular_thickness(&self) -> Real {
        let apex_half_angle = self.radius.atan2(self.half_height);
        assert!(apex_half_angle >= 0.0);
        let basis_angle = Real::frac_pi_2() - apex_half_angle;
        basis_angle.min(apex_half_angle * 2.0)
    }
    fn as_support_map(&self) -> Option<&dyn SupportMap> {
        Some(self as &dyn SupportMap)
    }
    fn as_polygonal_feature_map(&self) -> Option<(&dyn PolygonalFeatureMap, Real)> {
        Some((self as &dyn PolygonalFeatureMap, 0.0))
    }
}
impl Shape for HalfSpace {
    #[cfg(feature = "std")]
    fn clone_box(&self) -> Box<dyn Shape> {
        Box::new(*self)
    }
    fn compute_local_aabb(&self) -> Aabb {
        self.local_aabb()
    }
    fn compute_local_bounding_sphere(&self) -> BoundingSphere {
        self.local_bounding_sphere()
    }
    fn compute_aabb(&self, position: &Isometry<Real>) -> Aabb {
        self.aabb(position)
    }
    fn is_convex(&self) -> bool {
        true
    }
    fn ccd_thickness(&self) -> Real {
        f32::MAX as Real
    }
    fn ccd_angular_thickness(&self) -> Real {
        Real::pi()
    }
    fn mass_properties(&self, _: Real) -> MassProperties {
        MassProperties::zero()
    }
    fn shape_type(&self) -> ShapeType {
        ShapeType::HalfSpace
    }
    fn as_typed_shape(&self) -> TypedShape {
        TypedShape::HalfSpace(self)
    }
}
macro_rules! impl_shape_for_round_shape(
    ($($S: ty, $Tag: ident);*) => {$(
        impl Shape for RoundShape<$S> {
            #[cfg(feature = "std")]
            fn clone_box(&self) -> Box<dyn Shape> {
                Box::new(self.clone())
            }
            fn compute_local_aabb(&self) -> Aabb {
                self.inner_shape.local_aabb().loosened(self.border_radius)
            }
            fn compute_local_bounding_sphere(&self) -> BoundingSphere {
                self.inner_shape.local_bounding_sphere().loosened(self.border_radius)
            }
            fn compute_aabb(&self, position: &Isometry<Real>) -> Aabb {
                self.inner_shape.aabb(position).loosened(self.border_radius)
            }
            fn mass_properties(&self, density: Real) -> MassProperties {
                self.inner_shape.mass_properties(density)
            }
            fn is_convex(&self) -> bool {
                self.inner_shape.is_convex()
            }
            fn shape_type(&self) -> ShapeType {
                ShapeType::$Tag
            }
            fn as_typed_shape(&self) -> TypedShape {
                TypedShape::$Tag(self)
            }
            fn ccd_thickness(&self) -> Real {
                self.inner_shape.ccd_thickness() + self.border_radius
            }
            fn ccd_angular_thickness(&self) -> Real {
                self.inner_shape.ccd_angular_thickness()
            }
            fn as_support_map(&self) -> Option<&dyn SupportMap> {
                Some(self as &dyn SupportMap)
            }
            fn as_polygonal_feature_map(&self) -> Option<(&dyn PolygonalFeatureMap, Real)> {
                Some((&self.inner_shape as &dyn PolygonalFeatureMap, self.border_radius))
            }
        }
    )*}
);
impl_shape_for_round_shape!(
    Cuboid, RoundCuboid;
    Triangle, RoundTriangle
);
#[cfg(feature = "dim2")]
#[cfg(feature = "std")]
impl_shape_for_round_shape!(ConvexPolygon, RoundConvexPolygon);
#[cfg(feature = "dim3")]
impl_shape_for_round_shape!(
    Cylinder, RoundCylinder;
    Cone, RoundCone
);
#[cfg(feature = "dim3")]
#[cfg(feature = "std")]
impl_shape_for_round_shape!(ConvexPolyhedron, RoundConvexPolyhedron);