parry3d/query/shape_cast/
shape_cast_support_map_support_map.rs1use crate::math::{Pose, Real, Vector};
2use crate::query::details;
3use crate::query::details::ShapeCastOptions;
4use crate::query::gjk::{self, VoronoiSimplex};
5use crate::query::{ShapeCastHit, ShapeCastStatus};
6use crate::shape::{RoundShapeRef, SupportMap};
7use num::Zero;
8
9pub fn cast_shapes_support_map_support_map<G1, G2>(
11 pos12: &Pose,
12 vel12: Vector,
13 g1: &G1,
14 g2: &G2,
15 options: ShapeCastOptions,
16) -> Option<ShapeCastHit>
17where
18 G1: ?Sized + SupportMap,
19 G2: ?Sized + SupportMap,
20{
21 let gjk_result = if options.target_distance > 0.0 {
22 let round_g1 = RoundShapeRef {
23 inner_shape: g1,
24 border_radius: options.target_distance,
25 };
26 gjk::directional_distance(pos12, &round_g1, g2, vel12, &mut VoronoiSimplex::new())
27 } else {
28 gjk::directional_distance(pos12, g1, g2, vel12, &mut VoronoiSimplex::new())
29 };
30
31 gjk_result.and_then(|(time_of_impact, normal1, witness1, witness2)| {
32 if time_of_impact > options.max_time_of_impact {
33 None
34 } else if (options.compute_impact_geometry_on_penetration || !options.stop_at_penetration)
35 && time_of_impact < 1.0e-5
36 {
37 let contact = details::contact_support_map_support_map(pos12, g1, g2, Real::MAX)?;
38 let normal_vel = contact.normal1.dot(vel12);
39
40 if !options.stop_at_penetration && normal_vel >= 0.0 {
41 None
42 } else {
43 Some(ShapeCastHit {
44 time_of_impact,
45 normal1: contact.normal1,
46 normal2: contact.normal2,
47 witness1: contact.point1,
48 witness2: contact.point2,
49 status: ShapeCastStatus::PenetratingOrWithinTargetDist,
50 })
51 }
52 } else {
53 Some(ShapeCastHit {
54 time_of_impact,
55 normal1,
56 normal2: pos12.rotation.inverse() * -normal1,
57 witness1: witness1 - normal1 * options.target_distance,
58 witness2: pos12.inverse_transform_point(witness2),
59 status: if time_of_impact.is_zero() {
60 ShapeCastStatus::PenetratingOrWithinTargetDist
61 } else {
62 ShapeCastStatus::Converged
63 },
64 })
65 }
66 })
67}