1use crate::lefdef::{DefDieArea, DefPoint};
4use crate::mod_def::tracks::{TrackDefinition, TrackOrientation};
5#[derive(Clone)]
6pub(crate) struct VerilogImport {
7 pub(crate) sources: Vec<String>,
8 pub(crate) incdirs: Vec<String>,
9 pub(crate) defines: Vec<(String, String)>,
10 pub(crate) skip_unsupported: bool,
11 pub(crate) ignore_unknown_modules: bool,
12}
13
14#[derive(Debug, Clone, Copy, PartialEq, Eq)]
17pub struct Coordinate {
18 pub x: i64,
19 pub y: i64,
20}
21
22impl std::ops::Add for Coordinate {
23 type Output = Coordinate;
24
25 fn add(self, rhs: Coordinate) -> Coordinate {
26 Coordinate {
27 x: self.x + rhs.x,
28 y: self.y + rhs.y,
29 }
30 }
31}
32
33impl std::ops::Add<&Coordinate> for Coordinate {
34 type Output = Coordinate;
35
36 fn add(self, rhs: &Coordinate) -> Coordinate {
37 Coordinate {
38 x: self.x + rhs.x,
39 y: self.y + rhs.y,
40 }
41 }
42}
43
44impl std::ops::Add<Coordinate> for &Coordinate {
45 type Output = Coordinate;
46
47 fn add(self, rhs: Coordinate) -> Coordinate {
48 Coordinate {
49 x: self.x + rhs.x,
50 y: self.y + rhs.y,
51 }
52 }
53}
54
55impl std::ops::Add for &Coordinate {
56 type Output = Coordinate;
57
58 fn add(self, rhs: &Coordinate) -> Coordinate {
59 Coordinate {
60 x: self.x + rhs.x,
61 y: self.y + rhs.y,
62 }
63 }
64}
65
66impl std::ops::Sub for Coordinate {
67 type Output = Coordinate;
68
69 fn sub(self, rhs: Coordinate) -> Coordinate {
70 Coordinate {
71 x: self.x - rhs.x,
72 y: self.y - rhs.y,
73 }
74 }
75}
76
77impl std::ops::Sub<&Coordinate> for Coordinate {
78 type Output = Coordinate;
79
80 fn sub(self, rhs: &Coordinate) -> Coordinate {
81 Coordinate {
82 x: self.x - rhs.x,
83 y: self.y - rhs.y,
84 }
85 }
86}
87
88impl std::ops::Sub<Coordinate> for &Coordinate {
89 type Output = Coordinate;
90
91 fn sub(self, rhs: Coordinate) -> Coordinate {
92 Coordinate {
93 x: self.x - rhs.x,
94 y: self.y - rhs.y,
95 }
96 }
97}
98
99impl std::ops::Sub for &Coordinate {
100 type Output = Coordinate;
101
102 fn sub(self, rhs: &Coordinate) -> Coordinate {
103 Coordinate {
104 x: self.x - rhs.x,
105 y: self.y - rhs.y,
106 }
107 }
108}
109
110impl From<(i64, i64)> for Coordinate {
111 fn from(value: (i64, i64)) -> Self {
112 Coordinate {
113 x: value.0,
114 y: value.1,
115 }
116 }
117}
118
119impl Coordinate {
120 pub fn apply_transform(&self, transform: &Mat3) -> Coordinate {
121 let vector = nalgebra::Vector3::new(self.x, self.y, 1);
122 let result = transform.0 * vector;
123 Coordinate {
124 x: result[0],
125 y: result[1],
126 }
127 }
128
129 pub fn with_x(&self, x: i64) -> Coordinate {
130 Coordinate { x, y: self.y }
131 }
132
133 pub fn with_y(&self, y: i64) -> Coordinate {
134 Coordinate { x: self.x, y }
135 }
136
137 pub fn to_transform(&self) -> Mat3 {
138 Mat3::translate(self.x, self.y)
139 }
140}
141
142#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
144pub struct Range {
145 pub min: Option<i64>,
146 pub max: Option<i64>,
147}
148
149impl Range {
150 pub fn new(a: i64, b: i64) -> Self {
153 if a <= b {
154 Range {
155 min: Some(a),
156 max: Some(b),
157 }
158 } else {
159 Range {
160 min: Some(b),
161 max: Some(a),
162 }
163 }
164 }
165
166 pub fn from_min(min: i64) -> Self {
168 Range {
169 min: Some(min),
170 max: None,
171 }
172 }
173
174 pub fn from_max(max: i64) -> Self {
176 Range {
177 min: None,
178 max: Some(max),
179 }
180 }
181
182 pub fn any() -> Self {
184 Range {
185 min: None,
186 max: None,
187 }
188 }
189
190 pub fn contains(&self, value: i64) -> bool {
193 self.min.is_none_or(|min| value >= min) && self.max.is_none_or(|max| value <= max)
194 }
195
196 pub fn is_subset_of(&self, other: &Range) -> bool {
199 self.min
200 .is_none_or(|self_min| other.min.is_none_or(|other_min| self_min >= other_min))
201 && self
202 .max
203 .is_none_or(|self_max| other.max.is_none_or(|other_max| self_max <= other_max))
204 }
205
206 pub fn intersection(&self, other: &Range) -> Option<Range> {
208 let min = match (self.min, other.min) {
209 (Some(a), Some(b)) => Some(a.max(b)),
210 (Some(a), None) => Some(a),
211 (None, Some(b)) => Some(b),
212 (None, None) => None,
213 };
214 let max = match (self.max, other.max) {
215 (Some(a), Some(b)) => Some(a.min(b)),
216 (Some(a), None) => Some(a),
217 (None, Some(b)) => Some(b),
218 (None, None) => None,
219 };
220 match (min, max) {
221 (Some(min_val), Some(max_val)) if min_val > max_val => None,
222 _ => Some(Range { min, max }),
223 }
224 }
225}
226
227impl std::fmt::Display for Range {
228 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
229 match (self.min, self.max) {
230 (Some(min), Some(max)) => write!(f, "[{min}, {max}]"),
231 (Some(min), None) => write!(f, "[{min}, ...]"),
232 (None, Some(max)) => write!(f, "[..., {max}]"),
233 (None, None) => write!(f, "[...]"),
234 }
235 }
236}
237
238pub struct Edge {
240 pub a: Coordinate,
241 pub b: Coordinate,
242}
243
244#[derive(Clone, Copy, Debug, PartialEq, Eq)]
246pub enum EdgeOrientation {
247 North,
248 South,
249 East,
250 West,
251}
252
253impl Edge {
254 pub fn orientation(&self) -> Option<EdgeOrientation> {
257 if self.a.y == self.b.y {
258 if self.a.x < self.b.x {
259 Some(EdgeOrientation::East)
260 } else {
261 Some(EdgeOrientation::West)
262 }
263 } else if self.a.x == self.b.x {
264 if self.a.y < self.b.y {
265 Some(EdgeOrientation::North)
266 } else {
267 Some(EdgeOrientation::South)
268 }
269 } else {
270 None
271 }
272 }
273
274 pub fn get_x_range(&self) -> Range {
276 Range::new(self.a.x, self.b.x)
277 }
278
279 pub fn get_y_range(&self) -> Range {
281 Range::new(self.a.y, self.b.y)
282 }
283
284 pub fn get_coord_range(&self) -> Option<Range> {
286 let edge_orientation = self.orientation()?;
287 match edge_orientation {
288 EdgeOrientation::North | EdgeOrientation::South => Some(self.get_y_range()),
289 EdgeOrientation::East | EdgeOrientation::West => Some(self.get_x_range()),
290 }
291 }
292
293 pub fn distance_to_coordinate(&self, point: &Coordinate) -> Option<i64> {
296 match self.orientation()? {
297 EdgeOrientation::North | EdgeOrientation::South => {
298 if self.get_y_range().contains(point.y) {
299 Some(i64::abs_diff(point.x, self.a.x) as i64)
300 } else {
301 None
302 }
303 }
304 EdgeOrientation::East | EdgeOrientation::West => {
305 if self.get_x_range().contains(point.x) {
306 Some(i64::abs_diff(point.y, self.a.y) as i64)
307 } else {
308 None
309 }
310 }
311 }
312 }
313
314 pub fn get_index_range(&self, track: &TrackDefinition) -> Option<Range> {
317 let edge_orientation = self.orientation()?;
318
319 let coord_range = match (&track.orientation, edge_orientation) {
320 (TrackOrientation::Horizontal, EdgeOrientation::North | EdgeOrientation::South) => {
321 self.get_y_range()
322 }
323 (TrackOrientation::Vertical, EdgeOrientation::East | EdgeOrientation::West) => {
324 self.get_x_range()
325 }
326 _ => return None,
327 };
328
329 let track_range = track.convert_coord_range_to_index_range(&coord_range);
330
331 let round_trip_coord_range: Range = track.convert_index_range_to_coord_range(&track_range);
334 assert!(round_trip_coord_range.is_subset_of(&coord_range));
335
336 Some(track_range)
337 }
338
339 pub fn get_position_on_edge(&self, track: &TrackDefinition, track_index_on_edge: usize) -> i64 {
342 let start_stop = self.get_index_range(track).unwrap();
343 let start_index = start_stop.min.unwrap();
344 track.index_to_position(start_index + (track_index_on_edge as i64))
345 }
346
347 pub fn get_coordinate_on_edge(
350 &self,
351 track: &TrackDefinition,
352 track_index_on_edge: usize,
353 ) -> Coordinate {
354 let position = self.get_position_on_edge(track, track_index_on_edge);
355 match track.orientation {
356 TrackOrientation::Horizontal => Coordinate {
357 x: self.a.x,
358 y: position,
359 },
360 TrackOrientation::Vertical => Coordinate {
361 x: position,
362 y: self.a.y,
363 },
364 }
365 }
366
367 pub fn to_pin_transform(&self) -> Mat3 {
371 match self.orientation() {
372 Some(EdgeOrientation::North) => Mat3::from_orientation(Orientation::R270),
373 Some(EdgeOrientation::South) => Mat3::from_orientation(Orientation::R90),
374 Some(EdgeOrientation::East) => Mat3::from_orientation(Orientation::R180),
375 Some(EdgeOrientation::West) => Mat3::from_orientation(Orientation::R0),
376 None => panic!("Edge is not axis-aligned; only rectilinear edges are supported"),
377 }
378 }
379}
380
381#[derive(Debug, Clone, Copy, PartialEq, Eq)]
382pub enum Orientation {
383 R0,
384 R90,
385 R180,
386 R270,
387 MX,
388 MY,
389 MX90,
390 MY90,
391}
392
393impl Orientation {
394 pub fn prepend_transform(&self, transform: &Orientation) -> Self {
395 (&Mat3::from_orientation(*transform) * &Mat3::from_orientation(*self)).as_orientation()
396 }
397
398 pub fn append_transform(&self, transform: &Orientation) -> Self {
399 (&Mat3::from_orientation(*self) * &Mat3::from_orientation(*transform)).as_orientation()
400 }
401}
402
403#[derive(Debug, Clone)]
404pub struct Polygon(pub Vec<Coordinate>);
405pub struct BoundingBox {
406 pub min_x: i64,
407 pub max_x: i64,
408 pub min_y: i64,
409 pub max_y: i64,
410}
411
412impl BoundingBox {
413 pub fn get_width(&self) -> i64 {
414 self.max_x - self.min_x
415 }
416
417 pub fn get_height(&self) -> i64 {
418 self.max_y - self.min_y
419 }
420
421 pub fn get_width_height(&self) -> (i64, i64) {
422 (self.get_width(), self.get_height())
423 }
424
425 pub fn center(&self) -> Coordinate {
426 Coordinate {
427 x: (self.min_x + self.max_x) / 2,
428 y: (self.min_y + self.max_y) / 2,
429 }
430 }
431
432 pub fn union(&self, other: &BoundingBox) -> BoundingBox {
433 BoundingBox {
434 min_x: self.min_x.min(other.min_x),
435 max_x: self.max_x.max(other.max_x),
436 min_y: self.min_y.min(other.min_y),
437 max_y: self.max_y.max(other.max_y),
438 }
439 }
440
441 pub fn intersects(&self, other: &BoundingBox) -> bool {
442 (self.min_x < other.max_x)
444 && (self.max_x > other.min_x)
445 && (self.min_y < other.max_y)
446 && (self.max_y > other.min_y)
447 }
448
449 pub fn covers(&self, other: &BoundingBox) -> bool {
450 (self.min_x <= other.min_x)
453 && (self.max_x >= other.max_x)
454 && (self.min_y <= other.min_y)
455 && (self.max_y >= other.max_y)
456 }
457
458 pub fn apply_transform(&self, m: &Mat3) -> BoundingBox {
459 Polygon::from_bbox(self).apply_transform(m).bbox()
460 }
461
462 pub fn x_distance(&self, other: &BoundingBox) -> i64 {
463 if self.max_x < other.min_x {
464 other.min_x - self.max_x
465 } else if other.max_x < self.min_x {
466 self.min_x - other.max_x
467 } else {
468 0
469 }
470 }
471
472 pub fn y_distance(&self, other: &BoundingBox) -> i64 {
473 if self.max_y < other.min_y {
474 other.min_y - self.max_y
475 } else if other.max_y < self.min_y {
476 self.min_y - other.max_y
477 } else {
478 0
479 }
480 }
481
482 pub fn gap(&self, other: &BoundingBox) -> i64 {
483 self.x_distance(other) + self.y_distance(other)
484 }
485}
486
487impl Polygon {
488 pub fn new(points: Vec<Coordinate>) -> Self {
489 Polygon(points)
490 }
491 pub fn get_edge(&self, i: usize) -> Edge {
493 assert!(i < self.0.len(), "Edge index out of bounds");
494 let a = self.0[i];
495 let b = self.0[(i + 1) % self.0.len()];
496 Edge { a, b }
497 }
498
499 pub fn closest_edge_index(&self, point: &Coordinate) -> Option<usize> {
500 self.closest_edge_index_where(point, |_| true)
501 }
502
503 pub fn closest_edge_index_where<F>(&self, point: &Coordinate, mut predicate: F) -> Option<usize>
504 where
505 F: FnMut(&Edge) -> bool,
506 {
507 let mut best: Option<(usize, i64)> = None;
508 for idx in 0..self.num_edges() {
509 let edge = self.get_edge(idx);
510 if !predicate(&edge) {
511 continue;
512 }
513 if let Some(distance) = edge.distance_to_coordinate(point) {
514 match &mut best {
515 Some((_, best_distance)) if distance >= *best_distance => {}
516 _ => best = Some((idx, distance)),
517 }
518 }
519 }
520 best.map(|(idx, _)| idx)
521 }
522
523 pub fn from_width_height(width: i64, height: i64) -> Self {
524 Self::from_bbox(&BoundingBox {
525 min_x: 0,
526 min_y: 0,
527 max_x: width,
528 max_y: height,
529 })
530 }
531
532 pub fn from_bbox(bbox: &BoundingBox) -> Self {
533 Self::new(vec![
534 Coordinate {
535 x: bbox.min_x,
536 y: bbox.min_y,
537 },
538 Coordinate {
539 x: bbox.min_x,
540 y: bbox.max_y,
541 },
542 Coordinate {
543 x: bbox.max_x,
544 y: bbox.max_y,
545 },
546 Coordinate {
547 x: bbox.max_x,
548 y: bbox.min_y,
549 },
550 ])
551 }
552
553 pub fn apply_transform(&self, m: &Mat3) -> Polygon {
554 let pts = self
555 .0
556 .iter()
557 .map(|p| {
558 let v = nalgebra::Vector3::new(p.x, p.y, 1);
559 let result = m.0 * v;
560 Coordinate {
561 x: result[0],
562 y: result[1],
563 }
564 })
565 .collect();
566 Polygon(pts)
567 }
568
569 pub fn bbox(&self) -> BoundingBox {
570 let mut min_x = i64::MAX;
571 let mut max_x = i64::MIN;
572 let mut min_y = i64::MAX;
573 let mut max_y = i64::MIN;
574 for p in &self.0 {
575 if p.x < min_x {
576 min_x = p.x;
577 }
578 if p.x > max_x {
579 max_x = p.x;
580 }
581 if p.y < min_y {
582 min_y = p.y;
583 }
584 if p.y > max_y {
585 max_y = p.y;
586 }
587 }
588 BoundingBox {
589 min_x,
590 max_x,
591 min_y,
592 max_y,
593 }
594 }
595
596 pub fn is_rectangular(&self) -> bool {
598 let points = &self.0;
599 points.len() == 4 && self.is_rectilinear()
600 }
601
602 pub fn is_rectilinear(&self) -> bool {
604 let points = &self.0;
605 for i in 0..points.len() {
606 let a = points[i];
607 let b = points[(i + 1) % points.len()];
608 if !(a.x == b.x || a.y == b.y) {
609 return false;
610 }
611 if a.x == b.x && a.y == b.y {
612 return false;
613 }
614 }
615 true
616 }
617
618 pub fn is_clockwise(&self) -> bool {
621 let points = &self.0;
622
623 assert!(points.len() >= 3, "need at least 3 vertices");
624
625 let mut twice_area: i128 = 0; for (idx, point) in points.iter().enumerate() {
627 let point_next = points[(idx + 1) % points.len()];
628 let (x, y) = (point.x as i128, point.y as i128);
629 let (x_next, y_next) = (point_next.x as i128, point_next.y as i128);
630 twice_area += (x * y_next) - (x_next * y);
631 }
632
633 twice_area < 0
634 }
635
636 pub fn starts_with_leftmost_vertical_edge(&self) -> bool {
640 let points = &self.0;
641
642 assert!(
643 points.len() >= 2,
644 "need at least 2 vertices to determine if a polygon starts with the leftmost vertical edge"
645 );
646
647 if points[0].x != points[1].x {
648 return false;
650 }
651
652 let first_x = points[0].x;
653 let first_y = points[0].y.min(points[1].y);
654
655 for idx in 1..points.len() {
656 let point = points[idx];
657 let point_next = points[(idx + 1) % points.len()];
658 if point.x != point_next.x {
659 continue;
661 } else if point.x > first_x {
662 continue;
664 } else if point.x < first_x {
665 return false;
667 } else if point.y.min(point_next.y) < first_y {
668 return false;
670 }
671 }
672
673 true
674 }
675
676 pub fn num_vertices(&self) -> usize {
677 self.0.len()
678 }
679
680 pub fn num_edges(&self) -> usize {
681 self.0.len()
682 }
683
684 pub fn edge_index_for_coordinate(&self, coordinate: &Coordinate) -> Option<usize> {
685 for idx in 0..self.num_edges() {
686 let edge = self.get_edge(idx);
687 match edge.orientation() {
688 Some(EdgeOrientation::North | EdgeOrientation::South) => {
689 if edge.get_y_range().contains(coordinate.y) && coordinate.x == edge.a.x {
690 return Some(idx);
691 }
692 }
693 Some(EdgeOrientation::East | EdgeOrientation::West) => {
694 if edge.get_x_range().contains(coordinate.x) && coordinate.y == edge.a.y {
695 return Some(idx);
696 }
697 }
698 None => continue,
699 }
700 }
701 None
702 }
703
704 pub fn find_opposite_edge(&self, coordinate: &Coordinate) -> Result<usize, String> {
705 let src_edge_idx = self.edge_index_for_coordinate(coordinate).unwrap();
706 let src_edge = self.get_edge(src_edge_idx);
707
708 let src_is_horiz = match src_edge.orientation() {
709 Some(EdgeOrientation::North | EdgeOrientation::South) => false,
710 Some(EdgeOrientation::East | EdgeOrientation::West) => true,
711 None => {
712 return Err(
713 "Edge is not axis-aligned; only rectilinear edges are supported".to_string(),
714 );
715 }
716 };
717
718 for dst_edge_idx in 0..self.num_edges() {
719 if dst_edge_idx == src_edge_idx {
720 continue;
721 }
722
723 let dst_edge = self.get_edge(dst_edge_idx);
724 let dst_is_horiz = match dst_edge.orientation() {
725 Some(EdgeOrientation::North | EdgeOrientation::South) => false,
726 Some(EdgeOrientation::East | EdgeOrientation::West) => true,
727 None => continue,
728 };
729
730 if (src_is_horiz && dst_is_horiz && dst_edge.get_x_range().contains(coordinate.x))
731 || (!src_is_horiz)
732 && (!dst_is_horiz)
733 && dst_edge.get_y_range().contains(coordinate.y)
734 {
735 return Ok(dst_edge_idx);
736 } else {
737 continue;
738 }
739 }
740 Err("Unable to locate a unique opposite edge".to_string())
741 }
742
743 pub fn centroid(&self) -> Coordinate {
745 let mut centroid = Coordinate { x: 0, y: 0 };
746 for p in &self.0 {
747 centroid.x += p.x;
748 centroid.y += p.y;
749 }
750 centroid.x /= self.0.len() as i64;
751 centroid.y /= self.0.len() as i64;
752 centroid
753 }
754
755 pub fn to_def_die_area(&self) -> DefDieArea {
756 DefDieArea {
757 points: self.0.iter().map(|p| DefPoint { x: p.x, y: p.y }).collect(),
758 }
759 }
760
761 pub fn to_geo_polygon(&self) -> geo::Polygon<i64> {
762 geo::Polygon::new(
763 geo::LineString::from(
764 self.0
765 .iter()
766 .map(|p| geo::Point::new(p.x, p.y))
767 .collect::<Vec<_>>(),
768 ),
769 vec![],
770 )
771 }
772
773 pub fn to_geo_polygon_f64(&self) -> geo::Polygon<f64> {
774 geo::Polygon::new(
775 geo::LineString::from(
776 self.0
777 .iter()
778 .map(|p| {
779 if (p.x as f64) as i64 != p.x || (p.y as f64) as i64 != p.y {
781 panic!(
782 "Coordinate values cannot be represented exactly as f64: ({}, {})",
783 p.x, p.y
784 );
785 }
786 geo::Point::new(p.x as f64, p.y as f64)
787 })
788 .collect::<Vec<_>>(),
789 ),
790 vec![],
791 )
792 }
793}
794
795impl std::ops::Add<Coordinate> for Polygon {
796 type Output = Polygon;
797
798 fn add(self, rhs: Coordinate) -> Polygon {
799 Polygon(
800 self.0
801 .into_iter()
802 .map(|point| point + rhs)
803 .collect::<Vec<_>>(),
804 )
805 }
806}
807
808impl std::ops::Add<Coordinate> for &Polygon {
809 type Output = Polygon;
810
811 fn add(self, rhs: Coordinate) -> Polygon {
812 Polygon(self.0.iter().map(|point| point + rhs).collect::<Vec<_>>())
813 }
814}
815
816impl std::ops::Sub<Coordinate> for Polygon {
817 type Output = Polygon;
818
819 fn sub(self, rhs: Coordinate) -> Polygon {
820 Polygon(
821 self.0
822 .into_iter()
823 .map(|point| point - rhs)
824 .collect::<Vec<_>>(),
825 )
826 }
827}
828
829impl std::ops::Sub<Coordinate> for &Polygon {
830 type Output = Polygon;
831
832 fn sub(self, rhs: Coordinate) -> Polygon {
833 Polygon(self.0.iter().map(|point| point - rhs).collect::<Vec<_>>())
834 }
835}
836
837impl PartialEq for Polygon {
838 fn eq(&self, other: &Self) -> bool {
839 let a = &self.0;
840 let b = &other.0;
841 if a.len() != b.len() {
842 return false;
843 }
844 if a.is_empty() {
845 return true;
846 }
847 for start in 0..b.len() {
849 let mut all_match = true;
850 for (i, a_i) in a.iter().enumerate() {
851 let j = (start + i) % b.len();
852 if a_i != &b[j] {
853 all_match = false;
854 break;
855 }
856 }
857 if all_match {
858 return true;
859 }
860 }
861 false
862 }
863}
864
865impl Eq for Polygon {}
866
867#[derive(Debug, Clone, Copy)]
868pub struct Placement {
869 pub coordinate: Coordinate,
870 pub orientation: Orientation,
871}
872
873impl Default for Placement {
874 fn default() -> Self {
875 Placement {
876 coordinate: Coordinate { x: 0, y: 0 },
877 orientation: Orientation::R0,
878 }
879 }
880}
881
882impl Placement {
883 pub fn transform(&self) -> Mat3 {
884 Mat3::from_orientation_then_translation(&self.orientation, &self.coordinate)
885 }
886}
887
888#[derive(Debug, Clone, Copy, PartialEq, Eq)]
889#[repr(transparent)]
890pub struct Mat3(pub nalgebra::Matrix3<i64>);
891
892impl Mat3 {
893 pub fn identity() -> Mat3 {
894 Mat3(nalgebra::Matrix3::identity())
895 }
896
897 pub fn translate(dx: i64, dy: i64) -> Mat3 {
898 Mat3(nalgebra::Matrix3::new(1, 0, dx, 0, 1, dy, 0, 0, 1))
899 }
900
901 pub fn from_orientation(o: Orientation) -> Mat3 {
902 const ROTATE_90: Mat3 = Mat3(nalgebra::Matrix3::new(0, -1, 0, 1, 0, 0, 0, 0, 1));
903 const MIRROR_X: Mat3 = Mat3(nalgebra::Matrix3::new(1, 0, 0, 0, -1, 0, 0, 0, 1));
904 const MIRROR_Y: Mat3 = Mat3(nalgebra::Matrix3::new(-1, 0, 0, 0, 1, 0, 0, 0, 1));
905
906 match o {
907 Orientation::R0 => Self::identity(),
908 Orientation::R90 => ROTATE_90,
909 Orientation::R180 => &ROTATE_90 * &ROTATE_90,
910 Orientation::R270 => &(&ROTATE_90 * &ROTATE_90) * &ROTATE_90,
911 Orientation::MX => MIRROR_X,
912 Orientation::MY => MIRROR_Y,
913 Orientation::MX90 => &ROTATE_90 * &MIRROR_X,
914 Orientation::MY90 => &ROTATE_90 * &MIRROR_Y,
915 }
916 }
917
918 pub fn as_orientation(&self) -> Orientation {
919 for orientation in [
920 Orientation::R0,
921 Orientation::R90,
922 Orientation::R180,
923 Orientation::R270,
924 Orientation::MX,
925 Orientation::MY,
926 Orientation::MX90,
927 Orientation::MY90,
928 ] {
929 let ref_mat = Self::from_orientation(orientation);
930 if self.0.fixed_view::<2, 2>(0, 0) == ref_mat.0.fixed_view::<2, 2>(0, 0) {
931 return orientation;
932 }
933 }
934 panic!("Unsupported orientation: {self:?}");
935 }
936
937 pub fn as_coordinate(&self) -> Coordinate {
938 Coordinate {
939 x: self.0[(0, 2)],
940 y: self.0[(1, 2)],
941 }
942 }
943
944 pub fn from_orientation_then_translation(
945 orientation: &Orientation,
946 translation: &Coordinate,
947 ) -> Mat3 {
948 let orientation_transform = Mat3::from_orientation(*orientation);
949 let translation_transform = Mat3::translate(translation.x, translation.y);
950
951 &translation_transform * &orientation_transform
952 }
953
954 pub fn inverse(&self) -> Mat3 {
955 let m = &self.0;
956 assert!(
957 m[(2, 0)] == 0 && m[(2, 1)] == 0 && m[(2, 2)] == 1,
958 "Matrix is not a valid 2D homogeneous transformation (bottom row must be [0, 0, 1]), got [{}, {}, {}]",
959 m[(2, 0)],
960 m[(2, 1)],
961 m[(2, 2)]
962 );
963
964 let r = m.fixed_view::<2, 2>(0, 0).into_owned();
965 let det = r[(0, 0)] * r[(1, 1)] - r[(1, 0)] * r[(0, 1)];
966 assert!(
967 det == 1 || det == -1,
968 "Rotation part of the matrix must have determinant +1 or -1, got {}",
969 det
970 );
971
972 let t = m.fixed_view::<2, 1>(0, 2).into_owned();
973
974 let rt = r.transpose();
975
976 let minus_rt_t = -(rt * t);
977
978 let mut inv = nalgebra::Matrix3::<i64>::zeros();
979 inv.fixed_view_mut::<2, 2>(0, 0).copy_from(&rt);
980 inv.fixed_view_mut::<2, 1>(0, 2).copy_from(&minus_rt_t);
981 inv[(2, 2)] = 1;
982
983 Mat3(inv)
984 }
985}
986
987impl std::ops::Mul<&Mat3> for &Mat3 {
988 type Output = Mat3;
989 fn mul(self, rhs: &Mat3) -> Mat3 {
990 Mat3(self.0 * rhs.0)
991 }
992}
993
994#[derive(Debug, Clone)]
996pub struct PhysicalPin {
997 pub layer: String,
998 pub polygon: Polygon,
999 pub transform: Mat3,
1000}
1001
1002impl PhysicalPin {
1003 pub fn new(layer: impl AsRef<str>, polygon: Polygon) -> Self {
1004 Self::from_transform(layer, polygon, Mat3::identity())
1005 }
1006
1007 pub fn from_transform(layer: impl AsRef<str>, polygon: Polygon, transform: Mat3) -> Self {
1008 Self {
1009 layer: layer.as_ref().to_string(),
1010 polygon,
1011 transform,
1012 }
1013 }
1014
1015 pub fn with_transform(&self, transform: Mat3) -> Self {
1016 Self::from_transform(&self.layer, self.polygon.clone(), transform)
1017 }
1018
1019 pub fn from_orientation_then_translation(
1020 layer: impl AsRef<str>,
1021 polygon: Polygon,
1022 orientation: Orientation,
1023 translation: Coordinate,
1024 ) -> Self {
1025 let transform = Mat3::from_orientation_then_translation(&orientation, &translation);
1026 Self::from_transform(layer, polygon, transform)
1027 }
1028
1029 pub fn with_orientation_then_translation(
1030 &self,
1031 orientation: Orientation,
1032 translation: Coordinate,
1033 ) -> Self {
1034 Self::from_orientation_then_translation(
1035 &self.layer,
1036 self.polygon.clone(),
1037 orientation,
1038 translation,
1039 )
1040 }
1041
1042 pub fn from_translation(
1043 layer: impl AsRef<str>,
1044 polygon: Polygon,
1045 translation: Coordinate,
1046 ) -> Self {
1047 let transform = Mat3::translate(translation.x, translation.y);
1048 Self::from_transform(layer, polygon, transform)
1049 }
1050
1051 pub fn with_translation(&self, translation: Coordinate) -> Self {
1052 Self::from_translation(&self.layer, self.polygon.clone(), translation)
1053 }
1054
1055 pub fn transformed_polygon(&self) -> Polygon {
1056 self.polygon.apply_transform(&self.transform)
1057 }
1058
1059 pub fn translation(&self) -> Coordinate {
1060 self.transform.as_coordinate()
1061 }
1062}
1063
1064impl std::ops::Add<Coordinate> for PhysicalPin {
1065 type Output = PhysicalPin;
1066
1067 fn add(self, rhs: Coordinate) -> PhysicalPin {
1068 PhysicalPin {
1069 layer: self.layer,
1070 transform: {
1071 let mut transform = self.transform;
1072 transform.0[(0, 2)] += rhs.x;
1073 transform.0[(1, 2)] += rhs.y;
1074 transform
1075 },
1076 polygon: self.polygon,
1077 }
1078 }
1079}
1080
1081impl std::ops::Add<Coordinate> for &PhysicalPin {
1082 type Output = PhysicalPin;
1083
1084 fn add(self, rhs: Coordinate) -> PhysicalPin {
1085 PhysicalPin {
1086 layer: self.layer.clone(),
1087 transform: {
1088 let mut transform = self.transform;
1089 transform.0[(0, 2)] += rhs.x;
1090 transform.0[(1, 2)] += rhs.y;
1091 transform
1092 },
1093 polygon: self.polygon.clone(),
1094 }
1095 }
1096}