pyedb 0.56.0__py3-none-any.whl → 0.57.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_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/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 +14 -16
- pyedb/dotnet/database/dotnet/database.py +1 -0
- pyedb/dotnet/database/edb_data/control_file.py +6 -3
- pyedb/dotnet/database/edb_data/nets_data.py +3 -3
- pyedb/dotnet/database/edb_data/padstacks_data.py +5 -2
- 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/hfss.py +9 -8
- pyedb/dotnet/database/layout_validation.py +6 -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 +1 -1
- pyedb/dotnet/database/siwave.py +4 -3
- pyedb/dotnet/database/stackup.py +50 -26
- pyedb/dotnet/database/utilities/heatsink.py +0 -1
- 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 +5 -2
- pyedb/dotnet/edb.py +39 -34
- pyedb/exceptions.py +1 -2
- pyedb/extensions/create_cell_array.py +19 -5
- 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 +4 -5
- pyedb/generic/plot.py +2 -2
- pyedb/grpc/database/_typing.py +0 -0
- pyedb/grpc/database/components.py +7 -8
- pyedb/grpc/database/control_file.py +14 -35
- pyedb/grpc/database/definition/materials.py +1 -1
- pyedb/grpc/database/definition/package_def.py +6 -3
- pyedb/grpc/database/definition/padstack_def.py +4 -7
- pyedb/grpc/database/hfss.py +1 -4
- pyedb/grpc/database/hierarchy/component.py +3 -4
- 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 +226 -244
- 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 +5 -16
- pyedb/grpc/database/primitive/bondwire.py +3 -67
- pyedb/grpc/database/primitive/circle.py +42 -3
- pyedb/grpc/database/primitive/padstack_instance.py +17 -19
- pyedb/grpc/database/primitive/path.py +154 -5
- 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/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 +39 -56
- pyedb/grpc/database/stackup.py +50 -27
- pyedb/grpc/database/terminal/bundle_terminal.py +10 -3
- pyedb/grpc/database/terminal/pingroup_terminal.py +8 -1
- pyedb/grpc/database/terminal/terminal.py +19 -8
- 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 +6 -3
- pyedb/grpc/edb.py +24 -19
- 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/downloads.py +1 -0
- pyedb/misc/misc.py +5 -2
- pyedb/misc/siw_feature_config/emc_rule_checker_settings.py +1 -1
- pyedb/misc/utilities.py +0 -1
- pyedb/modeler/geometry_operators.py +3 -2
- {pyedb-0.56.0.dist-info → pyedb-0.57.0.dist-info}/METADATA +3 -3
- {pyedb-0.56.0.dist-info → pyedb-0.57.0.dist-info}/RECORD +99 -97
- {pyedb-0.56.0.dist-info → pyedb-0.57.0.dist-info}/WHEEL +0 -0
- {pyedb-0.56.0.dist-info → pyedb-0.57.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -224,8 +224,11 @@ class LayoutValidation:
|
|
|
224
224
|
if el.layout_obj.obj_type.value == 0:
|
|
225
225
|
if not el.is_void:
|
|
226
226
|
sum += el.area()
|
|
227
|
-
except:
|
|
228
|
-
|
|
227
|
+
except Exception as e:
|
|
228
|
+
self._pedb._logger.warning(
|
|
229
|
+
f"A(n) {type(e).__name__} error occurred while calculating area "
|
|
230
|
+
f"for element {elem} - Default value of 0 is used: {str(e)}"
|
|
231
|
+
)
|
|
229
232
|
return sum
|
|
230
233
|
|
|
231
234
|
if order_by_area:
|
pyedb/grpc/database/modeler.py
CHANGED
|
@@ -23,20 +23,20 @@
|
|
|
23
23
|
"""
|
|
24
24
|
This module contains these classes: `EdbLayout` and `Shape`.
|
|
25
25
|
"""
|
|
26
|
+
|
|
26
27
|
import math
|
|
27
28
|
from typing import Any, Dict, List, Optional, Union
|
|
28
29
|
|
|
29
30
|
from ansys.edb.core.geometry.arc_data import ArcData as GrpcArcData
|
|
30
31
|
from ansys.edb.core.geometry.point_data import PointData as GrpcPointData
|
|
31
32
|
from ansys.edb.core.geometry.polygon_data import (
|
|
33
|
+
PolygonData as GrpcPolygonData,
|
|
32
34
|
PolygonSenseType as GrpcPolygonSenseType,
|
|
33
35
|
)
|
|
34
|
-
from ansys.edb.core.geometry.polygon_data import PolygonData as GrpcPolygonData
|
|
35
36
|
from ansys.edb.core.hierarchy.pin_group import PinGroup as GrpcPinGroup
|
|
36
37
|
from ansys.edb.core.inner.exceptions import InvalidArgumentException
|
|
37
38
|
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
|
|
39
|
+
from ansys.edb.core.primitive.path import PathCornerType as GrpcPathCornerType, PathEndCapType as GrpcPathEndCapType
|
|
40
40
|
from ansys.edb.core.primitive.rectangle import (
|
|
41
41
|
RectangleRepresentationType as GrpcRectangleRepresentationType,
|
|
42
42
|
)
|
|
@@ -61,7 +61,7 @@ class Modeler(object):
|
|
|
61
61
|
>>> edb_layout = edbapp.modeler
|
|
62
62
|
"""
|
|
63
63
|
|
|
64
|
-
def __getitem__(self, name: Union[str, int]) ->
|
|
64
|
+
def __getitem__(self, name: Union[str, int]) -> Primitive:
|
|
65
65
|
"""Get a primitive by name or ID.
|
|
66
66
|
|
|
67
67
|
Parameters
|
|
@@ -71,7 +71,7 @@ class Modeler(object):
|
|
|
71
71
|
|
|
72
72
|
Returns
|
|
73
73
|
-------
|
|
74
|
-
:class:`pyedb.
|
|
74
|
+
:class:`pyedb.grpc.database.primitive.primitive.Primitive`
|
|
75
75
|
Primitive instance if found, None otherwise.
|
|
76
76
|
|
|
77
77
|
Raises
|
|
@@ -79,21 +79,151 @@ class Modeler(object):
|
|
|
79
79
|
TypeError
|
|
80
80
|
If name is not str or int.
|
|
81
81
|
"""
|
|
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
|
|
82
|
+
|
|
83
|
+
if isinstance(name, int):
|
|
84
|
+
return self._primitives.get(name)
|
|
85
|
+
return self.primitives_by_name.get(name)
|
|
91
86
|
|
|
92
87
|
def __init__(self, p_edb) -> None:
|
|
93
88
|
"""Initialize Modeler instance."""
|
|
94
89
|
self._pedb = p_edb
|
|
95
|
-
|
|
96
|
-
self.
|
|
90
|
+
# Core cache
|
|
91
|
+
self._primitives: dict[str, Primitive] = {}
|
|
92
|
+
|
|
93
|
+
# Lazy indexes
|
|
94
|
+
self._primitives_by_name: dict[str, Primitive] | None = None
|
|
95
|
+
self._primitives_by_net: dict[str, list[Primitive]] | None = None
|
|
96
|
+
self._primitives_by_layer: dict[str, list[Primitive]] | None = None
|
|
97
|
+
self._primitives_by_layer_and_net: Dict[str, Dict[str, List[Primitive]]] | None = None
|
|
98
|
+
|
|
99
|
+
# ============================================================
|
|
100
|
+
|
|
101
|
+
# Cache management
|
|
102
|
+
# ============================================================
|
|
103
|
+
|
|
104
|
+
def _reload_all(self):
|
|
105
|
+
"""Force reload of all primitives and reset indexes."""
|
|
106
|
+
self._primitives = {p.edb_uid: p for p in self._pedb.layout.primitives}
|
|
107
|
+
self._primitives_by_name = None
|
|
108
|
+
self._primitives_by_net = None
|
|
109
|
+
self._primitives_by_layer = None
|
|
110
|
+
self._primitives_by_layer_and_net = None
|
|
111
|
+
|
|
112
|
+
def _add_primitive(self, prim: Any):
|
|
113
|
+
"""Add primitive wrapper to caches."""
|
|
114
|
+
self._primitives[prim.edb_uid] = prim
|
|
115
|
+
if self._primitives_by_name is not None:
|
|
116
|
+
self._primitives_by_name[prim.aedt_name] = prim
|
|
117
|
+
if self._primitives_by_net is not None and hasattr(prim, "net"):
|
|
118
|
+
self._primitives_by_net.setdefault(prim.net, []).append(prim)
|
|
119
|
+
if hasattr(prim, "layer"):
|
|
120
|
+
if self._primitives_by_layer is not None and prim.layer_name:
|
|
121
|
+
self._primitives_by_layer.setdefault(prim.layer_name, []).append(prim)
|
|
122
|
+
|
|
123
|
+
def _remove_primitive(self, prim: Primitive):
|
|
124
|
+
"""Remove primitive wrapper from all caches efficiently and safely."""
|
|
125
|
+
uid = prim.edb_uid
|
|
126
|
+
|
|
127
|
+
# 1. Remove from primary cache
|
|
128
|
+
self._primitives.pop(uid, None)
|
|
129
|
+
|
|
130
|
+
# 2. Remove from name cache if initialized
|
|
131
|
+
if self._primitives_by_name is not None:
|
|
132
|
+
self._primitives_by_name.pop(prim.aedt_name, None)
|
|
133
|
+
|
|
134
|
+
# 3. Remove from net cache if initialized
|
|
135
|
+
if self._primitives_by_net is not None and hasattr(prim, "net") and not prim.net.is_null:
|
|
136
|
+
net_name = prim.net.name
|
|
137
|
+
net_prims = self._primitives_by_net.get(net_name)
|
|
138
|
+
if net_prims:
|
|
139
|
+
try:
|
|
140
|
+
net_prims.remove(prim)
|
|
141
|
+
except ValueError:
|
|
142
|
+
pass # Not found, skip
|
|
143
|
+
if not net_prims:
|
|
144
|
+
self._primitives_by_net.pop(net_name, None)
|
|
145
|
+
|
|
146
|
+
# 4. Remove from layer cache if initialized
|
|
147
|
+
if self._primitives_by_layer is not None and hasattr(prim, "layer") and prim.layer_name:
|
|
148
|
+
layer_name = prim.layer.name
|
|
149
|
+
layer_prims = self._primitives_by_layer.get(layer_name)
|
|
150
|
+
if layer_prims:
|
|
151
|
+
try:
|
|
152
|
+
layer_prims.remove(prim)
|
|
153
|
+
except ValueError:
|
|
154
|
+
pass
|
|
155
|
+
if not layer_prims:
|
|
156
|
+
self._primitives_by_layer.pop(layer_name, None)
|
|
157
|
+
|
|
158
|
+
# 5. Remove from layer+net cache if initialized
|
|
159
|
+
if self._primitives_by_layer_and_net is not None:
|
|
160
|
+
if hasattr(prim, "layer") and hasattr(prim, "net") and not prim.net.is_null:
|
|
161
|
+
layer_name = prim.layer.name
|
|
162
|
+
net_name = prim.net.name
|
|
163
|
+
layer_dict = self._primitives_by_layer_and_net.get(layer_name)
|
|
164
|
+
if layer_dict:
|
|
165
|
+
net_list = layer_dict.get(net_name)
|
|
166
|
+
if net_list:
|
|
167
|
+
try:
|
|
168
|
+
net_list.remove(prim)
|
|
169
|
+
except ValueError:
|
|
170
|
+
pass
|
|
171
|
+
if not net_list:
|
|
172
|
+
layer_dict.pop(net_name, None)
|
|
173
|
+
if not layer_dict:
|
|
174
|
+
self._primitives_by_layer_and_net.pop(layer_name, None)
|
|
175
|
+
|
|
176
|
+
@property
|
|
177
|
+
def primitives(self) -> list[Primitive]:
|
|
178
|
+
if not self._primitives:
|
|
179
|
+
self._reload_all()
|
|
180
|
+
return list(self._primitives.values())
|
|
181
|
+
|
|
182
|
+
@property
|
|
183
|
+
def primitives_by_name(self):
|
|
184
|
+
if self._primitives_by_name is None:
|
|
185
|
+
self._primitives_by_name = {p.aedt_name: p for p in self.primitives}
|
|
186
|
+
return self._primitives_by_name
|
|
187
|
+
|
|
188
|
+
@property
|
|
189
|
+
def primitives_by_net(self):
|
|
190
|
+
if self._primitives_by_net is None:
|
|
191
|
+
d = {}
|
|
192
|
+
for p in self.primitives:
|
|
193
|
+
if hasattr(p, "net"):
|
|
194
|
+
d.setdefault(p.net.name, []).append(p)
|
|
195
|
+
self._primitives_by_net = d
|
|
196
|
+
return self._primitives_by_net
|
|
197
|
+
|
|
198
|
+
@property
|
|
199
|
+
def primitives_by_layer(self):
|
|
200
|
+
if self._primitives_by_layer is None:
|
|
201
|
+
d = {}
|
|
202
|
+
for p in self.primitives:
|
|
203
|
+
if p.layer_name:
|
|
204
|
+
d.setdefault(p.layer_name, []).append(p)
|
|
205
|
+
self._primitives_by_layer = d
|
|
206
|
+
return self._primitives_by_layer
|
|
207
|
+
|
|
208
|
+
@property
|
|
209
|
+
def primitives_by_layer_and_net(self) -> Dict[str, Dict[str, List[Primitive]]]:
|
|
210
|
+
"""Return all primitives indexed first by layer, then by net.
|
|
211
|
+
|
|
212
|
+
Returns
|
|
213
|
+
-------
|
|
214
|
+
dict
|
|
215
|
+
Nested dictionary: layer -> net -> list[Primitive]
|
|
216
|
+
"""
|
|
217
|
+
if self._primitives_by_layer_and_net is None:
|
|
218
|
+
idx: Dict[str, Dict[str, List[Primitive]]] = {}
|
|
219
|
+
for prim in self.primitives:
|
|
220
|
+
if not prim.layer_name or not hasattr(prim, "net") or prim.net.is_null:
|
|
221
|
+
continue
|
|
222
|
+
layer = prim.layer_name
|
|
223
|
+
net = prim.net.name
|
|
224
|
+
idx.setdefault(layer, {}).setdefault(net, []).append(prim)
|
|
225
|
+
self._primitives_by_layer_and_net = idx
|
|
226
|
+
return self._primitives_by_layer_and_net
|
|
97
227
|
|
|
98
228
|
@property
|
|
99
229
|
def _edb(self) -> Any:
|
|
@@ -211,17 +341,6 @@ class Modeler(object):
|
|
|
211
341
|
else:
|
|
212
342
|
return False
|
|
213
343
|
|
|
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
344
|
@property
|
|
226
345
|
def polygons_by_layer(self) -> Dict[str, List[Primitive]]:
|
|
227
346
|
"""Primitives organized by layer names.
|
|
@@ -231,47 +350,13 @@ class Modeler(object):
|
|
|
231
350
|
dict
|
|
232
351
|
Dictionary where keys are layer names and values are lists of polygons.
|
|
233
352
|
"""
|
|
234
|
-
|
|
235
|
-
for lay in self.layers:
|
|
236
|
-
_primitives_by_layer[lay] = self.get_polygons_by_layer(lay)
|
|
237
|
-
return _primitives_by_layer
|
|
238
|
-
|
|
239
|
-
@property
|
|
240
|
-
def primitives_by_net(self) -> Dict[str, List[Primitive]]:
|
|
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 = {}
|
|
353
|
+
polygon_by_layer = {}
|
|
263
354
|
for lay in self.layers:
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
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
|
|
355
|
+
if lay in self.primitives_by_layer:
|
|
356
|
+
polygon_by_layer[lay] = [prim for prim in self.primitives_by_layer[lay] if prim.type == "polygon"]
|
|
357
|
+
else:
|
|
358
|
+
polygon_by_layer[lay] = []
|
|
359
|
+
return polygon_by_layer
|
|
275
360
|
|
|
276
361
|
@property
|
|
277
362
|
def rectangles(self) -> List[Rectangle]:
|
|
@@ -332,15 +417,10 @@ class Modeler(object):
|
|
|
332
417
|
list
|
|
333
418
|
List of polygon objects.
|
|
334
419
|
"""
|
|
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
|
|
420
|
+
polygons = self.polygons_by_layer.get(layer_name, [])
|
|
421
|
+
if net_list:
|
|
422
|
+
polygons = [p for p in polygons if p.net_name in net_list]
|
|
423
|
+
return polygons
|
|
344
424
|
|
|
345
425
|
def get_primitive_by_layer_and_point(
|
|
346
426
|
self,
|
|
@@ -617,7 +697,7 @@ class Modeler(object):
|
|
|
617
697
|
polygon_data = points
|
|
618
698
|
else:
|
|
619
699
|
raise TypeError("Points must be a list of points or a PolygonData object.")
|
|
620
|
-
path = Path.create(
|
|
700
|
+
path = Path(self._pedb).create(
|
|
621
701
|
layout=self._active_layout,
|
|
622
702
|
layer=layer_name,
|
|
623
703
|
net=net,
|
|
@@ -676,7 +756,7 @@ class Modeler(object):
|
|
|
676
756
|
end_cap_style=end_cap_style,
|
|
677
757
|
corner_style=corner_style,
|
|
678
758
|
)
|
|
679
|
-
|
|
759
|
+
self._add_primitive(primitive) # update cache
|
|
680
760
|
return primitive
|
|
681
761
|
|
|
682
762
|
def create_polygon(
|
|
@@ -729,10 +809,13 @@ class Modeler(object):
|
|
|
729
809
|
self._logger.error("Failed to create void polygon data")
|
|
730
810
|
return False
|
|
731
811
|
polygon_data.holes.append(void_polygon_data)
|
|
732
|
-
polygon = Polygon
|
|
812
|
+
polygon = Polygon(self._pedb, None).create(
|
|
813
|
+
layout=self._active_layout, layer=layer_name, net=net, polygon_data=polygon_data
|
|
814
|
+
)
|
|
733
815
|
if polygon.is_null or polygon_data is False: # pragma: no cover
|
|
734
816
|
self._logger.error("Null polygon created")
|
|
735
817
|
return False
|
|
818
|
+
self._add_primitive(polygon)
|
|
736
819
|
return Polygon(self._pedb, polygon)
|
|
737
820
|
|
|
738
821
|
def create_rectangle(
|
|
@@ -780,12 +863,11 @@ class Modeler(object):
|
|
|
780
863
|
"""
|
|
781
864
|
edb_net = self._pedb.nets.find_or_create_net(net_name)
|
|
782
865
|
if representation_type == "lower_left_upper_right":
|
|
783
|
-
|
|
784
|
-
rect = Rectangle.create(
|
|
866
|
+
rect = Rectangle(self._pedb).create(
|
|
785
867
|
layout=self._active_layout,
|
|
786
868
|
layer=layer_name,
|
|
787
869
|
net=edb_net,
|
|
788
|
-
rep_type=
|
|
870
|
+
rep_type=representation_type,
|
|
789
871
|
param1=Value(lower_left_point[0]),
|
|
790
872
|
param2=Value(lower_left_point[1]),
|
|
791
873
|
param3=Value(upper_right_point[0]),
|
|
@@ -809,7 +891,7 @@ class Modeler(object):
|
|
|
809
891
|
height = Value(width)
|
|
810
892
|
else:
|
|
811
893
|
height = Value(width)
|
|
812
|
-
rect = Rectangle.create(
|
|
894
|
+
rect = Rectangle(self._pedb).create(
|
|
813
895
|
layout=self._active_layout,
|
|
814
896
|
layer=layer_name,
|
|
815
897
|
net=edb_net,
|
|
@@ -822,7 +904,8 @@ class Modeler(object):
|
|
|
822
904
|
rotation=Value(rotation),
|
|
823
905
|
)
|
|
824
906
|
if not rect.is_null:
|
|
825
|
-
|
|
907
|
+
self._add_primitive(rect)
|
|
908
|
+
return rect
|
|
826
909
|
return False
|
|
827
910
|
|
|
828
911
|
def create_circle(
|
|
@@ -850,7 +933,7 @@ class Modeler(object):
|
|
|
850
933
|
"""
|
|
851
934
|
edb_net = self._pedb.nets.find_or_create_net(net_name)
|
|
852
935
|
|
|
853
|
-
circle = Circle.create(
|
|
936
|
+
circle = Circle(self._pedb).create(
|
|
854
937
|
layout=self._active_layout,
|
|
855
938
|
layer=layer_name,
|
|
856
939
|
net=edb_net,
|
|
@@ -859,7 +942,8 @@ class Modeler(object):
|
|
|
859
942
|
radius=Value(radius),
|
|
860
943
|
)
|
|
861
944
|
if not circle.is_null:
|
|
862
|
-
|
|
945
|
+
self._add_primitive(circle)
|
|
946
|
+
return circle
|
|
863
947
|
return False
|
|
864
948
|
|
|
865
949
|
def delete_primitives(self, net_names: Union[str, List[str]]) -> bool:
|
|
@@ -952,120 +1036,6 @@ class Modeler(object):
|
|
|
952
1036
|
void_circle.delete()
|
|
953
1037
|
return True
|
|
954
1038
|
|
|
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
1039
|
def _validatePoint(self, point, allowArcs=True):
|
|
1070
1040
|
if len(point) == 2:
|
|
1071
1041
|
if not isinstance(point[0], (int, float, str)):
|
|
@@ -1113,17 +1083,6 @@ class Modeler(object):
|
|
|
1113
1083
|
self._logger.error("Arc point descriptor has incorrect number of elements (%s)", len(point))
|
|
1114
1084
|
return False
|
|
1115
1085
|
|
|
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
1086
|
def parametrize_trace_width(
|
|
1128
1087
|
self,
|
|
1129
1088
|
nets_name: Union[str, List[str]],
|
|
@@ -1207,39 +1166,31 @@ class Modeler(object):
|
|
|
1207
1166
|
all_voids = []
|
|
1208
1167
|
list_polygon_data = []
|
|
1209
1168
|
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:
|
|
1169
|
+
for poly in self.polygons_by_layer.get(lay, []):
|
|
1170
|
+
if poly.net_name:
|
|
1171
|
+
poly_by_nets.setdefault(poly.net_name, []).append(poly)
|
|
1172
|
+
for net, polys in poly_by_nets.items():
|
|
1220
1173
|
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)
|
|
1174
|
+
for p in polys:
|
|
1175
|
+
list_polygon_data.append(p.polygon_data)
|
|
1176
|
+
delete_list.append(p)
|
|
1177
|
+
all_voids.extend(p.voids)
|
|
1178
|
+
united = GrpcPolygonData.unite(list_polygon_data)
|
|
1179
|
+
for item in united:
|
|
1180
|
+
for void in all_voids:
|
|
1181
|
+
if item.intersection_type(void.polygon_data) == 2:
|
|
1182
|
+
item.add_hole(void.polygon_data)
|
|
1231
1183
|
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:
|
|
1184
|
+
for void in all_voids:
|
|
1185
|
+
for poly in poly_by_nets[net]: # pragma no cover
|
|
1186
|
+
if void.polygon_data.intersection_type(poly.polygon_data).value >= 2:
|
|
1187
|
+
try:
|
|
1188
|
+
id = delete_list.index(poly)
|
|
1189
|
+
except ValueError:
|
|
1190
|
+
id = -1
|
|
1191
|
+
if id >= 0:
|
|
1192
|
+
delete_list.pop(id)
|
|
1193
|
+
for poly in list(set(delete_list)):
|
|
1243
1194
|
poly.delete()
|
|
1244
1195
|
|
|
1245
1196
|
if delete_padstack_gemometries:
|
|
@@ -1268,7 +1219,7 @@ class Modeler(object):
|
|
|
1268
1219
|
new_poly = poly.polygon_data.defeature(tol=tolerance)
|
|
1269
1220
|
if not new_poly.points:
|
|
1270
1221
|
self._pedb.logger.error(
|
|
1271
|
-
f"Defeaturing on polygon {poly.id} returned empty polygon, tolerance threshold
|
|
1222
|
+
f"Defeaturing on polygon {poly.id} returned empty polygon, tolerance threshold might too large. "
|
|
1272
1223
|
)
|
|
1273
1224
|
return False
|
|
1274
1225
|
poly.polygon_data = new_poly
|
|
@@ -1431,7 +1382,9 @@ class Modeler(object):
|
|
|
1431
1382
|
end_context=end_cell_inst,
|
|
1432
1383
|
start_context=start_cell_inst,
|
|
1433
1384
|
)
|
|
1434
|
-
|
|
1385
|
+
bondwire = Bondwire(self._pedb, bw)
|
|
1386
|
+
self._add_primitive(bondwire)
|
|
1387
|
+
return bondwire
|
|
1435
1388
|
|
|
1436
1389
|
def create_pin_group(
|
|
1437
1390
|
self,
|
|
@@ -1502,3 +1455,32 @@ class Modeler(object):
|
|
|
1502
1455
|
if net_obj:
|
|
1503
1456
|
obj.net = net_obj[0]
|
|
1504
1457
|
return self._pedb.siwave.pin_groups[name]
|
|
1458
|
+
|
|
1459
|
+
@staticmethod
|
|
1460
|
+
def add_void(shape: "Primitive", void_shape: Union["Primitive", List["Primitive"]]) -> bool:
|
|
1461
|
+
"""Add void to shape.
|
|
1462
|
+
|
|
1463
|
+
Parameters
|
|
1464
|
+
----------
|
|
1465
|
+
shape : :class:`pyedb.dotnet.database.edb_data.primitives_data.Primitive`
|
|
1466
|
+
Main shape.
|
|
1467
|
+
void_shape : list or :class:`pyedb.dotnet.database.edb_data.primitives_data.Primitive`
|
|
1468
|
+
Void shape(s).
|
|
1469
|
+
|
|
1470
|
+
Returns
|
|
1471
|
+
-------
|
|
1472
|
+
bool
|
|
1473
|
+
True if successful, False otherwise.
|
|
1474
|
+
"""
|
|
1475
|
+
if not isinstance(void_shape, list):
|
|
1476
|
+
void_shape = [void_shape]
|
|
1477
|
+
for void in void_shape:
|
|
1478
|
+
if isinstance(void, Primitive):
|
|
1479
|
+
shape._edb_object.add_void(void)
|
|
1480
|
+
flag = True
|
|
1481
|
+
else:
|
|
1482
|
+
shape._edb_object.add_void(void)
|
|
1483
|
+
flag = True
|
|
1484
|
+
if not flag:
|
|
1485
|
+
return flag
|
|
1486
|
+
return True
|
|
@@ -20,15 +20,18 @@
|
|
|
20
20
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
21
|
# SOFTWARE.
|
|
22
22
|
|
|
23
|
+
from __future__ import annotations
|
|
23
24
|
|
|
25
|
+
from typing import TYPE_CHECKING
|
|
26
|
+
|
|
27
|
+
if TYPE_CHECKING:
|
|
28
|
+
from pyedb.grpc.database.net.net import Net
|
|
24
29
|
import re
|
|
25
30
|
|
|
26
31
|
from ansys.edb.core.net.differential_pair import (
|
|
27
32
|
DifferentialPair as GrpcDifferentialPair,
|
|
28
33
|
)
|
|
29
34
|
|
|
30
|
-
from pyedb.grpc.database.net.net import Net
|
|
31
|
-
|
|
32
35
|
|
|
33
36
|
class DifferentialPairs:
|
|
34
37
|
def __init__(self, pedb):
|
|
@@ -131,9 +134,13 @@ class DifferentialPair(GrpcDifferentialPair):
|
|
|
131
134
|
@property
|
|
132
135
|
def positive_net(self) -> Net:
|
|
133
136
|
"""Positive Net."""
|
|
137
|
+
from pyedb.grpc.database.net.net import Net
|
|
138
|
+
|
|
134
139
|
return Net(self._pedb, super().positive_net)
|
|
135
140
|
|
|
136
141
|
@property
|
|
137
142
|
def negative_net(self) -> Net:
|
|
138
143
|
"""Negative Net."""
|
|
144
|
+
from pyedb.grpc.database.net.net import Net
|
|
145
|
+
|
|
139
146
|
return Net(self._pedb, super().negative_net)
|