1use crate::{
16 Bbox, CellBuilder, CellId, CellName, Instance, LayerIndex, Library, Polygon, Rect, Repetition,
17 Shape, Trans, Vec2,
18};
19use std::collections::HashMap;
20
21pub fn flatten(
25 lib: &Library,
26 cell: CellId,
27 max_depth: usize,
28 new_name: impl Into<CellName>,
29) -> CellBuilder {
30 let mut out = CellBuilder::new(new_name);
31 walk(lib, cell, Trans::IDENTITY, max_depth, &mut out);
32 out
33}
34
35fn walk(
36 lib: &Library,
37 cell: CellId,
38 trans: Trans,
39 depth_remaining: usize,
40 out: &mut CellBuilder,
41) {
42 let c = lib.get(cell);
43 for layer in c.layers() {
45 for shape in c.shapes_on(layer) {
46 let s = shape.transform(trans);
47 out.add_shape(layer, s);
48 }
49 }
50 if depth_remaining == 0 {
51 for inst in c.instances() {
53 let mut new_inst = inst.clone();
54 new_inst.trans = trans.compose(inst.trans);
55 out.add_instance(new_inst);
56 }
57 return;
58 }
59 for inst in c.instances() {
60 for placement in expand_repetition(inst) {
61 let composed = trans.compose(placement);
62 walk(lib, inst.cell, composed, depth_remaining - 1, out);
63 }
64 }
65}
66
67fn expand_repetition(inst: &Instance) -> Vec<Trans> {
68 match &inst.repetition {
69 None => vec![inst.trans],
70 Some(Repetition::Regular {
71 col,
72 row,
73 n_cols,
74 n_rows,
75 }) => {
76 let mut out = Vec::with_capacity((*n_cols as usize) * (*n_rows as usize));
77 for j in 0..*n_rows {
78 for i in 0..*n_cols {
79 let extra = Trans::translate(Vec2::new(
80 col.x * i as i64 + row.x * j as i64,
81 col.y * i as i64 + row.y * j as i64,
82 ));
83 out.push(extra.compose(inst.trans));
84 }
85 }
86 out
87 }
88 Some(Repetition::Irregular { offsets }) => {
89 let mut out = Vec::with_capacity(offsets.len() + 1);
90 out.push(inst.trans);
91 for o in offsets {
92 let extra = Trans::translate(*o);
93 out.push(extra.compose(inst.trans));
94 }
95 out
96 }
97 }
98}
99
100#[derive(Default, Clone, Debug)]
103pub struct LayerMap {
104 inner: HashMap<LayerIndex, LayerIndex>,
105}
106
107impl LayerMap {
108 pub fn new() -> Self {
109 Self::default()
110 }
111
112 pub fn map(mut self, from: LayerIndex, to: LayerIndex) -> Self {
113 self.inner.insert(from, to);
114 self
115 }
116
117 pub fn translate(&self, layer: LayerIndex) -> LayerIndex {
118 self.inner.get(&layer).copied().unwrap_or(layer)
119 }
120
121 pub fn is_empty(&self) -> bool {
122 self.inner.is_empty()
123 }
124}
125
126pub fn remap_layers(lib: &Library, cell: CellId, map: &LayerMap) -> CellBuilder {
130 let c = lib.get(cell);
131 let mut out = CellBuilder::new(c.name().clone());
132 for layer in c.layers() {
133 let dst = map.translate(layer);
134 for shape in c.shapes_on(layer) {
135 out.add_shape(dst, shape.clone());
136 }
137 }
138 for inst in c.instances() {
139 out.add_instance(inst.clone());
140 }
141 out
142}
143
144pub fn clip_cell(
151 lib: &Library,
152 cell: CellId,
153 bbox: Bbox,
154 new_name: impl Into<CellName>,
155) -> CellBuilder {
156 let c = lib.get(cell);
157 let mut out = CellBuilder::new(new_name);
158 if bbox.is_empty() {
159 return out;
160 }
161 for layer in c.layers() {
162 for shape in c.shapes_on(layer) {
163 let sbb = shape.bbox();
164 if !sbb.intersects(&bbox) {
165 continue;
166 }
167 match shape {
168 Shape::Box(r) => {
169 let clipped = bbox_intersection(r.bbox, bbox);
170 if !clipped.is_empty() {
171 out.add_shape(layer, Rect::new(clipped));
172 }
173 }
174 Shape::Polygon(p) => {
175 out.add_shape(layer, p.clone());
178 }
179 Shape::Path(p) => out.add_shape(layer, p.clone()),
180 Shape::Text(t) => {
181 if bbox.contains(t.anchor) {
182 out.add_shape(layer, t.clone());
183 }
184 }
185 }
186 }
187 }
188 for inst in c.instances() {
189 let anchor = klayout_core_alias::Point::new(inst.trans.disp.x, inst.trans.disp.y);
193 if bbox.contains(anchor) {
194 out.add_instance(inst.clone());
195 }
196 }
197 out
198}
199
200mod klayout_core_alias {
201 pub use crate::Point;
202}
203
204fn bbox_intersection(a: Bbox, b: Bbox) -> Bbox {
205 if a.is_empty() || b.is_empty() {
206 return Bbox::EMPTY;
207 }
208 let min = klayout_core_alias::Point::new(a.min.x.max(b.min.x), a.min.y.max(b.min.y));
209 let max = klayout_core_alias::Point::new(a.max.x.min(b.max.x), a.max.y.min(b.max.y));
210 if min.x > max.x || min.y > max.y {
211 Bbox::EMPTY
212 } else {
213 Bbox::new(min, max)
214 }
215}
216
217pub fn local_bbox(lib: &Library, cell: CellId) -> Bbox {
220 lib.get(cell).local_bbox()
221}
222
223#[allow(dead_code)]
224fn _polygon_marker(_: &Polygon) {}
225
226pub fn replace_instances<F: Fn(CellId) -> bool>(
230 lib: &Library,
231 cell: CellId,
232 predicate: F,
233 replacement: CellId,
234) -> CellBuilder {
235 let c = lib.get(cell);
236 let mut out = CellBuilder::new(c.name().clone());
237 for layer in c.layers() {
238 for shape in c.shapes_on(layer) {
239 out.add_shape(layer, shape.clone());
240 }
241 }
242 for inst in c.instances() {
243 let mut new_inst = inst.clone();
244 if predicate(inst.cell) {
245 new_inst.cell = replacement;
246 }
247 out.add_instance(new_inst);
248 }
249 out
250}
251