Skip to main content

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}