1use std::cmp::Ordering;
2
3use crate::shape::Point;
4
5type NumType = u32;
9
10#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
12pub struct PointId(pub(crate) NumType);
13
14impl PointId {
15 pub fn as_usize(&self) -> usize {
17 self.0 as usize
18 }
19
20 pub(crate) fn get(&self, points: &Points) -> Point {
22 unsafe { points.get_point_uncheck(*self) }
23 }
24}
25
26#[derive(Clone, Default)]
27pub struct PointsBuilder {
28 points: Vec<PointWithEdge>,
29}
30
31impl PointsBuilder {
32 pub fn with_capacity(cap: usize) -> Self {
33 Self {
34 points: Vec::with_capacity(cap),
35 }
36 }
37
38 pub fn add_steiner_point(&mut self, point: Point) -> PointId {
40 let point_id = PointId(self.points.len() as NumType);
41 self.points.push(PointWithEdge {
42 point,
43 edges: PointEdges::None,
44 });
45 point_id
46 }
47
48 pub fn add_steiner_points(&mut self, points: impl IntoIterator<Item = Point>) {
50 self.points
51 .extend(points.into_iter().map(|p| PointWithEdge {
52 point: p,
53 edges: PointEdges::None,
54 }));
55 }
56
57 pub(crate) fn get_point_mut(&mut self, point_id: PointId) -> Option<&mut PointWithEdge> {
58 self.points.get_mut(point_id.as_usize())
59 }
60
61 pub fn build(self) -> Points {
62 Points::new(self.points)
63 }
64}
65
66#[derive(Clone, Copy)]
67pub enum PointEdges {
68 None,
69 One(PointId),
70 Two(PointId, PointId),
71}
72
73impl PointEdges {
74 pub fn push(&mut self, point_id: PointId) {
75 *self = match self {
76 PointEdges::None => PointEdges::One(point_id),
77 PointEdges::One(p0) => PointEdges::Two(*p0, point_id),
78 PointEdges::Two(_, _) => panic!("one point only has two edges"),
79 };
80 }
81}
82
83#[derive(Clone, Copy)]
84pub struct PointWithEdge {
85 pub point: Point,
86 pub edges: PointEdges,
87}
88
89impl Iterator for PointEdges {
90 type Item = PointId;
91
92 fn next(&mut self) -> Option<Self::Item> {
93 let mut result = None;
94 let new_self = match std::mem::replace(self, PointEdges::None) {
95 PointEdges::None => PointEdges::None,
96 PointEdges::One(p) => {
97 result = Some(p);
98 PointEdges::None
99 }
100 PointEdges::Two(p0, p1) => {
101 result = Some(p0);
102 PointEdges::One(p1)
103 }
104 };
105 *self = new_self;
106 result
107 }
108}
109
110#[derive(Clone)]
112pub struct Points {
113 points: Vec<PointWithEdge>,
114 y_sorted: Vec<PointId>,
115 pub head: PointId,
116 pub tail: PointId,
117}
118
119impl Points {
120 pub fn new(mut points: Vec<PointWithEdge>) -> Self {
121 let mut xmax = f64::MIN;
122 let mut xmin = f64::MAX;
123 let mut ymax = f64::MIN;
124 let mut ymin = f64::MAX;
125
126 let mut unsorted_points = points
127 .iter()
128 .enumerate()
129 .map(|(idx, p)| {
130 xmax = xmax.max(p.point.x);
131 xmin = xmin.min(p.point.x);
132 ymax = ymax.max(p.point.y);
133 ymin = ymin.min(p.point.y);
134 (PointId(idx as NumType), p.point)
135 })
136 .collect::<Vec<_>>();
137
138 unsorted_points.sort_by(|p1, p2| {
140 let p1 = p1.1;
141 let p2 = p2.1;
142
143 if p1.y < p2.y {
144 Ordering::Less
145 } else if p1.y == p2.y {
146 if p1.x < p2.x {
147 Ordering::Less
148 } else {
149 Ordering::Greater
150 }
151 } else {
152 Ordering::Greater
153 }
154 });
155 let sorted_ids = unsorted_points
156 .into_iter()
157 .map(|(idx, _)| idx)
158 .collect::<Vec<_>>();
159
160 let (head, tail) = {
161 let dx = (xmax - xmin) * 0.3;
162 let dy = (ymax - ymin) * 0.3;
163
164 let head = Point::new(xmin - dx, ymin - dy);
165 let head_id = PointId(points.len() as NumType);
166 points.push(PointWithEdge {
167 point: head,
168 edges: PointEdges::None,
169 });
170
171 let tail = Point::new(xmax + dx, ymin - dy);
172 let tail_id = PointId(points.len() as NumType);
173 points.push(PointWithEdge {
174 point: tail,
175 edges: PointEdges::None,
176 });
177 (head_id, tail_id)
178 };
179
180 Self {
181 points,
182 y_sorted: sorted_ids,
183 head,
184 tail,
185 }
186 }
187
188 pub fn len(&self) -> usize {
189 self.points.len()
190 }
191
192 pub fn get_point(&self, point_id: PointId) -> Option<Point> {
194 self.points
195 .get(point_id.as_usize())
196 .map(|p| &p.point)
197 .cloned()
198 }
199
200 pub unsafe fn get_point_uncheck(&self, point_id: PointId) -> Point {
202 unsafe { self.points.get_unchecked(point_id.as_usize()).point }
203 }
204
205 pub fn iter_point_by_y<'a>(
206 &'a self,
207 order: usize,
208 ) -> impl Iterator<Item = (PointId, Point, PointEdges)> + 'a {
209 self.y_sorted.iter().skip(order).map(|id| {
210 let point = unsafe { self.points.get_unchecked(id.as_usize()).clone() };
211 (*id, point.point, point.edges)
212 })
213 }
214
215 pub fn get_id_by_y(&self, order: usize) -> Option<PointId> {
218 self.y_sorted.get(order).cloned()
219 }
220
221 pub fn iter(&self) -> impl Iterator<Item = (PointId, &Point, PointEdges)> {
223 self.points
224 .iter()
225 .enumerate()
226 .map(|(idx, p)| (PointId(idx as NumType), &p.point, p.edges))
227 }
228}