1#![allow(unused_variables)]
9
10use fnv::FnvHashMap;
11use num_traits::{PrimInt, Signed};
12use rstar::{RTree, RTreeObject};
13
14use crate::prelude::*;
15
16pub struct RegionSearchAdapter<T>
21where
22 T: LayoutBase,
23 T::Coord: PrimInt + Signed + std::fmt::Debug,
24{
25 chip: T,
27 shape_rtrees:
29 FnvHashMap<T::CellId, FnvHashMap<T::LayerId, RTree<ShapeEntry<T::ShapeId, T::Coord>>>>,
30 instance_rtree: FnvHashMap<T::CellId, RTree<CellInstanceEntry<T>>>,
32 cell_bounding_boxes: FnvHashMap<T::CellId, Rect<T::Coord>>,
34}
35
36#[derive(Debug, Clone, PartialEq)]
38pub struct ShapeEntry<ShapeId, Coord> {
39 bounding_box: Rect<Coord>,
40 shape_id: ShapeId,
41}
42
43#[derive(Debug, Clone, PartialEq)]
45pub struct CellInstanceEntry<L: LayoutBase> {
46 bounding_box: Rect<L::Coord>,
47 cell_inst_id: L::CellInstId,
48}
49
50impl<ShapeId, Coord> BoundingBox<Coord> for ShapeEntry<ShapeId, Coord>
52where
53 Coord: PrimInt,
54{
55 fn bounding_box(&self) -> Rect<Coord> {
56 self.bounding_box
57 }
58}
59
60impl<ShapeId, Coord> RTreeObject for ShapeEntry<ShapeId, Coord>
62where
63 Coord: PrimInt + Signed + std::fmt::Debug,
64{
65 type Envelope = rstar::AABB<[Coord; 2]>;
66
67 fn envelope(&self) -> Self::Envelope {
68 let bbox = self.bounding_box();
69
70 rstar::AABB::from_corners(bbox.lower_left().into(), bbox.upper_right().into())
71 }
72}
73
74impl<L> BoundingBox<L::Coord> for CellInstanceEntry<L>
76where
77 L: LayoutBase,
78 L::Coord: PrimInt,
79{
80 fn bounding_box(&self) -> Rect<L::Coord> {
81 self.bounding_box
82 }
83}
84
85impl<L> RTreeObject for CellInstanceEntry<L>
87where
88 L: LayoutBase,
89 L::Coord: PrimInt + Signed + std::fmt::Debug,
90{
91 type Envelope = rstar::AABB<[L::Coord; 2]>;
92
93 fn envelope(&self) -> Self::Envelope {
94 let bbox = self.bounding_box();
95
96 rstar::AABB::from_corners(bbox.lower_left().into(), bbox.upper_right().into())
97 }
98}
99
100impl<T> RegionSearchAdapter<T>
101where
102 T: LayoutBase,
103 T::Coord: PrimInt + Signed + std::fmt::Debug,
104{
105 pub fn new(chip: T) -> Self {
107 let mut region_search = Self {
108 chip,
109 shape_rtrees: Default::default(),
110 instance_rtree: Default::default(),
111 cell_bounding_boxes: Default::default(),
112 };
113
114 region_search.create_shape_trees();
115 region_search.create_cell_instance_trees();
116
117 region_search
118 }
119
120 fn create_shape_trees(&mut self) {
121 let mut cell_rtrees: FnvHashMap<_, _> = Default::default();
123 for cell in self.chip.each_cell_bottom_to_top() {
124 let mut rtrees: FnvHashMap<_, RTree<_>> = Default::default();
125
126 for layer in self.chip.each_layer() {
127 let mut all_shapes = vec![];
129 self.chip
130 .for_each_shape(&cell, &layer, |shape_id, geometry| {
131 if let Some(bounding_box) = geometry.try_bounding_box() {
132 let rtree_entry = ShapeEntry {
133 bounding_box,
134 shape_id: shape_id.clone(),
135 };
136 all_shapes.push(rtree_entry)
137 }
138 });
139
140 let rtree = RTree::bulk_load(all_shapes);
142
143 rtrees.insert(layer, rtree);
144 }
145 cell_rtrees.insert(cell, rtrees);
146 }
147
148 self.shape_rtrees = cell_rtrees;
149 }
150
151 fn create_cell_instance_trees(&mut self) {
152 for cell in self.chip.each_cell_bottom_to_top() {
153 let shape_bbox = self.compute_shape_bbox(&cell);
155
156 let instance_entries: Vec<_> = self
158 .chip
159 .each_cell_instance(&cell)
160 .filter_map(|inst| {
161 self.cell_bounding_boxes
162 .get(&self.chip.template_cell(&inst))
163 .map(|bbox| (inst, bbox))
164 })
165 .map(|(inst, bbox)| {
166 let tf = self.chip.get_transform(&inst);
167 let bbox_transformed = bbox.transform(|p| tf.transform_point(p));
168
169 CellInstanceEntry {
170 bounding_box: bbox_transformed,
171 cell_inst_id: inst,
172 }
173 })
174 .collect();
175
176 let rtree = RTree::bulk_load(instance_entries);
177
178 let cell_inst_bbox = if rtree.size() > 0 {
179 let envelope = rtree.root().envelope();
180 let bbox = Rect::new(envelope.lower(), envelope.upper());
181 Some(bbox)
182 } else {
183 None
184 };
185
186 let bbox = cell_inst_bbox
188 .into_iter()
189 .chain(shape_bbox)
190 .reduce(|acc, b| acc.add_rect(&b));
191
192 if let Some(bbox) = bbox {
193 self.cell_bounding_boxes.insert(cell.clone(), bbox);
194 }
195
196 self.instance_rtree.insert(cell, rtree);
197 }
198 }
199
200 fn compute_shape_bbox(&self, cell_id: &T::CellId) -> Option<Rect<T::Coord>> {
202 self.shape_rtrees
203 .get(cell_id)
204 .into_iter()
205 .flat_map(|layer_trees| layer_trees.values())
207 .map(|rtree| rtree.root().envelope())
209 .map(|envelope| Rect::new(envelope.lower(), envelope.upper()))
211 .reduce(|acc, b| acc.add_rect(&b))
213 }
214
215 #[allow(unused)]
217 fn compute_subcell_bboxes(&self, cell_id: &T::CellId) -> Option<Rect<T::Coord>> {
218 if let Some(instance_rtree) = self.instance_rtree.get(cell_id) {
219 if instance_rtree.size() > 0 {
220 let envelope = instance_rtree.root().envelope();
221 Some(Rect::new(envelope.lower(), envelope.upper()))
222 } else {
223 None
224 }
225 } else {
226 None
227 }
228 }
243}
244
245#[portrait::fill(portrait::delegate(H; self.chip))]
246impl<H> HierarchyIds for RegionSearchAdapter<H>
247where
248 H: LayoutBase,
249 H::Coord: PrimInt + Signed + std::fmt::Debug,
250{
251}
252
253#[portrait::fill(portrait::delegate(H; self.chip))]
255impl<H> HierarchyBase for RegionSearchAdapter<H>
256where
257 H: LayoutBase,
258 H::Coord: PrimInt + Signed + std::fmt::Debug,
259{
260 type NameType = H::NameType;
261}
262
263#[portrait::fill(portrait::delegate(L))]
264impl<L> LayoutIds for RegionSearchAdapter<L>
265where
266 L: LayoutBase,
267 L::Coord: PrimInt + Signed + std::fmt::Debug,
268{
269}
270#[portrait::fill(portrait::delegate(L; self.chip))]
273impl<L> LayoutBase for RegionSearchAdapter<L>
274where
275 L: LayoutBase,
276 L::Coord: PrimInt + Signed + std::fmt::Debug,
277{
278}
279
280impl<L> RegionSearch for RegionSearchAdapter<L>
281where
282 L: LayoutBase,
283 L::Coord: PrimInt + Signed + std::fmt::Debug,
284{
285 fn each_shape_in_region_per_layer(
286 &self,
287 cell: &Self::CellId,
288 layer_id: &Self::LayerId,
289 search_region: &Rect<Self::Coord>,
290 ) -> Box<dyn Iterator<Item = Self::ShapeId> + '_> {
291 let aabb = rect2aabb(search_region);
292
293 let intersecting_instances = self
294 .shape_rtrees
295 .get(cell)
296 .expect("cell not found")
297 .get(layer_id)
298 .into_iter()
299 .flat_map(move |rtree| rtree.locate_in_envelope_intersecting(&aabb))
300 .map(|shape_entry| shape_entry.shape_id.clone());
301
302 Box::new(intersecting_instances)
303 }
304
305 fn each_cell_instance_in_region(
306 &self,
307 cell: &Self::CellId,
308 search_region: &Rect<Self::Coord>,
309 ) -> Box<dyn Iterator<Item = Self::CellInstId> + '_> {
310 let intersecting_instances = self
311 .instance_rtree
312 .get(cell)
313 .expect("cell not found")
314 .locate_in_envelope_intersecting(&rect2aabb(search_region))
315 .map(|instance_entry| instance_entry.cell_inst_id.clone());
316
317 Box::new(intersecting_instances)
318 }
319}
320
321fn rect2aabb<Crd>(r: &Rect<Crd>) -> rstar::AABB<[Crd; 2]>
323where
324 Crd: PrimInt + Signed + std::fmt::Debug,
325{
326 rstar::AABB::from_corners(r.lower_left().into(), r.upper_right().into())
327}
328
329#[portrait::fill(portrait::delegate(N))]
330impl<N> NetlistIds for RegionSearchAdapter<N>
331where
332 N: NetlistIds + LayoutBase,
333 N::Coord: PrimInt + Signed + std::fmt::Debug,
334{
335}
336
337#[portrait::fill(portrait::delegate(N; self.chip))]
339impl<N> NetlistBase for RegionSearchAdapter<N>
340where
341 N: LayoutBase + NetlistBase,
342 N::Coord: PrimInt + Signed + std::fmt::Debug,
343{
344}
345
346#[portrait::fill(portrait::delegate(LN; self.chip))]
347impl<LN> L2NBase for RegionSearchAdapter<LN>
348where
349 LN: L2NBase,
350 LN::Coord: PrimInt + Signed + std::fmt::Debug,
351{
352}
353
354#[portrait::fill(portrait::delegate(H; self.chip))]
356impl<H> HierarchyEdit for RegionSearchAdapter<H>
357where
358 H: HierarchyEdit + LayoutBase,
359 H::Coord: PrimInt + Signed + std::fmt::Debug,
360{
361 fn create_cell(&mut self, name: H::NameType) -> H::CellId {
362 todo!()
363 }
364
365 fn remove_cell(&mut self, cell_id: &H::CellId) {
366 todo!()
367 }
368
369 fn create_cell_instance(
370 &mut self,
371 parent_cell: &H::CellId,
372 template_cell: &H::CellId,
373 name: Option<H::NameType>,
374 ) -> H::CellInstId {
375 todo!()
376 }
377
378 fn remove_cell_instance(&mut self, inst: &H::CellInstId) {
379 todo!()
380 }
381}
382
383#[portrait::fill(portrait::delegate(L; self.chip))]
385impl<L> LayoutEdit for RegionSearchAdapter<L>
386where
387 L: LayoutEdit,
388 L::Coord: PrimInt + Signed + std::fmt::Debug,
389{
390 fn insert_shape(
391 &mut self,
392 parent_cell: &L::CellId,
393 layer: &L::LayerId,
394 geometry: Geometry<L::Coord>,
395 ) -> L::ShapeId {
396 todo!("update RTree");
397 }
400
401 fn remove_shape(&mut self, shape_id: &L::ShapeId) -> Option<Geometry<L::Coord>> {
402 let _geo = self.chip.remove_shape(shape_id);
403 todo!("update RTree")
404 }
405
406 fn replace_shape(
407 &mut self,
408 shape_id: &L::ShapeId,
409 geometry: Geometry<L::Coord>,
410 ) -> Geometry<L::Coord> {
411 let _geo = self.chip.replace_shape(shape_id, geometry);
412 todo!("update RTree")
413 }
414
415 fn set_transform(&mut self, cell_inst: &L::CellInstId, tf: SimpleTransform<L::Coord>) {
416 self.chip.set_transform(cell_inst, tf);
417 todo!("update RTree")
418 }
419}
420
421#[portrait::fill(portrait::delegate(N; self.chip))]
423impl<N: NetlistEdit> NetlistEdit for RegionSearchAdapter<N>
424where
425 N: LayoutBase + NetlistEdit,
426 N::Coord: PrimInt + Signed + std::fmt::Debug,
427{
428}
429
430#[portrait::fill(portrait::delegate(LN; self.chip))]
431impl<LN> L2NEdit for RegionSearchAdapter<LN>
432where
433 LN: L2NEdit,
434 LN::Coord: PrimInt + Signed + std::fmt::Debug,
435{
436}
437
438#[test]
439fn test_create_region_search() {
440 let mut chip = Chip::new();
441
442 let top = chip.create_cell("TOP".to_string().into());
443 let layer1 = chip.create_layer(1, 0);
444 chip.insert_shape(&top, &layer1, Rect::new((0, 0), (10, 10)).into());
445
446 let region_search = RegionSearchAdapter::new(&mut chip);
447
448 assert_eq!(
449 region_search.cell_bounding_boxes[&top],
450 Rect::new((0, 0), (10, 10))
451 );
452}