doc_quad/geom/
validate.rs1use glam::Vec2;
3use geo_types::LineString;
4
5pub struct GeometryValidator;
6
7impl GeometryValidator {
8 pub fn validate_and_score(poly: &LineString<f32>) -> Option<(f32, [Vec2; 4])> {
14 if poly.0.len() != 5 {
15 return None;
16 }
17
18 let pts = [
19 Vec2::new(poly.0[0].x, poly.0[0].y),
20 Vec2::new(poly.0[1].x, poly.0[1].y),
21 Vec2::new(poly.0[2].x, poly.0[2].y),
22 Vec2::new(poly.0[3].x, poly.0[3].y),
23 ];
24
25 let mut area = 0.0f32;
27 for i in 0..4 {
28 let j = (i + 1) % 4;
29 area += pts[i].x * pts[j].y;
30 area -= pts[j].x * pts[i].y;
31 }
32 area = area.abs() * 0.5;
33
34 if area < f32::EPSILON {
35 return None;
36 }
37
38 let mut crosses = [0.0f32; 4];
40 for i in 0..4 {
41 let v1 = pts[(i + 1) % 4] - pts[i];
42 let v2 = pts[(i + 2) % 4] - pts[(i + 1) % 4];
43 crosses[i] = v1.x * v2.y - v1.y * v2.x;
44 }
45
46 let non_zero: Vec<f32> = crosses
48 .iter()
49 .filter(|&&c| c.abs() > area * 0.01) .copied()
51 .collect();
52
53 if non_zero.is_empty() {
54 log::warn!("[Geom::Validate] - Quadrilateral is fully degenerate.");
55 return None;
56 }
57
58 let positive_count = non_zero.iter().filter(|&&c| c > 0.0).count();
60 let negative_count = non_zero.len() - positive_count;
61 let minority_count = positive_count.min(negative_count);
62
63 if minority_count > 1 {
65 log::warn!(
66 "[Geom::Validate] - Quadrilateral failed convexity test ({} minority crosses).",
67 minority_count
68 );
69 return None;
70 }
71
72 Some((area, pts))
73 }
74}