parry2d/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-4
36 {
37 let contact = details::contact_support_map_support_map(pos12, g1, g2, Real::MAX)?;
43 let normal_vel = contact.normal1.dot(vel12);
44
45 if !options.stop_at_penetration && normal_vel >= 0.0 {
46 None
47 } else {
48 Some(ShapeCastHit {
49 time_of_impact,
50 normal1: contact.normal1,
51 normal2: contact.normal2,
52 witness1: contact.point1,
53 witness2: contact.point2,
54 status: if contact.dist < options.target_distance {
57 ShapeCastStatus::PenetratingOrWithinTargetDist
58 } else {
59 ShapeCastStatus::Converged
60 },
61 })
62 }
63 } else {
64 Some(ShapeCastHit {
65 time_of_impact,
66 normal1,
67 normal2: pos12.rotation.inverse() * -normal1,
68 witness1: witness1 - normal1 * options.target_distance,
69 witness2: pos12.inverse_transform_point(witness2),
70 status: if time_of_impact.is_zero() {
71 match details::contact_support_map_support_map(pos12, g1, g2, Real::MAX) {
75 Some(contact) if contact.dist >= options.target_distance => {
76 ShapeCastStatus::Converged
77 }
78 _ => ShapeCastStatus::PenetratingOrWithinTargetDist,
79 }
80 } else {
81 ShapeCastStatus::Converged
82 },
83 })
84 }
85 })
86}