1use super::TriMeshBuilderError;
2use crate::math::{Isometry, Point, Real, Vector, DIM};
3#[cfg(feature = "dim2")]
4use crate::shape::ConvexPolygon;
5#[cfg(feature = "serde-serialize")]
6use crate::shape::DeserializableTypedShape;
7#[cfg(feature = "dim3")]
8use crate::shape::HeightFieldFlags;
9use crate::shape::{
10 Ball, Capsule, Compound, Cuboid, HalfSpace, HeightField, Polyline, RoundShape, Segment, Shape,
11 TriMesh, TriMeshFlags, Triangle, TypedShape, Voxels,
12};
13#[cfg(feature = "dim3")]
14use crate::shape::{Cone, ConvexPolyhedron, Cylinder};
15use crate::transformation::vhacd::{VHACDParameters, VHACD};
16use crate::transformation::voxelization::{FillMode, VoxelSet};
17use alloc::sync::Arc;
18use alloc::{vec, vec::Vec};
19use core::fmt;
20use core::ops::Deref;
21use na::Unit;
22
23#[derive(Clone)]
25pub struct SharedShape(pub Arc<dyn Shape>);
26
27impl Deref for SharedShape {
28 type Target = dyn Shape;
29 fn deref(&self) -> &dyn Shape {
30 &*self.0
31 }
32}
33
34impl AsRef<dyn Shape> for SharedShape {
35 fn as_ref(&self) -> &dyn Shape {
36 &*self.0
37 }
38}
39
40impl fmt::Debug for SharedShape {
41 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
42 let typed_shape: TypedShape = (*self.0).as_typed_shape();
43 write!(f, "SharedShape ( Arc<{typed_shape:?}> )")
44 }
45}
46
47impl SharedShape {
48 pub fn new(shape: impl Shape) -> Self {
50 Self(Arc::new(shape))
51 }
52
53 pub fn make_mut(&mut self) -> &mut dyn Shape {
56 if Arc::get_mut(&mut self.0).is_none() {
57 let unique_self = self.0.clone_dyn();
58 self.0 = unique_self.into();
59 }
60 Arc::get_mut(&mut self.0).unwrap()
61 }
62
63 pub fn compound(shapes: Vec<(Isometry<Real>, SharedShape)>) -> Self {
65 let raw_shapes = shapes.into_iter().map(|s| (s.0, s.1)).collect();
66 let compound = Compound::new(raw_shapes);
67 SharedShape(Arc::new(compound))
68 }
69
70 pub fn ball(radius: Real) -> Self {
72 SharedShape(Arc::new(Ball::new(radius)))
73 }
74
75 pub fn halfspace(outward_normal: Unit<Vector<Real>>) -> Self {
77 SharedShape(Arc::new(HalfSpace::new(outward_normal)))
78 }
79
80 #[cfg(feature = "dim3")]
83 pub fn cylinder(half_height: Real, radius: Real) -> Self {
84 SharedShape(Arc::new(Cylinder::new(half_height, radius)))
85 }
86
87 #[cfg(feature = "dim3")]
91 pub fn round_cylinder(half_height: Real, radius: Real, border_radius: Real) -> Self {
92 SharedShape(Arc::new(RoundShape {
93 inner_shape: Cylinder::new(half_height, radius),
94 border_radius,
95 }))
96 }
97
98 #[cfg(feature = "dim3")]
102 pub fn round_cone(half_height: Real, radius: Real, border_radius: Real) -> Self {
103 SharedShape(Arc::new(RoundShape {
104 inner_shape: Cone::new(half_height, radius),
105 border_radius,
106 }))
107 }
108
109 #[cfg(feature = "dim3")]
112 pub fn cone(half_height: Real, radius: Real) -> Self {
113 SharedShape(Arc::new(Cone::new(half_height, radius)))
114 }
115
116 #[cfg(feature = "dim2")]
118 pub fn cuboid(hx: Real, hy: Real) -> Self {
119 SharedShape(Arc::new(Cuboid::new(Vector::new(hx, hy))))
120 }
121
122 #[cfg(feature = "dim2")]
124 pub fn round_cuboid(hx: Real, hy: Real, border_radius: Real) -> Self {
125 SharedShape(Arc::new(RoundShape {
126 inner_shape: Cuboid::new(Vector::new(hx, hy)),
127 border_radius,
128 }))
129 }
130
131 #[cfg(feature = "dim3")]
133 pub fn cuboid(hx: Real, hy: Real, hz: Real) -> Self {
134 SharedShape(Arc::new(Cuboid::new(Vector::new(hx, hy, hz))))
135 }
136
137 #[cfg(feature = "dim3")]
139 pub fn round_cuboid(hx: Real, hy: Real, hz: Real, border_radius: Real) -> Self {
140 SharedShape(Arc::new(RoundShape {
141 inner_shape: Cuboid::new(Vector::new(hx, hy, hz)),
142 border_radius,
143 }))
144 }
145
146 pub fn capsule(a: Point<Real>, b: Point<Real>, radius: Real) -> Self {
148 SharedShape(Arc::new(Capsule::new(a, b, radius)))
149 }
150
151 pub fn capsule_x(half_height: Real, radius: Real) -> Self {
153 let p = Point::from(Vector::x() * half_height);
154 Self::capsule(-p, p, radius)
155 }
156
157 pub fn capsule_y(half_height: Real, radius: Real) -> Self {
159 let p = Point::from(Vector::y() * half_height);
160 Self::capsule(-p, p, radius)
161 }
162
163 #[cfg(feature = "dim3")]
165 pub fn capsule_z(half_height: Real, radius: Real) -> Self {
166 let p = Point::from(Vector::z() * half_height);
167 Self::capsule(-p, p, radius)
168 }
169
170 pub fn segment(a: Point<Real>, b: Point<Real>) -> Self {
172 SharedShape(Arc::new(Segment::new(a, b)))
173 }
174
175 pub fn triangle(a: Point<Real>, b: Point<Real>, c: Point<Real>) -> Self {
177 SharedShape(Arc::new(Triangle::new(a, b, c)))
178 }
179 pub fn round_triangle(
181 a: Point<Real>,
182 b: Point<Real>,
183 c: Point<Real>,
184 border_radius: Real,
185 ) -> Self {
186 SharedShape(Arc::new(RoundShape {
187 inner_shape: Triangle::new(a, b, c),
188 border_radius,
189 }))
190 }
191
192 pub fn polyline(vertices: Vec<Point<Real>>, indices: Option<Vec<[u32; 2]>>) -> Self {
196 SharedShape(Arc::new(Polyline::new(vertices, indices)))
197 }
198
199 pub fn trimesh(
201 vertices: Vec<Point<Real>>,
202 indices: Vec<[u32; 3]>,
203 ) -> Result<Self, TriMeshBuilderError> {
204 Ok(SharedShape(Arc::new(TriMesh::new(vertices, indices)?)))
205 }
206
207 pub fn trimesh_with_flags(
210 vertices: Vec<Point<Real>>,
211 indices: Vec<[u32; 3]>,
212 flags: TriMeshFlags,
213 ) -> Result<Self, TriMeshBuilderError> {
214 Ok(SharedShape(Arc::new(TriMesh::with_flags(
215 vertices, indices, flags,
216 )?)))
217 }
218
219 pub fn voxels(voxel_size: Vector<Real>, grid_coords: &[Point<i32>]) -> Self {
229 let shape = Voxels::new(voxel_size, grid_coords);
230 SharedShape::new(shape)
231 }
232
233 pub fn voxels_from_points(voxel_size: Vector<Real>, points: &[Point<Real>]) -> Self {
238 let shape = Voxels::from_points(voxel_size, points);
239 SharedShape::new(shape)
240 }
241
242 pub fn voxelized_mesh(
245 vertices: &[Point<Real>],
246 indices: &[[u32; DIM]],
247 voxel_size: Real,
248 fill_mode: FillMode,
249 ) -> Self {
250 let mut voxels = VoxelSet::with_voxel_size(vertices, indices, voxel_size, fill_mode, true);
251 voxels.compute_bb();
252 Self::from_voxel_set(&voxels)
253 }
254
255 fn from_voxel_set(vox_set: &VoxelSet) -> Self {
256 let centers: Vec<_> = vox_set
257 .voxels()
258 .iter()
259 .map(|v| vox_set.get_voxel_point(v))
260 .collect();
261 let shape = Voxels::from_points(Vector::repeat(vox_set.scale), ¢ers);
262 SharedShape::new(shape)
263 }
264
265 pub fn voxelized_convex_decomposition(
268 vertices: &[Point<Real>],
269 indices: &[[u32; DIM]],
270 ) -> Vec<Self> {
271 Self::voxelized_convex_decomposition_with_params(
272 vertices,
273 indices,
274 &VHACDParameters::default(),
275 )
276 }
277
278 pub fn voxelized_convex_decomposition_with_params(
281 vertices: &[Point<Real>],
282 indices: &[[u32; DIM]],
283 params: &VHACDParameters,
284 ) -> Vec<Self> {
285 let mut parts = vec![];
286 let decomp = VHACD::decompose(params, vertices, indices, true);
287
288 for vox_set in decomp.voxel_parts() {
289 parts.push(Self::from_voxel_set(vox_set));
290 }
291
292 parts
293 }
294
295 pub fn convex_decomposition(vertices: &[Point<Real>], indices: &[[u32; DIM]]) -> Self {
298 Self::convex_decomposition_with_params(vertices, indices, &VHACDParameters::default())
299 }
300
301 pub fn round_convex_decomposition(
304 vertices: &[Point<Real>],
305 indices: &[[u32; DIM]],
306 border_radius: Real,
307 ) -> Self {
308 Self::round_convex_decomposition_with_params(
309 vertices,
310 indices,
311 &VHACDParameters::default(),
312 border_radius,
313 )
314 }
315
316 pub fn convex_decomposition_with_params(
319 vertices: &[Point<Real>],
320 indices: &[[u32; DIM]],
321 params: &VHACDParameters,
322 ) -> Self {
323 let mut parts = vec![];
324 let decomp = VHACD::decompose(params, vertices, indices, true);
325
326 #[cfg(feature = "dim2")]
327 for vertices in decomp.compute_exact_convex_hulls(vertices, indices) {
328 if let Some(convex) = Self::convex_polyline(vertices) {
329 parts.push((Isometry::identity(), convex));
330 }
331 }
332
333 #[cfg(feature = "dim3")]
334 for (vertices, indices) in decomp.compute_exact_convex_hulls(vertices, indices) {
335 if let Some(convex) = Self::convex_mesh(vertices, &indices) {
336 parts.push((Isometry::identity(), convex));
337 }
338 }
339
340 Self::compound(parts)
341 }
342
343 pub fn round_convex_decomposition_with_params(
346 vertices: &[Point<Real>],
347 indices: &[[u32; DIM]],
348 params: &VHACDParameters,
349 border_radius: Real,
350 ) -> Self {
351 let mut parts = vec![];
352 let decomp = VHACD::decompose(params, vertices, indices, true);
353
354 #[cfg(feature = "dim2")]
355 for vertices in decomp.compute_exact_convex_hulls(vertices, indices) {
356 if let Some(convex) = Self::round_convex_polyline(vertices, border_radius) {
357 parts.push((Isometry::identity(), convex));
358 }
359 }
360
361 #[cfg(feature = "dim3")]
362 for (vertices, indices) in decomp.compute_exact_convex_hulls(vertices, indices) {
363 if let Some(convex) = Self::round_convex_mesh(vertices, &indices, border_radius) {
364 parts.push((Isometry::identity(), convex));
365 }
366 }
367
368 Self::compound(parts)
369 }
370
371 pub fn convex_hull(points: &[Point<Real>]) -> Option<Self> {
373 #[cfg(feature = "dim2")]
374 return ConvexPolygon::from_convex_hull(points).map(|ch| SharedShape(Arc::new(ch)));
375 #[cfg(feature = "dim3")]
376 return ConvexPolyhedron::from_convex_hull(points).map(|ch| SharedShape(Arc::new(ch)));
377 }
378
379 #[cfg(feature = "dim2")]
392 pub fn convex_polyline(points: Vec<Point<Real>>) -> Option<Self> {
393 ConvexPolygon::from_convex_polyline(points).map(|ch| SharedShape(Arc::new(ch)))
394 }
395
396 #[cfg(feature = "dim2")]
404 pub fn convex_polyline_unmodified(points: Vec<Point<Real>>) -> Option<Self> {
405 ConvexPolygon::from_convex_polyline_unmodified(points).map(|ch| SharedShape(Arc::new(ch)))
406 }
407
408 #[cfg(feature = "dim3")]
412 pub fn convex_mesh(points: Vec<Point<Real>>, indices: &[[u32; 3]]) -> Option<Self> {
413 ConvexPolyhedron::from_convex_mesh(points, indices).map(|ch| SharedShape(Arc::new(ch)))
414 }
415
416 pub fn round_convex_hull(points: &[Point<Real>], border_radius: Real) -> Option<Self> {
419 #[cfg(feature = "dim2")]
420 return ConvexPolygon::from_convex_hull(points).map(|ch| {
421 SharedShape(Arc::new(RoundShape {
422 inner_shape: ch,
423 border_radius,
424 }))
425 });
426 #[cfg(feature = "dim3")]
427 return ConvexPolyhedron::from_convex_hull(points).map(|ch| {
428 SharedShape(Arc::new(RoundShape {
429 inner_shape: ch,
430 border_radius,
431 }))
432 });
433 }
434
435 #[cfg(feature = "dim2")]
439 pub fn round_convex_polyline(points: Vec<Point<Real>>, border_radius: Real) -> Option<Self> {
440 ConvexPolygon::from_convex_polyline(points).map(|ch| {
441 SharedShape(Arc::new(RoundShape {
442 inner_shape: ch,
443 border_radius,
444 }))
445 })
446 }
447
448 #[cfg(feature = "dim3")]
452 pub fn round_convex_mesh(
453 points: Vec<Point<Real>>,
454 indices: &[[u32; 3]],
455 border_radius: Real,
456 ) -> Option<Self> {
457 ConvexPolyhedron::from_convex_mesh(points, indices).map(|ch| {
458 SharedShape(Arc::new(RoundShape {
459 inner_shape: ch,
460 border_radius,
461 }))
462 })
463 }
464
465 #[cfg(feature = "dim2")]
468 pub fn heightfield(heights: na::DVector<Real>, scale: Vector<Real>) -> Self {
469 SharedShape(Arc::new(HeightField::new(heights, scale)))
470 }
471
472 #[cfg(feature = "dim3")]
475 pub fn heightfield(heights: na::DMatrix<Real>, scale: Vector<Real>) -> Self {
476 SharedShape(Arc::new(HeightField::new(heights, scale)))
477 }
478
479 #[cfg(feature = "dim3")]
482 pub fn heightfield_with_flags(
483 heights: na::DMatrix<Real>,
484 scale: Vector<Real>,
485 flags: HeightFieldFlags,
486 ) -> Self {
487 SharedShape(Arc::new(HeightField::with_flags(heights, scale, flags)))
488 }
489}
490
491#[cfg(feature = "serde-serialize")]
492impl serde::Serialize for SharedShape {
493 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
494 where
495 S: serde::Serializer,
496 {
497 self.0.as_typed_shape().serialize(serializer)
498 }
499}
500
501#[cfg(feature = "serde-serialize")]
502impl<'de> serde::Deserialize<'de> for SharedShape {
503 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
504 where
505 D: serde::Deserializer<'de>,
506 {
507 use crate::serde::de::Error;
508 DeserializableTypedShape::deserialize(deserializer)?
509 .into_shared_shape()
510 .ok_or(D::Error::custom("Cannot deserialize custom shape."))
511 }
512}