use crate::math::{Isometry, Point, Real, Vector, DIM};
#[cfg(feature = "dim2")]
use crate::shape::ConvexPolygon;
#[cfg(feature = "serde-serialize")]
use crate::shape::DeserializableTypedShape;
use crate::shape::{
Ball, Capsule, Compound, Cuboid, HalfSpace, HeightField, Polyline, RoundShape, Segment, Shape,
TriMesh, TriMeshFlags, Triangle, TypedShape,
};
#[cfg(feature = "dim3")]
use crate::shape::{Cone, ConvexPolyhedron, Cylinder};
use crate::transformation::vhacd::{VHACDParameters, VHACD};
use na::Unit;
use std::fmt;
use std::ops::Deref;
use std::sync::Arc;
#[derive(Clone)]
pub struct SharedShape(pub Arc<dyn Shape>);
impl Deref for SharedShape {
type Target = dyn Shape;
fn deref(&self) -> &dyn Shape {
&*self.0
}
}
impl AsRef<dyn Shape> for SharedShape {
fn as_ref(&self) -> &dyn Shape {
&*self.0
}
}
impl fmt::Debug for SharedShape {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let typed_shape: TypedShape = (*self.0).as_typed_shape();
write!(f, "SharedShape ( Arc<{:?}> )", typed_shape)
}
}
impl SharedShape {
pub fn new(shape: impl Shape) -> Self {
Self(Arc::new(shape))
}
pub fn make_mut(&mut self) -> &mut dyn Shape {
if Arc::get_mut(&mut self.0).is_none() {
let unique_self = self.0.clone_box();
self.0 = unique_self.into();
}
Arc::get_mut(&mut self.0).unwrap()
}
pub fn compound(shapes: Vec<(Isometry<Real>, SharedShape)>) -> Self {
let raw_shapes = shapes.into_iter().map(|s| (s.0, s.1)).collect();
let compound = Compound::new(raw_shapes);
SharedShape(Arc::new(compound))
}
pub fn ball(radius: Real) -> Self {
SharedShape(Arc::new(Ball::new(radius)))
}
pub fn halfspace(outward_normal: Unit<Vector<Real>>) -> Self {
SharedShape(Arc::new(HalfSpace::new(outward_normal)))
}
#[cfg(feature = "dim3")]
pub fn cylinder(half_height: Real, radius: Real) -> Self {
SharedShape(Arc::new(Cylinder::new(half_height, radius)))
}
#[cfg(feature = "dim3")]
pub fn round_cylinder(half_height: Real, radius: Real, border_radius: Real) -> Self {
SharedShape(Arc::new(RoundShape {
inner_shape: Cylinder::new(half_height, radius),
border_radius,
}))
}
#[cfg(feature = "dim3")]
pub fn round_cone(half_height: Real, radius: Real, border_radius: Real) -> Self {
SharedShape(Arc::new(RoundShape {
inner_shape: Cone::new(half_height, radius),
border_radius,
}))
}
#[cfg(feature = "dim3")]
pub fn cone(half_height: Real, radius: Real) -> Self {
SharedShape(Arc::new(Cone::new(half_height, radius)))
}
#[cfg(feature = "dim2")]
pub fn cuboid(hx: Real, hy: Real) -> Self {
SharedShape(Arc::new(Cuboid::new(Vector::new(hx, hy))))
}
#[cfg(feature = "dim2")]
pub fn round_cuboid(hx: Real, hy: Real, border_radius: Real) -> Self {
SharedShape(Arc::new(RoundShape {
inner_shape: Cuboid::new(Vector::new(hx, hy)),
border_radius,
}))
}
#[cfg(feature = "dim3")]
pub fn cuboid(hx: Real, hy: Real, hz: Real) -> Self {
SharedShape(Arc::new(Cuboid::new(Vector::new(hx, hy, hz))))
}
#[cfg(feature = "dim3")]
pub fn round_cuboid(hx: Real, hy: Real, hz: Real, border_radius: Real) -> Self {
SharedShape(Arc::new(RoundShape {
inner_shape: Cuboid::new(Vector::new(hx, hy, hz)),
border_radius,
}))
}
pub fn capsule(a: Point<Real>, b: Point<Real>, radius: Real) -> Self {
SharedShape(Arc::new(Capsule::new(a, b, radius)))
}
pub fn capsule_x(half_height: Real, radius: Real) -> Self {
let p = Point::from(Vector::x() * half_height);
Self::capsule(-p, p, radius)
}
pub fn capsule_y(half_height: Real, radius: Real) -> Self {
let p = Point::from(Vector::y() * half_height);
Self::capsule(-p, p, radius)
}
#[cfg(feature = "dim3")]
pub fn capsule_z(half_height: Real, radius: Real) -> Self {
let p = Point::from(Vector::z() * half_height);
Self::capsule(-p, p, radius)
}
pub fn segment(a: Point<Real>, b: Point<Real>) -> Self {
SharedShape(Arc::new(Segment::new(a, b)))
}
pub fn triangle(a: Point<Real>, b: Point<Real>, c: Point<Real>) -> Self {
SharedShape(Arc::new(Triangle::new(a, b, c)))
}
pub fn round_triangle(
a: Point<Real>,
b: Point<Real>,
c: Point<Real>,
border_radius: Real,
) -> Self {
SharedShape(Arc::new(RoundShape {
inner_shape: Triangle::new(a, b, c),
border_radius,
}))
}
pub fn polyline(vertices: Vec<Point<Real>>, indices: Option<Vec<[u32; 2]>>) -> Self {
SharedShape(Arc::new(Polyline::new(vertices, indices)))
}
pub fn trimesh(vertices: Vec<Point<Real>>, indices: Vec<[u32; 3]>) -> Self {
SharedShape(Arc::new(TriMesh::new(vertices, indices)))
}
pub fn trimesh_with_flags(
vertices: Vec<Point<Real>>,
indices: Vec<[u32; 3]>,
flags: TriMeshFlags,
) -> Self {
SharedShape(Arc::new(TriMesh::with_flags(vertices, indices, flags)))
}
pub fn convex_decomposition(vertices: &[Point<Real>], indices: &[[u32; DIM]]) -> Self {
Self::convex_decomposition_with_params(vertices, indices, &VHACDParameters::default())
}
pub fn round_convex_decomposition(
vertices: &[Point<Real>],
indices: &[[u32; DIM]],
border_radius: Real,
) -> Self {
Self::round_convex_decomposition_with_params(
vertices,
indices,
&VHACDParameters::default(),
border_radius,
)
}
pub fn convex_decomposition_with_params(
vertices: &[Point<Real>],
indices: &[[u32; DIM]],
params: &VHACDParameters,
) -> Self {
let mut parts = vec![];
let decomp = VHACD::decompose(params, vertices, indices, true);
#[cfg(feature = "dim2")]
for vertices in decomp.compute_exact_convex_hulls(vertices, indices) {
if let Some(convex) = Self::convex_polyline(vertices) {
parts.push((Isometry::identity(), convex));
}
}
#[cfg(feature = "dim3")]
for (vertices, indices) in decomp.compute_exact_convex_hulls(vertices, indices) {
if let Some(convex) = Self::convex_mesh(vertices, &indices) {
parts.push((Isometry::identity(), convex));
}
}
Self::compound(parts)
}
pub fn round_convex_decomposition_with_params(
vertices: &[Point<Real>],
indices: &[[u32; DIM]],
params: &VHACDParameters,
border_radius: Real,
) -> Self {
let mut parts = vec![];
let decomp = VHACD::decompose(params, vertices, indices, true);
#[cfg(feature = "dim2")]
for vertices in decomp.compute_exact_convex_hulls(vertices, indices) {
if let Some(convex) = Self::round_convex_polyline(vertices, border_radius) {
parts.push((Isometry::identity(), convex));
}
}
#[cfg(feature = "dim3")]
for (vertices, indices) in decomp.compute_exact_convex_hulls(vertices, indices) {
if let Some(convex) = Self::round_convex_mesh(vertices, &indices, border_radius) {
parts.push((Isometry::identity(), convex));
}
}
Self::compound(parts)
}
pub fn convex_hull(points: &[Point<Real>]) -> Option<Self> {
#[cfg(feature = "dim2")]
return ConvexPolygon::from_convex_hull(points).map(|ch| SharedShape(Arc::new(ch)));
#[cfg(feature = "dim3")]
return ConvexPolyhedron::from_convex_hull(points).map(|ch| SharedShape(Arc::new(ch)));
}
#[cfg(feature = "dim2")]
pub fn convex_polyline(points: Vec<Point<Real>>) -> Option<Self> {
ConvexPolygon::from_convex_polyline(points).map(|ch| SharedShape(Arc::new(ch)))
}
#[cfg(feature = "dim3")]
pub fn convex_mesh(points: Vec<Point<Real>>, indices: &[[u32; 3]]) -> Option<Self> {
ConvexPolyhedron::from_convex_mesh(points, indices).map(|ch| SharedShape(Arc::new(ch)))
}
pub fn round_convex_hull(points: &[Point<Real>], border_radius: Real) -> Option<Self> {
#[cfg(feature = "dim2")]
return ConvexPolygon::from_convex_hull(points).map(|ch| {
SharedShape(Arc::new(RoundShape {
inner_shape: ch,
border_radius,
}))
});
#[cfg(feature = "dim3")]
return ConvexPolyhedron::from_convex_hull(points).map(|ch| {
SharedShape(Arc::new(RoundShape {
inner_shape: ch,
border_radius,
}))
});
}
#[cfg(feature = "dim2")]
pub fn round_convex_polyline(points: Vec<Point<Real>>, border_radius: Real) -> Option<Self> {
ConvexPolygon::from_convex_polyline(points).map(|ch| {
SharedShape(Arc::new(RoundShape {
inner_shape: ch,
border_radius,
}))
})
}
#[cfg(feature = "dim3")]
pub fn round_convex_mesh(
points: Vec<Point<Real>>,
indices: &[[u32; 3]],
border_radius: Real,
) -> Option<Self> {
ConvexPolyhedron::from_convex_mesh(points, indices).map(|ch| {
SharedShape(Arc::new(RoundShape {
inner_shape: ch,
border_radius,
}))
})
}
#[cfg(feature = "dim2")]
pub fn heightfield(heights: na::DVector<Real>, scale: Vector<Real>) -> Self {
SharedShape(Arc::new(HeightField::new(heights, scale)))
}
#[cfg(feature = "dim3")]
pub fn heightfield(heights: na::DMatrix<Real>, scale: Vector<Real>) -> Self {
SharedShape(Arc::new(HeightField::new(heights, scale)))
}
}
#[cfg(feature = "serde-serialize")]
impl serde::Serialize for SharedShape {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
self.0.as_typed_shape().serialize(serializer)
}
}
#[cfg(feature = "serde-serialize")]
impl<'de> serde::Deserialize<'de> for SharedShape {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
use crate::serde::de::Error;
DeserializableTypedShape::deserialize(deserializer)?
.into_shared_shape()
.ok_or(D::Error::custom("Cannot deserialize custom shape."))
}
}