pyedb 0.56.0__py3-none-any.whl → 0.58.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of pyedb might be problematic. Click here for more details.
- pyedb/__init__.py +1 -1
- pyedb/configuration/cfg_data.py +3 -0
- pyedb/configuration/cfg_pin_groups.py +2 -0
- pyedb/configuration/cfg_terminals.py +232 -0
- pyedb/configuration/configuration.py +146 -3
- pyedb/dotnet/clr_module.py +1 -2
- pyedb/dotnet/database/Variables.py +30 -22
- pyedb/dotnet/database/cell/hierarchy/component.py +2 -8
- pyedb/dotnet/database/cell/layout.py +5 -1
- pyedb/dotnet/database/cell/primitive/primitive.py +2 -2
- pyedb/dotnet/database/cell/terminal/bundle_terminal.py +12 -0
- pyedb/dotnet/database/cell/terminal/pingroup_terminal.py +1 -1
- pyedb/dotnet/database/cell/terminal/terminal.py +38 -0
- pyedb/dotnet/database/components.py +15 -19
- pyedb/dotnet/database/dotnet/database.py +1 -0
- pyedb/dotnet/database/edb_data/control_file.py +19 -8
- pyedb/dotnet/database/edb_data/nets_data.py +3 -3
- pyedb/dotnet/database/edb_data/padstacks_data.py +39 -14
- pyedb/dotnet/database/edb_data/ports.py +0 -25
- pyedb/dotnet/database/edb_data/primitives_data.py +3 -3
- pyedb/dotnet/database/edb_data/raptor_x_simulation_setup_data.py +18 -19
- pyedb/dotnet/database/edb_data/simulation_configuration.py +3 -3
- pyedb/dotnet/database/edb_data/sources.py +21 -2
- pyedb/dotnet/database/general.py +1 -6
- pyedb/dotnet/database/hfss.py +9 -8
- pyedb/dotnet/database/layout_validation.py +14 -3
- pyedb/dotnet/database/materials.py +1 -3
- pyedb/dotnet/database/modeler.py +7 -3
- pyedb/dotnet/database/nets.py +27 -19
- pyedb/dotnet/database/padstack.py +4 -2
- pyedb/dotnet/database/sim_setup_data/io/siwave.py +54 -1
- pyedb/dotnet/database/siwave.py +4 -3
- pyedb/dotnet/database/stackup.py +55 -58
- pyedb/dotnet/database/utilities/heatsink.py +0 -1
- pyedb/dotnet/database/utilities/hfss_simulation_setup.py +81 -0
- pyedb/dotnet/database/utilities/simulation_setup.py +7 -5
- pyedb/dotnet/database/utilities/siwave_cpa_simulation_setup.py +1 -0
- pyedb/dotnet/database/utilities/siwave_simulation_setup.py +264 -13
- pyedb/dotnet/edb.py +65 -47
- pyedb/exceptions.py +1 -2
- pyedb/extensions/create_cell_array.py +67 -49
- pyedb/generic/data_handlers.py +13 -23
- pyedb/generic/design_types.py +9 -35
- pyedb/generic/filesystem.py +4 -2
- pyedb/generic/general_methods.py +28 -41
- pyedb/generic/plot.py +8 -23
- pyedb/generic/process.py +78 -10
- pyedb/grpc/database/_typing.py +0 -0
- pyedb/grpc/database/components.py +14 -13
- pyedb/grpc/database/control_file.py +27 -40
- pyedb/grpc/database/definition/materials.py +1 -1
- pyedb/grpc/database/definition/package_def.py +6 -3
- pyedb/grpc/database/definition/padstack_def.py +14 -12
- pyedb/grpc/database/hfss.py +1 -4
- pyedb/grpc/database/hierarchy/component.py +5 -13
- pyedb/grpc/database/hierarchy/pingroup.py +16 -3
- pyedb/grpc/database/layers/layer.py +1 -2
- pyedb/grpc/database/layers/stackup_layer.py +42 -19
- pyedb/grpc/database/layout/layout.py +43 -27
- pyedb/grpc/database/layout/voltage_regulator.py +6 -1
- pyedb/grpc/database/layout_validation.py +5 -2
- pyedb/grpc/database/modeler.py +254 -252
- pyedb/grpc/database/net/differential_pair.py +9 -2
- pyedb/grpc/database/net/extended_net.py +24 -9
- pyedb/grpc/database/net/net.py +14 -5
- pyedb/grpc/database/net/net_class.py +24 -7
- pyedb/grpc/database/nets.py +11 -43
- pyedb/grpc/database/padstacks.py +67 -119
- pyedb/grpc/database/primitive/bondwire.py +3 -67
- pyedb/grpc/database/primitive/circle.py +42 -3
- pyedb/grpc/database/primitive/padstack_instance.py +58 -31
- pyedb/grpc/database/primitive/path.py +160 -11
- pyedb/grpc/database/primitive/polygon.py +73 -7
- pyedb/grpc/database/primitive/primitive.py +2 -2
- pyedb/grpc/database/primitive/rectangle.py +105 -4
- pyedb/grpc/database/simulation_setup/hfss_general_settings.py +0 -2
- pyedb/grpc/database/simulation_setup/hfss_settings_options.py +0 -4
- pyedb/grpc/database/simulation_setup/hfss_simulation_setup.py +79 -0
- pyedb/grpc/database/simulation_setup/siwave_cpa_simulation_setup.py +1 -0
- pyedb/grpc/database/simulation_setup/sweep_data.py +1 -3
- pyedb/grpc/database/siwave.py +6 -13
- pyedb/grpc/database/source_excitations.py +46 -63
- pyedb/grpc/database/stackup.py +55 -60
- pyedb/grpc/database/terminal/bundle_terminal.py +10 -3
- pyedb/grpc/database/terminal/padstack_instance_terminal.py +9 -11
- pyedb/grpc/database/terminal/pingroup_terminal.py +8 -1
- pyedb/grpc/database/terminal/point_terminal.py +30 -0
- pyedb/grpc/database/terminal/terminal.py +35 -10
- pyedb/grpc/database/utility/heat_sink.py +0 -1
- pyedb/grpc/database/utility/hfss_extent_info.py +2 -2
- pyedb/grpc/database/utility/xml_control_file.py +19 -8
- pyedb/grpc/edb.py +63 -32
- pyedb/grpc/edb_init.py +1 -0
- pyedb/ipc2581/ecad/cad_data/layer_feature.py +6 -2
- pyedb/ipc2581/ecad/cad_data/step.py +1 -1
- pyedb/ipc2581/ipc2581.py +8 -7
- pyedb/libraries/common.py +3 -4
- pyedb/libraries/rf_libraries/base_functions.py +7 -16
- pyedb/libraries/rf_libraries/planar_antennas.py +3 -21
- pyedb/misc/aedtlib_personalib_install.py +2 -2
- pyedb/misc/downloads.py +19 -3
- pyedb/misc/misc.py +5 -2
- pyedb/misc/siw_feature_config/emc_rule_checker_settings.py +3 -2
- pyedb/misc/siw_feature_config/xtalk_scan/scan_config.py +0 -1
- pyedb/misc/utilities.py +0 -1
- pyedb/modeler/geometry_operators.py +3 -2
- {pyedb-0.56.0.dist-info → pyedb-0.58.0.dist-info}/METADATA +6 -7
- {pyedb-0.56.0.dist-info → pyedb-0.58.0.dist-info}/RECORD +110 -108
- {pyedb-0.56.0.dist-info → pyedb-0.58.0.dist-info}/WHEEL +0 -0
- {pyedb-0.56.0.dist-info → pyedb-0.58.0.dist-info}/licenses/LICENSE +0 -0
pyedb/grpc/database/modeler.py
CHANGED
|
@@ -23,20 +23,17 @@
|
|
|
23
23
|
"""
|
|
24
24
|
This module contains these classes: `EdbLayout` and `Shape`.
|
|
25
25
|
"""
|
|
26
|
+
|
|
26
27
|
import math
|
|
27
|
-
from typing import Any, Dict, List, Optional, Union
|
|
28
|
+
from typing import Any, Dict, Iterable, List, Optional, Union
|
|
28
29
|
|
|
29
|
-
from ansys.edb.core.geometry.arc_data import ArcData as GrpcArcData
|
|
30
30
|
from ansys.edb.core.geometry.point_data import PointData as GrpcPointData
|
|
31
31
|
from ansys.edb.core.geometry.polygon_data import (
|
|
32
|
-
|
|
32
|
+
PolygonData as GrpcPolygonData,
|
|
33
33
|
)
|
|
34
|
-
from ansys.edb.core.geometry.polygon_data import PolygonData as GrpcPolygonData
|
|
35
34
|
from ansys.edb.core.hierarchy.pin_group import PinGroup as GrpcPinGroup
|
|
36
|
-
from ansys.edb.core.inner.exceptions import InvalidArgumentException
|
|
37
35
|
from ansys.edb.core.primitive.bondwire import BondwireType as GrpcBondwireType
|
|
38
|
-
from ansys.edb.core.primitive.path import PathCornerType as GrpcPathCornerType
|
|
39
|
-
from ansys.edb.core.primitive.path import PathEndCapType as GrpcPathEndCapType
|
|
36
|
+
from ansys.edb.core.primitive.path import PathCornerType as GrpcPathCornerType, PathEndCapType as GrpcPathEndCapType
|
|
40
37
|
from ansys.edb.core.primitive.rectangle import (
|
|
41
38
|
RectangleRepresentationType as GrpcRectangleRepresentationType,
|
|
42
39
|
)
|
|
@@ -51,6 +48,25 @@ from pyedb.grpc.database.utility.layout_statistics import LayoutStatistics
|
|
|
51
48
|
from pyedb.grpc.database.utility.value import Value
|
|
52
49
|
|
|
53
50
|
|
|
51
|
+
def normalize_pairs(points: Iterable[float]) -> List[List[float]]:
|
|
52
|
+
"""
|
|
53
|
+
Convert any reasonable point description into [[x1, y1], [x2, y2], …]
|
|
54
|
+
"""
|
|
55
|
+
pts = list(points)
|
|
56
|
+
if not pts: # empty input
|
|
57
|
+
return []
|
|
58
|
+
|
|
59
|
+
# Detect flat vs nested
|
|
60
|
+
if isinstance(pts[0], (list, tuple)):
|
|
61
|
+
# already nested – just ensure every item is a *list* (not tuple)
|
|
62
|
+
return [list(pair) for pair in pts]
|
|
63
|
+
else:
|
|
64
|
+
# flat list – chunk into pairs
|
|
65
|
+
if len(pts) % 2:
|
|
66
|
+
raise ValueError("Odd number of coordinates supplied")
|
|
67
|
+
return [[pts[i], pts[i + 1]] for i in range(0, len(pts), 2)]
|
|
68
|
+
|
|
69
|
+
|
|
54
70
|
class Modeler(object):
|
|
55
71
|
"""Manages EDB methods for primitives management accessible from `Edb.modeler`.
|
|
56
72
|
|
|
@@ -61,7 +77,7 @@ class Modeler(object):
|
|
|
61
77
|
>>> edb_layout = edbapp.modeler
|
|
62
78
|
"""
|
|
63
79
|
|
|
64
|
-
def __getitem__(self, name: Union[str, int]) ->
|
|
80
|
+
def __getitem__(self, name: Union[str, int]) -> Primitive:
|
|
65
81
|
"""Get a primitive by name or ID.
|
|
66
82
|
|
|
67
83
|
Parameters
|
|
@@ -71,7 +87,7 @@ class Modeler(object):
|
|
|
71
87
|
|
|
72
88
|
Returns
|
|
73
89
|
-------
|
|
74
|
-
:class:`pyedb.
|
|
90
|
+
:class:`pyedb.grpc.database.primitive.primitive.Primitive`
|
|
75
91
|
Primitive instance if found, None otherwise.
|
|
76
92
|
|
|
77
93
|
Raises
|
|
@@ -79,21 +95,151 @@ class Modeler(object):
|
|
|
79
95
|
TypeError
|
|
80
96
|
If name is not str or int.
|
|
81
97
|
"""
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
or (isinstance(name, int) and i.id == name)
|
|
87
|
-
):
|
|
88
|
-
return i
|
|
89
|
-
self._pedb.logger.error("Primitive not found.")
|
|
90
|
-
return
|
|
98
|
+
|
|
99
|
+
if isinstance(name, int):
|
|
100
|
+
return self._primitives.get(name)
|
|
101
|
+
return self.primitives_by_name.get(name)
|
|
91
102
|
|
|
92
103
|
def __init__(self, p_edb) -> None:
|
|
93
104
|
"""Initialize Modeler instance."""
|
|
94
105
|
self._pedb = p_edb
|
|
95
|
-
|
|
96
|
-
self.
|
|
106
|
+
# Core cache
|
|
107
|
+
self._primitives: dict[str, Primitive] = {}
|
|
108
|
+
|
|
109
|
+
# Lazy indexes
|
|
110
|
+
self._primitives_by_name: dict[str, Primitive] | None = None
|
|
111
|
+
self._primitives_by_net: dict[str, list[Primitive]] | None = None
|
|
112
|
+
self._primitives_by_layer: dict[str, list[Primitive]] | None = None
|
|
113
|
+
self._primitives_by_layer_and_net: Dict[str, Dict[str, List[Primitive]]] | None = None
|
|
114
|
+
|
|
115
|
+
# ============================================================
|
|
116
|
+
|
|
117
|
+
# Cache management
|
|
118
|
+
# ============================================================
|
|
119
|
+
|
|
120
|
+
def _reload_all(self):
|
|
121
|
+
"""Force reload of all primitives and reset indexes."""
|
|
122
|
+
self._primitives = {p.edb_uid: p for p in self._pedb.layout.primitives}
|
|
123
|
+
self._primitives_by_name = None
|
|
124
|
+
self._primitives_by_net = None
|
|
125
|
+
self._primitives_by_layer = None
|
|
126
|
+
self._primitives_by_layer_and_net = None
|
|
127
|
+
|
|
128
|
+
def _add_primitive(self, prim: Any):
|
|
129
|
+
"""Add primitive wrapper to caches."""
|
|
130
|
+
self._primitives[prim.edb_uid] = prim
|
|
131
|
+
if self._primitives_by_name is not None:
|
|
132
|
+
self._primitives_by_name[prim.aedt_name] = prim
|
|
133
|
+
if self._primitives_by_net is not None and hasattr(prim, "net"):
|
|
134
|
+
self._primitives_by_net.setdefault(prim.net, []).append(prim)
|
|
135
|
+
if hasattr(prim, "layer"):
|
|
136
|
+
if self._primitives_by_layer is not None and prim.layer_name:
|
|
137
|
+
self._primitives_by_layer.setdefault(prim.layer_name, []).append(prim)
|
|
138
|
+
|
|
139
|
+
def _remove_primitive(self, prim: Primitive):
|
|
140
|
+
"""Remove primitive wrapper from all caches efficiently and safely."""
|
|
141
|
+
uid = prim.edb_uid
|
|
142
|
+
|
|
143
|
+
# 1. Remove from primary cache
|
|
144
|
+
self._primitives.pop(uid, None)
|
|
145
|
+
|
|
146
|
+
# 2. Remove from name cache if initialized
|
|
147
|
+
if self._primitives_by_name is not None:
|
|
148
|
+
self._primitives_by_name.pop(prim.aedt_name, None)
|
|
149
|
+
|
|
150
|
+
# 3. Remove from net cache if initialized
|
|
151
|
+
if self._primitives_by_net is not None and hasattr(prim, "net") and not prim.net.is_null:
|
|
152
|
+
net_name = prim.net.name
|
|
153
|
+
net_prims = self._primitives_by_net.get(net_name)
|
|
154
|
+
if net_prims:
|
|
155
|
+
try:
|
|
156
|
+
net_prims.remove(prim)
|
|
157
|
+
except ValueError:
|
|
158
|
+
pass # Not found, skip
|
|
159
|
+
if not net_prims:
|
|
160
|
+
self._primitives_by_net.pop(net_name, None)
|
|
161
|
+
|
|
162
|
+
# 4. Remove from layer cache if initialized
|
|
163
|
+
if self._primitives_by_layer is not None and hasattr(prim, "layer") and prim.layer_name:
|
|
164
|
+
layer_name = prim.layer.name
|
|
165
|
+
layer_prims = self._primitives_by_layer.get(layer_name)
|
|
166
|
+
if layer_prims:
|
|
167
|
+
try:
|
|
168
|
+
layer_prims.remove(prim)
|
|
169
|
+
except ValueError:
|
|
170
|
+
pass
|
|
171
|
+
if not layer_prims:
|
|
172
|
+
self._primitives_by_layer.pop(layer_name, None)
|
|
173
|
+
|
|
174
|
+
# 5. Remove from layer+net cache if initialized
|
|
175
|
+
if self._primitives_by_layer_and_net is not None:
|
|
176
|
+
if hasattr(prim, "layer") and hasattr(prim, "net") and not prim.net.is_null:
|
|
177
|
+
layer_name = prim.layer.name
|
|
178
|
+
net_name = prim.net.name
|
|
179
|
+
layer_dict = self._primitives_by_layer_and_net.get(layer_name)
|
|
180
|
+
if layer_dict:
|
|
181
|
+
net_list = layer_dict.get(net_name)
|
|
182
|
+
if net_list:
|
|
183
|
+
try:
|
|
184
|
+
net_list.remove(prim)
|
|
185
|
+
except ValueError:
|
|
186
|
+
pass
|
|
187
|
+
if not net_list:
|
|
188
|
+
layer_dict.pop(net_name, None)
|
|
189
|
+
if not layer_dict:
|
|
190
|
+
self._primitives_by_layer_and_net.pop(layer_name, None)
|
|
191
|
+
|
|
192
|
+
@property
|
|
193
|
+
def primitives(self) -> list[Primitive]:
|
|
194
|
+
if not self._primitives:
|
|
195
|
+
self._reload_all()
|
|
196
|
+
return list(self._primitives.values())
|
|
197
|
+
|
|
198
|
+
@property
|
|
199
|
+
def primitives_by_name(self):
|
|
200
|
+
if self._primitives_by_name is None:
|
|
201
|
+
self._primitives_by_name = {p.aedt_name: p for p in self.primitives}
|
|
202
|
+
return self._primitives_by_name
|
|
203
|
+
|
|
204
|
+
@property
|
|
205
|
+
def primitives_by_net(self):
|
|
206
|
+
if self._primitives_by_net is None:
|
|
207
|
+
d = {}
|
|
208
|
+
for p in self.primitives:
|
|
209
|
+
if hasattr(p, "net"):
|
|
210
|
+
d.setdefault(p.net.name, []).append(p)
|
|
211
|
+
self._primitives_by_net = d
|
|
212
|
+
return self._primitives_by_net
|
|
213
|
+
|
|
214
|
+
@property
|
|
215
|
+
def primitives_by_layer(self):
|
|
216
|
+
if self._primitives_by_layer is None:
|
|
217
|
+
d = {}
|
|
218
|
+
for p in self.primitives:
|
|
219
|
+
if p.layer_name:
|
|
220
|
+
d.setdefault(p.layer_name, []).append(p)
|
|
221
|
+
self._primitives_by_layer = d
|
|
222
|
+
return self._primitives_by_layer
|
|
223
|
+
|
|
224
|
+
@property
|
|
225
|
+
def primitives_by_layer_and_net(self) -> Dict[str, Dict[str, List[Primitive]]]:
|
|
226
|
+
"""Return all primitives indexed first by layer, then by net.
|
|
227
|
+
|
|
228
|
+
Returns
|
|
229
|
+
-------
|
|
230
|
+
dict
|
|
231
|
+
Nested dictionary: layer -> net -> list[Primitive]
|
|
232
|
+
"""
|
|
233
|
+
if self._primitives_by_layer_and_net is None:
|
|
234
|
+
idx: Dict[str, Dict[str, List[Primitive]]] = {}
|
|
235
|
+
for prim in self.primitives:
|
|
236
|
+
if not prim.layer_name or not hasattr(prim, "net") or prim.net.is_null:
|
|
237
|
+
continue
|
|
238
|
+
layer = prim.layer_name
|
|
239
|
+
net = prim.net.name
|
|
240
|
+
idx.setdefault(layer, {}).setdefault(net, []).append(prim)
|
|
241
|
+
self._primitives_by_layer_and_net = idx
|
|
242
|
+
return self._primitives_by_layer_and_net
|
|
97
243
|
|
|
98
244
|
@property
|
|
99
245
|
def _edb(self) -> Any:
|
|
@@ -211,17 +357,6 @@ class Modeler(object):
|
|
|
211
357
|
else:
|
|
212
358
|
return False
|
|
213
359
|
|
|
214
|
-
@property
|
|
215
|
-
def primitives(self) -> List[Primitive]:
|
|
216
|
-
"""All primitives in the layout.
|
|
217
|
-
|
|
218
|
-
Returns
|
|
219
|
-
-------
|
|
220
|
-
list
|
|
221
|
-
List of :class:`pyedb.dotnet.database.edb_data.primitives_data.Primitive` objects.
|
|
222
|
-
"""
|
|
223
|
-
return self._pedb.layout.primitives
|
|
224
|
-
|
|
225
360
|
@property
|
|
226
361
|
def polygons_by_layer(self) -> Dict[str, List[Primitive]]:
|
|
227
362
|
"""Primitives organized by layer names.
|
|
@@ -231,47 +366,13 @@ class Modeler(object):
|
|
|
231
366
|
dict
|
|
232
367
|
Dictionary where keys are layer names and values are lists of polygons.
|
|
233
368
|
"""
|
|
234
|
-
|
|
369
|
+
polygon_by_layer = {}
|
|
235
370
|
for lay in self.layers:
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
"""Primitives organized by net names.
|
|
242
|
-
|
|
243
|
-
Returns
|
|
244
|
-
-------
|
|
245
|
-
dict
|
|
246
|
-
Dictionary where keys are net names and values are lists of primitives.
|
|
247
|
-
"""
|
|
248
|
-
_prim_by_net = {}
|
|
249
|
-
for net, net_obj in self._pedb.nets.nets.items():
|
|
250
|
-
_prim_by_net[net] = [i for i in net_obj.primitives]
|
|
251
|
-
return _prim_by_net
|
|
252
|
-
|
|
253
|
-
@property
|
|
254
|
-
def primitives_by_layer(self) -> Dict[str, List[Primitive]]:
|
|
255
|
-
"""Primitives organized by layer names.
|
|
256
|
-
|
|
257
|
-
Returns
|
|
258
|
-
-------
|
|
259
|
-
dict
|
|
260
|
-
Dictionary where keys are layer names and values are lists of primitives.
|
|
261
|
-
"""
|
|
262
|
-
_primitives_by_layer = {}
|
|
263
|
-
for lay in self.layers:
|
|
264
|
-
_primitives_by_layer[lay] = []
|
|
265
|
-
for lay in self._pedb.stackup.non_stackup_layers:
|
|
266
|
-
_primitives_by_layer[lay] = []
|
|
267
|
-
for i in self._layout.primitives:
|
|
268
|
-
try:
|
|
269
|
-
lay = i.layer.name
|
|
270
|
-
if lay in _primitives_by_layer:
|
|
271
|
-
_primitives_by_layer[lay].append(i)
|
|
272
|
-
except (InvalidArgumentException, AttributeError):
|
|
273
|
-
pass
|
|
274
|
-
return _primitives_by_layer
|
|
371
|
+
if lay in self.primitives_by_layer:
|
|
372
|
+
polygon_by_layer[lay] = [prim for prim in self.primitives_by_layer[lay] if prim.type == "polygon"]
|
|
373
|
+
else:
|
|
374
|
+
polygon_by_layer[lay] = []
|
|
375
|
+
return polygon_by_layer
|
|
275
376
|
|
|
276
377
|
@property
|
|
277
378
|
def rectangles(self) -> List[Rectangle]:
|
|
@@ -332,15 +433,10 @@ class Modeler(object):
|
|
|
332
433
|
list
|
|
333
434
|
List of polygon objects.
|
|
334
435
|
"""
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
if
|
|
338
|
-
|
|
339
|
-
if net_list and el.net.name in net_list:
|
|
340
|
-
objinst.append(el)
|
|
341
|
-
else:
|
|
342
|
-
objinst.append(el)
|
|
343
|
-
return objinst
|
|
436
|
+
polygons = self.polygons_by_layer.get(layer_name, [])
|
|
437
|
+
if net_list:
|
|
438
|
+
polygons = [p for p in polygons if p.net_name in net_list]
|
|
439
|
+
return polygons
|
|
344
440
|
|
|
345
441
|
def get_primitive_by_layer_and_point(
|
|
346
442
|
self,
|
|
@@ -603,7 +699,8 @@ class Modeler(object):
|
|
|
603
699
|
else:
|
|
604
700
|
corner_style = GrpcPathCornerType.MITER
|
|
605
701
|
_points = []
|
|
606
|
-
if isinstance(points, list):
|
|
702
|
+
if isinstance(points, (list, tuple)):
|
|
703
|
+
points = normalize_pairs(points)
|
|
607
704
|
for pt in points:
|
|
608
705
|
_pt = []
|
|
609
706
|
for coord in pt:
|
|
@@ -617,7 +714,7 @@ class Modeler(object):
|
|
|
617
714
|
polygon_data = points
|
|
618
715
|
else:
|
|
619
716
|
raise TypeError("Points must be a list of points or a PolygonData object.")
|
|
620
|
-
path = Path.create(
|
|
717
|
+
path = Path(self._pedb).create(
|
|
621
718
|
layout=self._active_layout,
|
|
622
719
|
layer=layer_name,
|
|
623
720
|
net=net,
|
|
@@ -634,7 +731,7 @@ class Modeler(object):
|
|
|
634
731
|
|
|
635
732
|
def create_trace(
|
|
636
733
|
self,
|
|
637
|
-
path_list: Union[
|
|
734
|
+
path_list: Union[Iterable[float], GrpcPolygonData],
|
|
638
735
|
layer_name: str,
|
|
639
736
|
width: float = 1,
|
|
640
737
|
net_name: str = "",
|
|
@@ -646,8 +743,9 @@ class Modeler(object):
|
|
|
646
743
|
|
|
647
744
|
Parameters
|
|
648
745
|
----------
|
|
649
|
-
path_list :
|
|
650
|
-
List of [x,y]
|
|
746
|
+
path_list : Iterable
|
|
747
|
+
List of points [x,y] or [[x, y], ...]
|
|
748
|
+
or [(x, y)...].
|
|
651
749
|
layer_name : str
|
|
652
750
|
Layer name.
|
|
653
751
|
width : float, optional
|
|
@@ -676,7 +774,7 @@ class Modeler(object):
|
|
|
676
774
|
end_cap_style=end_cap_style,
|
|
677
775
|
corner_style=corner_style,
|
|
678
776
|
)
|
|
679
|
-
|
|
777
|
+
self._add_primitive(primitive) # update cache
|
|
680
778
|
return primitive
|
|
681
779
|
|
|
682
780
|
def create_polygon(
|
|
@@ -723,16 +821,21 @@ class Modeler(object):
|
|
|
723
821
|
for void in voids:
|
|
724
822
|
if isinstance(void, list):
|
|
725
823
|
void_polygon_data = GrpcPolygonData(points=void)
|
|
824
|
+
elif isinstance(void, GrpcPolygonData):
|
|
825
|
+
void_polygon_data = void
|
|
726
826
|
else:
|
|
727
827
|
void_polygon_data = void.polygon_data
|
|
728
828
|
if not void_polygon_data.points:
|
|
729
829
|
self._logger.error("Failed to create void polygon data")
|
|
730
830
|
return False
|
|
731
831
|
polygon_data.holes.append(void_polygon_data)
|
|
732
|
-
polygon = Polygon
|
|
832
|
+
polygon = Polygon(self._pedb, None).create(
|
|
833
|
+
layout=self._active_layout, layer=layer_name, net=net, polygon_data=polygon_data
|
|
834
|
+
)
|
|
733
835
|
if polygon.is_null or polygon_data is False: # pragma: no cover
|
|
734
836
|
self._logger.error("Null polygon created")
|
|
735
837
|
return False
|
|
838
|
+
self._add_primitive(polygon)
|
|
736
839
|
return Polygon(self._pedb, polygon)
|
|
737
840
|
|
|
738
841
|
def create_rectangle(
|
|
@@ -780,12 +883,11 @@ class Modeler(object):
|
|
|
780
883
|
"""
|
|
781
884
|
edb_net = self._pedb.nets.find_or_create_net(net_name)
|
|
782
885
|
if representation_type == "lower_left_upper_right":
|
|
783
|
-
|
|
784
|
-
rect = Rectangle.create(
|
|
886
|
+
rect = Rectangle(self._pedb).create(
|
|
785
887
|
layout=self._active_layout,
|
|
786
888
|
layer=layer_name,
|
|
787
889
|
net=edb_net,
|
|
788
|
-
rep_type=
|
|
890
|
+
rep_type=representation_type,
|
|
789
891
|
param1=Value(lower_left_point[0]),
|
|
790
892
|
param2=Value(lower_left_point[1]),
|
|
791
893
|
param3=Value(upper_right_point[0]),
|
|
@@ -809,7 +911,7 @@ class Modeler(object):
|
|
|
809
911
|
height = Value(width)
|
|
810
912
|
else:
|
|
811
913
|
height = Value(width)
|
|
812
|
-
rect = Rectangle.create(
|
|
914
|
+
rect = Rectangle(self._pedb).create(
|
|
813
915
|
layout=self._active_layout,
|
|
814
916
|
layer=layer_name,
|
|
815
917
|
net=edb_net,
|
|
@@ -822,7 +924,8 @@ class Modeler(object):
|
|
|
822
924
|
rotation=Value(rotation),
|
|
823
925
|
)
|
|
824
926
|
if not rect.is_null:
|
|
825
|
-
|
|
927
|
+
self._add_primitive(rect)
|
|
928
|
+
return rect
|
|
826
929
|
return False
|
|
827
930
|
|
|
828
931
|
def create_circle(
|
|
@@ -850,7 +953,7 @@ class Modeler(object):
|
|
|
850
953
|
"""
|
|
851
954
|
edb_net = self._pedb.nets.find_or_create_net(net_name)
|
|
852
955
|
|
|
853
|
-
circle = Circle.create(
|
|
956
|
+
circle = Circle(self._pedb).create(
|
|
854
957
|
layout=self._active_layout,
|
|
855
958
|
layer=layer_name,
|
|
856
959
|
net=edb_net,
|
|
@@ -859,7 +962,8 @@ class Modeler(object):
|
|
|
859
962
|
radius=Value(radius),
|
|
860
963
|
)
|
|
861
964
|
if not circle.is_null:
|
|
862
|
-
|
|
965
|
+
self._add_primitive(circle)
|
|
966
|
+
return circle
|
|
863
967
|
return False
|
|
864
968
|
|
|
865
969
|
def delete_primitives(self, net_names: Union[str, List[str]]) -> bool:
|
|
@@ -952,120 +1056,6 @@ class Modeler(object):
|
|
|
952
1056
|
void_circle.delete()
|
|
953
1057
|
return True
|
|
954
1058
|
|
|
955
|
-
@staticmethod
|
|
956
|
-
@staticmethod
|
|
957
|
-
def add_void(shape: "Primitive", void_shape: Union["Primitive", List["Primitive"]]) -> bool:
|
|
958
|
-
"""Add void to shape.
|
|
959
|
-
|
|
960
|
-
Parameters
|
|
961
|
-
----------
|
|
962
|
-
shape : :class:`pyedb.dotnet.database.edb_data.primitives_data.Primitive`
|
|
963
|
-
Main shape.
|
|
964
|
-
void_shape : list or :class:`pyedb.dotnet.database.edb_data.primitives_data.Primitive`
|
|
965
|
-
Void shape(s).
|
|
966
|
-
|
|
967
|
-
Returns
|
|
968
|
-
-------
|
|
969
|
-
bool
|
|
970
|
-
True if successful, False otherwise.
|
|
971
|
-
"""
|
|
972
|
-
if not isinstance(void_shape, list):
|
|
973
|
-
void_shape = [void_shape]
|
|
974
|
-
for void in void_shape:
|
|
975
|
-
if isinstance(void, Primitive):
|
|
976
|
-
shape._edb_object.add_void(void)
|
|
977
|
-
flag = True
|
|
978
|
-
else:
|
|
979
|
-
shape._edb_object.add_void(void)
|
|
980
|
-
flag = True
|
|
981
|
-
if not flag:
|
|
982
|
-
return flag
|
|
983
|
-
return True
|
|
984
|
-
|
|
985
|
-
def _createPolygonDataFromPolygon(self, shape):
|
|
986
|
-
points = shape.points
|
|
987
|
-
if not self._validatePoint(points[0]):
|
|
988
|
-
self._logger.error("Error validating point.")
|
|
989
|
-
return None
|
|
990
|
-
arcs = []
|
|
991
|
-
is_parametric = False
|
|
992
|
-
for i in range(len(points) - 1):
|
|
993
|
-
if i == 0:
|
|
994
|
-
startPoint = points[-1]
|
|
995
|
-
endPoint = points[i]
|
|
996
|
-
else:
|
|
997
|
-
startPoint = points[i - 1]
|
|
998
|
-
endPoint = points[i]
|
|
999
|
-
|
|
1000
|
-
if not self._validatePoint(endPoint):
|
|
1001
|
-
return None
|
|
1002
|
-
startPoint = [Value(i) for i in startPoint]
|
|
1003
|
-
endPoint = [Value(i) for i in endPoint]
|
|
1004
|
-
if len(endPoint) == 2:
|
|
1005
|
-
is_parametric = (
|
|
1006
|
-
is_parametric
|
|
1007
|
-
or startPoint[0].is_parametric
|
|
1008
|
-
or startPoint[1].is_parametric
|
|
1009
|
-
or endPoint[0].is_parametric
|
|
1010
|
-
or endPoint[1].is_parametric
|
|
1011
|
-
)
|
|
1012
|
-
arc = GrpcArcData(
|
|
1013
|
-
GrpcPointData([startPoint[0], startPoint[1]]), GrpcPointData([endPoint[0], endPoint[1]])
|
|
1014
|
-
)
|
|
1015
|
-
arcs.append(arc)
|
|
1016
|
-
elif len(endPoint) == 3:
|
|
1017
|
-
is_parametric = (
|
|
1018
|
-
is_parametric
|
|
1019
|
-
or startPoint[0].is_parametric
|
|
1020
|
-
or startPoint[1].is_parametric
|
|
1021
|
-
or endPoint[0].is_parametric
|
|
1022
|
-
or endPoint[1].is_parametric
|
|
1023
|
-
or endPoint[2].is_parametric
|
|
1024
|
-
)
|
|
1025
|
-
arc = GrpcArcData(
|
|
1026
|
-
GrpcPointData([startPoint[0], startPoint[1]]),
|
|
1027
|
-
GrpcPointData([endPoint[0], endPoint[1]]),
|
|
1028
|
-
kwarg={"height": endPoint[2]},
|
|
1029
|
-
)
|
|
1030
|
-
arcs.append(arc)
|
|
1031
|
-
elif len(endPoint) == 5:
|
|
1032
|
-
is_parametric = (
|
|
1033
|
-
is_parametric
|
|
1034
|
-
or startPoint[0].is_parametric
|
|
1035
|
-
or startPoint[1].is_parametric
|
|
1036
|
-
or endPoint[0].is_parametric
|
|
1037
|
-
or endPoint[1].is_parametric
|
|
1038
|
-
or endPoint[3].is_parametric
|
|
1039
|
-
or endPoint[4].is_parametric
|
|
1040
|
-
)
|
|
1041
|
-
if endPoint[2].is_cw:
|
|
1042
|
-
rotationDirection = GrpcPolygonSenseType.SENSE_CW
|
|
1043
|
-
elif endPoint[2].is_ccw:
|
|
1044
|
-
rotationDirection = GrpcPolygonSenseType.SENSE_CCW
|
|
1045
|
-
else:
|
|
1046
|
-
self._logger.error("Invalid rotation direction %s is specified.", endPoint[2])
|
|
1047
|
-
return None
|
|
1048
|
-
arc = GrpcArcData(
|
|
1049
|
-
GrpcPointData(startPoint),
|
|
1050
|
-
GrpcPointData(endPoint),
|
|
1051
|
-
)
|
|
1052
|
-
# arc.direction = rotationDirection,
|
|
1053
|
-
# arc.center = GrpcPointData([endPoint[3], endPoint[4]]),
|
|
1054
|
-
arcs.append(arc)
|
|
1055
|
-
polygon = GrpcPolygonData(arcs=arcs)
|
|
1056
|
-
if not is_parametric:
|
|
1057
|
-
return polygon
|
|
1058
|
-
else:
|
|
1059
|
-
k = 0
|
|
1060
|
-
for pt in points:
|
|
1061
|
-
point = [Value(i) for i in pt]
|
|
1062
|
-
new_points = GrpcPointData(point)
|
|
1063
|
-
if len(point) > 2:
|
|
1064
|
-
k += 1
|
|
1065
|
-
polygon.set_point(k, new_points)
|
|
1066
|
-
k += 1
|
|
1067
|
-
return polygon
|
|
1068
|
-
|
|
1069
1059
|
def _validatePoint(self, point, allowArcs=True):
|
|
1070
1060
|
if len(point) == 2:
|
|
1071
1061
|
if not isinstance(point[0], (int, float, str)):
|
|
@@ -1113,17 +1103,6 @@ class Modeler(object):
|
|
|
1113
1103
|
self._logger.error("Arc point descriptor has incorrect number of elements (%s)", len(point))
|
|
1114
1104
|
return False
|
|
1115
1105
|
|
|
1116
|
-
def _createPolygonDataFromRectangle(self, shape):
|
|
1117
|
-
# if not self._validatePoint(shape.pointA, False) or not self._validatePoint(shape.pointB, False):
|
|
1118
|
-
# return None
|
|
1119
|
-
# pointA = GrpcPointData(pointA[0]), self._get_edb_value(shape.pointA[1])
|
|
1120
|
-
# )
|
|
1121
|
-
# pointB = self._edb.Geometry.PointData(
|
|
1122
|
-
# self._get_edb_value(shape.pointB[0]), self._get_edb_value(shape.pointB[1])
|
|
1123
|
-
# )
|
|
1124
|
-
# return self._edb.geometry.polygon_data.create_from_bbox((pointA, pointB))
|
|
1125
|
-
pass
|
|
1126
|
-
|
|
1127
1106
|
def parametrize_trace_width(
|
|
1128
1107
|
self,
|
|
1129
1108
|
nets_name: Union[str, List[str]],
|
|
@@ -1207,39 +1186,31 @@ class Modeler(object):
|
|
|
1207
1186
|
all_voids = []
|
|
1208
1187
|
list_polygon_data = []
|
|
1209
1188
|
delete_list = []
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
poly
|
|
1213
|
-
|
|
1214
|
-
if poly.net.name:
|
|
1215
|
-
poly_by_nets[poly.net.name] = [poly]
|
|
1216
|
-
else:
|
|
1217
|
-
if poly.net.name:
|
|
1218
|
-
poly_by_nets[poly.net.name].append(poly)
|
|
1219
|
-
for net in poly_by_nets:
|
|
1189
|
+
for poly in self.polygons_by_layer.get(lay, []):
|
|
1190
|
+
if poly.net_name:
|
|
1191
|
+
poly_by_nets.setdefault(poly.net_name, []).append(poly)
|
|
1192
|
+
for net, polys in poly_by_nets.items():
|
|
1220
1193
|
if net in net_names_list or not net_names_list:
|
|
1221
|
-
for
|
|
1222
|
-
list_polygon_data.append(
|
|
1223
|
-
delete_list.append(
|
|
1224
|
-
all_voids.
|
|
1225
|
-
|
|
1226
|
-
for item in
|
|
1227
|
-
for
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
item.add_hole(void.polygon_data)
|
|
1194
|
+
for p in polys:
|
|
1195
|
+
list_polygon_data.append(p.polygon_data)
|
|
1196
|
+
delete_list.append(p)
|
|
1197
|
+
all_voids.extend(p.voids)
|
|
1198
|
+
united = GrpcPolygonData.unite(list_polygon_data)
|
|
1199
|
+
for item in united:
|
|
1200
|
+
for void in all_voids:
|
|
1201
|
+
if item.intersection_type(void.polygon_data) == 2:
|
|
1202
|
+
item.add_hole(void.polygon_data)
|
|
1231
1203
|
self.create_polygon(item, layer_name=lay, voids=[], net_name=net)
|
|
1232
|
-
for
|
|
1233
|
-
for
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
for poly in delete_list:
|
|
1204
|
+
for void in all_voids:
|
|
1205
|
+
for poly in poly_by_nets[net]: # pragma no cover
|
|
1206
|
+
if void.polygon_data.intersection_type(poly.polygon_data).value >= 2:
|
|
1207
|
+
try:
|
|
1208
|
+
id = delete_list.index(poly)
|
|
1209
|
+
except ValueError:
|
|
1210
|
+
id = -1
|
|
1211
|
+
if id >= 0:
|
|
1212
|
+
delete_list.pop(id)
|
|
1213
|
+
for poly in list(set(delete_list)):
|
|
1243
1214
|
poly.delete()
|
|
1244
1215
|
|
|
1245
1216
|
if delete_padstack_gemometries:
|
|
@@ -1268,7 +1239,7 @@ class Modeler(object):
|
|
|
1268
1239
|
new_poly = poly.polygon_data.defeature(tol=tolerance)
|
|
1269
1240
|
if not new_poly.points:
|
|
1270
1241
|
self._pedb.logger.error(
|
|
1271
|
-
f"Defeaturing on polygon {poly.id} returned empty polygon, tolerance threshold
|
|
1242
|
+
f"Defeaturing on polygon {poly.id} returned empty polygon, tolerance threshold might too large. "
|
|
1272
1243
|
)
|
|
1273
1244
|
return False
|
|
1274
1245
|
poly.polygon_data = new_poly
|
|
@@ -1431,7 +1402,9 @@ class Modeler(object):
|
|
|
1431
1402
|
end_context=end_cell_inst,
|
|
1432
1403
|
start_context=start_cell_inst,
|
|
1433
1404
|
)
|
|
1434
|
-
|
|
1405
|
+
bondwire = Bondwire(self._pedb, bw)
|
|
1406
|
+
self._add_primitive(bondwire)
|
|
1407
|
+
return bondwire
|
|
1435
1408
|
|
|
1436
1409
|
def create_pin_group(
|
|
1437
1410
|
self,
|
|
@@ -1502,3 +1475,32 @@ class Modeler(object):
|
|
|
1502
1475
|
if net_obj:
|
|
1503
1476
|
obj.net = net_obj[0]
|
|
1504
1477
|
return self._pedb.siwave.pin_groups[name]
|
|
1478
|
+
|
|
1479
|
+
@staticmethod
|
|
1480
|
+
def add_void(shape: "Primitive", void_shape: Union["Primitive", List["Primitive"]]) -> bool:
|
|
1481
|
+
"""Add void to shape.
|
|
1482
|
+
|
|
1483
|
+
Parameters
|
|
1484
|
+
----------
|
|
1485
|
+
shape : :class:`pyedb.dotnet.database.edb_data.primitives_data.Primitive`
|
|
1486
|
+
Main shape.
|
|
1487
|
+
void_shape : list or :class:`pyedb.dotnet.database.edb_data.primitives_data.Primitive`
|
|
1488
|
+
Void shape(s).
|
|
1489
|
+
|
|
1490
|
+
Returns
|
|
1491
|
+
-------
|
|
1492
|
+
bool
|
|
1493
|
+
True if successful, False otherwise.
|
|
1494
|
+
"""
|
|
1495
|
+
if not isinstance(void_shape, list):
|
|
1496
|
+
void_shape = [void_shape]
|
|
1497
|
+
for void in void_shape:
|
|
1498
|
+
if isinstance(void, Primitive):
|
|
1499
|
+
shape._edb_object.add_void(void)
|
|
1500
|
+
flag = True
|
|
1501
|
+
else:
|
|
1502
|
+
shape._edb_object.add_void(void)
|
|
1503
|
+
flag = True
|
|
1504
|
+
if not flag:
|
|
1505
|
+
return flag
|
|
1506
|
+
return True
|