use crate::math::{Isometry, Real};
use crate::query::contact_manifolds::{NormalConstraints, NormalConstraintsPair};
use crate::query::{
self,
gjk::{GJKResult, VoronoiSimplex},
ContactManifold, TrackedContact,
};
use crate::shape::{PackedFeatureId, PolygonalFeature, PolygonalFeatureMap, Shape};
use na::Unit;
pub fn contact_manifold_pfm_pfm_shapes<ManifoldData, ContactData>(
pos12: &Isometry<Real>,
shape1: &dyn Shape,
shape2: &dyn Shape,
normal_constraints1: Option<&dyn NormalConstraints>,
normal_constraints2: Option<&dyn NormalConstraints>,
prediction: Real,
manifold: &mut ContactManifold<ManifoldData, ContactData>,
) where
ManifoldData: Default,
ContactData: Default + Copy,
{
if let (Some((pfm1, border_radius1)), Some((pfm2, border_radius2))) = (
shape1.as_polygonal_feature_map(),
shape2.as_polygonal_feature_map(),
) {
contact_manifold_pfm_pfm(
pos12,
pfm1,
border_radius1,
normal_constraints1,
pfm2,
border_radius2,
normal_constraints2,
prediction,
manifold,
);
}
}
pub fn contact_manifold_pfm_pfm<'a, ManifoldData, ContactData, S1, S2>(
pos12: &Isometry<Real>,
pfm1: &'a S1,
border_radius1: Real,
normal_constraints1: Option<&dyn NormalConstraints>,
pfm2: &'a S2,
border_radius2: Real,
normal_constraints2: Option<&dyn NormalConstraints>,
prediction: Real,
manifold: &mut ContactManifold<ManifoldData, ContactData>,
) where
S1: ?Sized + PolygonalFeatureMap,
S2: ?Sized + PolygonalFeatureMap,
ManifoldData: Default,
ContactData: Default + Copy,
{
if manifold.try_update_contacts_eps(pos12, crate::utils::COS_1_DEGREES, 1.0e-6) {
return;
}
let init_dir = Unit::try_new(manifold.local_n1, crate::math::DEFAULT_EPSILON);
let total_prediction = prediction + border_radius1 + border_radius2;
let contact = query::details::contact_support_map_support_map_with_params(
pos12,
pfm1,
pfm2,
total_prediction,
&mut VoronoiSimplex::new(),
init_dir,
);
let old_manifold_points = manifold.points.clone();
manifold.clear();
match contact {
GJKResult::ClosestPoints(p1, p2_1, dir) => {
let mut local_n1 = dir;
let mut local_n2 = pos12.inverse_transform_unit_vector(&-dir);
let dist = (p2_1 - p1).dot(&local_n1);
if !(normal_constraints1, normal_constraints2).project_local_normals(
pos12,
local_n1.as_mut_unchecked(),
local_n2.as_mut_unchecked(),
) {
return;
}
let mut feature1 = PolygonalFeature::default();
let mut feature2 = PolygonalFeature::default();
pfm1.local_support_feature(&local_n1, &mut feature1);
pfm2.local_support_feature(&local_n2, &mut feature2);
PolygonalFeature::contacts(
pos12,
&pos12.inverse(),
&local_n1,
&local_n2,
&feature1,
&feature2,
manifold,
false,
);
if (cfg!(feature = "dim3") || cfg!(feature = "dim2") && manifold.points.is_empty())
&& local_n1 == dir
{
let contact = TrackedContact::new(
p1,
pos12.inverse_transform_point(&p2_1),
PackedFeatureId::UNKNOWN, PackedFeatureId::UNKNOWN,
(p2_1 - p1).dot(&local_n1),
);
manifold.points.push(contact);
}
if normal_constraints1.is_some() || normal_constraints2.is_some() {
manifold
.points
.retain(|pt| dist >= 0.0 || pt.dist >= 0.0 || pt.dist >= dist * 5.0);
}
if border_radius1 != 0.0 || border_radius2 != 0.0 {
for contact in &mut manifold.points {
contact.local_p1 += *local_n1 * border_radius1;
contact.local_p2 += *local_n2 * border_radius2;
contact.dist -= border_radius1 + border_radius2;
}
}
manifold.local_n1 = *local_n1;
manifold.local_n2 = *local_n2;
}
GJKResult::NoIntersection(dir) => {
manifold.local_n1 = *dir;
}
_ => {
manifold.local_n1.fill(0.0);
}
}
manifold.match_contacts(&old_manifold_points);
}