axiolid_exact_arrangement/
ring.rs1use axiolid_core::Point2;
4
5pub fn point_order(left: &Point2, right: &Point2) -> std::cmp::Ordering {
7 left.x
8 .total_cmp(&right.x)
9 .then_with(|| left.y.total_cmp(&right.y))
10}
11
12pub fn sequence_order(left: &[Point2], right: &[Point2]) -> std::cmp::Ordering {
14 left.iter()
15 .zip(right)
16 .map(|(a, b)| point_order(a, b))
17 .find(|order| order.is_ne())
18 .unwrap_or_else(|| left.len().cmp(&right.len()))
19}
20
21pub fn canonical_start(points: &[Point2]) -> usize {
25 let rotated = |start: usize| -> Vec<Point2> {
26 points[start..]
27 .iter()
28 .chain(&points[..start])
29 .copied()
30 .collect()
31 };
32 let smallest = points.iter().min_by(|l, r| point_order(l, r)).copied();
33 (0..points.len())
34 .filter(|&start| Some(points[start]) == smallest)
35 .min_by(|&left, &right| sequence_order(&rotated(left), &rotated(right)))
36 .unwrap_or(0)
37}
38
39pub fn canonical_rotation(points: Vec<Point2>) -> Vec<Point2> {
42 let start = canonical_start(&points);
43 points[start..]
44 .iter()
45 .chain(&points[..start])
46 .copied()
47 .collect()
48}