pyedb 0.2.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 +17 -0
- pyedb/dotnet/__init__.py +0 -0
- pyedb/dotnet/application/Variables.py +2261 -0
- pyedb/dotnet/application/__init__.py +0 -0
- pyedb/dotnet/clr_module.py +103 -0
- pyedb/dotnet/edb.py +4237 -0
- pyedb/dotnet/edb_core/__init__.py +1 -0
- pyedb/dotnet/edb_core/cell/__init__.py +0 -0
- pyedb/dotnet/edb_core/cell/hierarchy/__init__.py +0 -0
- pyedb/dotnet/edb_core/cell/hierarchy/model.py +66 -0
- pyedb/dotnet/edb_core/components.py +2669 -0
- pyedb/dotnet/edb_core/configuration.py +423 -0
- pyedb/dotnet/edb_core/definition/__init__.py +0 -0
- pyedb/dotnet/edb_core/definition/component_def.py +166 -0
- pyedb/dotnet/edb_core/definition/component_model.py +30 -0
- pyedb/dotnet/edb_core/definition/definition_obj.py +18 -0
- pyedb/dotnet/edb_core/definition/definitions.py +12 -0
- pyedb/dotnet/edb_core/dotnet/__init__.py +0 -0
- pyedb/dotnet/edb_core/dotnet/database.py +1218 -0
- pyedb/dotnet/edb_core/dotnet/layout.py +238 -0
- pyedb/dotnet/edb_core/dotnet/primitive.py +1517 -0
- pyedb/dotnet/edb_core/edb_data/__init__.py +0 -0
- pyedb/dotnet/edb_core/edb_data/components_data.py +938 -0
- pyedb/dotnet/edb_core/edb_data/connectable.py +113 -0
- pyedb/dotnet/edb_core/edb_data/control_file.py +1268 -0
- pyedb/dotnet/edb_core/edb_data/design_options.py +35 -0
- pyedb/dotnet/edb_core/edb_data/edbvalue.py +45 -0
- pyedb/dotnet/edb_core/edb_data/hfss_extent_info.py +330 -0
- pyedb/dotnet/edb_core/edb_data/hfss_simulation_setup_data.py +1607 -0
- pyedb/dotnet/edb_core/edb_data/layer_data.py +576 -0
- pyedb/dotnet/edb_core/edb_data/nets_data.py +281 -0
- pyedb/dotnet/edb_core/edb_data/obj_base.py +19 -0
- pyedb/dotnet/edb_core/edb_data/padstacks_data.py +2080 -0
- pyedb/dotnet/edb_core/edb_data/ports.py +287 -0
- pyedb/dotnet/edb_core/edb_data/primitives_data.py +1397 -0
- pyedb/dotnet/edb_core/edb_data/simulation_configuration.py +2914 -0
- pyedb/dotnet/edb_core/edb_data/simulation_setup.py +716 -0
- pyedb/dotnet/edb_core/edb_data/siwave_simulation_setup_data.py +1205 -0
- pyedb/dotnet/edb_core/edb_data/sources.py +514 -0
- pyedb/dotnet/edb_core/edb_data/terminals.py +632 -0
- pyedb/dotnet/edb_core/edb_data/utilities.py +148 -0
- pyedb/dotnet/edb_core/edb_data/variables.py +91 -0
- pyedb/dotnet/edb_core/general.py +181 -0
- pyedb/dotnet/edb_core/hfss.py +1646 -0
- pyedb/dotnet/edb_core/layout.py +1244 -0
- pyedb/dotnet/edb_core/layout_validation.py +272 -0
- pyedb/dotnet/edb_core/materials.py +939 -0
- pyedb/dotnet/edb_core/net_class.py +335 -0
- pyedb/dotnet/edb_core/nets.py +1215 -0
- pyedb/dotnet/edb_core/padstack.py +1389 -0
- pyedb/dotnet/edb_core/siwave.py +1427 -0
- pyedb/dotnet/edb_core/stackup.py +2703 -0
- pyedb/edb_logger.py +396 -0
- pyedb/generic/__init__.py +0 -0
- pyedb/generic/constants.py +1063 -0
- pyedb/generic/data_handlers.py +320 -0
- pyedb/generic/design_types.py +104 -0
- pyedb/generic/filesystem.py +150 -0
- pyedb/generic/general_methods.py +1535 -0
- pyedb/generic/plot.py +1840 -0
- pyedb/generic/process.py +285 -0
- pyedb/generic/settings.py +224 -0
- pyedb/ipc2581/__init__.py +0 -0
- pyedb/ipc2581/bom/__init__.py +0 -0
- pyedb/ipc2581/bom/bom.py +21 -0
- pyedb/ipc2581/bom/bom_item.py +32 -0
- pyedb/ipc2581/bom/characteristics.py +37 -0
- pyedb/ipc2581/bom/refdes.py +16 -0
- pyedb/ipc2581/content/__init__.py +0 -0
- pyedb/ipc2581/content/color.py +38 -0
- pyedb/ipc2581/content/content.py +55 -0
- pyedb/ipc2581/content/dictionary_color.py +29 -0
- pyedb/ipc2581/content/dictionary_fill.py +28 -0
- pyedb/ipc2581/content/dictionary_line.py +30 -0
- pyedb/ipc2581/content/entry_color.py +13 -0
- pyedb/ipc2581/content/entry_line.py +14 -0
- pyedb/ipc2581/content/fill.py +15 -0
- pyedb/ipc2581/content/layer_ref.py +10 -0
- pyedb/ipc2581/content/standard_geometries_dictionary.py +72 -0
- pyedb/ipc2581/ecad/__init__.py +0 -0
- pyedb/ipc2581/ecad/cad_data/__init__.py +0 -0
- pyedb/ipc2581/ecad/cad_data/assembly_drawing.py +26 -0
- pyedb/ipc2581/ecad/cad_data/cad_data.py +37 -0
- pyedb/ipc2581/ecad/cad_data/component.py +41 -0
- pyedb/ipc2581/ecad/cad_data/drill.py +30 -0
- pyedb/ipc2581/ecad/cad_data/feature.py +54 -0
- pyedb/ipc2581/ecad/cad_data/layer.py +41 -0
- pyedb/ipc2581/ecad/cad_data/layer_feature.py +151 -0
- pyedb/ipc2581/ecad/cad_data/logical_net.py +32 -0
- pyedb/ipc2581/ecad/cad_data/outline.py +25 -0
- pyedb/ipc2581/ecad/cad_data/package.py +104 -0
- pyedb/ipc2581/ecad/cad_data/padstack_def.py +38 -0
- pyedb/ipc2581/ecad/cad_data/padstack_hole_def.py +24 -0
- pyedb/ipc2581/ecad/cad_data/padstack_instance.py +62 -0
- pyedb/ipc2581/ecad/cad_data/padstack_pad_def.py +26 -0
- pyedb/ipc2581/ecad/cad_data/path.py +89 -0
- pyedb/ipc2581/ecad/cad_data/phy_net.py +80 -0
- pyedb/ipc2581/ecad/cad_data/pin.py +31 -0
- pyedb/ipc2581/ecad/cad_data/polygon.py +169 -0
- pyedb/ipc2581/ecad/cad_data/profile.py +40 -0
- pyedb/ipc2581/ecad/cad_data/stackup.py +31 -0
- pyedb/ipc2581/ecad/cad_data/stackup_group.py +42 -0
- pyedb/ipc2581/ecad/cad_data/stackup_layer.py +21 -0
- pyedb/ipc2581/ecad/cad_data/step.py +275 -0
- pyedb/ipc2581/ecad/cad_header.py +33 -0
- pyedb/ipc2581/ecad/ecad.py +19 -0
- pyedb/ipc2581/ecad/spec.py +46 -0
- pyedb/ipc2581/history_record.py +37 -0
- pyedb/ipc2581/ipc2581.py +387 -0
- pyedb/ipc2581/logistic_header.py +25 -0
- pyedb/misc/__init__.py +0 -0
- pyedb/misc/aedtlib_personalib_install.py +14 -0
- pyedb/misc/downloads.py +322 -0
- pyedb/misc/misc.py +67 -0
- pyedb/misc/pyedb.runtimeconfig.json +13 -0
- pyedb/misc/siw_feature_config/__init__.py +0 -0
- pyedb/misc/siw_feature_config/emc/__init__.py +0 -0
- pyedb/misc/siw_feature_config/emc/component_tags.py +46 -0
- pyedb/misc/siw_feature_config/emc/net_tags.py +37 -0
- pyedb/misc/siw_feature_config/emc/tag_library.py +62 -0
- pyedb/misc/siw_feature_config/emc/xml_generic.py +78 -0
- pyedb/misc/siw_feature_config/emc_rule_checker_settings.py +179 -0
- pyedb/misc/utilities.py +27 -0
- pyedb/modeler/geometry_operators.py +2082 -0
- pyedb-0.2.0.dist-info/LICENSE +21 -0
- pyedb-0.2.0.dist-info/METADATA +208 -0
- pyedb-0.2.0.dist-info/RECORD +128 -0
- pyedb-0.2.0.dist-info/WHEEL +4 -0
|
@@ -0,0 +1,1244 @@
|
|
|
1
|
+
"""
|
|
2
|
+
This module contains these classes: `EdbLayout` and `Shape`.
|
|
3
|
+
"""
|
|
4
|
+
import math
|
|
5
|
+
import warnings
|
|
6
|
+
|
|
7
|
+
from pyedb.dotnet.edb_core.dotnet.primitive import (
|
|
8
|
+
BondwireDotNet,
|
|
9
|
+
CircleDotNet,
|
|
10
|
+
PathDotNet,
|
|
11
|
+
PolygonDotNet,
|
|
12
|
+
RectangleDotNet,
|
|
13
|
+
)
|
|
14
|
+
from pyedb.dotnet.edb_core.edb_data.primitives_data import EDBPrimitives, cast
|
|
15
|
+
from pyedb.dotnet.edb_core.edb_data.utilities import EDBStatistics
|
|
16
|
+
from pyedb.dotnet.edb_core.general import convert_py_list_to_net_list
|
|
17
|
+
from pyedb.generic.general_methods import pyedb_function_handler
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class EdbLayout(object):
|
|
21
|
+
"""Manages EDB methods for primitives management accessible from `Edb.modeler` property.
|
|
22
|
+
|
|
23
|
+
Examples
|
|
24
|
+
--------
|
|
25
|
+
>>> from pyedb import Edb
|
|
26
|
+
>>> edbapp = Edb("myaedbfolder", edbversion="2021.2")
|
|
27
|
+
>>> edb_layout = edbapp.modeler
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
def __init__(self, p_edb):
|
|
31
|
+
self._pedb = p_edb
|
|
32
|
+
|
|
33
|
+
@property
|
|
34
|
+
def _edb(self):
|
|
35
|
+
return self._pedb.edb_api
|
|
36
|
+
|
|
37
|
+
def _get_edb_value(self, value):
|
|
38
|
+
return self._pedb.edb_value(value)
|
|
39
|
+
|
|
40
|
+
@property
|
|
41
|
+
def _logger(self):
|
|
42
|
+
"""Logger."""
|
|
43
|
+
return self._pedb.logger
|
|
44
|
+
|
|
45
|
+
@property
|
|
46
|
+
def _edbutils(self):
|
|
47
|
+
return self._pedb.edbutils
|
|
48
|
+
|
|
49
|
+
@property
|
|
50
|
+
def _active_layout(self):
|
|
51
|
+
return self._pedb.active_layout
|
|
52
|
+
|
|
53
|
+
@property
|
|
54
|
+
def _layout(self):
|
|
55
|
+
return self._pedb.layout
|
|
56
|
+
|
|
57
|
+
@property
|
|
58
|
+
def _cell(self):
|
|
59
|
+
return self._pedb.active_cell
|
|
60
|
+
|
|
61
|
+
@property
|
|
62
|
+
def db(self):
|
|
63
|
+
"""Db object."""
|
|
64
|
+
return self._pedb.active_db
|
|
65
|
+
|
|
66
|
+
@property
|
|
67
|
+
def layers(self):
|
|
68
|
+
"""Dictionary of layers.
|
|
69
|
+
|
|
70
|
+
Returns
|
|
71
|
+
-------
|
|
72
|
+
dict
|
|
73
|
+
Dictionary of layers.
|
|
74
|
+
"""
|
|
75
|
+
return self._pedb.stackup.layers
|
|
76
|
+
|
|
77
|
+
@property
|
|
78
|
+
def primitives(self):
|
|
79
|
+
"""Primitives.
|
|
80
|
+
|
|
81
|
+
Returns
|
|
82
|
+
-------
|
|
83
|
+
list of :class:`pyedb.dotnet.edb_core.edb_data.primitives_data.EDBPrimitives`
|
|
84
|
+
List of primitives.
|
|
85
|
+
"""
|
|
86
|
+
_prims = []
|
|
87
|
+
if self._active_layout:
|
|
88
|
+
for lay_obj in self._layout.primitives:
|
|
89
|
+
_prims.append(cast(lay_obj, self._pedb))
|
|
90
|
+
return _prims
|
|
91
|
+
|
|
92
|
+
@property
|
|
93
|
+
def polygons_by_layer(self):
|
|
94
|
+
"""Primitives with layer names as keys.
|
|
95
|
+
|
|
96
|
+
Returns
|
|
97
|
+
-------
|
|
98
|
+
dict
|
|
99
|
+
Dictionary of primitives with layer names as keys.
|
|
100
|
+
"""
|
|
101
|
+
_primitives_by_layer = {}
|
|
102
|
+
for lay in self.layers:
|
|
103
|
+
_primitives_by_layer[lay] = self.get_polygons_by_layer(lay)
|
|
104
|
+
return _primitives_by_layer
|
|
105
|
+
|
|
106
|
+
@property
|
|
107
|
+
def primitives_by_net(self):
|
|
108
|
+
"""Primitives with net names as keys.
|
|
109
|
+
|
|
110
|
+
Returns
|
|
111
|
+
-------
|
|
112
|
+
dict
|
|
113
|
+
Dictionary of primitives with nat names as keys.
|
|
114
|
+
"""
|
|
115
|
+
_prim_by_net = {}
|
|
116
|
+
for net, net_obj in self._pedb.nets.nets.items():
|
|
117
|
+
_prim_by_net[net] = [cast(i, self._pedb) for i in net_obj.primitives]
|
|
118
|
+
return _prim_by_net
|
|
119
|
+
|
|
120
|
+
@property
|
|
121
|
+
def primitives_by_layer(self):
|
|
122
|
+
"""Primitives with layer names as keys.
|
|
123
|
+
|
|
124
|
+
Returns
|
|
125
|
+
-------
|
|
126
|
+
dict
|
|
127
|
+
Dictionary of primitives with layer names as keys.
|
|
128
|
+
"""
|
|
129
|
+
_primitives_by_layer = {}
|
|
130
|
+
for lay in self.layers:
|
|
131
|
+
_primitives_by_layer[lay] = []
|
|
132
|
+
for i in self._layout.primitives:
|
|
133
|
+
lay = i.GetLayer().GetName()
|
|
134
|
+
if not lay:
|
|
135
|
+
continue
|
|
136
|
+
_primitives_by_layer[lay].append(cast(i, self._pedb))
|
|
137
|
+
return _primitives_by_layer
|
|
138
|
+
|
|
139
|
+
@property
|
|
140
|
+
def rectangles(self):
|
|
141
|
+
"""Rectangles.
|
|
142
|
+
|
|
143
|
+
Returns
|
|
144
|
+
-------
|
|
145
|
+
list of :class:`pyedb.dotnet.edb_core.edb_data.primitives_data.EDBPrimitives`
|
|
146
|
+
List of rectangles.
|
|
147
|
+
|
|
148
|
+
"""
|
|
149
|
+
return [i for i in self.primitives if isinstance(i, RectangleDotNet)]
|
|
150
|
+
|
|
151
|
+
@property
|
|
152
|
+
def circles(self):
|
|
153
|
+
"""Circles.
|
|
154
|
+
|
|
155
|
+
Returns
|
|
156
|
+
-------
|
|
157
|
+
list of :class:`pyedb.dotnet.edb_core.edb_data.primitives_data.EDBPrimitives`
|
|
158
|
+
List of circles.
|
|
159
|
+
|
|
160
|
+
"""
|
|
161
|
+
return [i for i in self.primitives if isinstance(i, CircleDotNet)]
|
|
162
|
+
|
|
163
|
+
@property
|
|
164
|
+
def paths(self):
|
|
165
|
+
"""Paths.
|
|
166
|
+
|
|
167
|
+
Returns
|
|
168
|
+
-------
|
|
169
|
+
list of :class:`pyedb.dotnet.edb_core.edb_data.primitives_data.EDBPrimitives`
|
|
170
|
+
List of paths.
|
|
171
|
+
"""
|
|
172
|
+
return [i for i in self.primitives if isinstance(i, PathDotNet)]
|
|
173
|
+
|
|
174
|
+
@property
|
|
175
|
+
def bondwires(self):
|
|
176
|
+
"""Bondwires.
|
|
177
|
+
|
|
178
|
+
Returns
|
|
179
|
+
-------
|
|
180
|
+
list of :class:`pyedb.dotnet.edb_core.edb_data.primitives_data.EDBPrimitives`
|
|
181
|
+
List of bondwires.
|
|
182
|
+
"""
|
|
183
|
+
return [i for i in self.primitives if isinstance(i, BondwireDotNet)]
|
|
184
|
+
|
|
185
|
+
@property
|
|
186
|
+
def polygons(self):
|
|
187
|
+
"""Polygons.
|
|
188
|
+
|
|
189
|
+
Returns
|
|
190
|
+
-------
|
|
191
|
+
list of :class:`pyedb.dotnet.edb_core.edb_data.primitives_data.EDBPrimitives`
|
|
192
|
+
List of polygons.
|
|
193
|
+
"""
|
|
194
|
+
return [i for i in self.primitives if isinstance(i, PolygonDotNet)]
|
|
195
|
+
|
|
196
|
+
@pyedb_function_handler()
|
|
197
|
+
def get_polygons_by_layer(self, layer_name, net_list=None):
|
|
198
|
+
"""Retrieve polygons by a layer.
|
|
199
|
+
|
|
200
|
+
Parameters
|
|
201
|
+
----------
|
|
202
|
+
layer_name : str
|
|
203
|
+
Name of the layer.
|
|
204
|
+
net_list : list, optional
|
|
205
|
+
List of net names.
|
|
206
|
+
|
|
207
|
+
Returns
|
|
208
|
+
-------
|
|
209
|
+
list
|
|
210
|
+
List of primitive objects.
|
|
211
|
+
"""
|
|
212
|
+
objinst = []
|
|
213
|
+
for el in self.polygons:
|
|
214
|
+
if el.GetLayer().GetName() == layer_name:
|
|
215
|
+
if net_list and el.GetNet().GetName() in net_list:
|
|
216
|
+
objinst.append(el)
|
|
217
|
+
else:
|
|
218
|
+
objinst.append(el)
|
|
219
|
+
return objinst
|
|
220
|
+
|
|
221
|
+
@pyedb_function_handler()
|
|
222
|
+
def get_polygon_bounding_box(self, polygon):
|
|
223
|
+
"""Retrieve a polygon bounding box.
|
|
224
|
+
|
|
225
|
+
Parameters
|
|
226
|
+
----------
|
|
227
|
+
polygon :
|
|
228
|
+
Name of the polygon.
|
|
229
|
+
|
|
230
|
+
Returns
|
|
231
|
+
-------
|
|
232
|
+
list
|
|
233
|
+
List of bounding box coordinates in the format ``[-x, -y, +x, +y]``.
|
|
234
|
+
|
|
235
|
+
Examples
|
|
236
|
+
--------
|
|
237
|
+
>>> poly = edb_core.modeler.get_polygons_by_layer("GND")
|
|
238
|
+
>>> bounding = edb_core.modeler.get_polygon_bounding_box(poly[0])
|
|
239
|
+
"""
|
|
240
|
+
bounding = []
|
|
241
|
+
try:
|
|
242
|
+
bounding_box = polygon.GetPolygonData().GetBBox()
|
|
243
|
+
bounding = [
|
|
244
|
+
bounding_box.Item1.X.ToDouble(),
|
|
245
|
+
bounding_box.Item1.Y.ToDouble(),
|
|
246
|
+
bounding_box.Item2.X.ToDouble(),
|
|
247
|
+
bounding_box.Item2.Y.ToDouble(),
|
|
248
|
+
]
|
|
249
|
+
except:
|
|
250
|
+
pass
|
|
251
|
+
return bounding
|
|
252
|
+
|
|
253
|
+
@pyedb_function_handler()
|
|
254
|
+
def get_polygon_points(self, polygon):
|
|
255
|
+
"""Retrieve polygon points.
|
|
256
|
+
|
|
257
|
+
.. note::
|
|
258
|
+
For arcs, one point is returned.
|
|
259
|
+
|
|
260
|
+
Parameters
|
|
261
|
+
----------
|
|
262
|
+
polygon :
|
|
263
|
+
class: `dotnet.edb_core.edb_data.primitives_data.EDBPrimitives`
|
|
264
|
+
|
|
265
|
+
Returns
|
|
266
|
+
-------
|
|
267
|
+
list
|
|
268
|
+
List of tuples. Each tuple provides x, y point coordinate. If the length of two consecutives tuples
|
|
269
|
+
from the list equals 2, a segment is defined. The first tuple defines the starting point while the second
|
|
270
|
+
tuple the ending one. If the length of one tuple equals one, that means a polyline is defined and the value
|
|
271
|
+
is giving the arc height. Therefore to polyline is defined as starting point for the tuple
|
|
272
|
+
before in the list, the current one the arc height and the tuple after the polyline ending point.
|
|
273
|
+
|
|
274
|
+
Examples
|
|
275
|
+
--------
|
|
276
|
+
|
|
277
|
+
>>> poly = edb_core.modeler.get_polygons_by_layer("GND")
|
|
278
|
+
>>> points = edb_core.modeler.get_polygon_points(poly[0])
|
|
279
|
+
|
|
280
|
+
"""
|
|
281
|
+
points = []
|
|
282
|
+
i = 0
|
|
283
|
+
continue_iterate = True
|
|
284
|
+
prev_point = None
|
|
285
|
+
while continue_iterate:
|
|
286
|
+
try:
|
|
287
|
+
point = polygon.GetPolygonData().GetPoint(i)
|
|
288
|
+
if prev_point != point:
|
|
289
|
+
if point.IsArc():
|
|
290
|
+
points.append([point.X.ToDouble()])
|
|
291
|
+
else:
|
|
292
|
+
points.append([point.X.ToDouble(), point.Y.ToDouble()])
|
|
293
|
+
prev_point = point
|
|
294
|
+
i += 1
|
|
295
|
+
else:
|
|
296
|
+
continue_iterate = False
|
|
297
|
+
except:
|
|
298
|
+
continue_iterate = False
|
|
299
|
+
return points
|
|
300
|
+
|
|
301
|
+
@pyedb_function_handler()
|
|
302
|
+
def parametrize_polygon(self, polygon, selection_polygon, offset_name="offsetx", origin=None):
|
|
303
|
+
"""Parametrize pieces of a polygon based on another polygon.
|
|
304
|
+
|
|
305
|
+
Parameters
|
|
306
|
+
----------
|
|
307
|
+
polygon :
|
|
308
|
+
Name of the polygon.
|
|
309
|
+
selection_polygon :
|
|
310
|
+
Polygon to use as a filter.
|
|
311
|
+
offset_name : str, optional
|
|
312
|
+
Name of the offset to create. The default is ``"offsetx"``.
|
|
313
|
+
origin : list, optional
|
|
314
|
+
List of the X and Y origins, which impacts the vector
|
|
315
|
+
computation and is needed to determine expansion direction.
|
|
316
|
+
The default is ``None``, in which case the vector is
|
|
317
|
+
computed from the polygon's center.
|
|
318
|
+
|
|
319
|
+
Returns
|
|
320
|
+
-------
|
|
321
|
+
bool
|
|
322
|
+
``True`` when successful, ``False`` when failed.
|
|
323
|
+
"""
|
|
324
|
+
|
|
325
|
+
def calc_slope(point, origin):
|
|
326
|
+
if point[0] - origin[0] != 0:
|
|
327
|
+
slope = math.atan((point[1] - origin[1]) / (point[0] - origin[0]))
|
|
328
|
+
xcoeff = math.sin(slope)
|
|
329
|
+
ycoeff = math.cos(slope)
|
|
330
|
+
|
|
331
|
+
else:
|
|
332
|
+
if point[1] > 0:
|
|
333
|
+
xcoeff = 0
|
|
334
|
+
ycoeff = 1
|
|
335
|
+
else:
|
|
336
|
+
xcoeff = 0
|
|
337
|
+
ycoeff = -1
|
|
338
|
+
if ycoeff > 0:
|
|
339
|
+
ycoeff = "+" + str(ycoeff)
|
|
340
|
+
else:
|
|
341
|
+
ycoeff = str(ycoeff)
|
|
342
|
+
if xcoeff > 0:
|
|
343
|
+
xcoeff = "+" + str(xcoeff)
|
|
344
|
+
else:
|
|
345
|
+
xcoeff = str(xcoeff)
|
|
346
|
+
return xcoeff, ycoeff
|
|
347
|
+
|
|
348
|
+
selection_polygon_data = selection_polygon.GetPolygonData()
|
|
349
|
+
poligon_data = polygon.GetPolygonData()
|
|
350
|
+
bound_center = poligon_data.GetBoundingCircleCenter()
|
|
351
|
+
bound_center2 = selection_polygon_data.GetBoundingCircleCenter()
|
|
352
|
+
center = [bound_center.X.ToDouble(), bound_center.Y.ToDouble()]
|
|
353
|
+
center2 = [bound_center2.X.ToDouble(), bound_center2.Y.ToDouble()]
|
|
354
|
+
x1, y1 = calc_slope(center2, center)
|
|
355
|
+
|
|
356
|
+
if not origin:
|
|
357
|
+
origin = [center[0] + float(x1) * 10000, center[1] + float(y1) * 10000]
|
|
358
|
+
self._pedb.add_design_variable(offset_name, 0.0, is_parameter=True)
|
|
359
|
+
i = 0
|
|
360
|
+
continue_iterate = True
|
|
361
|
+
prev_point = None
|
|
362
|
+
while continue_iterate:
|
|
363
|
+
try:
|
|
364
|
+
point = poligon_data.GetPoint(i)
|
|
365
|
+
if prev_point != point:
|
|
366
|
+
check_inside = selection_polygon_data.PointInPolygon(point)
|
|
367
|
+
if check_inside:
|
|
368
|
+
xcoeff, ycoeff = calc_slope([point.X.ToDouble(), point.X.ToDouble()], origin)
|
|
369
|
+
|
|
370
|
+
new_points = self._pedb.point_data(
|
|
371
|
+
point.X.ToString() + "{}*{}".format(xcoeff, offset_name),
|
|
372
|
+
point.Y.ToString() + "{}*{}".format(ycoeff, offset_name),
|
|
373
|
+
)
|
|
374
|
+
poligon_data.SetPoint(i, new_points)
|
|
375
|
+
prev_point = point
|
|
376
|
+
i += 1
|
|
377
|
+
else:
|
|
378
|
+
continue_iterate = False
|
|
379
|
+
except:
|
|
380
|
+
continue_iterate = False
|
|
381
|
+
polygon.SetPolygonData(poligon_data)
|
|
382
|
+
return True
|
|
383
|
+
|
|
384
|
+
@pyedb_function_handler()
|
|
385
|
+
def _create_path(
|
|
386
|
+
self,
|
|
387
|
+
path_list,
|
|
388
|
+
layer_name,
|
|
389
|
+
width=1,
|
|
390
|
+
net_name="",
|
|
391
|
+
start_cap_style="Round",
|
|
392
|
+
end_cap_style="Round",
|
|
393
|
+
corner_style="Round",
|
|
394
|
+
):
|
|
395
|
+
"""
|
|
396
|
+
Create a path based on a list of points.
|
|
397
|
+
|
|
398
|
+
Parameters
|
|
399
|
+
----------
|
|
400
|
+
path_list : :class:`dotnet.edb_core.layout.Shape`
|
|
401
|
+
List of points.
|
|
402
|
+
layer_name : str
|
|
403
|
+
Name of the layer on which to create the path.
|
|
404
|
+
width : float, optional
|
|
405
|
+
Width of the path. The default is ``1``.
|
|
406
|
+
net_name : str, optional
|
|
407
|
+
Name of the net. The default is ``""``.
|
|
408
|
+
start_cap_style : str, optional
|
|
409
|
+
Style of the cap at its start. Options are ``"Round"``,
|
|
410
|
+
``"Extended",`` and ``"Flat"``. The default is
|
|
411
|
+
``"Round"``.
|
|
412
|
+
end_cap_style : str, optional
|
|
413
|
+
Style of the cap at its end. Options are ``"Round"``,
|
|
414
|
+
``"Extended",`` and ``"Flat"``. The default is
|
|
415
|
+
``"Round"``.
|
|
416
|
+
corner_style : str, optional
|
|
417
|
+
Style of the corner. Options are ``"Round"``,
|
|
418
|
+
``"Sharp"`` and ``"Mitered"``. The default is ``"Round"``.
|
|
419
|
+
|
|
420
|
+
Returns
|
|
421
|
+
-------
|
|
422
|
+
:class:`pyedb.dotnet.edb_core.edb_data.primitives_data.EDBPrimitives`
|
|
423
|
+
``True`` when successful, ``False`` when failed.
|
|
424
|
+
"""
|
|
425
|
+
net = self._pedb.nets.find_or_create_net(net_name)
|
|
426
|
+
if start_cap_style.lower() == "round":
|
|
427
|
+
start_cap_style = self._edb.cell.primitive.PathEndCapStyle.Round
|
|
428
|
+
elif start_cap_style.lower() == "extended":
|
|
429
|
+
start_cap_style = self._edb.cell.primitive.PathEndCapStyle.Extended # pragma: no cover
|
|
430
|
+
else:
|
|
431
|
+
start_cap_style = self._edb.cell.primitive.PathEndCapStyle.Flat # pragma: no cover
|
|
432
|
+
if end_cap_style.lower() == "round":
|
|
433
|
+
end_cap_style = self._edb.cell.primitive.PathEndCapStyle.Round # pragma: no cover
|
|
434
|
+
elif end_cap_style.lower() == "extended":
|
|
435
|
+
end_cap_style = self._edb.cell.primitive.PathEndCapStyle.Extended # pragma: no cover
|
|
436
|
+
else:
|
|
437
|
+
end_cap_style = self._edb.cell.primitive.PathEndCapStyle.Flat
|
|
438
|
+
if corner_style.lower() == "round":
|
|
439
|
+
corner_style = self._edb.cell.primitive.PathCornerStyle.RoundCorner
|
|
440
|
+
elif corner_style.lower() == "sharp":
|
|
441
|
+
corner_style = self._edb.cell.primitive.PathCornerStyle.SharpCorner # pragma: no cover
|
|
442
|
+
else:
|
|
443
|
+
corner_style = self._edb.cell.primitive.PathCornerStyle.MiterCorner # pragma: no cover
|
|
444
|
+
|
|
445
|
+
pointlists = [self._pedb.point_data(i[0], i[1]) for i in path_list.points]
|
|
446
|
+
polygonData = self._edb.geometry.polygon_data.dotnetobj(convert_py_list_to_net_list(pointlists), False)
|
|
447
|
+
polygon = self._edb.cell.primitive.path.create(
|
|
448
|
+
self._active_layout,
|
|
449
|
+
layer_name,
|
|
450
|
+
net,
|
|
451
|
+
self._get_edb_value(width),
|
|
452
|
+
start_cap_style,
|
|
453
|
+
end_cap_style,
|
|
454
|
+
corner_style,
|
|
455
|
+
polygonData,
|
|
456
|
+
)
|
|
457
|
+
if polygon.IsNull(): # pragma: no cover
|
|
458
|
+
self._logger.error("Null path created")
|
|
459
|
+
return False
|
|
460
|
+
return cast(polygon, self._pedb)
|
|
461
|
+
|
|
462
|
+
@pyedb_function_handler()
|
|
463
|
+
def create_trace(
|
|
464
|
+
self,
|
|
465
|
+
path_list,
|
|
466
|
+
layer_name,
|
|
467
|
+
width=1,
|
|
468
|
+
net_name="",
|
|
469
|
+
start_cap_style="Round",
|
|
470
|
+
end_cap_style="Round",
|
|
471
|
+
corner_style="Round",
|
|
472
|
+
):
|
|
473
|
+
"""
|
|
474
|
+
Create a trace based on a list of points.
|
|
475
|
+
|
|
476
|
+
Parameters
|
|
477
|
+
----------
|
|
478
|
+
path_list : list
|
|
479
|
+
List of points.
|
|
480
|
+
layer_name : str
|
|
481
|
+
Name of the layer on which to create the path.
|
|
482
|
+
width : float, optional
|
|
483
|
+
Width of the path. The default is ``1``.
|
|
484
|
+
net_name : str, optional
|
|
485
|
+
Name of the net. The default is ``""``.
|
|
486
|
+
start_cap_style : str, optional
|
|
487
|
+
Style of the cap at its start. Options are ``"Round"``,
|
|
488
|
+
``"Extended",`` and ``"Flat"``. The default is
|
|
489
|
+
``"Round"``.
|
|
490
|
+
end_cap_style : str, optional
|
|
491
|
+
Style of the cap at its end. Options are ``"Round"``,
|
|
492
|
+
``"Extended",`` and ``"Flat"``. The default is
|
|
493
|
+
``"Round"``.
|
|
494
|
+
corner_style : str, optional
|
|
495
|
+
Style of the corner. Options are ``"Round"``,
|
|
496
|
+
``"Sharp"`` and ``"Mitered"``. The default is ``"Round"``.
|
|
497
|
+
|
|
498
|
+
Returns
|
|
499
|
+
-------
|
|
500
|
+
:class:`pyedb.dotnet.edb_core.edb_data.primitives_data.EDBPrimitives`
|
|
501
|
+
"""
|
|
502
|
+
path = self.Shape("Polygon", points=path_list)
|
|
503
|
+
primitive = self._create_path(
|
|
504
|
+
path,
|
|
505
|
+
layer_name=layer_name,
|
|
506
|
+
net_name=net_name,
|
|
507
|
+
width=width,
|
|
508
|
+
start_cap_style=start_cap_style,
|
|
509
|
+
end_cap_style=end_cap_style,
|
|
510
|
+
corner_style=corner_style,
|
|
511
|
+
)
|
|
512
|
+
|
|
513
|
+
return primitive
|
|
514
|
+
|
|
515
|
+
@pyedb_function_handler()
|
|
516
|
+
def create_polygon(self, main_shape, layer_name, voids=[], net_name=""):
|
|
517
|
+
"""Create a polygon based on a list of points and voids.
|
|
518
|
+
|
|
519
|
+
Parameters
|
|
520
|
+
----------
|
|
521
|
+
main_shape : list of points or PolygonData or ``modeler.Shape``
|
|
522
|
+
Shape or point lists of the main object. Point list can be in the format of `[[x1,y1], [x2,y2],..,[xn,yn]]`.
|
|
523
|
+
Each point can be:
|
|
524
|
+
- [x, y] coordinate
|
|
525
|
+
- [x, y, height] for an arc with specific height (between previous point and actual point)
|
|
526
|
+
- [x, y, rotation, xc, yc] for an arc given a point, rotation and center.
|
|
527
|
+
layer_name : str
|
|
528
|
+
Name of the layer on which to create the polygon.
|
|
529
|
+
voids : list, optional
|
|
530
|
+
List of shape objects for voids or points that creates the shapes. The default is``[]``.
|
|
531
|
+
net_name : str, optional
|
|
532
|
+
Name of the net. The default is ``""``.
|
|
533
|
+
|
|
534
|
+
Returns
|
|
535
|
+
-------
|
|
536
|
+
bool, :class:`dotnet.edb_core.edb_data.primitives.EDBPrimitives`
|
|
537
|
+
Polygon when successful, ``False`` when failed.
|
|
538
|
+
"""
|
|
539
|
+
net = self._pedb.nets.find_or_create_net(net_name)
|
|
540
|
+
if isinstance(main_shape, list):
|
|
541
|
+
arcs = []
|
|
542
|
+
for _ in range(len(main_shape)):
|
|
543
|
+
arcs.append(
|
|
544
|
+
self._edb.Geometry.ArcData(
|
|
545
|
+
self._pedb.point_data(0, 0),
|
|
546
|
+
self._pedb.point_data(0, 0),
|
|
547
|
+
)
|
|
548
|
+
)
|
|
549
|
+
polygonData = self._edb.Geometry.PolygonData.CreateFromArcs(convert_py_list_to_net_list(arcs), True)
|
|
550
|
+
|
|
551
|
+
for idx, i in enumerate(main_shape):
|
|
552
|
+
pdata_0 = self._pedb.edb_value(i[0])
|
|
553
|
+
pdata_1 = self._pedb.edb_value(i[1])
|
|
554
|
+
new_points = self._edb.Geometry.PointData(pdata_0, pdata_1)
|
|
555
|
+
polygonData.SetPoint(idx, new_points)
|
|
556
|
+
|
|
557
|
+
elif isinstance(main_shape, EdbLayout.Shape):
|
|
558
|
+
polygonData = self.shape_to_polygon_data(main_shape)
|
|
559
|
+
else:
|
|
560
|
+
polygonData = main_shape
|
|
561
|
+
if not polygonData or polygonData.IsNull():
|
|
562
|
+
self._logger.error("Failed to create main shape polygon data")
|
|
563
|
+
return False
|
|
564
|
+
for void in voids:
|
|
565
|
+
if isinstance(void, list):
|
|
566
|
+
void = self.Shape("polygon", points=void)
|
|
567
|
+
voidPolygonData = self.shape_to_polygon_data(void)
|
|
568
|
+
elif isinstance(void, EdbLayout.Shape):
|
|
569
|
+
voidPolygonData = self.shape_to_polygon_data(void)
|
|
570
|
+
else:
|
|
571
|
+
voidPolygonData = void
|
|
572
|
+
if voidPolygonData is False or voidPolygonData is None or voidPolygonData.IsNull():
|
|
573
|
+
self._logger.error("Failed to create void polygon data")
|
|
574
|
+
return False
|
|
575
|
+
polygonData.AddHole(voidPolygonData)
|
|
576
|
+
polygon = self._edb.cell.primitive.polygon.create(self._active_layout, layer_name, net, polygonData)
|
|
577
|
+
if polygon.IsNull() or polygonData is False: # pragma: no cover
|
|
578
|
+
self._logger.error("Null polygon created")
|
|
579
|
+
return False
|
|
580
|
+
else:
|
|
581
|
+
return cast(polygon, self._pedb)
|
|
582
|
+
|
|
583
|
+
@pyedb_function_handler()
|
|
584
|
+
def create_polygon_from_points(self, point_list, layer_name, net_name=""):
|
|
585
|
+
"""Create a new polygon from a point list.
|
|
586
|
+
|
|
587
|
+
.. deprecated:: 0.6.73
|
|
588
|
+
Use :func:`create_polygon` method instead. It now supports point lists as arguments.
|
|
589
|
+
|
|
590
|
+
Parameters
|
|
591
|
+
----------
|
|
592
|
+
point_list : list
|
|
593
|
+
Point list in the format of `[[x1,y1], [x2,y2],..,[xn,yn]]`.
|
|
594
|
+
Each point can be:
|
|
595
|
+
- [x,y] coordinate
|
|
596
|
+
- [x,y, height] for an arc with specific height (between previous point and actual point)
|
|
597
|
+
- [x,y, rotation, xc,yc] for an arc given a point, rotation and center.
|
|
598
|
+
layer_name : str
|
|
599
|
+
Name of layer on which create the polygon.
|
|
600
|
+
net_name : str, optional
|
|
601
|
+
Name of the net on which create the polygon.
|
|
602
|
+
|
|
603
|
+
Returns
|
|
604
|
+
-------
|
|
605
|
+
:class:`pyedb.dotnet.edb_core.edb_data.primitives_data.EDBPrimitives`
|
|
606
|
+
"""
|
|
607
|
+
warnings.warn(
|
|
608
|
+
"Use :func:`create_polygon` method instead. It now supports point lists as arguments.", DeprecationWarning
|
|
609
|
+
)
|
|
610
|
+
return self.create_polygon(point_list, layer_name, net_name=net_name)
|
|
611
|
+
|
|
612
|
+
@pyedb_function_handler()
|
|
613
|
+
def create_rectangle(
|
|
614
|
+
self,
|
|
615
|
+
layer_name,
|
|
616
|
+
net_name="",
|
|
617
|
+
lower_left_point="",
|
|
618
|
+
upper_right_point="",
|
|
619
|
+
center_point="",
|
|
620
|
+
width="",
|
|
621
|
+
height="",
|
|
622
|
+
representation_type="LowerLeftUpperRight",
|
|
623
|
+
corner_radius="0mm",
|
|
624
|
+
rotation="0deg",
|
|
625
|
+
):
|
|
626
|
+
"""Create rectangle.
|
|
627
|
+
|
|
628
|
+
Parameters
|
|
629
|
+
----------
|
|
630
|
+
layer_name : str
|
|
631
|
+
Name of the layer on which to create the rectangle.
|
|
632
|
+
net_name : str
|
|
633
|
+
Name of the net. The default is ``""``.
|
|
634
|
+
lower_left_point : list
|
|
635
|
+
Lower left point when ``representation_type="LowerLeftUpperRight"``. The default is ``""``.
|
|
636
|
+
upper_right_point : list
|
|
637
|
+
Upper right point when ``representation_type="LowerLeftUpperRight"``. The default is ``""``.
|
|
638
|
+
center_point : list
|
|
639
|
+
Center point when ``representation_type="CenterWidthHeight"``. The default is ``""``.
|
|
640
|
+
width : str
|
|
641
|
+
Width of the rectangle when ``representation_type="CenterWidthHeight"``. The default is ``""``.
|
|
642
|
+
height : str
|
|
643
|
+
Height of the rectangle when ``representation_type="CenterWidthHeight"``. The default is ``""``.
|
|
644
|
+
representation_type : str, optional
|
|
645
|
+
Type of the rectangle representation. The default is ``LowerLeftUpperRight``. Options are
|
|
646
|
+
``"LowerLeftUpperRight"`` and ``"CenterWidthHeight"``.
|
|
647
|
+
corner_radius : str, optional
|
|
648
|
+
Radius of the rectangle corner. The default is ``"0mm"``.
|
|
649
|
+
rotation : str, optional
|
|
650
|
+
Rotation of the rectangle. The default is ``"0deg"``.
|
|
651
|
+
|
|
652
|
+
Returns
|
|
653
|
+
-------
|
|
654
|
+
:class:`pyedb.dotnet.edb_core.edb_data.primitives_data.EDBPrimitives`
|
|
655
|
+
Rectangle when successful, ``False`` when failed.
|
|
656
|
+
"""
|
|
657
|
+
edb_net = self._pedb.nets.find_or_create_net(net_name)
|
|
658
|
+
if representation_type == "LowerLeftUpperRight":
|
|
659
|
+
rep_type = self._edb.cell.primitive.RectangleRepresentationType.LowerLeftUpperRight
|
|
660
|
+
rect = self._edb.cell.primitive.rectangle.create(
|
|
661
|
+
self._active_layout,
|
|
662
|
+
layer_name,
|
|
663
|
+
edb_net.net_obj,
|
|
664
|
+
rep_type,
|
|
665
|
+
self._get_edb_value(lower_left_point[0]),
|
|
666
|
+
self._get_edb_value(lower_left_point[1]),
|
|
667
|
+
self._get_edb_value(upper_right_point[0]),
|
|
668
|
+
self._get_edb_value(upper_right_point[1]),
|
|
669
|
+
self._get_edb_value(corner_radius),
|
|
670
|
+
self._get_edb_value(rotation),
|
|
671
|
+
)
|
|
672
|
+
else:
|
|
673
|
+
rep_type = self._edb.cell.primitive.RectangleRepresentationType.CenterWidthHeight
|
|
674
|
+
rect = self._edb.cell.primitive.rectangle.create(
|
|
675
|
+
self._active_layout,
|
|
676
|
+
layer_name,
|
|
677
|
+
edb_net.net_obj,
|
|
678
|
+
rep_type,
|
|
679
|
+
self._get_edb_value(center_point[0]),
|
|
680
|
+
self._get_edb_value(center_point[1]),
|
|
681
|
+
self._get_edb_value(width),
|
|
682
|
+
self._get_edb_value(height),
|
|
683
|
+
self._get_edb_value(corner_radius),
|
|
684
|
+
self._get_edb_value(rotation),
|
|
685
|
+
)
|
|
686
|
+
if rect:
|
|
687
|
+
return cast(rect, self._pedb)
|
|
688
|
+
return False # pragma: no cover
|
|
689
|
+
|
|
690
|
+
@pyedb_function_handler()
|
|
691
|
+
def create_circle(self, layer_name, x, y, radius, net_name=""):
|
|
692
|
+
"""Create a circle on a specified layer.
|
|
693
|
+
|
|
694
|
+
Parameters
|
|
695
|
+
----------
|
|
696
|
+
layer_name : str
|
|
697
|
+
Name of the layer.
|
|
698
|
+
x : float
|
|
699
|
+
Position on the X axis.
|
|
700
|
+
y : float
|
|
701
|
+
Position on the Y axis.
|
|
702
|
+
radius : float
|
|
703
|
+
Radius of the circle.
|
|
704
|
+
net_name : str, optional
|
|
705
|
+
Name of the net. The default is ``None``, in which case the
|
|
706
|
+
default name is assigned.
|
|
707
|
+
|
|
708
|
+
Returns
|
|
709
|
+
-------
|
|
710
|
+
:class:`pyedb.dotnet.edb_core.edb_data.primitives_data.EDBPrimitives`
|
|
711
|
+
Objects of the circle created when successful.
|
|
712
|
+
"""
|
|
713
|
+
edb_net = self._pedb.nets.find_or_create_net(net_name)
|
|
714
|
+
|
|
715
|
+
circle = self._edb.cell.primitive.circle.create(
|
|
716
|
+
self._active_layout,
|
|
717
|
+
layer_name,
|
|
718
|
+
edb_net,
|
|
719
|
+
self._get_edb_value(x),
|
|
720
|
+
self._get_edb_value(y),
|
|
721
|
+
self._get_edb_value(radius),
|
|
722
|
+
)
|
|
723
|
+
if circle:
|
|
724
|
+
return cast(circle, self._pedb)
|
|
725
|
+
return False # pragma: no cover
|
|
726
|
+
|
|
727
|
+
@pyedb_function_handler()
|
|
728
|
+
def delete_primitives(self, net_names):
|
|
729
|
+
"""Delete primitives by net names.
|
|
730
|
+
|
|
731
|
+
Parameters
|
|
732
|
+
----------
|
|
733
|
+
net_names : str, list
|
|
734
|
+
Names of the nets to delete.
|
|
735
|
+
|
|
736
|
+
Returns
|
|
737
|
+
-------
|
|
738
|
+
bool
|
|
739
|
+
``True`` when successful, ``False`` when failed.
|
|
740
|
+
|
|
741
|
+
References
|
|
742
|
+
----------
|
|
743
|
+
|
|
744
|
+
>>> Edb.modeler.delete_primitives(net_names=["GND"])
|
|
745
|
+
"""
|
|
746
|
+
if not isinstance(net_names, list): # pragma: no cover
|
|
747
|
+
net_names = [net_names]
|
|
748
|
+
|
|
749
|
+
for p in self.primitives[:]:
|
|
750
|
+
if p.net_name in net_names:
|
|
751
|
+
p.delete()
|
|
752
|
+
return True
|
|
753
|
+
|
|
754
|
+
@pyedb_function_handler()
|
|
755
|
+
def get_primitives(self, net_name=None, layer_name=None, prim_type=None, is_void=False):
|
|
756
|
+
"""Get primitives by conditions.
|
|
757
|
+
|
|
758
|
+
Parameters
|
|
759
|
+
----------
|
|
760
|
+
net_name : str, optional
|
|
761
|
+
Set filter on net_name. Default is `None`.
|
|
762
|
+
layer_name : str, optional
|
|
763
|
+
Set filter on layer_name. Default is `None`.
|
|
764
|
+
prim_type : str, optional
|
|
765
|
+
Set filter on primitive type. Default is `None`.
|
|
766
|
+
is_void : bool
|
|
767
|
+
Set filter on is_void. Default is 'False'
|
|
768
|
+
Returns
|
|
769
|
+
-------
|
|
770
|
+
list
|
|
771
|
+
List of filtered primitives
|
|
772
|
+
"""
|
|
773
|
+
prims = []
|
|
774
|
+
for el in self.primitives:
|
|
775
|
+
if not el.type:
|
|
776
|
+
continue
|
|
777
|
+
if net_name:
|
|
778
|
+
if not el.net_name == net_name:
|
|
779
|
+
continue
|
|
780
|
+
if layer_name:
|
|
781
|
+
if not el.layer_name == layer_name:
|
|
782
|
+
continue
|
|
783
|
+
if prim_type:
|
|
784
|
+
if not el.type == prim_type:
|
|
785
|
+
continue
|
|
786
|
+
if not el.is_void == is_void:
|
|
787
|
+
continue
|
|
788
|
+
prims.append(el)
|
|
789
|
+
return prims
|
|
790
|
+
|
|
791
|
+
@pyedb_function_handler()
|
|
792
|
+
def fix_circle_void_for_clipping(self):
|
|
793
|
+
"""Fix issues when circle void are clipped due to a bug in EDB.
|
|
794
|
+
|
|
795
|
+
Returns
|
|
796
|
+
-------
|
|
797
|
+
bool
|
|
798
|
+
``True`` when successful, ``False`` when no changes were applied.
|
|
799
|
+
"""
|
|
800
|
+
for void_circle in self.circles:
|
|
801
|
+
if not void_circle.is_void:
|
|
802
|
+
continue
|
|
803
|
+
(
|
|
804
|
+
res,
|
|
805
|
+
center_x,
|
|
806
|
+
center_y,
|
|
807
|
+
radius,
|
|
808
|
+
) = void_circle.primitive_object.GetParameters()
|
|
809
|
+
|
|
810
|
+
cloned_circle = self._edb.cell.primitive.circle.create(
|
|
811
|
+
self._active_layout,
|
|
812
|
+
void_circle.layer_name,
|
|
813
|
+
void_circle.net,
|
|
814
|
+
self._get_edb_value(center_x),
|
|
815
|
+
self._get_edb_value(center_y),
|
|
816
|
+
self._get_edb_value(radius),
|
|
817
|
+
)
|
|
818
|
+
if res:
|
|
819
|
+
cloned_circle.SetIsNegative(True)
|
|
820
|
+
void_circle.Delete()
|
|
821
|
+
return True
|
|
822
|
+
|
|
823
|
+
@pyedb_function_handler()
|
|
824
|
+
def add_void(self, shape, void_shape):
|
|
825
|
+
"""Add a void into a shape.
|
|
826
|
+
|
|
827
|
+
Parameters
|
|
828
|
+
----------
|
|
829
|
+
shape : Polygon
|
|
830
|
+
Shape of the main object.
|
|
831
|
+
void_shape : list, Path
|
|
832
|
+
Shape of the voids.
|
|
833
|
+
"""
|
|
834
|
+
flag = False
|
|
835
|
+
if isinstance(shape, EDBPrimitives):
|
|
836
|
+
shape = shape.primitive_object
|
|
837
|
+
if not isinstance(void_shape, list):
|
|
838
|
+
void_shape = [void_shape]
|
|
839
|
+
for void in void_shape:
|
|
840
|
+
if isinstance(void, EDBPrimitives):
|
|
841
|
+
flag = shape.AddVoid(void.primitive_object)
|
|
842
|
+
else:
|
|
843
|
+
flag = shape.AddVoid(void)
|
|
844
|
+
if not flag:
|
|
845
|
+
return flag
|
|
846
|
+
return True
|
|
847
|
+
|
|
848
|
+
@pyedb_function_handler()
|
|
849
|
+
def shape_to_polygon_data(self, shape):
|
|
850
|
+
"""Convert a shape to polygon data.
|
|
851
|
+
|
|
852
|
+
Parameters
|
|
853
|
+
----------
|
|
854
|
+
shape : :class:`pyedb.dotnet.edb_core.layout.EdbLayout.Shape`
|
|
855
|
+
Type of the shape to convert. Options are ``"rectangle"`` and ``"polygon"``.
|
|
856
|
+
"""
|
|
857
|
+
if shape.type == "polygon":
|
|
858
|
+
return self._createPolygonDataFromPolygon(shape)
|
|
859
|
+
elif shape.type == "rectangle":
|
|
860
|
+
return self._createPolygonDataFromRectangle(shape)
|
|
861
|
+
else:
|
|
862
|
+
self._logger.error(
|
|
863
|
+
"Unsupported shape type %s when creating a polygon primitive.",
|
|
864
|
+
shape.type,
|
|
865
|
+
)
|
|
866
|
+
return None
|
|
867
|
+
|
|
868
|
+
@pyedb_function_handler()
|
|
869
|
+
def _createPolygonDataFromPolygon(self, shape):
|
|
870
|
+
points = shape.points
|
|
871
|
+
if not self._validatePoint(points[0]):
|
|
872
|
+
self._logger.error("Error validating point.")
|
|
873
|
+
return None
|
|
874
|
+
arcs = []
|
|
875
|
+
is_parametric = False
|
|
876
|
+
for i in range(len(points) - 1):
|
|
877
|
+
if i == 0:
|
|
878
|
+
startPoint = points[-1]
|
|
879
|
+
endPoint = points[i]
|
|
880
|
+
else:
|
|
881
|
+
startPoint = points[i - 1]
|
|
882
|
+
endPoint = points[i]
|
|
883
|
+
|
|
884
|
+
if not self._validatePoint(endPoint):
|
|
885
|
+
return None
|
|
886
|
+
startPoint = [self._get_edb_value(i) for i in startPoint]
|
|
887
|
+
endPoint = [self._get_edb_value(i) for i in endPoint]
|
|
888
|
+
if len(endPoint) == 2:
|
|
889
|
+
is_parametric = (
|
|
890
|
+
is_parametric
|
|
891
|
+
or startPoint[0].IsParametric()
|
|
892
|
+
or startPoint[1].IsParametric()
|
|
893
|
+
or endPoint[0].IsParametric()
|
|
894
|
+
or endPoint[1].IsParametric()
|
|
895
|
+
)
|
|
896
|
+
arc = self._edb.geometry.arc_data(
|
|
897
|
+
self._pedb.point_data(startPoint[0].ToDouble(), startPoint[1].ToDouble()),
|
|
898
|
+
self._pedb.point_data(endPoint[0].ToDouble(), endPoint[1].ToDouble()),
|
|
899
|
+
)
|
|
900
|
+
arcs.append(arc)
|
|
901
|
+
elif len(endPoint) == 3:
|
|
902
|
+
is_parametric = (
|
|
903
|
+
is_parametric
|
|
904
|
+
or startPoint[0].IsParametric()
|
|
905
|
+
or startPoint[1].IsParametric()
|
|
906
|
+
or endPoint[0].IsParametric()
|
|
907
|
+
or endPoint[1].IsParametric()
|
|
908
|
+
or endPoint[2].IsParametric()
|
|
909
|
+
)
|
|
910
|
+
arc = self._edb.geometry.arc_data(
|
|
911
|
+
self._pedb.point_data(startPoint[0].ToDouble(), startPoint[1].ToDouble()),
|
|
912
|
+
self._pedb.point_data(endPoint[0].ToDouble(), endPoint[1].ToDouble()),
|
|
913
|
+
endPoint[2].ToDouble(),
|
|
914
|
+
)
|
|
915
|
+
arcs.append(arc)
|
|
916
|
+
elif len(endPoint) == 5:
|
|
917
|
+
is_parametric = (
|
|
918
|
+
is_parametric
|
|
919
|
+
or startPoint[0].IsParametric()
|
|
920
|
+
or startPoint[1].IsParametric()
|
|
921
|
+
or endPoint[0].IsParametric()
|
|
922
|
+
or endPoint[1].IsParametric()
|
|
923
|
+
or endPoint[3].IsParametric()
|
|
924
|
+
or endPoint[4].IsParametric()
|
|
925
|
+
)
|
|
926
|
+
rotationDirection = self._edb.geometry.geometry.RotationDirection.Colinear
|
|
927
|
+
if endPoint[2].ToString() == "cw":
|
|
928
|
+
rotationDirection = self._edb.geometry.geometry.RotationDirection.CW
|
|
929
|
+
elif endPoint[2].ToString() == "ccw":
|
|
930
|
+
rotationDirection = self._edb.geometry.geometry.RotationDirection.CCW
|
|
931
|
+
else:
|
|
932
|
+
self._logger.error("Invalid rotation direction %s is specified.", endPoint[2])
|
|
933
|
+
return None
|
|
934
|
+
arc = self._edb.geometry.arc_data(
|
|
935
|
+
self._pedb.point_data(startPoint[0].ToDouble(), startPoint[1].ToDouble()),
|
|
936
|
+
self._pedb.point_data(endPoint[0].ToDouble(), endPoint[1].ToDouble()),
|
|
937
|
+
rotationDirection,
|
|
938
|
+
self._pedb.point_data(endPoint[3].ToDouble(), endPoint[4].ToDouble()),
|
|
939
|
+
)
|
|
940
|
+
arcs.append(arc)
|
|
941
|
+
polygon = self._edb.geometry.polygon_data.create_from_arcs(arcs, True)
|
|
942
|
+
if not is_parametric:
|
|
943
|
+
return polygon
|
|
944
|
+
else:
|
|
945
|
+
k = 0
|
|
946
|
+
for pt in points:
|
|
947
|
+
point = [self._get_edb_value(i) for i in pt]
|
|
948
|
+
new_points = self._edb.geometry.point_data(point[0], point[1])
|
|
949
|
+
if len(point) > 2:
|
|
950
|
+
k += 1
|
|
951
|
+
polygon.SetPoint(k, new_points)
|
|
952
|
+
k += 1
|
|
953
|
+
return polygon
|
|
954
|
+
|
|
955
|
+
@pyedb_function_handler()
|
|
956
|
+
def _validatePoint(self, point, allowArcs=True):
|
|
957
|
+
if len(point) == 2:
|
|
958
|
+
if not isinstance(point[0], (int, float, str)):
|
|
959
|
+
self._logger.error("Point X value must be a number.")
|
|
960
|
+
return False
|
|
961
|
+
if not isinstance(point[1], (int, float, str)):
|
|
962
|
+
self._logger.error("Point Y value must be a number.")
|
|
963
|
+
return False
|
|
964
|
+
return True
|
|
965
|
+
elif len(point) == 3:
|
|
966
|
+
if not allowArcs: # pragma: no cover
|
|
967
|
+
self._logger.error("Arc found but arcs are not allowed in _validatePoint.")
|
|
968
|
+
return False
|
|
969
|
+
if not isinstance(point[0], (int, float, str)): # pragma: no cover
|
|
970
|
+
self._logger.error("Point X value must be a number.")
|
|
971
|
+
return False
|
|
972
|
+
if not isinstance(point[1], (int, float, str)): # pragma: no cover
|
|
973
|
+
self._logger.error("Point Y value must be a number.")
|
|
974
|
+
return False
|
|
975
|
+
if not isinstance(point[1], (int, float, str)): # pragma: no cover
|
|
976
|
+
self._logger.error("Invalid point height.")
|
|
977
|
+
return False
|
|
978
|
+
return True
|
|
979
|
+
elif len(point) == 5:
|
|
980
|
+
if not allowArcs: # pragma: no cover
|
|
981
|
+
self._logger.error("Arc found but arcs are not allowed in _validatePoint.")
|
|
982
|
+
return False
|
|
983
|
+
if not isinstance(point[0], (int, float, str)): # pragma: no cover
|
|
984
|
+
self._logger.error("Point X value must be a number.")
|
|
985
|
+
return False
|
|
986
|
+
if not isinstance(point[1], (int, float, str)): # pragma: no cover
|
|
987
|
+
self._logger.error("Point Y value must be a number.")
|
|
988
|
+
return False
|
|
989
|
+
if not isinstance(point[2], str) or point[2] not in ["cw", "ccw"]:
|
|
990
|
+
self._logger.error("Invalid rotation direction {} is specified.")
|
|
991
|
+
return False
|
|
992
|
+
if not isinstance(point[3], (int, float, str)): # pragma: no cover
|
|
993
|
+
self._logger.error("Arc center point X value must be a number.")
|
|
994
|
+
return False
|
|
995
|
+
if not isinstance(point[4], (int, float, str)): # pragma: no cover
|
|
996
|
+
self._logger.error("Arc center point Y value must be a number.")
|
|
997
|
+
return False
|
|
998
|
+
return True
|
|
999
|
+
else: # pragma: no cover
|
|
1000
|
+
self._logger.error("Arc point descriptor has incorrect number of elements (%s)", len(point))
|
|
1001
|
+
return False
|
|
1002
|
+
|
|
1003
|
+
def _createPolygonDataFromRectangle(self, shape):
|
|
1004
|
+
if not self._validatePoint(shape.pointA, False) or not self._validatePoint(shape.pointB, False):
|
|
1005
|
+
return None
|
|
1006
|
+
pointA = self._edb.geometry.point_data(
|
|
1007
|
+
self._get_edb_value(shape.pointA[0]), self._get_edb_value(shape.pointA[1])
|
|
1008
|
+
)
|
|
1009
|
+
pointB = self._edb.geometry.point_data(
|
|
1010
|
+
self._get_edb_value(shape.pointB[0]), self._get_edb_value(shape.pointB[1])
|
|
1011
|
+
)
|
|
1012
|
+
return self._edb.geometry.polygon_data.create_from_bbox((pointA, pointB))
|
|
1013
|
+
|
|
1014
|
+
class Shape(object):
|
|
1015
|
+
"""Shape class.
|
|
1016
|
+
|
|
1017
|
+
Parameters
|
|
1018
|
+
----------
|
|
1019
|
+
type : str, optional
|
|
1020
|
+
Type of the shape. Options are ``"circle"``, ``"rectangle"``, and ``"polygon"``.
|
|
1021
|
+
The default is ``"unknown``.
|
|
1022
|
+
pointA : optional
|
|
1023
|
+
Lower-left corner when ``type="rectangle"``. The default is ``None``.
|
|
1024
|
+
pointB : optional
|
|
1025
|
+
Upper-right corner when ``type="rectangle"``. The default is ``None``.
|
|
1026
|
+
centerPoint : optional
|
|
1027
|
+
Center point when ``type="circle"``. The default is ``None``.
|
|
1028
|
+
radius : optional
|
|
1029
|
+
Radius when ``type="circle"``. The default is ``None``.
|
|
1030
|
+
points : list, optional
|
|
1031
|
+
List of points when ``type="polygon"``. The default is ``None``.
|
|
1032
|
+
properties : dict, optional
|
|
1033
|
+
Dictionary of properties associated with the shape. The default is ``{}``.
|
|
1034
|
+
"""
|
|
1035
|
+
|
|
1036
|
+
def __init__(
|
|
1037
|
+
self,
|
|
1038
|
+
type="unknown", # noqa
|
|
1039
|
+
pointA=None,
|
|
1040
|
+
pointB=None,
|
|
1041
|
+
centerPoint=None,
|
|
1042
|
+
radius=None,
|
|
1043
|
+
points=None,
|
|
1044
|
+
properties={},
|
|
1045
|
+
): # noqa
|
|
1046
|
+
self.type = type
|
|
1047
|
+
self.pointA = pointA
|
|
1048
|
+
self.pointB = pointB
|
|
1049
|
+
self.centerPoint = centerPoint
|
|
1050
|
+
self.radius = radius
|
|
1051
|
+
self.points = points
|
|
1052
|
+
self.properties = properties
|
|
1053
|
+
|
|
1054
|
+
@pyedb_function_handler()
|
|
1055
|
+
def parametrize_trace_width(
|
|
1056
|
+
self,
|
|
1057
|
+
nets_name,
|
|
1058
|
+
layers_name=None,
|
|
1059
|
+
parameter_name="trace_width",
|
|
1060
|
+
variable_value=None,
|
|
1061
|
+
):
|
|
1062
|
+
"""Parametrize a Trace on specific layer or all stackup.
|
|
1063
|
+
|
|
1064
|
+
Parameters
|
|
1065
|
+
----------
|
|
1066
|
+
nets_name : str, list
|
|
1067
|
+
name of the net or list of nets to parametrize.
|
|
1068
|
+
layers_name : str, optional
|
|
1069
|
+
name of the layer or list of layers to which the net to parametrize has to be included.
|
|
1070
|
+
parameter_name : str, optional
|
|
1071
|
+
name of the parameter to create.
|
|
1072
|
+
variable_value : str, float, optional
|
|
1073
|
+
value with units of parameter to create.
|
|
1074
|
+
If None, the first trace width of Net will be used as parameter value.
|
|
1075
|
+
|
|
1076
|
+
Returns
|
|
1077
|
+
-------
|
|
1078
|
+
bool
|
|
1079
|
+
"""
|
|
1080
|
+
if isinstance(nets_name, str):
|
|
1081
|
+
nets_name = [nets_name]
|
|
1082
|
+
if isinstance(layers_name, str):
|
|
1083
|
+
layers_name = [layers_name]
|
|
1084
|
+
for net_name in nets_name:
|
|
1085
|
+
var_server = False
|
|
1086
|
+
for p in self.paths:
|
|
1087
|
+
if p.GetNet().GetName() == net_name:
|
|
1088
|
+
if not layers_name:
|
|
1089
|
+
if not var_server:
|
|
1090
|
+
if not variable_value:
|
|
1091
|
+
variable_value = p.GetWidth()
|
|
1092
|
+
result, var_server = self._pedb.add_design_variable(
|
|
1093
|
+
parameter_name, variable_value, is_parameter=True
|
|
1094
|
+
)
|
|
1095
|
+
p.SetWidth(self._pedb.edb_value(parameter_name))
|
|
1096
|
+
elif p.GetLayer().GetName() in layers_name:
|
|
1097
|
+
if not var_server:
|
|
1098
|
+
if not variable_value:
|
|
1099
|
+
variable_value = p.GetWidth()
|
|
1100
|
+
result, var_server = self._pedb.add_design_variable(
|
|
1101
|
+
parameter_name, variable_value, is_parameter=True
|
|
1102
|
+
)
|
|
1103
|
+
p.SetWidth(self._pedb.edb_value(parameter_name))
|
|
1104
|
+
return True
|
|
1105
|
+
|
|
1106
|
+
@pyedb_function_handler()
|
|
1107
|
+
def unite_polygons_on_layer(self, layer_name=None, delete_padstack_gemometries=False, net_list=[]):
|
|
1108
|
+
"""Try to unite all Polygons on specified layer.
|
|
1109
|
+
|
|
1110
|
+
Parameters
|
|
1111
|
+
----------
|
|
1112
|
+
layer_name : str, optional
|
|
1113
|
+
Name of layer name to unite objects on. The default is ``None``, in which case all layers are taken.
|
|
1114
|
+
delete_padstack_gemometries : bool, optional
|
|
1115
|
+
Whether to delete all padstack geometries. The default is ``False``.
|
|
1116
|
+
net_list : list[str] : optional
|
|
1117
|
+
Net list filter. The default is ``[]``, in which case all nets are taken.
|
|
1118
|
+
|
|
1119
|
+
Returns
|
|
1120
|
+
-------
|
|
1121
|
+
bool
|
|
1122
|
+
``True`` is successful.
|
|
1123
|
+
"""
|
|
1124
|
+
if isinstance(layer_name, str):
|
|
1125
|
+
layer_name = [layer_name]
|
|
1126
|
+
if not layer_name:
|
|
1127
|
+
layer_name = list(self._pedb.stackup.signal_layers.keys())
|
|
1128
|
+
|
|
1129
|
+
for lay in layer_name:
|
|
1130
|
+
self._logger.info("Uniting Objects on layer %s.", lay)
|
|
1131
|
+
poly_by_nets = {}
|
|
1132
|
+
if lay in list(self.polygons_by_layer.keys()):
|
|
1133
|
+
for poly in self.polygons_by_layer[lay]:
|
|
1134
|
+
if not poly.GetNet().GetName() in list(poly_by_nets.keys()):
|
|
1135
|
+
if poly.GetNet().GetName():
|
|
1136
|
+
poly_by_nets[poly.GetNet().GetName()] = [poly]
|
|
1137
|
+
else:
|
|
1138
|
+
if poly.GetNet().GetName():
|
|
1139
|
+
poly_by_nets[poly.GetNet().GetName()].append(poly)
|
|
1140
|
+
for net in poly_by_nets:
|
|
1141
|
+
if net in net_list or not net_list: # pragma no cover
|
|
1142
|
+
list_polygon_data = [i.GetPolygonData() for i in poly_by_nets[net]]
|
|
1143
|
+
all_voids = [i.Voids for i in poly_by_nets[net]]
|
|
1144
|
+
a = self._edb.geometry.polygon_data.unite(convert_py_list_to_net_list(list_polygon_data))
|
|
1145
|
+
for item in a:
|
|
1146
|
+
for v in all_voids:
|
|
1147
|
+
for void in v:
|
|
1148
|
+
if int(item.GetIntersectionType(void.GetPolygonData())) == 2:
|
|
1149
|
+
item.AddHole(void.GetPolygonData())
|
|
1150
|
+
poly = self._edb.cell.primitive.polygon.create(
|
|
1151
|
+
self._active_layout,
|
|
1152
|
+
lay,
|
|
1153
|
+
self._pedb.nets.nets[net],
|
|
1154
|
+
item,
|
|
1155
|
+
)
|
|
1156
|
+
list_to_delete = [i for i in poly_by_nets[net]]
|
|
1157
|
+
for v in all_voids:
|
|
1158
|
+
for void in v:
|
|
1159
|
+
for poly in poly_by_nets[net]: # pragma no cover
|
|
1160
|
+
if int(void.GetPolygonData().GetIntersectionType(poly.GetPolygonData())) >= 2:
|
|
1161
|
+
try:
|
|
1162
|
+
id = list_to_delete.index(poly)
|
|
1163
|
+
except ValueError:
|
|
1164
|
+
id = -1
|
|
1165
|
+
if id >= 0:
|
|
1166
|
+
list_to_delete.pop(id)
|
|
1167
|
+
|
|
1168
|
+
[i.Delete() for i in list_to_delete] # pragma no cover
|
|
1169
|
+
|
|
1170
|
+
if delete_padstack_gemometries:
|
|
1171
|
+
self._logger.info("Deleting Padstack Definitions")
|
|
1172
|
+
for pad in self._pedb.padstacks.definitions:
|
|
1173
|
+
p1 = self._pedb.padstacks.definitions[pad].edb_padstack.GetData()
|
|
1174
|
+
if len(p1.GetLayerNames()) > 1:
|
|
1175
|
+
self._pedb.padstacks.remove_pads_from_padstack(pad)
|
|
1176
|
+
return True
|
|
1177
|
+
|
|
1178
|
+
@pyedb_function_handler()
|
|
1179
|
+
def defeature_polygon(self, poly, tolerance=0.001):
|
|
1180
|
+
"""Defeature the polygon based on the maximum surface deviation criteria.
|
|
1181
|
+
|
|
1182
|
+
Parameters
|
|
1183
|
+
----------
|
|
1184
|
+
maximum_surface_deviation : float
|
|
1185
|
+
poly : Edb Polygon primitive
|
|
1186
|
+
Polygon to defeature.
|
|
1187
|
+
tolerance : float, optional
|
|
1188
|
+
Maximum tolerance criteria. The default is ``0.001``.
|
|
1189
|
+
|
|
1190
|
+
Returns
|
|
1191
|
+
-------
|
|
1192
|
+
bool
|
|
1193
|
+
``True`` when successful, ``False`` when failed.
|
|
1194
|
+
"""
|
|
1195
|
+
poly_data = poly.polygon_data
|
|
1196
|
+
new_poly = poly_data.edb_api.Defeature(tolerance)
|
|
1197
|
+
poly.polygon_data = new_poly
|
|
1198
|
+
return True
|
|
1199
|
+
|
|
1200
|
+
@pyedb_function_handler()
|
|
1201
|
+
def get_layout_statistics(self, evaluate_area=False, net_list=None):
|
|
1202
|
+
"""Return EDBStatistics object from a layout.
|
|
1203
|
+
|
|
1204
|
+
Parameters
|
|
1205
|
+
----------
|
|
1206
|
+
|
|
1207
|
+
evaluate_area : optional bool
|
|
1208
|
+
When True evaluates the layout metal surface, can take time-consuming,
|
|
1209
|
+
avoid using this option on large design.
|
|
1210
|
+
|
|
1211
|
+
Returns
|
|
1212
|
+
-------
|
|
1213
|
+
|
|
1214
|
+
EDBStatistics object.
|
|
1215
|
+
|
|
1216
|
+
"""
|
|
1217
|
+
stat_model = EDBStatistics()
|
|
1218
|
+
stat_model.num_layers = len(list(self._pedb.stackup.stackup_layers.values()))
|
|
1219
|
+
stat_model.num_capacitors = len(self._pedb.components.capacitors)
|
|
1220
|
+
stat_model.num_resistors = len(self._pedb.components.resistors)
|
|
1221
|
+
stat_model.num_inductors = len(self._pedb.components.inductors)
|
|
1222
|
+
bbox = self._pedb._hfss.get_layout_bounding_box(self._active_layout)
|
|
1223
|
+
stat_model._layout_size = bbox[2] - bbox[0], bbox[3] - bbox[1]
|
|
1224
|
+
stat_model.num_discrete_components = (
|
|
1225
|
+
len(self._pedb.components.Others) + len(self._pedb.components.ICs) + len(self._pedb.components.IOs)
|
|
1226
|
+
)
|
|
1227
|
+
stat_model.num_inductors = len(self._pedb.components.inductors)
|
|
1228
|
+
stat_model.num_resistors = len(self._pedb.components.resistors)
|
|
1229
|
+
stat_model.num_capacitors = len(self._pedb.components.capacitors)
|
|
1230
|
+
stat_model.num_nets = len(self._pedb.nets.nets)
|
|
1231
|
+
stat_model.num_traces = len(self._pedb.modeler.paths)
|
|
1232
|
+
stat_model.num_polygons = len(self._pedb.modeler.polygons)
|
|
1233
|
+
stat_model.num_vias = len(self._pedb.padstacks.instances)
|
|
1234
|
+
stat_model.stackup_thickness = self._pedb.stackup.get_layout_thickness()
|
|
1235
|
+
if evaluate_area:
|
|
1236
|
+
if net_list:
|
|
1237
|
+
netlist = list(self._pedb.nets.nets.keys())
|
|
1238
|
+
_poly = self._pedb.get_conformal_polygon_from_netlist(netlist)
|
|
1239
|
+
else:
|
|
1240
|
+
_poly = self._pedb.get_conformal_polygon_from_netlist()
|
|
1241
|
+
stat_model.occupying_surface = _poly.Area()
|
|
1242
|
+
outline_surface = stat_model.layout_size[0] * stat_model.layout_size[1]
|
|
1243
|
+
stat_model.occupying_ratio = stat_model.occupying_surface / outline_surface
|
|
1244
|
+
return stat_model
|