#![allow(warnings)]
use approx_det::{assert_relative_eq, relative_eq};
use glam::{Dot, UnitQuat, UnitVec3, Vec2, Vec3};
use wasm_bindgen_test::*;
use super::common::{
build_displaced_convexhull_test, get_input_wide, CollisionTestShape, Convex1ContactManifold,
ConvexHullInput, Mvec3,
};
use crate::collision_tasks::tests::common::{
convex4manifold_wide2convex4contact_manifold, Convex4ContactManifold, TestInput,
};
use crate::collision_tasks::ShapeWideTester;
use crate::shapes::{ConvexHullWide, CylinderWide};
use crate::traits::PairWideTest;
use crate::{ConvexHull, ConvexHullId, Cylinder, ShapeContainer};
wasm_bindgen_test_configure!(run_in_browser);
type InputTypeData = TestInput<Cylinder, ConvexHullInput>;
type InputType = TestInput<Cylinder, ConvexHullId>;
const ADJUST_DEPTH_FACTOR: f32 = 1.0;
fn test_cylinder_convex(input_data_bytes: &[u8], output_bytes: &[u8]) {
let input_data: InputTypeData =
serde_json::from_slice(input_data_bytes).expect("file should be proper JSON");
let hull_points = input_data.b.vertices;
let convex_hull = ConvexHull::new_unchecked(&hull_points);
let mut container = ShapeContainer::default();
let hull_id = container.add(convex_hull);
let input = InputType {
a: input_data.a,
b: hull_id,
speculative_margin: input_data.speculative_margin,
offset_b: input_data.offset_b,
orientation_a: input_data.orientation_a,
orientation_b: input_data.orientation_b,
};
let array = [input];
let mut output: Convex4ContactManifold =
serde_json::from_slice(output_bytes).expect("file should be proper JSON");
output.adjust_offset_a_to_shape_surface(ADJUST_DEPTH_FACTOR);
let outputs = [output];
let pair_count = array.len();
TestWide!(
CylinderWide,
ConvexHullWide,
array,
pair_count,
outputs,
convex4manifold_wide2convex4contact_manifold,
Some(&container),
compare
);
}
fn project(v: &Mvec3, x_axis: UnitVec3, y_axis: UnitVec3) -> Vec2 {
let offset = Vec3::new(v.x, v.y, v.z);
let x = x_axis.dot(offset);
let y = y_axis.dot(offset);
Vec2::new(x, y)
}
fn compare(v0: &Convex4ContactManifold, v1: &Convex4ContactManifold) {
let normal = UnitVec3::from_array_unchecked([v0.Normal.x, v0.Normal.y, v0.Normal.z]);
let (x_axis, y_axis) = normal.any_orthogonal_pair();
let v0 = v0.to_array();
let v1 = v1.to_array();
all_elements_offset_match_unique(&v0, &v1, x_axis, y_axis);
}
fn all_elements_offset_match_unique(
a: &[Convex1ContactManifold],
b: &[Convex1ContactManifold],
x_axis: UnitVec3,
y_axis: UnitVec3,
) -> bool {
let mut used_flags = vec![false; b.len()];
for v0 in a {
if !v0.contact_exists {
continue;
}
let mut matched = false;
for (j, v1) in b.iter().enumerate() {
if !v1.contact_exists {
continue;
}
if used_flags[j] {
continue;
}
let offset_equal = {
let v0_a0 = project(&v0.offset_a, x_axis, y_axis);
let v1_a0 = project(&v1.offset_a, x_axis, y_axis);
let distance = v0_a0.distance(v1_a0);
distance < 1e-3
};
let normal_equal = relative_eq!(v0.normal, v1.normal, epsilon = 1e-4);
let _ = v0.feature_id == v1.feature_id;
let depth_equal = relative_eq!(v0.depth, v1.depth, epsilon = 1e-5);
let contact_exist_equal = v0.contact_exists == v1.contact_exists;
if contact_exist_equal && depth_equal && normal_equal {
used_flags[j] = true;
matched = true;
break;
}
}
assert!(matched, "v0:{v0:?} \n b:{b:?}");
if !matched {
return false; }
}
true
}
#[test]
#[wasm_bindgen_test]
fn test_cylinder_convex_01_cylinder_cap_close_to_convex_face() {
let _ = env_logger::builder().is_test(true).try_init();
let input_data_bytes = include_bytes!(
"resource/cylinder_convex_hull/input01_cylinder_cap_close_to_convex_face.json"
);
let output_bytes = include_bytes!("resource/cylinder_convex_hull/output01.json");
test_cylinder_convex(input_data_bytes, output_bytes);
}
#[test]
#[wasm_bindgen_test]
fn test_cylinder_convex_02_cylinder_cap_tangent_to_convex_face() {
let _ = env_logger::builder().is_test(true).try_init();
let input_data_bytes = include_bytes!(
"resource/cylinder_convex_hull/input02_cylinder_cap_tangent_to_convex_face.json"
);
let output_bytes = include_bytes!("resource/cylinder_convex_hull/output02.json");
test_cylinder_convex(input_data_bytes, output_bytes);
}
#[test]
#[wasm_bindgen_test]
fn test_cylinder_convex_03_cylinder_cap_penetrate_convex_face() {
let _ = env_logger::builder().is_test(true).try_init();
let input_data_bytes = include_bytes!(
"resource/cylinder_convex_hull/input03_cylinder_cap_penetrate_convex_face.json"
);
let output_bytes = include_bytes!("resource/cylinder_convex_hull/output03.json");
test_cylinder_convex(input_data_bytes, output_bytes);
}
#[test]
#[wasm_bindgen_test]
fn test_cylinder_convex_04_cylinder_x_90_edge_close_to_convex_face() {
let _ = env_logger::builder().is_test(true).try_init();
let input_data_bytes = include_bytes!(
"resource/cylinder_convex_hull/input04_cylinder_x_90_edge_close_to_convex_face.json"
);
let output_bytes = include_bytes!("resource/cylinder_convex_hull/output04.json");
test_cylinder_convex(input_data_bytes, output_bytes);
}
#[test]
#[wasm_bindgen_test]
fn test_cylinder_convex_05_cylinder_x_90_edge_tangent_to_convex_face() {
let _ = env_logger::builder().is_test(true).try_init();
let input_data_bytes = include_bytes!(
"resource/cylinder_convex_hull/input05_cylinder_x_90_edge_tangent_to_convex_face.json"
);
let output_bytes = include_bytes!("resource/cylinder_convex_hull/output05.json");
test_cylinder_convex(input_data_bytes, output_bytes);
}
#[test]
#[wasm_bindgen_test]
fn test_cylinder_convex_06_cylinder_x_90_edge_penetrate_convex_face() {
let _ = env_logger::builder().is_test(true).try_init();
let input_data_bytes = include_bytes!(
"resource/cylinder_convex_hull/input06_cylinder_x_90_edge_penetrate_convex_face.json"
);
let output_bytes = include_bytes!("resource/cylinder_convex_hull/output06.json");
test_cylinder_convex(input_data_bytes, output_bytes);
}
#[test]
#[wasm_bindgen_test]
fn test_cylinder_convex_07_cylinder_edge_penetrate_convex_face() {
let _ = env_logger::builder().is_test(true).try_init();
let input_data_bytes = include_bytes!(
"resource/cylinder_convex_hull/input07_cylinder_edge_penetrate_convex_face.json"
);
let output_bytes = include_bytes!("resource/cylinder_convex_hull/output07.json");
test_cylinder_convex(input_data_bytes, output_bytes);
}
#[test]
#[wasm_bindgen_test]
fn test_cylinder_convex_08_no_contact() {
let _ = env_logger::builder().is_test(true).try_init();
let input_data_bytes = include_bytes!("resource/cylinder_convex_hull/input08_no_contact.json");
let output_bytes = include_bytes!("resource/cylinder_convex_hull/output08.json");
test_cylinder_convex(input_data_bytes, output_bytes);
}
#[test]
#[wasm_bindgen_test]
fn test_cylinder_convex_09_cylinder_bottom_cap_close_to_convex_face() {
let _ = env_logger::builder().is_test(true).try_init();
let input_data_bytes = include_bytes!(
"resource/cylinder_convex_hull/input09_cylinder_bottom_cap_close_to_convex_face.json"
);
let output_bytes = include_bytes!("resource/cylinder_convex_hull/output09.json");
test_cylinder_convex(input_data_bytes, output_bytes);
}
#[test]
#[wasm_bindgen_test]
fn test_cylinder_convex_10_cylinder_cap_close_to_big_convex_face() {
let _ = env_logger::builder().is_test(true).try_init();
let input_data_bytes = include_bytes!(
"resource/cylinder_convex_hull/input10_cylinder_cap_close_to_big_convex_face.json"
);
let output_bytes = include_bytes!("resource/cylinder_convex_hull/output10.json");
test_cylinder_convex(input_data_bytes, output_bytes);
}
#[test]
#[wasm_bindgen_test]
fn test_cylinder_convex_11_cylinder_cap_close_to_convex_vertex() {
let _ = env_logger::builder().is_test(true).try_init();
let input_data_bytes = include_bytes!(
"resource/cylinder_convex_hull/input11_cylinder_cap_close_to_convex_vertex.json"
);
let output_bytes = include_bytes!("resource/cylinder_convex_hull/output11.json");
test_cylinder_convex(input_data_bytes, output_bytes);
}
#[test]
#[wasm_bindgen_test]
fn test_cylinder_convex_12_cylinder_cap_tangent_convex_vertex() {
let _ = env_logger::builder().is_test(true).try_init();
let input_data_bytes = include_bytes!(
"resource/cylinder_convex_hull/input12_cylinder_cap_tangent_convex_vertex.json"
);
let output_bytes = include_bytes!("resource/cylinder_convex_hull/output12.json");
test_cylinder_convex(input_data_bytes, output_bytes);
}
#[test]
#[wasm_bindgen_test]
fn test_cylinder_convex_13_cylinder_cap_penetrate_convex_vertex() {
let _ = env_logger::builder().is_test(true).try_init();
let input_data_bytes = include_bytes!(
"resource/cylinder_convex_hull/input13_cylinder_cap_penetrate_convex_vertex.json"
);
let output_bytes = include_bytes!("resource/cylinder_convex_hull/output13.json");
test_cylinder_convex(input_data_bytes, output_bytes);
}
#[test]
#[wasm_bindgen_test]
#[cfg(not(feature = "qhull"))]
#[ignore]
fn test_cylinder_convex_14_cylinder_edge_penetrate_convex_vertex() {
let _ = env_logger::builder().is_test(true).try_init();
let input_data_bytes = include_bytes!(
"resource/cylinder_convex_hull/input14_cylinder_edge_penetrate_convex_vertex.json"
);
let output_bytes = include_bytes!("resource/cylinder_convex_hull/output14.json");
test_cylinder_convex(input_data_bytes, output_bytes);
}
#[test]
#[wasm_bindgen_test]
fn test_cylinder_convex_15_create_min_contact() {
let _ = env_logger::builder().is_test(true).try_init();
let input_data_bytes =
include_bytes!("resource/cylinder_convex_hull/input15_create_min_contact.json");
let output_bytes = include_bytes!("resource/cylinder_convex_hull/output15.json");
test_cylinder_convex(input_data_bytes, output_bytes);
}
#[test]
#[wasm_bindgen_test]
fn test_cylinder_convex_16_near_zero_angle_between_axis_and_edge_plane() {
let _ = env_logger::builder().is_test(true).try_init();
let input_data_bytes = include_bytes!(
"resource/cylinder_convex_hull/input16_near_zero_angle_between_axis_and_edge_plane.json"
);
let output_bytes = include_bytes!("resource/cylinder_convex_hull/output16.json");
test_cylinder_convex(input_data_bytes, output_bytes);
}
#[test]
#[wasm_bindgen_test]
fn test_cylinder_convex_17_cylinder_face_and_convex_face_one_contact_point() {
let _ = env_logger::builder().is_test(true).try_init();
let input_data_bytes = include_bytes!(
"resource/cylinder_convex_hull/input17_cylinder_face_and_convex_face_one_contact_point.json"
);
let output_bytes = include_bytes!("resource/cylinder_convex_hull/output17.json");
test_cylinder_convex(input_data_bytes, output_bytes);
}
#[test]
#[wasm_bindgen_test]
fn test_cylinder_convex_18_center_overlap() {
let _ = env_logger::builder().is_test(true).try_init();
let input_data_bytes =
include_bytes!("resource/cylinder_convex_hull/input18_center_overlap.json");
let output_bytes = include_bytes!("resource/cylinder_convex_hull/output18.json");
test_cylinder_convex(input_data_bytes, output_bytes);
}
#[test]
#[wasm_bindgen_test]
fn test_cylinder_convex_19_empty_candidates() {
let _ = env_logger::builder().is_test(true).try_init();
let input_data_bytes =
include_bytes!("resource/cylinder_convex_hull/input19_empty_candidates.json");
let output_bytes = include_bytes!("resource/cylinder_convex_hull/output19.json");
test_cylinder_convex(input_data_bytes, output_bytes);
}
#[test]
#[cfg(not(feature = "qhull"))]
fn test_cylinder_convex_shift() {
let shape_a = Cylinder::new(1., 2.);
let convexhull_cuboid_length = Vec3::new(4., 5., 6.);
let convexhull_displacement_vec = Vec3::new(1e0, 1e4, 1e2);
let desired_offset_b = Vec3::new(0., 4.1, 0.);
let rotation_a = UnitQuat::from_euler_default(-1., -2., -3.);
let rotation_b = UnitQuat::from_euler_default(1., 2., 3.);
build_displaced_convexhull_test(
&CollisionTestShape::Cylinder(shape_a),
convexhull_cuboid_length,
convexhull_displacement_vec,
desired_offset_b,
rotation_a,
rotation_b,
);
}