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 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}