1use crate::{triangles::TriangleId, PointId};
2
3#[derive(Clone, Copy, Debug)]
4pub struct Edge {
5 pub p: PointId,
7 pub q: PointId,
9}
10
11impl Edge {
12 pub fn new((p1_id, p1): (PointId, &Point), (p2_id, p2): (PointId, &Point)) -> Self {
13 let mut p: PointId = p1_id;
14 let mut q: PointId = p2_id;
15
16 if p1.y > p2.y {
17 q = p1_id;
18 p = p2_id;
19 } else if p1.y == p2.y {
20 if p1.x > p2.x {
21 q = p1_id;
22 p = p2_id;
23 } else if p1.x == p2.x {
24 assert!(false, "repeat points");
25 }
26 }
27
28 Self { p, q }
29 }
30}
31
32#[derive(Debug, Clone, Copy)]
33pub struct Point {
34 pub x: f64,
35 pub y: f64,
36}
37
38impl Default for Point {
39 fn default() -> Self {
40 Self { x: 0., y: 0. }
41 }
42}
43
44impl Point {
45 pub fn new(x: f64, y: f64) -> Self {
46 Self { x, y }
47 }
48
49 pub fn eq(&self, other: &Self) -> bool {
53 self.x == other.x && self.y == other.y
54 }
55}
56
57#[derive(Default, Clone, Copy)]
58pub struct EdgeAttr(u8);
59
60impl std::fmt::Debug for EdgeAttr {
61 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
62 f.debug_struct("EdgeAttr")
63 .field("constrained", &self.is_constrained())
64 .field("delaunay", &self.is_delaunay())
65 .finish()
66 }
67}
68
69impl EdgeAttr {
70 const CONSTRAINED: u8 = 1;
71 const CONSTRAINED_UNSET: u8 = Self::ALL ^ Self::CONSTRAINED;
72 const DELAUNAY: u8 = 1 << 1;
73 const DELAUNAY_UNSET: u8 = Self::ALL ^ Self::DELAUNAY;
74
75 const ALL: u8 = 0xFF;
76
77 fn set_constrained(&mut self, val: bool) {
78 if !val {
79 self.0 &= Self::CONSTRAINED_UNSET;
80 } else {
81 self.0 |= Self::CONSTRAINED;
82 }
83 }
84
85 fn is_constrained(&self) -> bool {
86 self.0 & Self::CONSTRAINED != 0
87 }
88
89 fn set_delaunay(&mut self, val: bool) {
90 if !val {
91 self.0 &= Self::DELAUNAY_UNSET;
92 } else {
93 self.0 |= Self::DELAUNAY;
94 }
95 }
96
97 fn is_delaunay(&self) -> bool {
98 self.0 & Self::DELAUNAY != 0
99 }
100}
101
102#[derive(Debug, Clone, Copy)]
104pub struct InnerTriangle {
105 pub points: [PointId; 3],
107
108 pub neighbors: [TriangleId; 3],
110
111 pub edge_attrs: [EdgeAttr; 3],
112
113 pub interior: bool,
115}
116
117impl InnerTriangle {
118 pub fn new(a: PointId, b: PointId, c: PointId) -> Self {
119 Self {
120 points: [a, b, c],
121 edge_attrs: [Default::default(), Default::default(), Default::default()],
122 neighbors: [TriangleId::INVALID; 3],
123 interior: false,
124 }
125 }
126
127 pub fn point_cw(&self, point: PointId) -> PointId {
129 if point == self.points[0] {
130 self.points[2]
131 } else if point == self.points[1] {
132 self.points[0]
133 } else if point == self.points[2] {
134 self.points[1]
135 } else {
136 panic!("point not belongs to triangle");
137 }
138 }
139
140 pub fn point_ccw(&self, point: PointId) -> PointId {
142 if point == self.points[0] {
143 self.points[1]
144 } else if point == self.points[1] {
145 self.points[2]
146 } else if point == self.points[2] {
147 self.points[0]
148 } else {
149 panic!("point not belongs to triangle");
150 }
151 }
152
153 pub fn opposite_point(&self, from_triangle: &InnerTriangle, point: PointId) -> PointId {
155 let cw = from_triangle.point_cw(point);
156 self.point_cw(cw)
157 }
158
159 #[inline(always)]
161 pub fn point_index(&self, point: PointId) -> Option<usize> {
162 if self.points[0] == point {
163 Some(0)
164 } else if self.points[1] == point {
165 Some(1)
166 } else if self.points[2] == point {
167 Some(2)
168 } else {
169 None
170 }
171 }
172
173 pub fn set_constrained_for_edge(&mut self, p: PointId, q: PointId) {
175 if let Some(index) = self.edge_index(p, q) {
176 self.edge_attrs[index].set_constrained(true);
177 }
178 }
179
180 #[inline(always)]
181 pub fn set_constrained(&mut self, edge_index: usize, val: bool) {
182 self.edge_attrs[edge_index].set_constrained(val);
183 }
184
185 pub fn is_constrained(&self, edge_index: usize) -> bool {
186 self.edge_attrs[edge_index].is_constrained()
187 }
188
189 #[inline(always)]
190 pub fn set_delaunay(&mut self, edge_index: usize, val: bool) {
191 self.edge_attrs[edge_index].set_delaunay(val);
192 }
193
194 pub fn is_delaunay(&self, edge_index: usize) -> bool {
195 self.edge_attrs[edge_index].is_delaunay()
196 }
197
198 pub fn edge_attr_ccw(&self, p: PointId) -> EdgeAttr {
199 if p == self.points[0] {
200 self.edge_attrs[2]
201 } else if p == self.points[1] {
202 self.edge_attrs[0]
203 } else if p == self.points[2] {
204 self.edge_attrs[1]
205 } else {
206 panic!("point not belongs to triangle");
207 }
208 }
209
210 pub fn set_edge_attr_ccw(&mut self, p: PointId, edge_attr: EdgeAttr) {
211 if p == self.points[0] {
212 self.edge_attrs[2] = edge_attr;
213 } else if p == self.points[1] {
214 self.edge_attrs[0] = edge_attr;
215 } else if p == self.points[2] {
216 self.edge_attrs[1] = edge_attr;
217 } else {
218 panic!("point not belongs to triangle");
219 }
220 }
221
222 pub fn set_edge_attr_cw(&mut self, p: PointId, val: EdgeAttr) {
223 if p == self.points[0] {
224 self.edge_attrs[1] = val;
225 } else if p == self.points[1] {
226 self.edge_attrs[2] = val;
227 } else if p == self.points[2] {
228 self.edge_attrs[0] = val;
229 } else {
230 panic!("point not belongs to triangle");
231 }
232 }
233
234 pub fn edge_attr_cw(&self, p: PointId) -> EdgeAttr {
235 if p == self.points[0] {
236 self.edge_attrs[1]
237 } else if p == self.points[1] {
238 self.edge_attrs[2]
239 } else if p == self.points[2] {
240 self.edge_attrs[0]
241 } else {
242 panic!("point not belongs to triangle");
243 }
244 }
245
246 pub fn constrained_edge_cw(&self, p: PointId) -> bool {
248 match self.point_index(p) {
249 Some(0) => self.edge_attrs[1].is_constrained(),
250 Some(1) => self.edge_attrs[2].is_constrained(),
251 Some(2) => self.edge_attrs[0].is_constrained(),
252 _ => panic!("point not belongs to triangle"),
253 }
254 }
255
256 pub fn neighbor_index(&self, tid: TriangleId) -> usize {
257 if self.neighbors[0] == tid {
258 0
259 } else if self.neighbors[1] == tid {
260 1
261 } else if self.neighbors[2] == tid {
262 2
263 } else {
264 panic!("not valid neighbor")
265 }
266 }
267
268 pub fn neighbor_ccw(&self, p: PointId) -> TriangleId {
270 if p == self.points[0] {
271 self.neighbors[2]
272 } else if p == self.points[1] {
273 self.neighbors[0]
274 } else if p == self.points[2] {
275 self.neighbors[1]
276 } else {
277 panic!("point not belongs to triangle");
278 }
279 }
280
281 pub fn neighbor_cw(&self, p: PointId) -> TriangleId {
283 if p == self.points[0] {
284 self.neighbors[1]
285 } else if p == self.points[1] {
286 self.neighbors[2]
287 } else if p == self.points[2] {
288 self.neighbors[0]
289 } else {
290 panic!("point not belongs to triangle");
291 }
292 }
293
294 pub fn neighbor_across(&self, p: PointId) -> TriangleId {
296 let Some(point_index) = self.point_index(p) else {
297 panic!("break here");
298 };
299 self.neighbors[point_index]
300 }
301
302 pub fn rotate_cw(&mut self, o_point: PointId, n_point: PointId) {
304 if o_point == self.points[0] {
305 self.points[1] = self.points[0];
306 self.points[0] = self.points[2];
307 self.points[2] = n_point;
308 } else if o_point == self.points[1] {
309 self.points[2] = self.points[1];
310 self.points[1] = self.points[0];
311 self.points[0] = n_point;
312 } else if o_point == self.points[2] {
313 self.points[0] = self.points[2];
314 self.points[2] = self.points[1];
315 self.points[1] = n_point;
316 } else {
317 panic!("point not belongs to triangle")
318 }
319 }
320
321 pub fn clear_neighbors(&mut self) {
322 self.neighbors = [TriangleId::INVALID; 3];
323 }
324
325 pub fn edge_index(&self, p: PointId, q: PointId) -> Option<usize> {
326 Some(if self.points[0] == p {
327 if self.points[1] == q {
328 2
329 } else if self.points[2] == q {
330 1
331 } else {
332 return None;
333 }
334 } else if self.points[1] == p {
335 if self.points[0] == q {
336 2
337 } else if self.points[2] == q {
338 0
339 } else {
340 return None;
341 }
342 } else if self.points[2] == p {
343 if self.points[0] == q {
344 1
345 } else if self.points[1] == q {
346 0
347 } else {
348 return None;
349 }
350 } else {
351 return None;
352 })
353 }
354
355 pub fn common_edge_index(&self, other: &Self) -> Option<(usize, usize)> {
356 Some(if self.points[1] == other.points[0] {
357 if self.points[2] == other.points[2] {
358 (0, 1)
359 } else if self.points[0] == other.points[1] {
360 (2, 2)
361 } else {
362 return None;
363 }
364 } else if self.points[1] == other.points[1] {
365 if self.points[2] == other.points[0] {
366 (0, 2)
367 } else if self.points[0] == other.points[2] {
368 (2, 0)
369 } else {
370 return None;
371 }
372 } else if self.points[1] == other.points[2] {
373 if self.points[2] == other.points[1] {
374 (0, 0)
375 } else if self.points[0] == other.points[0] {
376 (2, 1)
377 } else {
378 return None;
379 }
380 } else if self.points[0] == other.points[0] {
381 if self.points[2] == other.points[1] {
382 (1, 2)
383 } else if self.points[1] == other.points[2] {
384 (2, 1)
385 } else {
386 return None;
387 }
388 } else if self.points[0] == other.points[2] {
389 if self.points[2] == other.points[0] {
390 (1, 1)
391 } else if self.points[1] == other.points[1] {
392 (2, 0)
393 } else {
394 return None;
395 }
396 } else if self.points[0] == other.points[1] {
397 if self.points[1] == other.points[0] {
398 (2, 2)
399 } else if self.points[2] == other.points[2] {
400 (1, 0)
401 } else {
402 return None;
403 }
404 } else if self.points[2] == other.points[0] {
405 if self.points[0] == other.points[2] {
406 (1, 1)
407 } else if self.points[1] == other.points[1] {
408 (0, 2)
409 } else {
410 return None;
411 }
412 } else if self.points[2] == other.points[1] {
413 if self.points[0] == other.points[0] {
414 (1, 2)
415 } else if self.points[1] == other.points[2] {
416 (0, 0)
417 } else {
418 return None;
419 }
420 } else if self.points[2] == other.points[2] {
421 if self.points[1] == other.points[0] {
422 (0, 1)
423 } else if self.points[0] == other.points[1] {
424 (1, 0)
425 } else {
426 return None;
427 }
428 } else {
429 return None;
430 })
431 }
432}
433
434#[cfg(test)]
435mod tests {
436 use super::*;
437 use crate::PointId;
438
439 #[test]
440 fn test_legalize() {
441 let mut t = InnerTriangle::new(PointId(1), PointId(2), PointId(3));
449 t.rotate_cw(PointId(1), PointId(4));
450 assert_eq!(t.points, [PointId(3), PointId(1), PointId(4)]);
451
452 let mut t = InnerTriangle::new(PointId(1), PointId(2), PointId(3));
459 t.rotate_cw(PointId(3), PointId(4));
460 assert_eq!(t.points, [PointId(3), PointId(4), PointId(2)]);
461
462 let mut t = InnerTriangle::new(PointId(1), PointId(2), PointId(3));
463 t.rotate_cw(PointId(2), PointId(4));
464 assert_eq!(t.points, [PointId(4), PointId(1), PointId(2)]);
465 }
466
467 #[test]
468 fn test_edge_attr() {
469 let mut attr = EdgeAttr::default();
470 assert!(!attr.is_constrained());
471 attr.set_constrained(false);
472 assert!(!attr.is_constrained());
473 attr.set_constrained(true);
474 assert!(attr.is_constrained());
475 attr.set_constrained(false);
476 assert!(!attr.is_constrained());
477
478 assert!(!attr.is_delaunay());
479 attr.set_delaunay(false);
480 assert!(!attr.is_delaunay());
481 attr.set_delaunay(true);
482 assert!(attr.is_delaunay());
483 attr.set_delaunay(false);
484 assert!(!attr.is_delaunay());
485 }
486
487 #[test]
488 fn test_common_edge() {
489 for ((p1_0, p1_1, p1_2), (p2_0, p2_1, p2_2), common_edge) in [
490 ((0, 1, 2), (0, 4, 1), Some((2, 1))),
492 ((0, 1, 2), (0, 2, 4), Some((1, 2))),
493 ((0, 1, 2), (1, 0, 4), Some((2, 2))),
495 ((0, 1, 2), (4, 0, 2), Some((1, 0))),
496 ((0, 1, 2), (4, 1, 0), Some((2, 0))),
498 ((0, 1, 2), (2, 4, 0), Some((1, 1))),
499 ((0, 1, 2), (1, 0, 4), Some((2, 2))),
501 ((0, 1, 2), (1, 4, 2), Some((0, 1))),
502 ((0, 1, 2), (4, 2, 1), Some((0, 0))),
504 ((0, 1, 2), (2, 1, 4), Some((0, 2))),
505 ((0, 1, 2), (0, 4, 1), Some((2, 1))),
507 ((0, 1, 2), (4, 2, 1), Some((0, 0))),
508 ((0, 1, 2), (2, 1, 4), Some((0, 2))),
510 ((0, 1, 2), (2, 4, 0), Some((1, 1))),
511 ((0, 1, 2), (0, 2, 4), Some((1, 2))),
513 ((0, 1, 2), (4, 2, 1), Some((0, 0))),
514 ((0, 1, 2), (2, 4, 0), Some((1, 1))),
516 ((0, 1, 2), (2, 1, 4), Some((0, 2))),
517 ] {
518 let t = InnerTriangle::new(PointId(p1_0), PointId(p1_1), PointId(p1_2));
519 let ot = InnerTriangle::new(PointId(p2_0), PointId(p2_1), PointId(p2_2));
520 assert_eq!(
521 t.common_edge_index(&ot),
522 common_edge,
523 "({p1_0}, {p1_1}, {p1_2}) ({p2_0} {p2_1} {p2_2}) {common_edge:?}",
524 );
525 }
526 }
527}