gdsconv/
export.rs

1use arcstr::ArcStr;
2use gds::{
3    GdsBoundary, GdsElement, GdsLibrary, GdsPoint, GdsStrans, GdsStruct, GdsStructRef, GdsTextElem,
4    GdsUnits,
5};
6use geometry::{
7    corner::Corner,
8    point::Point,
9    prelude::{Orientation, Polygon},
10    rect::Rect,
11};
12use layir::{Cell, Element, Instance, Library, Shape, Text};
13
14use crate::GdsLayer;
15
16pub struct GdsExportOpts {
17    /// Name of the GDS library.
18    pub name: ArcStr,
19    pub units: Option<GdsUnits>,
20}
21
22pub fn export_gds(lib: Library<GdsLayer>, opts: GdsExportOpts) -> GdsLibrary {
23    let exporter = GdsExporter { opts, lib: &lib };
24    exporter.export()
25}
26
27struct GdsExporter<'a> {
28    opts: GdsExportOpts,
29    lib: &'a Library<GdsLayer>,
30}
31
32impl GdsExporter<'_> {
33    fn export(mut self) -> GdsLibrary {
34        let mut gds = if let Some(units) = self.opts.units.clone() {
35            GdsLibrary::with_units(self.opts.name.clone(), units)
36        } else {
37            GdsLibrary::new(self.opts.name.clone())
38        };
39        for id in self.lib.topological_order() {
40            let cell = self.lib.cell(id);
41            let strukt = self.export_cell(cell);
42            gds.structs.push(strukt);
43        }
44        gds
45    }
46
47    fn export_cell(&mut self, cell: &Cell<GdsLayer>) -> GdsStruct {
48        let mut gcell = GdsStruct::new(cell.name().clone());
49        for (_, port) in cell.ports() {
50            for elt in port.elements() {
51                gcell.elems.push(export_element(elt));
52            }
53        }
54        for elt in cell.elements() {
55            gcell.elems.push(export_element(elt));
56        }
57        for (_, inst) in cell.instances() {
58            gcell.elems.push(export_instance(self.lib, inst));
59        }
60        gcell
61    }
62}
63
64fn export_instance(lib: &Library<GdsLayer>, inst: &Instance) -> GdsElement {
65    let cell = lib.cell(inst.child());
66    GdsStructRef {
67        name: cell.name().clone(),
68        xy: export_point(inst.transformation().offset_point()),
69        strans: Some(export_orientation(inst.transformation().orientation())),
70        ..Default::default()
71    }
72    .into()
73}
74
75fn export_element(elt: &Element<GdsLayer>) -> GdsElement {
76    match elt {
77        Element::Shape(shape) => export_shape(shape),
78        Element::Text(text) => export_text(text),
79    }
80}
81
82fn export_shape(shape: &Shape<GdsLayer>) -> GdsElement {
83    match shape.shape() {
84        geometry::shape::Shape::Rect(rect) => GdsBoundary {
85            layer: shape.layer().0 as i16,
86            datatype: shape.layer().1 as i16,
87            xy: export_rect(rect),
88            ..Default::default()
89        }
90        .into(),
91        geometry::shape::Shape::Polygon(poly) => GdsBoundary {
92            layer: shape.layer().0 as i16,
93            datatype: shape.layer().1 as i16,
94            xy: export_polygon(poly),
95            ..Default::default()
96        }
97        .into(),
98    }
99}
100
101fn export_point(p: Point) -> GdsPoint {
102    let x = p.x.try_into().unwrap();
103    let y = p.y.try_into().unwrap();
104    GdsPoint::new(x, y)
105}
106
107fn export_polygon(poly: &Polygon) -> Vec<GdsPoint> {
108    let mut points: Vec<gds::GdsPoint> = poly
109        .points()
110        .iter()
111        .copied()
112        .map(export_point)
113        .collect::<Vec<_>>();
114    let point0 = export_point(poly.points()[0]);
115
116    points.push(point0);
117    points
118}
119
120fn export_rect(rect: &Rect) -> Vec<GdsPoint> {
121    let bl = export_point(rect.corner(Corner::LowerLeft));
122    let br = export_point(rect.corner(Corner::LowerRight));
123    let ur = export_point(rect.corner(Corner::UpperRight));
124    let ul = export_point(rect.corner(Corner::UpperLeft));
125    vec![bl.clone(), br, ur, ul, bl]
126}
127
128fn export_text(text: &Text<GdsLayer>) -> GdsElement {
129    GdsTextElem {
130        string: text.text().clone(),
131        layer: text.layer().0 as i16,
132        texttype: text.layer().1 as i16,
133        xy: export_point(text.transformation().offset_point()),
134        strans: Some(export_orientation(text.transformation().orientation())),
135        ..Default::default()
136    }
137    .into()
138}
139
140fn export_orientation(orientation: Orientation) -> GdsStrans {
141    GdsStrans {
142        reflected: orientation.reflect_vert(),
143        angle: Some(orientation.angle().degrees()),
144        ..Default::default()
145    }
146}