From 00250e4cc788908811b910458f9ed28f1e914ecb Mon Sep 17 00:00:00 2001 From: svandenb-dev Date: Tue, 25 Mar 2025 20:54:21 +0100 Subject: [PATCH 1/2] grpc transition PR#1005 tracker --- src/pyedb/grpc/database/layout/layout.py | 49 +++++++++++++++++-- .../database/primitive/padstack_instance.py | 2 +- tests/grpc/system/test_edb_layout.py | 9 +++- 3 files changed, 53 insertions(+), 7 deletions(-) diff --git a/src/pyedb/grpc/database/layout/layout.py b/src/pyedb/grpc/database/layout/layout.py index 4effe3e979..c223b36b23 100644 --- a/src/pyedb/grpc/database/layout/layout.py +++ b/src/pyedb/grpc/database/layout/layout.py @@ -26,6 +26,7 @@ from typing import Union from ansys.edb.core.layout.layout import Layout as GrpcLayout +import ansys.edb.core.primitive.primitive from pyedb.grpc.database.hierarchy.component import Component from pyedb.grpc.database.hierarchy.pingroup import PinGroup @@ -34,7 +35,12 @@ from pyedb.grpc.database.net.extended_net import ExtendedNet from pyedb.grpc.database.net.net import Net from pyedb.grpc.database.net.net_class import NetClass +from pyedb.grpc.database.primitive.bondwire import Bondwire +from pyedb.grpc.database.primitive.circle import Circle from pyedb.grpc.database.primitive.padstack_instance import PadstackInstance +from pyedb.grpc.database.primitive.path import Path +from pyedb.grpc.database.primitive.polygon import Polygon +from pyedb.grpc.database.primitive.rectangle import Rectangle from pyedb.grpc.database.terminal.bundle_terminal import BundleTerminal from pyedb.grpc.database.terminal.edge_terminal import EdgeTerminal from pyedb.grpc.database.terminal.padstack_instance_terminal import ( @@ -59,6 +65,26 @@ def cell(self): """ return self._pedb._active_cell + @property + def primitives(self): + prims = [] + for prim in super().primitives: + if isinstance(prim, ansys.edb.core.primitive.primitive.Path): + prims.append(Path(self._pedb, prim)) + elif isinstance(prim, ansys.edb.core.primitive.primitive.Polygon): + prims.append(Polygon(self._pedb, prim)) + elif isinstance(prim, ansys.edb.core.primitive.primitive.PadstackInstance): + prims.append(PadstackInstance(self._pedb, prim)) + elif isinstance(prim, ansys.edb.core.primitive.primitive.Rectangle): + prims.append(Rectangle(self._pedb, prim)) + elif isinstance(prim, ansys.edb.core.primitive.primitive.Circle): + prims.append(Circle(self._pedb, prim)) + elif isinstance(prim, ansys.edb.core.primitive.primitive.Bondwire): + prims.append(Bondwire(self._pedb, prim)) + else: + raise "Not valid primitive." + return prims + @property def terminals(self): """Get terminals belonging to active layout. @@ -180,17 +206,32 @@ def voltage_regulators(self): """ return [VoltageRegulator(self._pedb, i) for i in self._pedb.active_cell.layout.voltage_regulators] - def find_primitive(self, layer_name: Union[str, list]) -> list: + def find_primitive( + self, layer_name: Union[str, list] = None, name: Union[str, list] = None, net_name: Union[str, list] = None + ) -> list: """Find a primitive objects by layer name. - Parameters ---------- layer_name : str, list + layer_name : str, list, optional Name of the layer. + name : str, list, optional + Name of the primitive + net_name : str, list, optional + Name of the primitive Returns ------- List[:class:`Primitive Date: Mon, 31 Mar 2025 14:51:30 +0200 Subject: [PATCH 2/2] grpc transition PR#942 tracker --- src/pyedb/grpc/database/padstacks.py | 44 ++++++++++++++++++++++--- tests/grpc/system/test_edb_padstacks.py | 12 +++---- 2 files changed, 45 insertions(+), 11 deletions(-) diff --git a/src/pyedb/grpc/database/padstacks.py b/src/pyedb/grpc/database/padstacks.py index 769ba1e25e..0e5ae6f0b8 100644 --- a/src/pyedb/grpc/database/padstacks.py +++ b/src/pyedb/grpc/database/padstacks.py @@ -45,7 +45,9 @@ from ansys.edb.core.geometry.point_data import PointData as GrpcPointData from ansys.edb.core.geometry.polygon_data import PolygonData as GrpcPolygonData from ansys.edb.core.utility.value import Value as GrpcValue +import numpy as np import rtree +from scipy.spatial import ConvexHull from pyedb.generic.general_methods import generate_unique_name from pyedb.grpc.database.definition.padstack_def import PadstackDef @@ -1332,24 +1334,58 @@ def get_padstack_instances_rtree_index(self, nets=None): padstack_instances_index.insert(inst.id, inst.position) return padstack_instances_index - def get_padstack_instances_intersecting_bounding_box(self, bounding_box, nets=None): + def get_padstack_instances_id_intersecting_polygon(self, points, nets=None, padstack_instances_index=None): """Returns the list of padstack instances ID intersecting a given bounding box and nets. Parameters ---------- - bounding_box : tuple or list. + points : tuple or list. bounding box, [x1, y1, x2, y2] 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``. + padstack_instances_index : optional, Rtree object. + Can be provided optionally to prevent computing padstack instances Rtree index again. Returns ------- + List[int] + List of padstack instances ID intersecting the bounding box. + """ + if not points: + raise Exception("No points defining polygon was provided") + if not padstack_instances_index: + padstack_instances_index = {} + for inst in self.instances: + padstack_instances_index[inst.id] = inst.position + _x = [pt[0] for pt in points] + _y = [pt[1] for pt in points] + points = [_x, _y] + return [ + ind for ind, pt in padstack_instances_index.items() if GeometryOperators.is_point_in_polygon(pt, points) + ] + + def get_padstack_instances_intersecting_bounding_box(self, bounding_box, nets=None, padstack_instances_index=None): + """Returns the list of padstack instances ID intersecting a given bounding box and nets. + Parameters + ---------- + bounding_box : tuple or list. + bounding box, [x1, y1, x2, y2] + 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``. + padstack_instances_index : optional, Rtree object. + Can be provided optionally to prevent computing padstack instances Rtree index again. + Returns + ------- List of padstack instances ID intersecting the bounding box. """ if not bounding_box: raise Exception("No bounding box was provided") - index = self.get_padstack_instances_rtree_index(nets=nets) + if not padstack_instances_index: + index = self.get_padstack_instances_rtree_index(nets=nets) + else: + index = padstack_instances_index if not len(bounding_box) == 4: raise Exception("The bounding box length must be equal to 4") if isinstance(bounding_box, list): @@ -1479,7 +1515,7 @@ def merge_via(self, contour_boxes, net_filter=None, start_layer=None, stop_layer convex_hull_contour = ConvexHull(instances_pts) contour_points = list(instances_pts[convex_hull_contour.vertices]) layer = list(self._pedb.stackup.layers.values())[0].name - polygon = self._pedb.modeler.create_polygon(main_shape=contour_points, layer_name=layer) + polygon = self._pedb.modeler.create_polygon(points=contour_points, layer_name=layer) polygon_data = polygon.polygon_data polygon.delete() new_padstack_def = generate_unique_name("test") diff --git a/tests/grpc/system/test_edb_padstacks.py b/tests/grpc/system/test_edb_padstacks.py index deda14312a..93ead08eab 100644 --- a/tests/grpc/system/test_edb_padstacks.py +++ b/tests/grpc/system/test_edb_padstacks.py @@ -505,10 +505,8 @@ def test_via_fence(self): # assert edbapp.padstacks.definitions["v35h15"].hole_parameters["diameter"] == "0.2mm" def test_via_merge(self, edb_examples): - # TODO - # edbapp = edb_examples.get_si_verse() - # polygon = [[[118e-3, 60e-3], [125e-3, 60e-3], [124e-3, 56e-3], [118e-3, 56e-3]]] - # result = edbapp.padstacks.merge_via(contour_boxes=polygon, start_layer="1_Top", stop_layer="16_Bottom") - # assert len(result) == 1 - # edbapp.close() - pass + edbapp = edb_examples.get_si_verse() + polygon = [[[118e-3, 60e-3], [125e-3, 60e-3], [124e-3, 56e-3], [118e-3, 56e-3]]] + result = edbapp.padstacks.merge_via(contour_boxes=polygon, start_layer="1_Top", stop_layer="16_Bottom") + assert len(result) == 1 + edbapp.close()