diff options
Diffstat (limited to 'third_party/rust/plane-split/tests/main.rs')
-rw-r--r-- | third_party/rust/plane-split/tests/main.rs | 341 |
1 files changed, 341 insertions, 0 deletions
diff --git a/third_party/rust/plane-split/tests/main.rs b/third_party/rust/plane-split/tests/main.rs new file mode 100644 index 0000000000..0bcac5a179 --- /dev/null +++ b/third_party/rust/plane-split/tests/main.rs @@ -0,0 +1,341 @@ +use euclid::{ + approxeq::ApproxEq, + default::{Rect, Size2D, Transform3D}, + point2, point3, vec3, Angle, +}; +use plane_split::{Intersection, Line, LineProjection, NegativeHemisphereError, Plane, Polygon}; + +#[test] +fn line_proj_bounds() { + assert_eq!( + (-5.0f64, 4.0), + LineProjection { + markers: [-5.0f64, 1.0, 4.0, 2.0] + } + .get_bounds() + ); + assert_eq!( + (1f64, 4.0), + LineProjection { + markers: [4f64, 3.0, 2.0, 1.0] + } + .get_bounds() + ); +} + +#[test] +fn valid() { + let poly_a: Polygon<usize> = Polygon { + points: [ + point3(0.0, 0.0, 0.0), + point3(1.0, 1.0, 1.0), + point3(1.0, 1.0, 0.0), + point3(0.0, 1.0, 1.0), + ], + plane: Plane { + normal: vec3(0.0, 1.0, 0.0), + offset: -1.0, + }, + anchor: 0, + }; + assert!(!poly_a.is_valid()); // points[0] is outside + let poly_b: Polygon<usize> = Polygon { + points: [ + point3(0.0, 1.0, 0.0), + point3(1.0, 1.0, 1.0), + point3(1.0, 1.0, 0.0), + point3(0.0, 1.0, 1.0), + ], + plane: Plane { + normal: vec3(0.0, 1.0, 0.0), + offset: -1.0, + }, + anchor: 0, + }; + assert!(!poly_b.is_valid()); // winding is incorrect + let poly_c: Polygon<usize> = Polygon { + points: [ + point3(0.0, 0.0, 1.0), + point3(1.0, 0.0, 1.0), + point3(1.0, 1.0, 1.0), + point3(0.0, 1.0, 1.0), + ], + plane: Plane { + normal: vec3(0.0, 0.0, 1.0), + offset: -1.0, + }, + anchor: 0, + }; + assert!(poly_c.is_valid()); +} + +#[test] +fn empty() { + let poly = Polygon::from_points( + [ + point3(0.0, 0.0, 1.0), + point3(0.0, 0.0, 1.0), + point3(0.0, 0.00000001, 1.0), + point3(1.0, 0.0, 0.0), + ], + 1usize, + ); + assert_eq!(None, poly); +} + +fn test_transformed(rect: Rect<f64>, transform: Transform3D<f64>) { + let poly = Polygon::from_transformed_rect(rect, transform, 0).unwrap(); + assert!(poly.is_valid()); + + let inv_transform = transform.inverse().unwrap(); + let poly2 = + Polygon::from_transformed_rect_with_inverse(rect, &transform, &inv_transform, 0).unwrap(); + assert_eq!(poly.points, poly2.points); + assert!(poly.plane.offset.approx_eq(&poly2.plane.offset)); + assert!(poly.plane.normal.dot(poly2.plane.normal).approx_eq(&1.0)); +} + +#[test] +fn from_transformed_rect() { + let rect = Rect::new(point2(10.0, 10.0), Size2D::new(20.0, 30.0)); + let transform = Transform3D::rotation(0.5f64.sqrt(), 0.0, 0.5f64.sqrt(), Angle::radians(5.0)) + .pre_translate(vec3(0.0, 0.0, 10.0)); + test_transformed(rect, transform); +} + +#[test] +fn from_transformed_rect_perspective() { + let rect = Rect::new(point2(-10.0, -5.0), Size2D::new(20.0, 30.0)); + let mut transform = Transform3D::perspective(400.0).pre_translate(vec3(0.0, 0.0, 100.0)); + transform.m44 = 0.7; //for fun + test_transformed(rect, transform); +} + +#[test] +fn untransform_point() { + let poly: Polygon<usize> = Polygon { + points: [ + point3(0.0, 0.0, 0.0), + point3(0.5, 1.0, 0.0), + point3(1.5, 1.0, 0.0), + point3(1.0, 0.0, 0.0), + ], + plane: Plane { + normal: vec3(0.0, 1.0, 0.0), + offset: 0.0, + }, + anchor: 0, + }; + assert_eq!(poly.untransform_point(poly.points[0]), point2(0.0, 0.0)); + assert_eq!(poly.untransform_point(poly.points[1]), point2(1.0, 0.0)); + assert_eq!(poly.untransform_point(poly.points[2]), point2(1.0, 1.0)); + assert_eq!(poly.untransform_point(poly.points[3]), point2(0.0, 1.0)); +} + +#[test] +fn are_outside() { + let plane = Plane { + normal: vec3(0.0, 0.0, 1.0), + offset: -1.0, + }; + assert!(plane.are_outside(&[point3(0.0, 0.0, 1.1), point3(1.0, 1.0, 2.0),])); + assert!(plane.are_outside(&[point3(0.5, 0.5, 1.0),])); + assert!(!plane.are_outside(&[point3(0.0, 0.0, 1.0), point3(0.0, 0.0, -1.0),])); +} + +#[test] +fn intersect() { + let poly_a: Polygon<usize> = Polygon { + points: [ + point3(0.0, 0.0, 1.0), + point3(1.0, 0.0, 1.0), + point3(1.0, 1.0, 1.0), + point3(0.0, 1.0, 1.0), + ], + plane: Plane { + normal: vec3(0.0, 0.0, 1.0), + offset: -1.0, + }, + anchor: 0, + }; + assert!(poly_a.is_valid()); + let poly_b: Polygon<usize> = Polygon { + points: [ + point3(0.5, 0.0, 2.0), + point3(0.5, 1.0, 2.0), + point3(0.5, 1.0, 0.0), + point3(0.5, 0.0, 0.0), + ], + plane: Plane { + normal: vec3(1.0, 0.0, 0.0), + offset: -0.5, + }, + anchor: 0, + }; + assert!(poly_b.is_valid()); + + let intersection = match poly_a.intersect(&poly_b) { + Intersection::Inside(result) => result, + _ => panic!("Bad intersection"), + }; + assert!(intersection.is_valid()); + // confirm the origin is on both planes + assert!(poly_a + .plane + .signed_distance_to(&intersection.origin) + .approx_eq(&0.0)); + assert!(poly_b + .plane + .signed_distance_to(&intersection.origin) + .approx_eq(&0.0)); + // confirm the direction is coplanar to both planes + assert!(poly_a.plane.normal.dot(intersection.dir).approx_eq(&0.0)); + assert!(poly_b.plane.normal.dot(intersection.dir).approx_eq(&0.0)); + + let poly_c: Polygon<usize> = Polygon { + points: [ + point3(0.0, -1.0, 2.0), + point3(0.0, -1.0, 0.0), + point3(0.0, 0.0, 0.0), + point3(0.0, 0.0, 2.0), + ], + plane: Plane { + normal: vec3(1.0, 0.0, 0.0), + offset: 0.0, + }, + anchor: 0, + }; + assert!(poly_c.is_valid()); + let poly_d: Polygon<usize> = Polygon { + points: [ + point3(0.0, 0.0, 0.5), + point3(1.0, 0.0, 0.5), + point3(1.0, 1.0, 0.5), + point3(0.0, 1.0, 0.5), + ], + plane: Plane { + normal: vec3(0.0, 0.0, 1.0), + offset: -0.5, + }, + anchor: 0, + }; + assert!(poly_d.is_valid()); + + assert!(poly_a.intersect(&poly_c).is_outside()); + assert!(poly_a.intersect(&poly_d).is_outside()); +} + +fn test_cut(poly_base: &Polygon<usize>, extra_count: u8, line: Line) { + assert!(line.is_valid()); + + let normal = poly_base.plane.normal.cross(line.dir).normalize(); + let mut poly = poly_base.clone(); + let (extra1, extra2) = poly.split_with_normal(&line, &normal); + assert!(poly.is_valid() && poly_base.contains(&poly)); + assert_eq!(extra_count > 0, extra1.is_some()); + assert_eq!(extra_count > 1, extra2.is_some()); + if let Some(extra) = extra1 { + assert!(extra.is_valid() && poly_base.contains(&extra)); + } + if let Some(extra) = extra2 { + assert!(extra.is_valid() && poly_base.contains(&extra)); + } +} + +#[test] +fn split() { + let poly: Polygon<usize> = Polygon { + points: [ + point3(0.0, 1.0, 0.0), + point3(1.0, 1.0, 0.0), + point3(1.0, 1.0, 1.0), + point3(0.0, 1.0, 1.0), + ], + plane: Plane { + normal: vec3(0.0, 1.0, 0.0), + offset: -1.0, + }, + anchor: 0, + }; + + // non-intersecting line + test_cut( + &poly, + 0, + Line { + origin: point3(0.0, 1.0, 0.5), + dir: vec3(0.0, 1.0, 0.0), + }, + ); + + // simple cut (diff=2) + test_cut( + &poly, + 1, + Line { + origin: point3(0.0, 1.0, 0.5), + dir: vec3(1.0, 0.0, 0.0), + }, + ); + + // complex cut (diff=1, wrapped) + test_cut( + &poly, + 2, + Line { + origin: point3(0.0, 1.0, 0.5), + dir: vec3(0.5f64.sqrt(), 0.0, -0.5f64.sqrt()), + }, + ); + + // complex cut (diff=1, non-wrapped) + test_cut( + &poly, + 2, + Line { + origin: point3(0.5, 1.0, 0.0), + dir: vec3(0.5f64.sqrt(), 0.0, 0.5f64.sqrt()), + }, + ); + + // complex cut (diff=3) + test_cut( + &poly, + 2, + Line { + origin: point3(0.5, 1.0, 0.0), + dir: vec3(-0.5f64.sqrt(), 0.0, 0.5f64.sqrt()), + }, + ); + + // perfect diagonal + test_cut( + &poly, + 1, + Line { + origin: point3(0.0, 1.0, 0.0), + dir: vec3(0.5f64.sqrt(), 0.0, 0.5f64.sqrt()), + }, + ); +} + +#[test] +fn plane_unnormalized() { + let zero_vec = vec3(0.0000001, 0.0, 0.0); + let mut plane: Result<Option<Plane>, _> = Plane::from_unnormalized(zero_vec, 1.0); + assert_eq!(plane, Ok(None)); + plane = Plane::from_unnormalized(zero_vec, 0.0); + assert_eq!(plane, Err(NegativeHemisphereError)); + plane = Plane::from_unnormalized(zero_vec, -0.5); + assert_eq!(plane, Err(NegativeHemisphereError)); + + let plane = Plane::from_unnormalized(vec3(-3.0, 4.0, 0.0), 2.0) + .unwrap() + .unwrap(); + let expected = Plane { + normal: vec3(-3.0 / 5.0, 4.0 / 5.0, 0.0), + offset: 2.0 / 5.0, + }; + assert!(plane.normal.approx_eq(&expected.normal)); + assert!(plane.offset.approx_eq(&expected.offset)); +} |