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