From 0ee121ccc3112a6237a8de6dbb3e03f1ad2a8bb9 Mon Sep 17 00:00:00 2001 From: boyang2022 Date: Thu, 19 Dec 2024 09:20:51 +0100 Subject: [PATCH] FEAT: Reduce via in bounding box (#946) * add reduce vias in box * add doc * add doc * add test * move to system test * merge main into branch --- src/pyedb/dotnet/edb_core/padstack.py | 54 ++++++++++++++++++ .../example_models/TEDB/vias_300.aedb/edb.def | Bin 0 -> 163840 bytes tests/legacy/system/test_edb_padstacks.py | 14 +++++ tests/legacy/unit/test_padstack.py | 1 + 4 files changed, 69 insertions(+) create mode 100644 tests/example_models/TEDB/vias_300.aedb/edb.def diff --git a/src/pyedb/dotnet/edb_core/padstack.py b/src/pyedb/dotnet/edb_core/padstack.py index dc1c865fdc..4aa0c8c356 100644 --- a/src/pyedb/dotnet/edb_core/padstack.py +++ b/src/pyedb/dotnet/edb_core/padstack.py @@ -1755,3 +1755,57 @@ def merge_via_along_lines( for inst in _instances_to_delete: inst.delete() return True + + def reduce_via_in_bounding_box(self, bounding_box, x_samples, y_samples, nets=None): + """ + reduce the number of vias intersecting bounding box and nets by x and y samples. + + Parameters + ---------- + bounding_box : tuple or list. + bounding box, [x1, y1, x2, y2] + x_samples : int + y_samples : int + nets : str or list, optional + net name of list of nets name applying filtering on padstack instances selection. If ``None`` is provided + all instances are included in the index. Default value is ``None``. + + Returns + ------- + bool + ``True`` when succeeded ``False`` when failed. < + """ + + padstacks_inbox = self.get_padstack_instances_intersecting_bounding_box(bounding_box, nets) + if not padstacks_inbox: + self._logger.info("no padstack in bounding box") + return False + else: + if len(padstacks_inbox) <= (x_samples * y_samples): + self._logger.info(f"more samples {x_samples * y_samples} than existing {len(padstacks_inbox)}") + return False + else: + # extract ids and positions + vias = {item: self.instances[item].position for item in padstacks_inbox} + ids, positions = zip(*vias.items()) + pt_x, pt_y = zip(*positions) + + # meshgrid + _x_min, _x_max = min(pt_x), max(pt_x) + _y_min, _y_max = min(pt_y), max(pt_y) + + x_grid, y_grid = np.meshgrid( + np.linspace(_x_min, _x_max, x_samples), np.linspace(_y_min, _y_max, y_samples) + ) + + # mapping to meshgrid + to_keep = { + ids[np.argmin(np.square(_x - pt_x) + np.square(_y - pt_y))] + for _x, _y in zip(x_grid.ravel(), y_grid.ravel()) + } + + for item in padstacks_inbox: + if item not in to_keep: + self.instances[item].delete() + + return True diff --git a/tests/example_models/TEDB/vias_300.aedb/edb.def b/tests/example_models/TEDB/vias_300.aedb/edb.def new file mode 100644 index 0000000000000000000000000000000000000000..bb46d0e2b4fd68ad45db8d905e1509b74638ba35 GIT binary patch literal 163840 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