geosets_rs/
geometric_operations.rs1use ndarray::Array2;
2use thiserror::Error;
3
4#[derive(Debug, Error)]
5pub enum GeometryError {
6 #[error("Vertices must be a 2D array with shape (n, 2)")]
7 InvalidShape,
8}
9
10pub fn order_vertices_clockwise(vertices: Array2<f64>) -> Result<Array2<f64>, GeometryError> {
11 let n_vertices = vertices.nrows();
12
13 if vertices.dim().1 != 2 {
14 return Err(GeometryError::InvalidShape);
15 }
16
17 if n_vertices < 3 {
18 return Ok(vertices);
19 }
20
21 let centroid_x = vertices.column(0).mean().unwrap();
23 let centroid_y = vertices.column(1).mean().unwrap();
24
25 let mut vertex_angles: Vec<(usize, f64)> = (0..n_vertices)
27 .map(|i| {
28 let x = vertices[[i, 0]] - centroid_x;
29 let y = vertices[[i, 1]] - centroid_y;
30 let angle = y.atan2(x);
31 (i, angle)
32 })
33 .collect();
34
35 vertex_angles.sort_by(|a, b| b.1.partial_cmp(&a.1).unwrap());
37
38 let mut ordered_vertices = Array2::zeros((n_vertices, 2));
40 for (new_idx, (orig_idx, _)) in vertex_angles.iter().enumerate() {
41 ordered_vertices[[new_idx, 0]] = vertices[[*orig_idx, 0]];
42 ordered_vertices[[new_idx, 1]] = vertices[[*orig_idx, 1]];
43 }
44
45 Ok(ordered_vertices)
46}
47
48#[cfg(test)]
49mod tests {
50 use super::*;
51 use ndarray::array;
52
53 #[test]
54 fn test_order_vertices_clockwise() {
55 let vertices = array![
57 [1.0, 1.0], [0.0, 0.0], [1.0, 0.0], [0.0, 1.0] ];
62
63 let ordered = order_vertices_clockwise(vertices).unwrap();
64
65 assert_eq!(ordered.nrows(), 4);
67 assert_eq!(ordered.ncols(), 2);
68
69 println!("Ordered vertices: {:?}", ordered);
72 }
73}