reda_gds/models/primitive/transform.rs
1
2/// Contains two bytes of bit flags for Sref, Aref, and text transforrnation.
3/// - Bit 0 (the leftmost bit) specifies reflection.
4/// If bit 0 is set, the element is reflected about the X-axis before angular rotation.
5/// For an Aref, the entire array is reflected, with the individual array members rigidly attached.
6/// - Bit 13 flags absolute magnification.
7/// - Bit 14 flags absolute angle.
8/// - Bit 15 (the rightmost bit) and all remaining bits are reserved for future use and must be cleared.
9/// If this record is omitted, the element is assumed to have no reflection, non-absolute magnification, and non- absolute angle.
10#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
11pub struct GdsTransformFlag {
12 /// Reflect the element about the X-axis before rotation.
13 pub reflect: bool, // Bit 0 (leftmost bit)
14 /// Use absolute magnification.
15 pub absolute_magnification: bool, // Bit 13
16 /// Use absolute angle.
17 pub absolute_angle: bool, // Bit 14
18}
19
20impl GdsTransformFlag {
21 pub fn new(reflect: bool, absolute_magnification: bool, absolute_angle: bool) -> Self {
22 Self { reflect, absolute_angle, absolute_magnification }
23 }
24
25 /// Parse flags from a u16 bitfield.
26 pub fn from_u16(bits: u16) -> Self {
27 Self {
28 reflect: (bits & (1 << 15)) != 0, // Bit 0 (leftmost) == bit 15
29 absolute_magnification: (bits & (1 << 2)) != 0, // Bit 13 == bit 2 from MSB
30 absolute_angle: (bits & (1 << 1)) != 0, // Bit 14 == bit 1 from MSB
31 }
32 }
33
34 /// Convert the flags into a u16 bitfield.
35 pub fn to_u16(&self) -> u16 {
36 let mut bits = 0u16;
37 if self.reflect {
38 bits |= 1 << 15; // Bit 0 (leftmost)
39 }
40 if self.absolute_magnification {
41 bits |= 1 << 2; // Bit 13
42 }
43 if self.absolute_angle {
44 bits |= 1 << 1; // Bit 14
45 }
46 bits
47 }
48}
49
50#[derive(Debug, Clone, Copy, PartialEq)]
51pub struct GdsTransform {
52 /// STRANS record flags
53 pub flag: GdsTransformFlag,
54
55 /// MAG record
56 /// Eight-Byte Real Contains a double-precision real number (8 bytes), which is the magnification factor.
57 /// If this record is omitted, a magnification factor of one is assumed.
58 pub magnification: Option<f64>,
59
60 /// ANGLE record
61 /// Eight-Byte Real Contains a double-precision real number (8 bytes), which is the angular rotation factor.
62 pub angle: Option<f64>,
63}
64
65impl GdsTransform {
66 pub fn with_flag(bits: u16) -> Self {
67 Self {
68 flag: GdsTransformFlag::from_u16(bits),
69 magnification: None,
70 angle: None,
71 }
72 }
73
74 pub fn magnification(&self) -> f64 {
75 self.magnification.unwrap_or(1.0)
76 }
77
78 pub fn angle(&self) -> f64 {
79 self.angle.unwrap_or(0.0)
80 }
81}
82
83impl GdsTransform {
84 /// Identity transform: no reflection, no scaling, no rotation.
85 pub fn identity() -> Self {
86 Self {
87 flag: GdsTransformFlag::default(),
88 magnification: None,
89 angle: None,
90 }
91 }
92
93 /// Mirror across X-axis (GDSII reflect bit).
94 pub fn mirror_x() -> Self {
95 Self {
96 flag: GdsTransformFlag {
97 reflect: true,
98 absolute_magnification: false,
99 absolute_angle: false,
100 },
101 magnification: None,
102 angle: Some(0.0),
103 }
104 }
105
106 /// Mirror across Y-axis = mirror across X-axis + rotate 180° CCW.
107 pub fn mirror_y() -> Self {
108 Self {
109 flag: GdsTransformFlag {
110 reflect: true,
111 absolute_magnification: false,
112 absolute_angle: false,
113 },
114 magnification: None,
115 angle: Some(180.0),
116 }
117 }
118
119 /// Point inversion (mirror XY) = rotate 180° CCW.
120 pub fn mirror_xy() -> Self {
121 Self {
122 flag: GdsTransformFlag {
123 reflect: false,
124 absolute_magnification: false,
125 absolute_angle: false,
126 },
127 magnification: None,
128 angle: Some(180.0),
129 }
130 }
131
132 /// Set magnification (relative magnification unless absolute bit is set).
133 pub fn with_magnification(mut self, m: f64) -> Self {
134 assert!(m > 0.0, "magnification must be positive");
135 self.magnification = Some(m);
136 self
137 }
138
139 /// Set rotation angle in degrees (CCW, per GDSII spec).
140 pub fn with_rotation(mut self, angle_deg: f64) -> Self {
141 self.angle = Some(angle_deg);
142 self
143 }
144
145 /// Mark magnification as absolute.
146 pub fn absolute_magnification(mut self) -> Self {
147 self.flag.absolute_magnification = true;
148 self
149 }
150
151 /// Mark angle as absolute.
152 pub fn absolute_angle(mut self) -> Self {
153 self.flag.absolute_angle = true;
154 self
155 }
156}