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.

Files changed (128) hide show
  1. pyedb/__init__.py +17 -0
  2. pyedb/dotnet/__init__.py +0 -0
  3. pyedb/dotnet/application/Variables.py +2261 -0
  4. pyedb/dotnet/application/__init__.py +0 -0
  5. pyedb/dotnet/clr_module.py +103 -0
  6. pyedb/dotnet/edb.py +4237 -0
  7. pyedb/dotnet/edb_core/__init__.py +1 -0
  8. pyedb/dotnet/edb_core/cell/__init__.py +0 -0
  9. pyedb/dotnet/edb_core/cell/hierarchy/__init__.py +0 -0
  10. pyedb/dotnet/edb_core/cell/hierarchy/model.py +66 -0
  11. pyedb/dotnet/edb_core/components.py +2669 -0
  12. pyedb/dotnet/edb_core/configuration.py +423 -0
  13. pyedb/dotnet/edb_core/definition/__init__.py +0 -0
  14. pyedb/dotnet/edb_core/definition/component_def.py +166 -0
  15. pyedb/dotnet/edb_core/definition/component_model.py +30 -0
  16. pyedb/dotnet/edb_core/definition/definition_obj.py +18 -0
  17. pyedb/dotnet/edb_core/definition/definitions.py +12 -0
  18. pyedb/dotnet/edb_core/dotnet/__init__.py +0 -0
  19. pyedb/dotnet/edb_core/dotnet/database.py +1218 -0
  20. pyedb/dotnet/edb_core/dotnet/layout.py +238 -0
  21. pyedb/dotnet/edb_core/dotnet/primitive.py +1517 -0
  22. pyedb/dotnet/edb_core/edb_data/__init__.py +0 -0
  23. pyedb/dotnet/edb_core/edb_data/components_data.py +938 -0
  24. pyedb/dotnet/edb_core/edb_data/connectable.py +113 -0
  25. pyedb/dotnet/edb_core/edb_data/control_file.py +1268 -0
  26. pyedb/dotnet/edb_core/edb_data/design_options.py +35 -0
  27. pyedb/dotnet/edb_core/edb_data/edbvalue.py +45 -0
  28. pyedb/dotnet/edb_core/edb_data/hfss_extent_info.py +330 -0
  29. pyedb/dotnet/edb_core/edb_data/hfss_simulation_setup_data.py +1607 -0
  30. pyedb/dotnet/edb_core/edb_data/layer_data.py +576 -0
  31. pyedb/dotnet/edb_core/edb_data/nets_data.py +281 -0
  32. pyedb/dotnet/edb_core/edb_data/obj_base.py +19 -0
  33. pyedb/dotnet/edb_core/edb_data/padstacks_data.py +2080 -0
  34. pyedb/dotnet/edb_core/edb_data/ports.py +287 -0
  35. pyedb/dotnet/edb_core/edb_data/primitives_data.py +1397 -0
  36. pyedb/dotnet/edb_core/edb_data/simulation_configuration.py +2914 -0
  37. pyedb/dotnet/edb_core/edb_data/simulation_setup.py +716 -0
  38. pyedb/dotnet/edb_core/edb_data/siwave_simulation_setup_data.py +1205 -0
  39. pyedb/dotnet/edb_core/edb_data/sources.py +514 -0
  40. pyedb/dotnet/edb_core/edb_data/terminals.py +632 -0
  41. pyedb/dotnet/edb_core/edb_data/utilities.py +148 -0
  42. pyedb/dotnet/edb_core/edb_data/variables.py +91 -0
  43. pyedb/dotnet/edb_core/general.py +181 -0
  44. pyedb/dotnet/edb_core/hfss.py +1646 -0
  45. pyedb/dotnet/edb_core/layout.py +1244 -0
  46. pyedb/dotnet/edb_core/layout_validation.py +272 -0
  47. pyedb/dotnet/edb_core/materials.py +939 -0
  48. pyedb/dotnet/edb_core/net_class.py +335 -0
  49. pyedb/dotnet/edb_core/nets.py +1215 -0
  50. pyedb/dotnet/edb_core/padstack.py +1389 -0
  51. pyedb/dotnet/edb_core/siwave.py +1427 -0
  52. pyedb/dotnet/edb_core/stackup.py +2703 -0
  53. pyedb/edb_logger.py +396 -0
  54. pyedb/generic/__init__.py +0 -0
  55. pyedb/generic/constants.py +1063 -0
  56. pyedb/generic/data_handlers.py +320 -0
  57. pyedb/generic/design_types.py +104 -0
  58. pyedb/generic/filesystem.py +150 -0
  59. pyedb/generic/general_methods.py +1535 -0
  60. pyedb/generic/plot.py +1840 -0
  61. pyedb/generic/process.py +285 -0
  62. pyedb/generic/settings.py +224 -0
  63. pyedb/ipc2581/__init__.py +0 -0
  64. pyedb/ipc2581/bom/__init__.py +0 -0
  65. pyedb/ipc2581/bom/bom.py +21 -0
  66. pyedb/ipc2581/bom/bom_item.py +32 -0
  67. pyedb/ipc2581/bom/characteristics.py +37 -0
  68. pyedb/ipc2581/bom/refdes.py +16 -0
  69. pyedb/ipc2581/content/__init__.py +0 -0
  70. pyedb/ipc2581/content/color.py +38 -0
  71. pyedb/ipc2581/content/content.py +55 -0
  72. pyedb/ipc2581/content/dictionary_color.py +29 -0
  73. pyedb/ipc2581/content/dictionary_fill.py +28 -0
  74. pyedb/ipc2581/content/dictionary_line.py +30 -0
  75. pyedb/ipc2581/content/entry_color.py +13 -0
  76. pyedb/ipc2581/content/entry_line.py +14 -0
  77. pyedb/ipc2581/content/fill.py +15 -0
  78. pyedb/ipc2581/content/layer_ref.py +10 -0
  79. pyedb/ipc2581/content/standard_geometries_dictionary.py +72 -0
  80. pyedb/ipc2581/ecad/__init__.py +0 -0
  81. pyedb/ipc2581/ecad/cad_data/__init__.py +0 -0
  82. pyedb/ipc2581/ecad/cad_data/assembly_drawing.py +26 -0
  83. pyedb/ipc2581/ecad/cad_data/cad_data.py +37 -0
  84. pyedb/ipc2581/ecad/cad_data/component.py +41 -0
  85. pyedb/ipc2581/ecad/cad_data/drill.py +30 -0
  86. pyedb/ipc2581/ecad/cad_data/feature.py +54 -0
  87. pyedb/ipc2581/ecad/cad_data/layer.py +41 -0
  88. pyedb/ipc2581/ecad/cad_data/layer_feature.py +151 -0
  89. pyedb/ipc2581/ecad/cad_data/logical_net.py +32 -0
  90. pyedb/ipc2581/ecad/cad_data/outline.py +25 -0
  91. pyedb/ipc2581/ecad/cad_data/package.py +104 -0
  92. pyedb/ipc2581/ecad/cad_data/padstack_def.py +38 -0
  93. pyedb/ipc2581/ecad/cad_data/padstack_hole_def.py +24 -0
  94. pyedb/ipc2581/ecad/cad_data/padstack_instance.py +62 -0
  95. pyedb/ipc2581/ecad/cad_data/padstack_pad_def.py +26 -0
  96. pyedb/ipc2581/ecad/cad_data/path.py +89 -0
  97. pyedb/ipc2581/ecad/cad_data/phy_net.py +80 -0
  98. pyedb/ipc2581/ecad/cad_data/pin.py +31 -0
  99. pyedb/ipc2581/ecad/cad_data/polygon.py +169 -0
  100. pyedb/ipc2581/ecad/cad_data/profile.py +40 -0
  101. pyedb/ipc2581/ecad/cad_data/stackup.py +31 -0
  102. pyedb/ipc2581/ecad/cad_data/stackup_group.py +42 -0
  103. pyedb/ipc2581/ecad/cad_data/stackup_layer.py +21 -0
  104. pyedb/ipc2581/ecad/cad_data/step.py +275 -0
  105. pyedb/ipc2581/ecad/cad_header.py +33 -0
  106. pyedb/ipc2581/ecad/ecad.py +19 -0
  107. pyedb/ipc2581/ecad/spec.py +46 -0
  108. pyedb/ipc2581/history_record.py +37 -0
  109. pyedb/ipc2581/ipc2581.py +387 -0
  110. pyedb/ipc2581/logistic_header.py +25 -0
  111. pyedb/misc/__init__.py +0 -0
  112. pyedb/misc/aedtlib_personalib_install.py +14 -0
  113. pyedb/misc/downloads.py +322 -0
  114. pyedb/misc/misc.py +67 -0
  115. pyedb/misc/pyedb.runtimeconfig.json +13 -0
  116. pyedb/misc/siw_feature_config/__init__.py +0 -0
  117. pyedb/misc/siw_feature_config/emc/__init__.py +0 -0
  118. pyedb/misc/siw_feature_config/emc/component_tags.py +46 -0
  119. pyedb/misc/siw_feature_config/emc/net_tags.py +37 -0
  120. pyedb/misc/siw_feature_config/emc/tag_library.py +62 -0
  121. pyedb/misc/siw_feature_config/emc/xml_generic.py +78 -0
  122. pyedb/misc/siw_feature_config/emc_rule_checker_settings.py +179 -0
  123. pyedb/misc/utilities.py +27 -0
  124. pyedb/modeler/geometry_operators.py +2082 -0
  125. pyedb-0.2.0.dist-info/LICENSE +21 -0
  126. pyedb-0.2.0.dist-info/METADATA +208 -0
  127. pyedb-0.2.0.dist-info/RECORD +128 -0
  128. 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