1use std::f64;
2use std::sync::Arc;
3
4use na::RealField;
5use ncollide::pipeline::{
6 BroadPhaseProxyHandle, CollisionGroups, CollisionObject, CollisionObjectGraphIndex,
7 CollisionObjectRef, CollisionObjectUpdateFlags, GeometricQueryType,
8};
9use ncollide::shape::{Shape, ShapeHandle};
10use std::any::Any;
11
12use crate::material::{BasicMaterial, Material, MaterialHandle};
13use crate::math::{Isometry, Rotation, Vector};
14use crate::object::{BodyHandle, BodyPartHandle};
15
16use crate::utils::{UserData, UserDataBox};
17
18#[derive(Clone)]
20pub enum ColliderAnchor<N: RealField + Copy, Handle: BodyHandle> {
21 OnBodyPart {
23 body_part: BodyPartHandle<Handle>,
25 position_wrt_body_part: Isometry<N>,
27 },
28 OnDeformableBody {
30 body: Handle,
32 body_parts: Option<Arc<Vec<usize>>>,
37 },
38}
39
40impl<N: RealField + Copy, Handle: BodyHandle> ColliderAnchor<N, Handle> {
41 #[inline]
43 pub fn body(&self) -> Handle {
44 match self {
45 ColliderAnchor::OnBodyPart { body_part, .. } => body_part.0,
46 ColliderAnchor::OnDeformableBody { body, .. } => *body,
47 }
48 }
49}
50
51pub struct ColliderRemovalData<N: RealField + Copy, Handle: BodyHandle> {
53 pub(crate) anchor: ColliderAnchor<N, Handle>,
54 pub(crate) shape: ShapeHandle<N>,
55 pub(crate) density: N,
56 pub(crate) proxy_handle: BroadPhaseProxyHandle,
57 pub(crate) graph_index: CollisionObjectGraphIndex,
58}
59
60pub struct ColliderData<N: RealField + Copy, Handle: BodyHandle> {
64 margin: N,
65 density: N,
66 anchor: ColliderAnchor<N, Handle>,
67 body_status_dependent_ndofs: usize,
69 material: MaterialHandle<N>,
70 ccd_enabled: bool,
71 user_data: Option<Box<dyn Any + Send + Sync>>,
72}
73
74impl<N: RealField + Copy, Handle: BodyHandle> ColliderData<N, Handle> {
75 pub fn new(
77 margin: N,
78 density: N,
79 anchor: ColliderAnchor<N, Handle>,
80 body_status_dependent_ndofs: usize,
81 material: MaterialHandle<N>,
82 ) -> Self {
83 ColliderData {
84 margin,
85 density,
86 anchor,
87 body_status_dependent_ndofs,
88 material,
89 ccd_enabled: false,
90 user_data: None,
91 }
92 }
93
94 user_data_accessors!();
95
96 #[inline]
98 pub fn margin(&self) -> N {
99 self.margin
100 }
101
102 pub fn body(&self) -> Handle {
104 self.anchor.body()
105 }
106
107 pub fn anchor(&self) -> &ColliderAnchor<N, Handle> {
109 &self.anchor
110 }
111
112 pub fn density(&self) -> N {
114 self.density
115 }
116
117 pub fn position_wrt_body(&self) -> Isometry<N> {
119 if let ColliderAnchor::OnBodyPart {
120 position_wrt_body_part,
121 ..
122 } = self.anchor
123 {
124 position_wrt_body_part
125 } else {
126 Isometry::identity()
127 }
128 }
129
130 pub fn body_part(&self, subshape_id: usize) -> BodyPartHandle<Handle> {
132 match &self.anchor {
133 ColliderAnchor::OnBodyPart { body_part, .. } => *body_part,
134 ColliderAnchor::OnDeformableBody {
135 body, body_parts, ..
136 } => {
137 if let Some(body_parts) = body_parts {
138 BodyPartHandle(*body, body_parts[subshape_id])
139 } else {
140 BodyPartHandle(*body, subshape_id)
141 }
142 }
143 }
144 }
145
146 #[inline]
148 pub fn material(&self) -> &dyn Material<N> {
149 &*self.material
150 }
151
152 #[inline]
158 pub fn material_mut(&mut self) -> &mut dyn Material<N> {
159 self.material.make_mut()
160 }
161}
162
163#[repr(transparent)]
165pub struct Collider<N: RealField + Copy, Handle: BodyHandle>(
166 pub(crate) CollisionObject<N, ColliderData<N, Handle>>,
167); impl<N: RealField + Copy, Handle: BodyHandle> Collider<N, Handle> {
170 pub fn removal_data(&self) -> Option<ColliderRemovalData<N, Handle>> {
172 Some(ColliderRemovalData {
173 anchor: self.0.data().anchor.clone(),
174 shape: self.shape_handle().clone(),
175 density: self.0.data().density,
176 proxy_handle: self.0.proxy_handle()?,
177 graph_index: self.0.graph_index()?,
178 })
179 }
180
181 #[inline]
186 pub fn user_data(&self) -> Option<&(dyn Any + Send + Sync)> {
187 self.0.data().user_data.as_deref()
188 }
189
190 #[inline]
192 pub fn user_data_mut(&mut self) -> Option<&mut (dyn Any + Send + Sync)> {
193 self.0.data_mut().user_data.as_deref_mut()
194 }
195
196 #[inline]
198 pub fn set_user_data(
199 &mut self,
200 data: Option<Box<dyn Any + Send + Sync>>,
201 ) -> Option<Box<dyn Any + Send + Sync>> {
202 std::mem::replace(&mut self.0.data_mut().user_data, data)
203 }
204
205 #[inline]
207 pub fn take_user_data(&mut self) -> Option<Box<dyn Any + Send + Sync>> {
208 self.0.data_mut().user_data.take()
209 }
210
211 #[inline]
213 pub fn margin(&self) -> N {
214 self.0.data().margin()
215 }
216
217 #[inline]
219 pub fn set_margin(&mut self, margin: N) {
220 *self.0.update_flags_mut() |= CollisionObjectUpdateFlags::SHAPE_CHANGED;
221 self.0.data_mut().margin = margin;
222 }
223
224 #[inline]
226 pub fn clear_update_flags(&mut self) {
227 self.0.clear_update_flags()
228 }
229
230 #[inline]
232 pub fn density(&self) -> N {
233 self.0.data().density
234 }
235
236 #[inline]
238 pub fn body(&self) -> Handle {
239 self.0.data().body()
240 }
241
242 #[inline]
244 pub fn anchor(&self) -> &ColliderAnchor<N, Handle> {
245 self.0.data().anchor()
246 }
247
248 #[inline]
250 pub fn position_wrt_body(&self) -> Isometry<N> {
251 self.0.data().position_wrt_body()
252 }
253
254 #[inline]
256 pub fn body_part(&self, subshape_id: usize) -> BodyPartHandle<Handle> {
257 self.0.data().body_part(subshape_id)
258 }
259
260 #[inline]
262 pub fn material(&self) -> &dyn Material<N> {
263 self.0.data().material()
264 }
265
266 #[inline]
272 pub fn material_mut(&mut self) -> &mut dyn Material<N> {
273 self.0.data_mut().material_mut()
274 }
275
276 #[inline]
278 pub fn is_sensor(&self) -> bool {
279 self.query_type().is_proximity_query()
280 }
281
282 #[inline]
284 pub fn is_ccd_enabled(&self) -> bool {
285 self.0.data().ccd_enabled
286 }
287
288 #[inline]
290 pub fn enable_ccd(&mut self, enabled: bool) {
291 self.0.data_mut().ccd_enabled = enabled
292 }
293
294 #[inline]
295 pub(crate) fn body_status_dependent_ndofs(&self) -> usize {
296 self.0.data().body_status_dependent_ndofs
297 }
298
299 #[inline]
300 pub(crate) fn set_body_status_dependent_ndofs(&mut self, ndofs: usize) {
301 self.0.data_mut().body_status_dependent_ndofs = ndofs
302 }
303
304 #[inline]
312 pub fn graph_index(&self) -> Option<CollisionObjectGraphIndex> {
313 self.0.graph_index()
314 }
315
316 #[inline]
318 pub fn set_graph_index(&mut self, index: Option<CollisionObjectGraphIndex>) {
319 self.0.set_graph_index(index)
320 }
321
322 #[inline]
324 pub fn proxy_handle(&self) -> Option<BroadPhaseProxyHandle> {
325 self.0.proxy_handle()
326 }
327
328 #[inline]
330 pub fn set_proxy_handle(&mut self, handle: Option<BroadPhaseProxyHandle>) {
331 self.0.set_proxy_handle(handle)
332 }
333
334 #[inline]
336 pub fn position(&self) -> &Isometry<N> {
337 self.0.position()
338 }
339
340 #[inline]
342 pub fn set_position(&mut self, pos: Isometry<N>) {
343 self.0.set_position(pos)
344 }
345
346 #[inline]
348 pub fn set_position_with_prediction(&mut self, position: Isometry<N>, prediction: Isometry<N>) {
349 self.0.set_position_with_prediction(position, prediction)
350 }
351
352 #[inline]
356 pub fn set_deformations(&mut self, coords: &[N]) {
357 self.0.set_deformations(coords)
358 }
359
360 #[inline]
362 pub fn shape(&self) -> &dyn Shape<N> {
363 &**self.0.shape()
364 }
365
366 #[inline]
368 pub fn shape_handle(&self) -> &ShapeHandle<N> {
369 self.0.shape()
370 }
371
372 #[inline]
374 pub fn set_shape(&mut self, shape: ShapeHandle<N>) {
375 self.0.set_shape(shape)
376 }
377
378 #[inline]
380 pub fn collision_groups(&self) -> &CollisionGroups {
381 self.0.collision_groups()
382 }
383
384 #[inline]
386 pub fn set_collision_groups(&mut self, groups: CollisionGroups) {
387 self.0.set_collision_groups(groups)
388 }
389
390 #[inline]
392 pub fn query_type(&self) -> GeometricQueryType<N> {
393 self.0.query_type()
394 }
395
396 #[inline]
399 pub fn set_query_type(&mut self, query_type: GeometricQueryType<N>) {
400 self.0.set_query_type(query_type);
401 }
402}
403
404impl<N: RealField + Copy, Handle: BodyHandle> CollisionObjectRef<N> for Collider<N, Handle> {
405 fn graph_index(&self) -> Option<CollisionObjectGraphIndex> {
406 self.0.graph_index()
407 }
408
409 fn proxy_handle(&self) -> Option<BroadPhaseProxyHandle> {
410 self.0.proxy_handle()
411 }
412
413 fn position(&self) -> &Isometry<N> {
414 self.0.position()
415 }
416
417 fn predicted_position(&self) -> Option<&Isometry<N>> {
418 self.0.predicted_position()
419 }
420
421 fn shape(&self) -> &dyn Shape<N> {
422 self.0.shape().as_ref()
423 }
424
425 fn collision_groups(&self) -> &CollisionGroups {
426 self.0.collision_groups()
427 }
428
429 fn query_type(&self) -> GeometricQueryType<N> {
430 self.0.query_type()
431 }
432
433 fn update_flags(&self) -> CollisionObjectUpdateFlags {
434 self.0.update_flags()
435 }
436}
437
438pub struct ColliderDesc<N: RealField + Copy> {
442 user_data: Option<UserDataBox>,
443 margin: N,
444 collision_groups: CollisionGroups,
445 shape: ShapeHandle<N>,
446 position: Isometry<N>,
447 material: Option<MaterialHandle<N>>,
448 density: N,
449 linear_prediction: N,
450 angular_prediction: N,
451 is_sensor: bool,
452 ccd_enabled: bool,
453}
454
455impl<N: RealField + Copy> ColliderDesc<N> {
456 pub fn new(shape: ShapeHandle<N>) -> Self {
458 let linear_prediction = na::convert(0.001);
459 let angular_prediction = na::convert(f64::consts::PI / 180.0 * 5.0);
460
461 ColliderDesc {
462 user_data: None,
463 shape,
464 margin: Self::default_margin(),
465 collision_groups: CollisionGroups::default(),
466 position: Isometry::identity(),
467 material: None,
468 density: N::zero(),
469 linear_prediction,
470 angular_prediction,
471 is_sensor: false,
472 ccd_enabled: false,
473 }
474 }
475
476 pub fn default_margin() -> N {
478 na::convert(0.01)
479 }
480
481 user_data_desc_accessors!();
482
483 #[cfg(feature = "dim3")]
484 desc_custom_setters!(
485 self.rotation,
486 set_rotation,
487 axisangle: Vector<N> | { self.position.rotation = Rotation::new(axisangle) }
488 );
489
490 #[cfg(feature = "dim2")]
491 desc_custom_setters!(
492 self.rotation,
493 set_rotation,
494 angle: N | { self.position.rotation = Rotation::new(angle) }
495 );
496
497 desc_custom_setters!(
498 self.translation, set_translation, vector: Vector<N> | { self.position.translation.vector = vector }
499 self.material, set_material, material: MaterialHandle<N> | { self.material = Some(material) }
500 );
501
502 desc_setters!(
503 shape, set_shape, shape: ShapeHandle<N>
504 margin, set_margin, margin: N
505 density, set_density, density: N
506 collision_groups, set_collision_groups, collision_groups: CollisionGroups
507 linear_prediction, set_linear_prediction, linear_prediction: N
508 angular_prediction, set_angular_prediction, angular_prediction: N
509 sensor, set_is_sensor, is_sensor: bool
510 position, set_position, position: Isometry<N>
511 ccd_enabled, set_ccd_enabled, ccd_enabled: bool
512 );
513
514 #[cfg(feature = "dim3")]
515 desc_custom_getters!(self.get_rotation: Vector<N> | { self.position.rotation.scaled_axis() });
516
517 #[cfg(feature = "dim2")]
518 desc_custom_getters!(self.get_rotation: N | { self.position.rotation.angle() });
519
520 desc_custom_getters!(
521 self.get_shape: &dyn Shape<N> | { &*self.shape }
522 self.get_translation: &Vector<N> | { &self.position.translation.vector }
523 self.get_material: Option<&dyn Material<N>> | { self.material.as_deref() }
524 );
525
526 desc_getters!(
527 [val] get_margin -> margin: N
528 [val] get_density -> density: N
529 [val] get_collision_groups -> collision_groups: CollisionGroups
530 [val] get_linear_prediction -> linear_prediction: N
531 [val] get_angular_prediction -> angular_prediction: N
532 [val] is_sensor -> is_sensor: bool
533 [val] get_ccd_enabled -> ccd_enabled: bool
534 [ref] get_position -> position: Isometry<N>
535 );
536
537 pub fn build<Handle: BodyHandle>(
539 &self,
540 parent_handle: BodyPartHandle<Handle>,
541 ) -> Collider<N, Handle> {
542 let query = if self.is_sensor {
543 GeometricQueryType::Proximity(self.linear_prediction)
544 } else {
545 GeometricQueryType::Contacts(
546 self.margin + self.linear_prediction,
547 self.angular_prediction,
548 )
549 };
550
551 let anchor = ColliderAnchor::OnBodyPart {
552 body_part: parent_handle,
553 position_wrt_body_part: self.position,
554 };
555 let material = self
556 .material
557 .clone()
558 .unwrap_or_else(|| MaterialHandle::new(BasicMaterial::default()));
559 let mut data = ColliderData::new(self.margin, self.density, anchor, 0, material);
560 data.ccd_enabled = self.ccd_enabled;
561 data.user_data = self.user_data.as_ref().map(|data| data.0.to_any());
562 let co = CollisionObject::new(
563 None,
564 None,
565 self.position,
566 self.shape.clone(),
567 self.collision_groups,
568 query,
569 data,
570 );
571 Collider(co)
572 }
573}
574
575pub struct DeformableColliderDesc<N: RealField + Copy> {
577 user_data: Option<UserDataBox>,
578 margin: N,
579 collision_groups: CollisionGroups,
580 shape: ShapeHandle<N>,
581 material: Option<MaterialHandle<N>>,
582 linear_prediction: N,
583 angular_prediction: N,
584 is_sensor: bool,
585 ccd_enabled: bool,
586 body_parts_mapping: Option<Arc<Vec<usize>>>,
587}
588
589impl<N: RealField + Copy> DeformableColliderDesc<N> {
590 pub fn new(shape: ShapeHandle<N>) -> Self {
594 assert!(
595 shape.is_deformable_shape(),
596 "The the shape of a deformable collider must be deformable."
597 );
598 let linear_prediction = na::convert(0.002);
599 let angular_prediction = na::convert(f64::consts::PI / 180.0 * 5.0);
600
601 DeformableColliderDesc {
602 user_data: None,
603 shape,
604 margin: na::convert(0.01),
605 collision_groups: CollisionGroups::default(),
606 material: None,
607 linear_prediction,
608 angular_prediction,
609 is_sensor: false,
610 ccd_enabled: false,
611 body_parts_mapping: None,
612 }
613 }
614}
615
616impl<N: RealField + Copy> DeformableColliderDesc<N> {
617 user_data_desc_accessors!();
618
619 pub fn shape(mut self, shape: ShapeHandle<N>) -> Self {
623 assert!(
624 shape.is_deformable_shape(),
625 "The the shape of a deformable collider must be deformable."
626 );
627 self.shape = shape;
628 self
629 }
630
631 pub fn set_shape(&mut self, shape: ShapeHandle<N>) -> &mut Self {
635 assert!(
636 shape.is_deformable_shape(),
637 "The the shape of a deformable collider must be deformable."
638 );
639 self.shape = shape;
640 self
641 }
642
643 desc_custom_setters!(
644 self.material,
645 set_material,
646 material: MaterialHandle<N> | { self.material = Some(material) }
647 );
648
649 desc_setters!(
650 margin, set_margin, margin: N
651 collision_groups, set_collision_groups, collision_groups: CollisionGroups
652 linear_prediction, set_linear_prediction, linear_prediction: N
653 angular_prediction, set_angular_prediction, angular_prediction: N
654 as_sensor, set_as_sensor, is_sensor: bool
655 ccd_enabled, set_ccd_enabled, ccd_enabled: bool
656 body_parts_mapping, set_body_parts_mapping, body_parts_mapping: Option<Arc<Vec<usize>>>
657 );
658
659 desc_custom_getters!(
660 self.get_shape: &dyn Shape<N> | { &*self.shape }
661 self.get_material: Option<&dyn Material<N>> | { self.material.as_deref() }
662
663 );
664
665 desc_getters!(
666 [val] get_margin -> margin: N
667 [val] get_collision_groups -> collision_groups: CollisionGroups
668 [val] get_linear_prediction -> linear_prediction: N
669 [val] get_angular_prediction -> angular_prediction: N
670 [val] get_is_sensor -> is_sensor: bool
671 [val] get_ccd_enabled -> ccd_enabled: bool
672 );
673
674 pub fn build<Handle: BodyHandle>(&self, parent_handle: Handle) -> Collider<N, Handle> {
676 let query = if self.is_sensor {
677 GeometricQueryType::Proximity(self.linear_prediction)
678 } else {
679 GeometricQueryType::Contacts(
680 self.margin + self.linear_prediction,
681 self.angular_prediction,
682 )
683 };
684
685 let body_parts = self.body_parts_mapping.clone();
686 let anchor = ColliderAnchor::OnDeformableBody {
687 body: parent_handle,
688 body_parts,
689 };
690 let material = self
691 .material
692 .clone()
693 .unwrap_or_else(|| MaterialHandle::new(BasicMaterial::default()));
694 let mut data = ColliderData::new(self.margin, N::zero(), anchor, 0, material);
695 data.ccd_enabled = data.ccd_enabled;
696 data.user_data = self.user_data.as_ref().map(|data| data.0.to_any());
697
698 let co = CollisionObject::new(
699 None,
700 None,
701 Isometry::identity(),
702 self.shape.clone(),
703 self.collision_groups,
704 query,
705 data,
706 );
707 Collider(co)
708 }
709}