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,2080 @@
1
+ from collections import OrderedDict
2
+ import math
3
+ import re
4
+ import warnings
5
+
6
+ from pyedb.dotnet.clr_module import String, _clr
7
+ from pyedb.dotnet.edb_core.dotnet.database import PolygonDataDotNet
8
+ from pyedb.dotnet.edb_core.edb_data.edbvalue import EdbValue
9
+ from pyedb.dotnet.edb_core.edb_data.primitives_data import EDBPrimitivesMain
10
+ from pyedb.dotnet.edb_core.general import PadGeometryTpe, convert_py_list_to_net_list
11
+ from pyedb.generic.general_methods import (
12
+ generate_unique_name,
13
+ is_ironpython,
14
+ pyedb_function_handler,
15
+ )
16
+ from pyedb.modeler.geometry_operators import GeometryOperators
17
+
18
+
19
+ class EDBPadProperties(object):
20
+ """Manages EDB functionalities for pad properties.
21
+
22
+ Parameters
23
+ ----------
24
+ edb_padstack :
25
+
26
+ layer_name : str
27
+ Name of the layer.
28
+ pad_type :
29
+ Type of the pad.
30
+ pedbpadstack : str
31
+ Inherited AEDT object.
32
+
33
+ Examples
34
+ --------
35
+ >>> from pyedb import Edb
36
+ >>> edb = Edb(myedb, edbversion="2021.2")
37
+ >>> edb_pad_properties = edb.padstacks.definitions["MyPad"].pad_by_layer["TOP"]
38
+ """
39
+
40
+ def __init__(self, edb_padstack, layer_name, pad_type, p_edb_padstack):
41
+ self._edb_padstack = edb_padstack
42
+ self._pedbpadstack = p_edb_padstack
43
+ self.layer_name = layer_name
44
+ self.pad_type = pad_type
45
+
46
+ @property
47
+ def _padstack_methods(self):
48
+ return self._pedbpadstack._padstack_methods
49
+
50
+ @property
51
+ def _stackup_layers(self):
52
+ return self._pedbpadstack._stackup_layers
53
+
54
+ @property
55
+ def _edb(self):
56
+ return self._pedbpadstack._edb
57
+
58
+ def _get_edb_value(self, value):
59
+ return self._pedbpadstack._get_edb_value(value)
60
+
61
+ @property
62
+ def _pad_parameter_value(self):
63
+ pad_params = self._edb_padstack.GetData().GetPadParametersValue(
64
+ self.layer_name, self.int_to_pad_type(self.pad_type)
65
+ )
66
+ return pad_params
67
+
68
+ @property
69
+ def geometry_type(self):
70
+ """Geometry type.
71
+
72
+ Returns
73
+ -------
74
+ int
75
+ Type of the geometry.
76
+ """
77
+
78
+ padparams = self._edb_padstack.GetData().GetPadParametersValue(
79
+ self.layer_name, self.int_to_pad_type(self.pad_type)
80
+ )
81
+ return int(padparams[1])
82
+
83
+ @geometry_type.setter
84
+ def geometry_type(self, geom_type):
85
+ """0, NoGeometry. 1, Circle. 2 Square. 3, Rectangle. 4, Oval. 5, Bullet. 6, N-sided polygon. 7, Polygonal
86
+ shape.8, Round gap with 45 degree thermal ties. 9, Round gap with 90 degree thermal ties.10, Square gap
87
+ with 45 degree thermal ties. 11, Square gap with 90 degree thermal ties.
88
+ """
89
+ val = self._get_edb_value(0)
90
+ params = []
91
+ if geom_type == 0:
92
+ pass
93
+ elif geom_type == 1:
94
+ params = [val]
95
+ elif geom_type == 2:
96
+ params = [val]
97
+ elif geom_type == 3:
98
+ params = [val, val]
99
+ elif geom_type == 4:
100
+ params = [val, val, val]
101
+ elif geom_type == 5:
102
+ params = [val, val, val]
103
+ self._update_pad_parameters_parameters(geom_type=geom_type, params=params)
104
+
105
+ @property
106
+ def shape(self):
107
+ """Get the shape of the pad."""
108
+ return self._pad_parameter_value[1].ToString()
109
+
110
+ @shape.setter
111
+ def shape(self, value):
112
+ self._update_pad_parameters_parameters(geom_type=PadGeometryTpe[value].value)
113
+
114
+ @property
115
+ def parameters_values(self):
116
+ """Parameters.
117
+
118
+ Returns
119
+ -------
120
+ list
121
+ List of parameters.
122
+ """
123
+ return [i.tofloat for i in self.parameters.values()]
124
+
125
+ @property
126
+ def polygon_data(self):
127
+ """Parameters.
128
+
129
+ Returns
130
+ -------
131
+ list
132
+ List of parameters.
133
+ """
134
+ try:
135
+ pad_values = self._edb_padstack.GetData().GetPolygonalPadParameters(
136
+ self.layer_name, self.int_to_pad_type(self.pad_type)
137
+ )
138
+ if pad_values[1]:
139
+ return PolygonDataDotNet(self._edb._app, pad_values[1])
140
+ else:
141
+ return
142
+ except:
143
+ return
144
+
145
+ @property
146
+ def parameters(self):
147
+ """Get parameters.
148
+
149
+ Returns
150
+ -------
151
+ dict
152
+ """
153
+ value = list(self._pad_parameter_value[2])
154
+ if self.shape == PadGeometryTpe.Circle.name:
155
+ return OrderedDict({"Diameter": EdbValue(value[0])})
156
+ elif self.shape == PadGeometryTpe.Square.name:
157
+ return OrderedDict({"Size": EdbValue(value[0])})
158
+ elif self.shape == PadGeometryTpe.Rectangle.name:
159
+ return OrderedDict({"XSize": EdbValue(value[0]), "YSize": EdbValue(value[1])})
160
+ elif self.shape in [PadGeometryTpe.Oval.name, PadGeometryTpe.Bullet.name]:
161
+ return OrderedDict(
162
+ {"XSize": EdbValue(value[0]), "YSize": EdbValue(value[1]), "CornerRadius": EdbValue(value[2])}
163
+ )
164
+ elif self.shape == PadGeometryTpe.NSidedPolygon.name:
165
+ return OrderedDict({"Size": EdbValue(value[0]), "NumSides": EdbValue(value[1])})
166
+ elif self.shape in [PadGeometryTpe.Round45.name, PadGeometryTpe.Round90.name]: # pragma: no cover
167
+ return OrderedDict(
168
+ {"Inner": EdbValue(value[0]), "ChannelWidth": EdbValue(value[1]), "IsolationGap": EdbValue(value[2])}
169
+ )
170
+ else:
171
+ return OrderedDict() # pragma: no cover
172
+
173
+ @parameters.setter
174
+ def parameters(self, value):
175
+ """Set parameters.
176
+ "Circle", {"Diameter": "0.5mm"}
177
+
178
+ Parameters
179
+ ----------
180
+ value : dict
181
+ Pad parameters in dictionary.
182
+ >>> pad = Edb.padstacks["PlanarEMVia"]["TOP"]
183
+ >>> pad.shape = "Circle"
184
+ >>> pad.pad_parameters{"Diameter": "0.5mm"}
185
+ >>> pad.shape = "Bullet"
186
+ >>> pad.pad_parameters{"XSize": "0.5mm", "YSize": "0.5mm"}
187
+ """
188
+
189
+ if isinstance(value, dict):
190
+ value = {k: v.tostring if isinstance(v, EdbValue) else v for k, v in value.items()}
191
+ if self.shape == PadGeometryTpe.Circle.name:
192
+ params = [self._get_edb_value(value["Diameter"])]
193
+ elif self.shape == PadGeometryTpe.Square.name:
194
+ params = [self._get_edb_value(value["Size"])]
195
+ elif self.shape == PadGeometryTpe.Rectangle.name:
196
+ params = [self._get_edb_value(value["XSize"]), self._get_edb_value(value["YSize"])]
197
+ elif self.shape == [PadGeometryTpe.Oval.name, PadGeometryTpe.Bullet.name]:
198
+ params = [
199
+ self._get_edb_value(value["XSize"]),
200
+ self._get_edb_value(value["YSize"]),
201
+ self._get_edb_value(value["CornerRadius"]),
202
+ ]
203
+ elif self.shape in [PadGeometryTpe.Round45.name, PadGeometryTpe.Round90.name]: # pragma: no cover
204
+ params = [
205
+ self._get_edb_value(value["Inner"]),
206
+ self._get_edb_value(value["ChannelWidth"]),
207
+ self._get_edb_value(value["IsolationGap"]),
208
+ ]
209
+ else: # pragma: no cover
210
+ params = None
211
+ elif isinstance(value, list):
212
+ params = [self._get_edb_value(i) for i in value]
213
+ else:
214
+ params = [self._get_edb_value(value)]
215
+ self._update_pad_parameters_parameters(params=params)
216
+
217
+ @property
218
+ def offset_x(self):
219
+ """Offset for the X axis.
220
+
221
+ Returns
222
+ -------
223
+ str
224
+ Offset for the X axis.
225
+ """
226
+
227
+ pad_values = self._edb_padstack.GetData().GetPadParametersValue(
228
+ self.layer_name, self.int_to_pad_type(self.pad_type)
229
+ )
230
+ return pad_values[3].ToString()
231
+
232
+ @offset_x.setter
233
+ def offset_x(self, offset_value):
234
+ self._update_pad_parameters_parameters(offsetx=offset_value)
235
+
236
+ @property
237
+ def offset_y(self):
238
+ """Offset for the Y axis.
239
+
240
+ Returns
241
+ -------
242
+ str
243
+ Offset for the Y axis.
244
+ """
245
+
246
+ pad_values = self._edb_padstack.GetData().GetPadParametersValue(
247
+ self.layer_name, self.int_to_pad_type(self.pad_type)
248
+ )
249
+ return pad_values[4].ToString()
250
+
251
+ @offset_y.setter
252
+ def offset_y(self, offset_value):
253
+ self._update_pad_parameters_parameters(offsety=offset_value)
254
+
255
+ @property
256
+ def rotation(self):
257
+ """Rotation.
258
+
259
+ Returns
260
+ -------
261
+ str
262
+ Value for the rotation.
263
+ """
264
+
265
+ pad_values = self._edb_padstack.GetData().GetPadParametersValue(
266
+ self.layer_name, self.int_to_pad_type(self.pad_type)
267
+ )
268
+ return pad_values[5].ToString()
269
+
270
+ @rotation.setter
271
+ def rotation(self, rotation_value):
272
+ self._update_pad_parameters_parameters(rotation=rotation_value)
273
+
274
+ @pyedb_function_handler()
275
+ def int_to_pad_type(self, val=0):
276
+ """Convert an integer to an EDB.PadGeometryType.
277
+
278
+ Parameters
279
+ ----------
280
+ val : int
281
+
282
+ Returns
283
+ -------
284
+ object
285
+ EDB.PadType enumerator value.
286
+ """
287
+ return self._pedbpadstack._ppadstack.int_to_pad_type(val)
288
+
289
+ @pyedb_function_handler()
290
+ def int_to_geometry_type(self, val=0):
291
+ """Convert an integer to an EDB.PadGeometryType.
292
+
293
+ Parameters
294
+ ----------
295
+ val : int
296
+
297
+ Returns
298
+ -------
299
+ object
300
+ EDB.PadGeometryType enumerator value.
301
+ """
302
+ return self._pedbpadstack._ppadstack.int_to_geometry_type(val)
303
+
304
+ @pyedb_function_handler()
305
+ def _update_pad_parameters_parameters(
306
+ self,
307
+ layer_name=None,
308
+ pad_type=None,
309
+ geom_type=None,
310
+ params=None,
311
+ offsetx=None,
312
+ offsety=None,
313
+ rotation=None,
314
+ ):
315
+ """Update padstack parameters.
316
+
317
+ Parameters
318
+ ----------
319
+ layer_name : str, optional
320
+ Name of the layer. The default is ``None``.
321
+ pad_type : int, optional
322
+ Type of the pad. The default is ``None``.
323
+ geom_type : int, optional
324
+ Type of the geometry. The default is ``None``.
325
+ params : list, optional
326
+ The default is ``None``.
327
+ offsetx : float, optional
328
+ Offset value for the X axis. The default is ``None``.
329
+ offsety : float, optional
330
+ Offset value for the Y axis. The default is ``None``.
331
+ rotation : float, optional
332
+ Rotation value. The default is ``None``.
333
+
334
+ Returns
335
+ -------
336
+ bool
337
+ ``True`` when successful, ``False`` when failed.
338
+ """
339
+ originalPadstackDefinitionData = self._edb_padstack.GetData()
340
+ newPadstackDefinitionData = self._edb.definition.PadstackDefData(originalPadstackDefinitionData)
341
+ if not pad_type:
342
+ pad_type = self.pad_type
343
+ if not geom_type:
344
+ geom_type = self.geometry_type
345
+ if params:
346
+ params = convert_py_list_to_net_list(params)
347
+ else:
348
+ params = self._pad_parameter_value[2]
349
+ if not offsetx:
350
+ offsetx = self.offset_x
351
+ if not offsety:
352
+ offsety = self.offset_y
353
+ if not rotation:
354
+ rotation = self.rotation
355
+ if not layer_name:
356
+ layer_name = self.layer_name
357
+
358
+ newPadstackDefinitionData.SetPadParameters(
359
+ layer_name,
360
+ self.int_to_pad_type(pad_type),
361
+ self.int_to_geometry_type(geom_type),
362
+ params,
363
+ self._get_edb_value(offsetx),
364
+ self._get_edb_value(offsety),
365
+ self._get_edb_value(rotation),
366
+ )
367
+ self._edb_padstack.SetData(newPadstackDefinitionData)
368
+
369
+
370
+ class EDBPadstack(object):
371
+ """Manages EDB functionalities for a padstack.
372
+
373
+ Parameters
374
+ ----------
375
+ edb_padstack :
376
+
377
+ ppadstack : str
378
+ Inherited AEDT object.
379
+
380
+ Examples
381
+ --------
382
+ >>> from pyedb import Edb
383
+ >>> edb = Edb(myedb, edbversion="2021.2")
384
+ >>> edb_padstack = edb.padstacks.definitions["MyPad"]
385
+ """
386
+
387
+ def __init__(self, edb_padstack, ppadstack):
388
+ self.edb_padstack = edb_padstack
389
+ self._ppadstack = ppadstack
390
+ self.pad_by_layer = {}
391
+ self.antipad_by_layer = {}
392
+ self.thermalpad_by_layer = {}
393
+ self._bounding_box = []
394
+ self._hole_params = None
395
+ for layer in self.via_layers:
396
+ self.pad_by_layer[layer] = EDBPadProperties(edb_padstack, layer, 0, self)
397
+ self.antipad_by_layer[layer] = EDBPadProperties(edb_padstack, layer, 1, self)
398
+ self.thermalpad_by_layer[layer] = EDBPadProperties(edb_padstack, layer, 2, self)
399
+ pass
400
+
401
+ @property
402
+ def instances(self):
403
+ """Definitions Instances."""
404
+ name = self.name
405
+ return [i for i in self._ppadstack.instances.values() if i.padstack_definition == name]
406
+
407
+ @property
408
+ def name(self):
409
+ """Padstack Definition Name."""
410
+ return self.edb_padstack.GetName()
411
+
412
+ @property
413
+ def _padstack_methods(self):
414
+ return self._ppadstack._padstack_methods
415
+
416
+ @property
417
+ def _stackup_layers(self):
418
+ return self._ppadstack._stackup_layers
419
+
420
+ @property
421
+ def _edb(self):
422
+ return self._ppadstack._edb
423
+
424
+ def _get_edb_value(self, value):
425
+ return self._ppadstack._get_edb_value(value)
426
+
427
+ @property
428
+ def via_layers(self):
429
+ """Layers.
430
+
431
+ Returns
432
+ -------
433
+ list
434
+ List of layers.
435
+ """
436
+ return self.edb_padstack.GetData().GetLayerNames()
437
+
438
+ @property
439
+ def via_start_layer(self):
440
+ """Starting layer.
441
+
442
+ Returns
443
+ -------
444
+ str
445
+ Name of the starting layer.
446
+ """
447
+ return list(self.via_layers)[0]
448
+
449
+ @property
450
+ def via_stop_layer(self):
451
+ """Stopping layer.
452
+
453
+ Returns
454
+ -------
455
+ str
456
+ Name of the stopping layer.
457
+ """
458
+ return list(self.via_layers)[-1]
459
+
460
+ @property
461
+ def hole_params(self):
462
+ """Via Hole parameters values."""
463
+
464
+ viaData = self.edb_padstack.GetData()
465
+ self._hole_params = viaData.GetHoleParametersValue()
466
+ return self._hole_params
467
+
468
+ @property
469
+ def hole_parameters(self):
470
+ """Hole parameters.
471
+
472
+ Returns
473
+ -------
474
+ list
475
+ List of the hole parameters.
476
+ """
477
+ self._hole_parameters = self.hole_params[2]
478
+ return self._hole_parameters
479
+
480
+ @pyedb_function_handler()
481
+ def _update_hole_parameters(self, hole_type=None, params=None, offsetx=None, offsety=None, rotation=None):
482
+ """Update hole parameters.
483
+
484
+ Parameters
485
+ ----------
486
+ hole_type : optional
487
+ Type of the hole. The default is ``None``.
488
+ params : optional
489
+ The default is ``None``.
490
+ offsetx : float, optional
491
+ Offset value for the X axis. The default is ``None``.
492
+ offsety : float, optional
493
+ Offset value for the Y axis. The default is ``None``.
494
+ rotation : float, optional
495
+ Rotation value in degrees. The default is ``None``.
496
+
497
+ Returns
498
+ -------
499
+ bool
500
+ ``True`` when successful, ``False`` when failed.
501
+ """
502
+ originalPadstackDefinitionData = self.edb_padstack.GetData()
503
+ newPadstackDefinitionData = self._edb.definition.PadstackDefData(originalPadstackDefinitionData)
504
+ if not hole_type:
505
+ hole_type = self.hole_type
506
+ if not params:
507
+ params = self.hole_parameters
508
+ if isinstance(params, list):
509
+ params = convert_py_list_to_net_list(params)
510
+ if not offsetx:
511
+ offsetx = self.hole_offset_x
512
+ if not offsety:
513
+ offsety = self.hole_offset_y
514
+ if not rotation:
515
+ rotation = self.hole_rotation
516
+ newPadstackDefinitionData.SetHoleParameters(
517
+ hole_type,
518
+ params,
519
+ self._get_edb_value(offsetx),
520
+ self._get_edb_value(offsety),
521
+ self._get_edb_value(rotation),
522
+ )
523
+ self.edb_padstack.SetData(newPadstackDefinitionData)
524
+
525
+ @property
526
+ def hole_properties(self):
527
+ """Hole properties.
528
+
529
+ Returns
530
+ -------
531
+ list
532
+ List of float values for hole properties.
533
+ """
534
+ self._hole_properties = [i.ToDouble() for i in self.hole_params[2]]
535
+ return self._hole_properties
536
+
537
+ @hole_properties.setter
538
+ def hole_properties(self, propertylist):
539
+ if not isinstance(propertylist, list):
540
+ propertylist = [self._get_edb_value(propertylist)]
541
+ else:
542
+ propertylist = [self._get_edb_value(i) for i in propertylist]
543
+ self._update_hole_parameters(params=propertylist)
544
+
545
+ @property
546
+ def hole_type(self):
547
+ """Hole type.
548
+
549
+ Returns
550
+ -------
551
+ int
552
+ Type of the hole.
553
+ """
554
+ self._hole_type = self.hole_params[1]
555
+ return self._hole_type
556
+
557
+ @property
558
+ def hole_offset_x(self):
559
+ """Hole offset for the X axis.
560
+
561
+ Returns
562
+ -------
563
+ str
564
+ Hole offset value for the X axis.
565
+ """
566
+ self._hole_offset_x = self.hole_params[3].ToString()
567
+ return self._hole_offset_x
568
+
569
+ @hole_offset_x.setter
570
+ def hole_offset_x(self, offset):
571
+ self._hole_offset_x = offset
572
+ self._update_hole_parameters(offsetx=offset)
573
+
574
+ @property
575
+ def hole_offset_y(self):
576
+ """Hole offset for the Y axis.
577
+
578
+ Returns
579
+ -------
580
+ str
581
+ Hole offset value for the Y axis.
582
+ """
583
+ self._hole_offset_y = self.hole_params[4].ToString()
584
+ return self._hole_offset_y
585
+
586
+ @hole_offset_y.setter
587
+ def hole_offset_y(self, offset):
588
+ self._hole_offset_y = offset
589
+ self._update_hole_parameters(offsety=offset)
590
+
591
+ @property
592
+ def hole_rotation(self):
593
+ """Hole rotation.
594
+
595
+ Returns
596
+ -------
597
+ str
598
+ Value for the hole rotation.
599
+ """
600
+ self._hole_rotation = self.hole_params[5].ToString()
601
+ return self._hole_rotation
602
+
603
+ @hole_rotation.setter
604
+ def hole_rotation(self, rotation):
605
+ self._hole_rotation = rotation
606
+ self._update_hole_parameters(rotation=rotation)
607
+
608
+ @property
609
+ def hole_plating_ratio(self):
610
+ """Hole plating ratio.
611
+
612
+ Returns
613
+ -------
614
+ float
615
+ Percentage for the hole plating.
616
+ """
617
+ return self._edb.definition.PadstackDefData(self.edb_padstack.GetData()).GetHolePlatingPercentage()
618
+
619
+ @hole_plating_ratio.setter
620
+ def hole_plating_ratio(self, ratio):
621
+ originalPadstackDefinitionData = self.edb_padstack.GetData()
622
+ newPadstackDefinitionData = self._edb.definition.PadstackDefData(originalPadstackDefinitionData)
623
+ newPadstackDefinitionData.SetHolePlatingPercentage(self._get_edb_value(ratio))
624
+ self.edb_padstack.SetData(newPadstackDefinitionData)
625
+
626
+ @property
627
+ def hole_plating_thickness(self):
628
+ """Hole plating thickness.
629
+
630
+ Returns
631
+ -------
632
+ float
633
+ Thickness of the hole plating if present.
634
+ """
635
+ if len(self.hole_properties) > 0:
636
+ return (float(self.hole_properties[0]) * self.hole_plating_ratio / 100) / 2
637
+ else:
638
+ return 0
639
+
640
+ @hole_plating_thickness.setter
641
+ def hole_plating_thickness(self, value):
642
+ """Hole plating thickness.
643
+
644
+ Returns
645
+ -------
646
+ float
647
+ Thickness of the hole plating if present.
648
+ """
649
+ hr = 200 * float(value) / float(self.hole_properties[0])
650
+ self.hole_plating_ratio = hr
651
+
652
+ @property
653
+ def hole_finished_size(self):
654
+ """Finished hole size.
655
+
656
+ Returns
657
+ -------
658
+ float
659
+ Finished size of the hole (Total Size + PlatingThickess*2).
660
+ """
661
+ if len(self.hole_properties) > 0:
662
+ return float(self.hole_properties[0]) - (self.hole_plating_thickness * 2)
663
+ else:
664
+ return 0
665
+
666
+ @property
667
+ def material(self):
668
+ """Hole material.
669
+
670
+ Returns
671
+ -------
672
+ str
673
+ Material of the hole.
674
+ """
675
+ return self.edb_padstack.GetData().GetMaterial()
676
+
677
+ @material.setter
678
+ def material(self, materialname):
679
+ originalPadstackDefinitionData = self.edb_padstack.GetData()
680
+ newPadstackDefinitionData = self._edb.definition.PadstackDefData(originalPadstackDefinitionData)
681
+ newPadstackDefinitionData.SetMaterial(materialname)
682
+ self.edb_padstack.SetData(newPadstackDefinitionData)
683
+
684
+ @property
685
+ def padstack_instances(self):
686
+ """Get all the vias that belongs to active Padstack definition.
687
+
688
+ Returns
689
+ -------
690
+ dict
691
+ """
692
+ return {
693
+ id: via for id, via in self._ppadstack.padstack_instances.items() if via.padstack_definition == self.name
694
+ }
695
+
696
+ @property
697
+ def hole_range(self):
698
+ """Get hole range value from padstack definition.
699
+
700
+ Returns
701
+ -------
702
+ str
703
+ Possible returned values are ``"through"``, ``"begin_on_upper_pad"``,
704
+ ``"end_on_lower_pad"``, ``"upper_pad_to_lower_pad"``, and ``"undefined"``.
705
+ """
706
+ cloned_padstackdef_data = self._edb.definition.PadstackDefData(self.edb_padstack.GetData())
707
+ hole_ange_type = int(cloned_padstackdef_data.GetHoleRange())
708
+ if hole_ange_type == 0: # pragma no cover
709
+ return "through"
710
+ elif hole_ange_type == 1: # pragma no cover
711
+ return "begin_on_upper_pad"
712
+ elif hole_ange_type == 2: # pragma no cover
713
+ return "end_on_lower_pad"
714
+ elif hole_ange_type == 3: # pragma no cover
715
+ return "upper_pad_to_lower_pad"
716
+ else: # pragma no cover
717
+ return "undefined"
718
+
719
+ @hole_range.setter
720
+ def hole_range(self, value):
721
+ if isinstance(value, str): # pragma no cover
722
+ cloned_padstackdef_data = self._edb.definition.PadstackDefData(self.edb_padstack.GetData())
723
+ if value == "through": # pragma no cover
724
+ cloned_padstackdef_data.SetHoleRange(self._edb.definition.PadstackHoleRange.Through)
725
+ elif value == "begin_on_upper_pad": # pragma no cover
726
+ cloned_padstackdef_data.SetHoleRange(self._edb.definition.PadstackHoleRange.BeginOnUpperPad)
727
+ elif value == "end_on_lower_pad": # pragma no cover
728
+ cloned_padstackdef_data.SetHoleRange(self._edb.definition.PadstackHoleRange.EndOnLowerPad)
729
+ elif value == "upper_pad_to_lower_pad": # pragma no cover
730
+ cloned_padstackdef_data.SetHoleRange(self._edb.definition.PadstackHoleRange.UpperPadToLowerPad)
731
+ else: # pragma no cover
732
+ return
733
+ self.edb_padstack.SetData(cloned_padstackdef_data)
734
+
735
+ @pyedb_function_handler()
736
+ def convert_to_3d_microvias(self, convert_only_signal_vias=True, hole_wall_angle=15, delete_padstack_def=True):
737
+ """Convert actual padstack instance to microvias 3D Objects with a given aspect ratio.
738
+
739
+ Parameters
740
+ ----------
741
+ convert_only_signal_vias : bool, optional
742
+ Either to convert only vias belonging to signal nets or all vias. Defaults is ``True``.
743
+ hole_wall_angle : float, optional
744
+ Angle of laser penetration in degrees. The angle defines the bottom hole diameter with this formula:
745
+ HoleDiameter -2*tan(laser_angle* Hole depth). Hole depth is the height of the via (dielectric thickness).
746
+ The default is ``15``.
747
+ The bottom hole is ``0.75*HoleDepth/HoleDiam``.
748
+ delete_padstack_def : bool, optional
749
+ Whether to delete the padstack definition. The default is ``True``.
750
+ If ``False``, the padstack definition is not deleted and the hole size is set to zero.
751
+
752
+ Returns
753
+ -------
754
+ ``True`` when successful, ``False`` when failed.
755
+ """
756
+
757
+ if len(self.hole_properties) == 0:
758
+ self._ppadstack._pedb.logger.error("Microvias cannot be applied on vias using hole shape polygon")
759
+ return False
760
+
761
+ if self.via_start_layer == self.via_stop_layer:
762
+ self._ppadstack._pedb.logger.error("Microvias cannot be applied when Start and Stop Layers are the same.")
763
+ layout = self._ppadstack._pedb.active_layout
764
+ layers = self._ppadstack._pedb.stackup.signal_layers
765
+ layer_names = [i for i in list(layers.keys())]
766
+ if convert_only_signal_vias:
767
+ signal_nets = [i for i in list(self._ppadstack._pedb.nets.signal_nets.keys())]
768
+ topl, topz, bottoml, bottomz = self._ppadstack._pedb.stackup.stackup_limits(True)
769
+ try:
770
+ start_elevation = layers[self.via_start_layer].lower_elevation
771
+ except KeyError: # pragma: no cover
772
+ start_elevation = layers[self.instances[0].start_layer].lower_elevation
773
+ try:
774
+ stop_elevation = layers[self.via_start_layer].upper_elevation
775
+ except KeyError: # pragma: no cover
776
+ stop_elevation = layers[self.instances[0].stop_layer].upper_elevation
777
+
778
+ diel_thick = abs(start_elevation - stop_elevation)
779
+ rad1 = self.hole_properties[0] / 2
780
+ rad2 = self.hole_properties[0] / 2 - math.tan(hole_wall_angle * diel_thick * math.pi / 180)
781
+
782
+ if start_elevation < (topz + bottomz) / 2:
783
+ rad1, rad2 = rad2, rad1
784
+ i = 0
785
+ for via in list(self.padstack_instances.values()):
786
+ if convert_only_signal_vias and via.net_name in signal_nets or not convert_only_signal_vias:
787
+ pos = via.position
788
+ started = False
789
+ if len(self.pad_by_layer[self.via_start_layer].parameters) == 0:
790
+ self._edb.cell.primitive.polygon.create(
791
+ layout,
792
+ self.via_start_layer,
793
+ via._edb_padstackinstance.GetNet(),
794
+ self.pad_by_layer[self.via_start_layer].polygon_data.edb_api,
795
+ )
796
+ else:
797
+ self._edb.cell.primitive.circle.create(
798
+ layout,
799
+ self.via_start_layer,
800
+ via._edb_padstackinstance.GetNet(),
801
+ self._get_edb_value(pos[0]),
802
+ self._get_edb_value(pos[1]),
803
+ self._get_edb_value(self.pad_by_layer[self.via_start_layer].parameters_values[0] / 2),
804
+ )
805
+ if len(self.pad_by_layer[self.via_stop_layer].parameters) == 0:
806
+ self._edb.cell.primitive.polygon.create(
807
+ layout,
808
+ self.via_stop_layer,
809
+ via._edb_padstackinstance.GetNet(),
810
+ self.pad_by_layer[self.via_stop_layer].polygon_data.edb_api,
811
+ )
812
+ else:
813
+ self._edb.cell.primitive.circle.create(
814
+ layout,
815
+ self.via_stop_layer,
816
+ via._edb_padstackinstance.GetNet(),
817
+ self._get_edb_value(pos[0]),
818
+ self._get_edb_value(pos[1]),
819
+ self._get_edb_value(self.pad_by_layer[self.via_stop_layer].parameters_values[0] / 2),
820
+ )
821
+ for layer_name in layer_names:
822
+ stop = ""
823
+ if layer_name == via.start_layer or started:
824
+ start = layer_name
825
+ stop = layer_names[layer_names.index(layer_name) + 1]
826
+ cloned_circle = self._edb.cell.primitive.circle.create(
827
+ layout,
828
+ start,
829
+ via._edb_padstackinstance.GetNet(),
830
+ self._get_edb_value(pos[0]),
831
+ self._get_edb_value(pos[1]),
832
+ self._get_edb_value(rad1),
833
+ )
834
+ cloned_circle2 = self._edb.cell.primitive.circle.create(
835
+ layout,
836
+ stop,
837
+ via._edb_padstackinstance.GetNet(),
838
+ self._get_edb_value(pos[0]),
839
+ self._get_edb_value(pos[1]),
840
+ self._get_edb_value(rad2),
841
+ )
842
+ s3d = self._edb.cell.hierarchy._hierarchy.Structure3D.Create(
843
+ layout, generate_unique_name("via3d_" + via.aedt_name.replace("via_", ""), n=3)
844
+ )
845
+ s3d.AddMember(cloned_circle.prim_obj)
846
+ s3d.AddMember(cloned_circle2.prim_obj)
847
+ s3d.SetMaterial(self.material)
848
+ s3d.SetMeshClosureProp(self._edb.cell.hierarchy._hierarchy.Structure3D.TClosure.EndsClosed)
849
+ started = True
850
+ i += 1
851
+ if stop == via.stop_layer:
852
+ break
853
+ if delete_padstack_def: # pragma no cover
854
+ via.delete()
855
+ else: # pragma no cover
856
+ padstack_def = self._ppadstack.definitions[via.padstack_definition]
857
+ padstack_def.hole_properties = 0
858
+ self._ppadstack._pedb.logger.info("Padstack definition kept, hole size set to 0.")
859
+
860
+ self._ppadstack._pedb.logger.info("{} Converted successfully to 3D Objects.".format(i))
861
+ return True
862
+
863
+ @pyedb_function_handler()
864
+ def split_to_microvias(self):
865
+ """Convert actual padstack definition to multiple microvias definitions.
866
+
867
+ Returns
868
+ -------
869
+ List of :class:`pyedb.dotnet.edb_core.padstackEDBPadstack`
870
+ """
871
+ if self.via_start_layer == self.via_stop_layer:
872
+ self._ppadstack._pedb.logger.error("Microvias cannot be applied when Start and Stop Layers are the same.")
873
+ layout = self._ppadstack._pedb.active_layout
874
+ layers = self._ppadstack._pedb.stackup.signal_layers
875
+ layer_names = [i for i in list(layers.keys())]
876
+ if abs(layer_names.index(self.via_start_layer) - layer_names.index(self.via_stop_layer)) < 2:
877
+ self._ppadstack._pedb.logger.error(
878
+ "Conversion can be applied only if Padstack definition is composed by more than 2 layers."
879
+ )
880
+ return False
881
+ started = False
882
+ p1 = self.edb_padstack.GetData()
883
+ new_instances = []
884
+ for layer_name in layer_names:
885
+ stop = ""
886
+ if layer_name == self.via_start_layer or started:
887
+ start = layer_name
888
+ stop = layer_names[layer_names.index(layer_name) + 1]
889
+ new_padstack_name = "MV_{}_{}_{}".format(self.name, start, stop)
890
+ included = [start, stop]
891
+ new_padstack_definition_data = self._ppadstack._pedb.edb_api.definition.PadstackDefData.Create()
892
+ new_padstack_definition_data.AddLayers(convert_py_list_to_net_list(included))
893
+ for layer in included:
894
+ pl = self.pad_by_layer[layer]
895
+ new_padstack_definition_data.SetPadParameters(
896
+ layer,
897
+ self._ppadstack._pedb.edb_api.definition.PadType.RegularPad,
898
+ pl.int_to_geometry_type(pl.geometry_type),
899
+ list(
900
+ pl._edb_padstack.GetData().GetPadParametersValue(
901
+ pl.layer_name, pl.int_to_pad_type(pl.pad_type)
902
+ )
903
+ )[2],
904
+ pl._edb_padstack.GetData().GetPadParametersValue(
905
+ pl.layer_name, pl.int_to_pad_type(pl.pad_type)
906
+ )[3],
907
+ pl._edb_padstack.GetData().GetPadParametersValue(
908
+ pl.layer_name, pl.int_to_pad_type(pl.pad_type)
909
+ )[4],
910
+ pl._edb_padstack.GetData().GetPadParametersValue(
911
+ pl.layer_name, pl.int_to_pad_type(pl.pad_type)
912
+ )[5],
913
+ )
914
+ pl = self.antipad_by_layer[layer]
915
+ new_padstack_definition_data.SetPadParameters(
916
+ layer,
917
+ self._ppadstack._pedb.edb_api.definition.PadType.AntiPad,
918
+ pl.int_to_geometry_type(pl.geometry_type),
919
+ list(
920
+ pl._edb_padstack.GetData().GetPadParametersValue(
921
+ pl.layer_name, pl.int_to_pad_type(pl.pad_type)
922
+ )
923
+ )[2],
924
+ pl._edb_padstack.GetData().GetPadParametersValue(
925
+ pl.layer_name, pl.int_to_pad_type(pl.pad_type)
926
+ )[3],
927
+ pl._edb_padstack.GetData().GetPadParametersValue(
928
+ pl.layer_name, pl.int_to_pad_type(pl.pad_type)
929
+ )[4],
930
+ pl._edb_padstack.GetData().GetPadParametersValue(
931
+ pl.layer_name, pl.int_to_pad_type(pl.pad_type)
932
+ )[5],
933
+ )
934
+ pl = self.thermalpad_by_layer[layer]
935
+ new_padstack_definition_data.SetPadParameters(
936
+ layer,
937
+ self._ppadstack._pedb.edb_api.definition.PadType.ThermalPad,
938
+ pl.int_to_geometry_type(pl.geometry_type),
939
+ list(
940
+ pl._edb_padstack.GetData().GetPadParametersValue(
941
+ pl.layer_name, pl.int_to_pad_type(pl.pad_type)
942
+ )
943
+ )[2],
944
+ pl._edb_padstack.GetData().GetPadParametersValue(
945
+ pl.layer_name, pl.int_to_pad_type(pl.pad_type)
946
+ )[3],
947
+ pl._edb_padstack.GetData().GetPadParametersValue(
948
+ pl.layer_name, pl.int_to_pad_type(pl.pad_type)
949
+ )[4],
950
+ pl._edb_padstack.GetData().GetPadParametersValue(
951
+ pl.layer_name, pl.int_to_pad_type(pl.pad_type)
952
+ )[5],
953
+ )
954
+ new_padstack_definition_data.SetHoleParameters(
955
+ self.hole_type,
956
+ self.hole_parameters,
957
+ self._get_edb_value(self.hole_offset_x),
958
+ self._get_edb_value(self.hole_offset_y),
959
+ self._get_edb_value(self.hole_rotation),
960
+ )
961
+ new_padstack_definition_data.SetMaterial(self.material)
962
+ new_padstack_definition_data.SetHolePlatingPercentage(self._get_edb_value(self.hole_plating_ratio))
963
+ padstack_definition = self._edb.definition.PadstackDef.Create(
964
+ self._ppadstack._pedb.active_db, new_padstack_name
965
+ )
966
+ padstack_definition.SetData(new_padstack_definition_data)
967
+ new_instances.append(EDBPadstack(padstack_definition, self._ppadstack))
968
+ started = True
969
+ if self.via_stop_layer == stop:
970
+ break
971
+ i = 0
972
+ for via in list(self.padstack_instances.values()):
973
+ for inst in new_instances:
974
+ instance = inst.edb_padstack
975
+ from_layer = [
976
+ l
977
+ for l in self._ppadstack._pedb.stackup._edb_layer_list
978
+ if l.GetName() == list(instance.GetData().GetLayerNames())[0]
979
+ ][0]
980
+ to_layer = [
981
+ l
982
+ for l in self._ppadstack._pedb.stackup._edb_layer_list
983
+ if l.GetName() == list(instance.GetData().GetLayerNames())[-1]
984
+ ][0]
985
+ padstack_instance = self._edb.cell.primitive.padstack_instance.create(
986
+ layout,
987
+ via._edb_padstackinstance.GetNet(),
988
+ generate_unique_name(instance.GetName()),
989
+ instance,
990
+ via._edb_padstackinstance.GetPositionAndRotationValue()[1],
991
+ via._edb_padstackinstance.GetPositionAndRotationValue()[2],
992
+ from_layer,
993
+ to_layer,
994
+ None,
995
+ None,
996
+ )
997
+ padstack_instance.SetIsLayoutPin(via.is_pin)
998
+ i += 1
999
+ via.delete()
1000
+ self._ppadstack._pedb.logger.info("Created {} new microvias.".format(i))
1001
+ return new_instances
1002
+
1003
+ @pyedb_function_handler()
1004
+ def _update_layer_names(self, old_name, updated_name):
1005
+ """Update padstack definition layer name when layer name is edited with the layer name setter.
1006
+ Parameters
1007
+ ----------
1008
+ old_name
1009
+ old name : str
1010
+ updated_name
1011
+ new name : str
1012
+ Returns
1013
+ -------
1014
+ bool
1015
+ ``True`` when succeed ``False`` when failed.
1016
+ """
1017
+ cloned_padstack_data = self._edb.definition.PadstackDefData(self.edb_padstack.GetData())
1018
+ new_padstack_data = self._edb.definition.PadstackDefData.Create()
1019
+ layers_name = cloned_padstack_data.GetLayerNames()
1020
+ layers_to_add = []
1021
+ for layer in layers_name:
1022
+ if layer == old_name:
1023
+ layers_to_add.append(updated_name)
1024
+ else:
1025
+ layers_to_add.append(layer)
1026
+ new_padstack_data.AddLayers(convert_py_list_to_net_list(layers_to_add))
1027
+ for layer in layers_name:
1028
+ updated_pad = self.pad_by_layer[layer]
1029
+ if not updated_pad.geometry_type == 0: # pragma no cover
1030
+ pad_type = self._edb.definition.PadType.RegularPad
1031
+ geom_type = self.pad_by_layer[layer]._pad_parameter_value[1]
1032
+ parameters = self.pad_by_layer[layer]._pad_parameter_value[2]
1033
+ offset_x = self.pad_by_layer[layer]._pad_parameter_value[3]
1034
+ offset_y = self.pad_by_layer[layer]._pad_parameter_value[4]
1035
+ rot = self.pad_by_layer[layer]._pad_parameter_value[5]
1036
+ if layer == old_name: # pragma no cover
1037
+ new_padstack_data.SetPadParameters(
1038
+ updated_name, pad_type, geom_type, parameters, offset_x, offset_y, rot
1039
+ )
1040
+ else:
1041
+ new_padstack_data.SetPadParameters(layer, pad_type, geom_type, parameters, offset_x, offset_y, rot)
1042
+
1043
+ updated_anti_pad = self.antipad_by_layer[layer]
1044
+ if not updated_anti_pad.geometry_type == 0: # pragma no cover
1045
+ pad_type = self._edb.definition.PadType.AntiPad
1046
+ geom_type = self.pad_by_layer[layer]._pad_parameter_value[1]
1047
+ parameters = self.pad_by_layer[layer]._pad_parameter_value[2]
1048
+ offset_x = self.pad_by_layer[layer]._pad_parameter_value[3]
1049
+ offset_y = self.pad_by_layer[layer]._pad_parameter_value[4]
1050
+ rotation = self.pad_by_layer[layer]._pad_parameter_value[5]
1051
+ if layer == old_name: # pragma no cover
1052
+ new_padstack_data.SetPadParameters(
1053
+ updated_name, pad_type, geom_type, parameters, offset_x, offset_y, rotation
1054
+ )
1055
+ else:
1056
+ new_padstack_data.SetPadParameters(
1057
+ layer, pad_type, geom_type, parameters, offset_x, offset_y, rotation
1058
+ )
1059
+
1060
+ updated_thermal_pad = self.thermalpad_by_layer[layer]
1061
+ if not updated_thermal_pad.geometry_type == 0: # pragma no cover
1062
+ pad_type = self._edb.definition.PadType.ThermalPad
1063
+ geom_type = self.pad_by_layer[layer]._pad_parameter_value[1]
1064
+ parameters = self.pad_by_layer[layer]._pad_parameter_value[2]
1065
+ offset_x = self.pad_by_layer[layer]._pad_parameter_value[3]
1066
+ offset_y = self.pad_by_layer[layer]._pad_parameter_value[4]
1067
+ rotation = self.pad_by_layer[layer]._pad_parameter_value[5]
1068
+ if layer == old_name: # pragma no cover
1069
+ new_padstack_data.SetPadParameters(
1070
+ updated_name, pad_type, geom_type, parameters, offset_x, offset_y, rotation
1071
+ )
1072
+ else:
1073
+ new_padstack_data.SetPadParameters(
1074
+ layer, pad_type, geom_type, parameters, offset_x, offset_y, rotation
1075
+ )
1076
+
1077
+ hole_param = cloned_padstack_data.GetHoleParameters()
1078
+ if hole_param[0]:
1079
+ hole_geom = hole_param[1]
1080
+ hole_params = convert_py_list_to_net_list([self._get_edb_value(i) for i in hole_param[2]])
1081
+ hole_off_x = self._get_edb_value(hole_param[3])
1082
+ hole_off_y = self._get_edb_value(hole_param[4])
1083
+ hole_rot = self._get_edb_value(hole_param[5])
1084
+ new_padstack_data.SetHoleParameters(hole_geom, hole_params, hole_off_x, hole_off_y, hole_rot)
1085
+
1086
+ new_padstack_data.SetHolePlatingPercentage(self._get_edb_value(cloned_padstack_data.GetHolePlatingPercentage()))
1087
+
1088
+ new_padstack_data.SetHoleRange(cloned_padstack_data.GetHoleRange())
1089
+ new_padstack_data.SetMaterial(cloned_padstack_data.GetMaterial())
1090
+ new_padstack_data.SetSolderBallMaterial(cloned_padstack_data.GetSolderBallMaterial())
1091
+ solder_ball_param = cloned_padstack_data.GetSolderBallParameter()
1092
+ if solder_ball_param[0]:
1093
+ new_padstack_data.SetSolderBallParameter(
1094
+ self._get_edb_value(solder_ball_param[1]), self._get_edb_value(solder_ball_param[2])
1095
+ )
1096
+ new_padstack_data.SetSolderBallPlacement(cloned_padstack_data.GetSolderBallPlacement())
1097
+ new_padstack_data.SetSolderBallShape(cloned_padstack_data.GetSolderBallShape())
1098
+ self.edb_padstack.SetData(new_padstack_data)
1099
+ return True
1100
+
1101
+
1102
+ class EDBPadstackInstance(EDBPrimitivesMain):
1103
+ """Manages EDB functionalities for a padstack.
1104
+
1105
+ Parameters
1106
+ ----------
1107
+ edb_padstackinstance :
1108
+
1109
+ _pedb :
1110
+ Inherited AEDT object.
1111
+
1112
+ Examples
1113
+ --------
1114
+ >>> from pyedb import Edb
1115
+ >>> edb = Edb(myedb, edbversion="2021.2")
1116
+ >>> edb_padstack_instance = edb.padstacks.instances[0]
1117
+ """
1118
+
1119
+ def __init__(self, edb_padstackinstance, _pedb):
1120
+ super().__init__(edb_padstackinstance, _pedb)
1121
+ self._edb_padstackinstance = self._edb_object
1122
+ self._bounding_box = []
1123
+ self._object_instance = None
1124
+ self._position = []
1125
+ self._pdef = None
1126
+
1127
+ def get_terminal(self, name=None, create_new_terminal=False):
1128
+ """Get PadstackInstanceTerminal object.
1129
+
1130
+ Parameters
1131
+ ----------
1132
+ name : str, optional
1133
+ Name of the terminal. Only applicable when create_new_terminal is True.
1134
+ create_new_terminal : bool, optional
1135
+ Whether to create a new terminal.
1136
+
1137
+ Returns
1138
+ -------
1139
+ :class:`pyedb.dotnet.edb_core.edb_data.terminals`
1140
+ """
1141
+
1142
+ if create_new_terminal:
1143
+ term = self._create_terminal(name)
1144
+ else:
1145
+ from pyedb.dotnet.edb_core.edb_data.terminals import (
1146
+ PadstackInstanceTerminal,
1147
+ )
1148
+
1149
+ term = PadstackInstanceTerminal(self._pedb, self._edb_object.GetPadstackInstanceTerminal())
1150
+ if not term.is_null:
1151
+ return term
1152
+
1153
+ @pyedb_function_handler()
1154
+ def _create_terminal(self, name=None):
1155
+ """Create a padstack instance terminal"""
1156
+ from pyedb.dotnet.edb_core.edb_data.terminals import PadstackInstanceTerminal
1157
+
1158
+ term = PadstackInstanceTerminal(self._pedb, self._edb_object.GetPadstackInstanceTerminal())
1159
+ return term.create(self, name)
1160
+
1161
+ @pyedb_function_handler()
1162
+ def create_coax_port(self, name=None, radial_extent_factor=0):
1163
+ """Create a coax port."""
1164
+ port = self.create_port(name)
1165
+ port.radial_extent_factor = radial_extent_factor
1166
+ return port
1167
+
1168
+ @pyedb_function_handler
1169
+ def create_port(self, name=None, reference=None, is_circuit_port=False):
1170
+ """Create a port on the padstack.
1171
+
1172
+ Parameters
1173
+ ----------
1174
+ name : str, optional
1175
+ Name of the port. The default is ``None``, in which case a name is automatically assigned.
1176
+ reference : class:`pyedb.dotnet.edb_core.edb_data.nets_data.EDBNetsData`, \
1177
+ class:`pyedb.dotnet.edb_core.edb_data.padstacks_data.EDBPadstackInstance`, \
1178
+ class:`pyedb.dotnet.edb_core.edb_data.sources.PinGroup`, optional
1179
+ Negative terminal of the port.
1180
+ is_circuit_port : bool, optional
1181
+ Whether it is a circuit port.
1182
+ """
1183
+ terminal = self._create_terminal(name)
1184
+ if reference:
1185
+ ref_terminal = reference._create_terminal(terminal.name + "_ref")
1186
+ if reference._edb_object.ToString() == "PinGroup":
1187
+ is_circuit_port = True
1188
+ else:
1189
+ ref_terminal = None
1190
+
1191
+ return self._pedb.create_port(terminal, ref_terminal, is_circuit_port)
1192
+
1193
+ @property
1194
+ def _em_properties(self):
1195
+ """Get EM properties."""
1196
+ default = (
1197
+ r"$begin 'EM properties'\n"
1198
+ r"\tType('Mesh')\n"
1199
+ r"\tDataId='EM properties1'\n"
1200
+ r"\t$begin 'Properties'\n"
1201
+ r"\t\tGeneral=''\n"
1202
+ r"\t\tModeled='true'\n"
1203
+ r"\t\tUnion='true'\n"
1204
+ r"\t\t'Use Precedence'='false'\n"
1205
+ r"\t\t'Precedence Value'='1'\n"
1206
+ r"\t\tPlanarEM=''\n"
1207
+ r"\t\tRefined='true'\n"
1208
+ r"\t\tRefineFactor='1'\n"
1209
+ r"\t\tNoEdgeMesh='false'\n"
1210
+ r"\t\tHFSS=''\n"
1211
+ r"\t\t'Solve Inside'='false'\n"
1212
+ r"\t\tSIwave=''\n"
1213
+ r"\t\t'DCIR Equipotential Region'='false'\n"
1214
+ r"\t$end 'Properties'\n"
1215
+ r"$end 'EM properties'\n"
1216
+ )
1217
+
1218
+ pid = self._pedb.edb_api.ProductId.Designer
1219
+ _, p = self._edb_padstackinstance.GetProductProperty(pid, 18, "")
1220
+ if p:
1221
+ return p
1222
+ else:
1223
+ return default
1224
+
1225
+ @_em_properties.setter
1226
+ def _em_properties(self, em_prop):
1227
+ """Set EM properties"""
1228
+ pid = self._pedb.edb_api.ProductId.Designer
1229
+ self._edb_padstackinstance.SetProductProperty(pid, 18, em_prop)
1230
+
1231
+ @property
1232
+ def dcir_equipotential_region(self):
1233
+ """Check whether dcir equipotential region is enabled.
1234
+
1235
+ Returns
1236
+ -------
1237
+ bool
1238
+ """
1239
+ pattern = r"'DCIR Equipotential Region'='([^']+)'"
1240
+ em_pp = self._em_properties
1241
+ result = re.search(pattern, em_pp).group(1)
1242
+ if result == "true":
1243
+ return True
1244
+ else:
1245
+ return False
1246
+
1247
+ @dcir_equipotential_region.setter
1248
+ def dcir_equipotential_region(self, value):
1249
+ """Set dcir equipotential region."""
1250
+ pp = r"'DCIR Equipotential Region'='true'" if value else r"'DCIR Equipotential Region'='false'"
1251
+ em_pp = self._em_properties
1252
+ pattern = r"'DCIR Equipotential Region'='([^']+)'"
1253
+ new_em_pp = re.sub(pattern, pp, em_pp)
1254
+ self._em_properties = new_em_pp
1255
+
1256
+ @property
1257
+ def object_instance(self):
1258
+ """Return Ansys.Ansoft.Edb.LayoutInstance.LayoutObjInstance object."""
1259
+ if not self._object_instance:
1260
+ self._object_instance = (
1261
+ self._edb_padstackinstance.GetLayout()
1262
+ .GetLayoutInstance()
1263
+ .GetLayoutObjInstance(self._edb_padstackinstance, None)
1264
+ )
1265
+ return self._object_instance
1266
+
1267
+ @property
1268
+ def bounding_box(self):
1269
+ """Get bounding box of the padstack instance.
1270
+ Because this method is slow, the bounding box is stored in a variable and reused.
1271
+
1272
+ Returns
1273
+ -------
1274
+ list of float
1275
+ """
1276
+ if self._bounding_box:
1277
+ return self._bounding_box
1278
+ bbox = self.object_instance.GetBBox()
1279
+ self._bounding_box = [
1280
+ [bbox.Item1.X.ToDouble(), bbox.Item1.Y.ToDouble()],
1281
+ [bbox.Item2.X.ToDouble(), bbox.Item2.Y.ToDouble()],
1282
+ ]
1283
+ return self._bounding_box
1284
+
1285
+ @pyedb_function_handler()
1286
+ def in_polygon(self, polygon_data, include_partial=True, simple_check=False):
1287
+ """Check if padstack Instance is in given polygon data.
1288
+
1289
+ Parameters
1290
+ ----------
1291
+ polygon_data : PolygonData Object
1292
+ include_partial : bool, optional
1293
+ Whether to include partial intersecting instances. The default is ``True``.
1294
+ simple_check : bool, optional
1295
+ Whether to perform a single check based on the padstack center or check the padstack bounding box.
1296
+
1297
+ Returns
1298
+ -------
1299
+ bool
1300
+ ``True`` when successful, ``False`` when failed.
1301
+ """
1302
+ pos = [i for i in self.position]
1303
+ int_val = 1 if polygon_data.PointInPolygon(self._pedb.point_data(*pos)) else 0
1304
+ if int_val == 0:
1305
+ return False
1306
+
1307
+ if simple_check:
1308
+ # pos = [i for i in self.position]
1309
+ # int_val = 1 if polygon_data.PointInPolygon(self._pedb.point_data(*pos)) else 0
1310
+ return True
1311
+ else:
1312
+ plane = self._pedb.modeler.Shape("rectangle", pointA=self.bounding_box[0], pointB=self.bounding_box[1])
1313
+ rectangle_data = self._pedb.modeler.shape_to_polygon_data(plane)
1314
+ int_val = polygon_data.GetIntersectionType(rectangle_data)
1315
+ # Intersection type:
1316
+ # 0 = objects do not intersect
1317
+ # 1 = this object fully inside other (no common contour points)
1318
+ # 2 = other object fully inside this
1319
+ # 3 = common contour points 4 = undefined intersection
1320
+ if int_val == 0:
1321
+ return False
1322
+ elif include_partial:
1323
+ return True
1324
+ elif int_val < 3:
1325
+ return True
1326
+ else:
1327
+ return False
1328
+
1329
+ @property
1330
+ def pin(self):
1331
+ """EDB padstack object."""
1332
+ warnings.warn("`pin` is deprecated.", DeprecationWarning)
1333
+ return self._edb_padstackinstance
1334
+
1335
+ @property
1336
+ def padstack_definition(self):
1337
+ """Padstack definition.
1338
+
1339
+ Returns
1340
+ -------
1341
+ str
1342
+ Name of the padstack definition.
1343
+ """
1344
+ self._pdef = self._edb_padstackinstance.GetPadstackDef().GetName()
1345
+ return self._pdef
1346
+
1347
+ @property
1348
+ def backdrill_top(self):
1349
+ """Backdrill layer from top.
1350
+
1351
+ Returns
1352
+ -------
1353
+ tuple
1354
+ Tuple of the layer name, drill diameter, and offset if it exists.
1355
+ """
1356
+ layer = self._pedb.edb_api.cell.layer("", self._pedb.edb_api.cell.layer_type.SignalLayer)
1357
+ val = self._pedb.edb_value(0)
1358
+ offset = self._pedb.edb_value(0.0)
1359
+ if is_ironpython: # pragma: no cover
1360
+ diameter = _clr.StrongBox[type(val)]()
1361
+ drill_to_layer = _clr.StrongBox[self._pedb.edb_api.Cell.ILayerReadOnly]()
1362
+ flag = self._edb_padstackinstance.GetBackDrillParametersLayerValue(drill_to_layer, offset, diameter, False)
1363
+ else:
1364
+ (
1365
+ flag,
1366
+ drill_to_layer,
1367
+ offset,
1368
+ diameter,
1369
+ ) = self._edb_padstackinstance.GetBackDrillParametersLayerValue(layer, offset, val, False)
1370
+ if flag:
1371
+ if offset.ToDouble():
1372
+ return drill_to_layer.GetName(), diameter.ToString(), offset.ToString()
1373
+ else:
1374
+ return drill_to_layer.GetName(), diameter.ToString()
1375
+ else:
1376
+ return
1377
+
1378
+ def set_backdrill_top(self, drill_depth, drill_diameter, offset=0.0):
1379
+ """Set backdrill from top.
1380
+
1381
+ Parameters
1382
+ ----------
1383
+ drill_depth : str
1384
+ Name of the drill to layer.
1385
+ drill_diameter : float, str
1386
+ Diameter of backdrill size.
1387
+ offset : float, str
1388
+ Offset for the backdrill. The default is ``0.0``. If the value is other than the
1389
+ default, the stub does not stop at the layer. In AEDT, this parameter is called
1390
+ "Mfg stub length".
1391
+
1392
+ Returns
1393
+ -------
1394
+ bool
1395
+ True if success, False otherwise.
1396
+ """
1397
+ layer = self._pedb.stackup.layers[drill_depth]._edb_layer
1398
+ val = self._pedb.edb_value(drill_diameter)
1399
+ offset = self._pedb.edb_value(offset)
1400
+ if offset.ToDouble():
1401
+ return self._edb_padstackinstance.SetBackDrillParameters(layer, offset, val, False)
1402
+ else:
1403
+ return self._edb_padstackinstance.SetBackDrillParameters(layer, val, False)
1404
+
1405
+ @property
1406
+ def backdrill_bottom(self):
1407
+ """Backdrill layer from bottom.
1408
+
1409
+ Returns
1410
+ -------
1411
+ tuple
1412
+ Tuple of the layer name, drill diameter, and drill offset if it exists.
1413
+ """
1414
+ layer = self._pedb.edb_api.cell.layer("", self._pedb.edb_api.cell.layer_type.SignalLayer)
1415
+ val = self._pedb.edb_value(0)
1416
+ offset = self._pedb.edb_value(0.0)
1417
+ if is_ironpython: # pragma: no cover
1418
+ diameter = _clr.StrongBox[type(val)]()
1419
+ drill_to_layer = _clr.StrongBox[self._pedb.edb_api.Cell.ILayerReadOnly]()
1420
+ flag = self._edb_padstackinstance.GetBackDrillParametersLayerValue(drill_to_layer, offset, diameter, True)
1421
+ else:
1422
+ (
1423
+ flag,
1424
+ drill_to_layer,
1425
+ offset,
1426
+ diameter,
1427
+ ) = self._edb_padstackinstance.GetBackDrillParametersLayerValue(layer, offset, val, True)
1428
+ if flag:
1429
+ if offset.ToDouble():
1430
+ return drill_to_layer.GetName(), diameter.ToString(), offset.ToString()
1431
+ else:
1432
+ return drill_to_layer.GetName(), diameter.ToString()
1433
+ else:
1434
+ return
1435
+
1436
+ def set_backdrill_bottom(self, drill_depth, drill_diameter, offset=0.0):
1437
+ """Set backdrill from bottom.
1438
+
1439
+ Parameters
1440
+ ----------
1441
+ drill_depth : str
1442
+ Name of the drill to layer.
1443
+ drill_diameter : float, str
1444
+ Diameter of the backdrill size.
1445
+ offset : float, str, optional
1446
+ Offset for the backdrill. The default is ``0.0``. If the value is other than the
1447
+ default, the stub does not stop at the layer. In AEDT, this parameter is called
1448
+ "Mfg stub length".
1449
+
1450
+ Returns
1451
+ -------
1452
+ bool
1453
+ True if success, False otherwise.
1454
+ """
1455
+ layer = self._pedb.stackup.layers[drill_depth]._edb_layer
1456
+ val = self._pedb.edb_value(drill_diameter)
1457
+ offset = self._pedb.edb_value(offset)
1458
+ if offset.ToDouble():
1459
+ return self._edb_padstackinstance.SetBackDrillParameters(layer, offset, val, True)
1460
+ else:
1461
+ return self._edb_padstackinstance.SetBackDrillParameters(layer, val, True)
1462
+
1463
+ @property
1464
+ def start_layer(self):
1465
+ """Starting layer.
1466
+
1467
+ Returns
1468
+ -------
1469
+ str
1470
+ Name of the starting layer.
1471
+ """
1472
+ layer = self._pedb.edb_api.cell.layer("", self._pedb.edb_api.cell.layer_type.SignalLayer)
1473
+ _, start_layer, stop_layer = self._edb_padstackinstance.GetLayerRange()
1474
+
1475
+ if start_layer:
1476
+ return start_layer.GetName()
1477
+ return None
1478
+
1479
+ @start_layer.setter
1480
+ def start_layer(self, layer_name):
1481
+ stop_layer = self._pedb.stackup.signal_layers[self.stop_layer]._edb_layer
1482
+ layer = self._pedb.stackup.signal_layers[layer_name]._edb_layer
1483
+ self._edb_padstackinstance.SetLayerRange(layer, stop_layer)
1484
+
1485
+ @property
1486
+ def stop_layer(self):
1487
+ """Stopping layer.
1488
+
1489
+ Returns
1490
+ -------
1491
+ str
1492
+ Name of the stopping layer.
1493
+ """
1494
+ layer = self._pedb.edb_api.cell.layer("", self._pedb.edb_api.cell.layer_type.SignalLayer)
1495
+ _, start_layer, stop_layer = self._edb_padstackinstance.GetLayerRange()
1496
+
1497
+ if stop_layer:
1498
+ return stop_layer.GetName()
1499
+ return None
1500
+
1501
+ @stop_layer.setter
1502
+ def stop_layer(self, layer_name):
1503
+ start_layer = self._pedb.stackup.signal_layers[self.start_layer]._edb_layer
1504
+ layer = self._pedb.stackup.signal_layers[layer_name]._edb_layer
1505
+ self._edb_padstackinstance.SetLayerRange(start_layer, layer)
1506
+
1507
+ @property
1508
+ def layer_range_names(self):
1509
+ """List of all layers to which the padstack instance belongs."""
1510
+ _, start_layer, stop_layer = self._edb_padstackinstance.GetLayerRange()
1511
+ started = False
1512
+ layer_list = []
1513
+ start_layer_name = start_layer.GetName()
1514
+ stop_layer_name = stop_layer.GetName()
1515
+ for layer_name in list(self._pedb.stackup.layers.keys()):
1516
+ if started:
1517
+ layer_list.append(layer_name)
1518
+ if layer_name == stop_layer_name or layer_name == start_layer_name:
1519
+ break
1520
+ elif layer_name == start_layer_name:
1521
+ started = True
1522
+ layer_list.append(layer_name)
1523
+ if layer_name == stop_layer_name:
1524
+ break
1525
+ elif layer_name == stop_layer_name:
1526
+ started = True
1527
+ layer_list.append(layer_name)
1528
+ if layer_name == start_layer_name:
1529
+ break
1530
+ return layer_list
1531
+
1532
+ @property
1533
+ def net_name(self):
1534
+ """Net name.
1535
+
1536
+ Returns
1537
+ -------
1538
+ str
1539
+ Name of the net.
1540
+ """
1541
+ return self._edb_padstackinstance.GetNet().GetName()
1542
+
1543
+ @net_name.setter
1544
+ def net_name(self, val):
1545
+ if not isinstance(val, str):
1546
+ try:
1547
+ self._edb_padstackinstance.SetNet(val.net_obj)
1548
+ except:
1549
+ raise AttributeError("Value inserted not found. Input has to be net name or net object.")
1550
+ elif val in self._pedb.nets.netlist:
1551
+ net = self._pedb.nets.nets[val].net_object
1552
+ self._edb_padstackinstance.SetNet(net)
1553
+ else:
1554
+ raise AttributeError("Value inserted not found. Input has to be net name or net object.")
1555
+
1556
+ @property
1557
+ def is_pin(self):
1558
+ """Determines whether this padstack instance is a layout pin.
1559
+
1560
+ Returns
1561
+ -------
1562
+ bool
1563
+ True if this padstack type is a layout pin, False otherwise.
1564
+ """
1565
+ return self._edb_padstackinstance.IsLayoutPin()
1566
+
1567
+ @is_pin.setter
1568
+ def is_pin(self, pin):
1569
+ """Set padstack type
1570
+
1571
+ Parameters
1572
+ ----------
1573
+ pin : bool
1574
+ True if set this padstack instance as pin, False otherwise
1575
+ """
1576
+ self._edb_padstackinstance.SetIsLayoutPin(pin)
1577
+
1578
+ @property
1579
+ def position(self):
1580
+ """Padstack instance position.
1581
+
1582
+ Returns
1583
+ -------
1584
+ list
1585
+ List of ``[x, y]`` coordinates for the padstack instance position.
1586
+ """
1587
+ self._position = []
1588
+ out = self._edb_padstackinstance.GetPositionAndRotationValue()
1589
+ if self._edb_padstackinstance.GetComponent():
1590
+ out2 = self._edb_padstackinstance.GetComponent().GetTransform().TransformPoint(out[1])
1591
+ self._position = [out2.X.ToDouble(), out2.Y.ToDouble()]
1592
+ elif out[0]:
1593
+ self._position = [out[1].X.ToDouble(), out[1].Y.ToDouble()]
1594
+ return self._position
1595
+
1596
+ @position.setter
1597
+ def position(self, value):
1598
+ pos = []
1599
+ for v in value:
1600
+ if isinstance(v, (float, int, str)):
1601
+ pos.append(self._pedb.edb_value(v))
1602
+ else:
1603
+ pos.append(v)
1604
+ point_data = self._pedb.edb_api.geometry.point_data(pos[0], pos[1])
1605
+ self._edb_padstackinstance.SetPositionAndRotation(point_data, self._pedb.edb_value(self.rotation))
1606
+
1607
+ @property
1608
+ def rotation(self):
1609
+ """Padstack instance rotation.
1610
+
1611
+ Returns
1612
+ -------
1613
+ float
1614
+ Rotatation value for the padstack instance.
1615
+ """
1616
+ point_data = self._pedb.edb_api.geometry.point_data(self._pedb.edb_value(0.0), self._pedb.edb_value(0.0))
1617
+ out = self._edb_padstackinstance.GetPositionAndRotationValue()
1618
+
1619
+ if out[0]:
1620
+ return out[2].ToDouble()
1621
+
1622
+ @property
1623
+ def name(self):
1624
+ """Padstack Instance Name. If it is a pin, the syntax will be like in AEDT ComponentName-PinName."""
1625
+ if self.is_pin:
1626
+ comp_name = self._edb_padstackinstance.GetComponent().GetName()
1627
+ pin_name = self._edb_padstackinstance.GetName()
1628
+ return "-".join([comp_name, pin_name])
1629
+ else:
1630
+ return self._edb_padstackinstance.GetName()
1631
+
1632
+ @name.setter
1633
+ def name(self, value):
1634
+ self._edb_padstackinstance.SetName(value)
1635
+ self._edb_padstackinstance.SetProductProperty(self._pedb.edb_api.ProductId.Designer, 11, value)
1636
+
1637
+ @property
1638
+ def metal_volume(self):
1639
+ """Metal volume of the via hole instance in cubic units (m3). Metal plating ratio is accounted.
1640
+
1641
+ Returns
1642
+ -------
1643
+ float
1644
+ Metal volume of the via hole instance.
1645
+
1646
+ """
1647
+ volume = 0
1648
+ if not self.start_layer == self.stop_layer:
1649
+ start_layer = self.start_layer
1650
+ stop_layer = self.stop_layer
1651
+ if self.backdrill_top: # pragma no cover
1652
+ start_layer = self.backdrill_top[0]
1653
+ if self.backdrill_bottom: # pragma no cover
1654
+ stop_layer = self.backdrill_bottom[0]
1655
+ padstack_def = self._pedb.padstacks.definitions[self.padstack_definition]
1656
+ hole_diam = 0
1657
+ try: # pragma no cover
1658
+ hole_diam = padstack_def.hole_properties[0]
1659
+ except: # pragma no cover
1660
+ pass
1661
+ if hole_diam: # pragma no cover
1662
+ hole_finished_size = padstack_def.hole_finished_size
1663
+ via_length = (
1664
+ self._pedb.stackup.signal_layers[start_layer].upper_elevation
1665
+ - self._pedb.stackup.signal_layers[stop_layer].lower_elevation
1666
+ )
1667
+ volume = (math.pi * (hole_diam / 2) ** 2 - math.pi * (hole_finished_size / 2) ** 2) * via_length
1668
+ return volume
1669
+
1670
+ @property
1671
+ def pin_number(self):
1672
+ """Get pin number."""
1673
+ return self._edb_padstackinstance.GetName()
1674
+
1675
+ @property
1676
+ def aedt_name(self):
1677
+ """Retrieve the pin name that is shown in AEDT.
1678
+
1679
+ .. note::
1680
+ To obtain the EDB core pin name, use `pin.GetName()`.
1681
+
1682
+ Returns
1683
+ -------
1684
+ str
1685
+ Name of the pin in AEDT.
1686
+
1687
+ Examples
1688
+ --------
1689
+
1690
+ >>> from pyedb import Edb
1691
+ >>> edbapp = Edb("myaedbfolder", "project name", "release version")
1692
+ >>> edbapp.padstacks.instances[111].get_aedt_pin_name()
1693
+
1694
+ """
1695
+ if is_ironpython:
1696
+ name = _clr.Reference[String]()
1697
+ self._edb_padstackinstance.GetProductProperty(self._pedb.edb_api.ProductId.Designer, 11, name)
1698
+ else:
1699
+ val = String("")
1700
+ _, name = self._edb_padstackinstance.GetProductProperty(self._pedb.edb_api.ProductId.Designer, 11, val)
1701
+ name = str(name).strip("'")
1702
+ return name
1703
+
1704
+ @pyedb_function_handler()
1705
+ def parametrize_position(self, prefix=None):
1706
+ """Parametrize the instance position.
1707
+
1708
+ Parameters
1709
+ ----------
1710
+ prefix : str, optional
1711
+ Prefix for the variable name. Default is ``None``.
1712
+ Example `"MyVariableName"` will create 2 Project variables $MyVariableNamesX and $MyVariableNamesY.
1713
+
1714
+ Returns
1715
+ -------
1716
+ List
1717
+ List of variables created.
1718
+ """
1719
+ p = self.position
1720
+ if not prefix:
1721
+ var_name = "${}_pos".format(self.name)
1722
+ else:
1723
+ var_name = "${}".format(prefix)
1724
+ self._pedb.add_project_variable(var_name + "X", p[0])
1725
+ self._pedb.add_project_variable(var_name + "Y", p[1])
1726
+ self.position = [var_name + "X", var_name + "Y"]
1727
+ return [var_name + "X", var_name + "Y"]
1728
+
1729
+ @pyedb_function_handler()
1730
+ def delete_padstack_instance(self):
1731
+ """Delete this padstack instance.
1732
+
1733
+ .. deprecated:: 0.6.28
1734
+ Use :func:`delete` property instead.
1735
+ """
1736
+ warnings.warn("`delete_padstack_instance` is deprecated. Use `delete` instead.", DeprecationWarning)
1737
+ self._edb_padstackinstance.Delete()
1738
+ return True
1739
+
1740
+ @pyedb_function_handler()
1741
+ def in_voids(self, net_name=None, layer_name=None):
1742
+ """Check if this padstack instance is in any void.
1743
+
1744
+ Parameters
1745
+ ----------
1746
+ net_name : str
1747
+ Net name of the voids to be checked. Default is ``None``.
1748
+ layer_name : str
1749
+ Layer name of the voids to be checked. Default is ``None``.
1750
+
1751
+ Returns
1752
+ -------
1753
+ list
1754
+ List of the voids that include this padstack instance.
1755
+ """
1756
+ x_pos = self._pedb.edb_value(self.position[0])
1757
+ y_pos = self._pedb.edb_value(self.position[1])
1758
+ point_data = self._pedb.modeler._edb.geometry.point_data(x_pos, y_pos)
1759
+
1760
+ voids = []
1761
+ for prim in self._pedb.modeler.get_primitives(net_name, layer_name, is_void=True):
1762
+ if prim.primitive_object.GetPolygonData().PointInPolygon(point_data):
1763
+ voids.append(prim)
1764
+ return voids
1765
+
1766
+ @property
1767
+ def pingroups(self):
1768
+ """Pin groups that the pin belongs to.
1769
+
1770
+ Returns
1771
+ -------
1772
+ list
1773
+ List of pin groups that the pin belongs to.
1774
+ """
1775
+ return self._edb_padstackinstance.GetPinGroups()
1776
+
1777
+ @property
1778
+ def placement_layer(self):
1779
+ """Placement layer.
1780
+
1781
+ Returns
1782
+ -------
1783
+ str
1784
+ Name of the placement layer.
1785
+ """
1786
+ return self._edb_padstackinstance.GetGroup().GetPlacementLayer().Clone().GetName()
1787
+
1788
+ @property
1789
+ def lower_elevation(self):
1790
+ """Lower elevation of the placement layer.
1791
+
1792
+ Returns
1793
+ -------
1794
+ float
1795
+ Lower elavation of the placement layer.
1796
+ """
1797
+ try:
1798
+ return self._edb_padstackinstance.GetGroup().GetPlacementLayer().Clone().GetLowerElevation()
1799
+ except AttributeError: # pragma: no cover
1800
+ return None
1801
+
1802
+ @property
1803
+ def upper_elevation(self):
1804
+ """Upper elevation of the placement layer.
1805
+
1806
+ Returns
1807
+ -------
1808
+ float
1809
+ Upper elevation of the placement layer.
1810
+ """
1811
+ try:
1812
+ return self._edb_padstackinstance.GetGroup().GetPlacementLayer().Clone().GetUpperElevation()
1813
+ except AttributeError: # pragma: no cover
1814
+ return None
1815
+
1816
+ @property
1817
+ def top_bottom_association(self):
1818
+ """Top/bottom association of the placement layer.
1819
+
1820
+ Returns
1821
+ -------
1822
+ int
1823
+ Top/bottom association of the placement layer.
1824
+
1825
+ * 0 Top associated.
1826
+ * 1 No association.
1827
+ * 2 Bottom associated.
1828
+ * 4 Number of top/bottom association type.
1829
+ * -1 Undefined.
1830
+ """
1831
+ return int(self._edb_padstackinstance.GetGroup().GetPlacementLayer().GetTopBottomAssociation())
1832
+
1833
+ @pyedb_function_handler()
1834
+ def create_rectangle_in_pad(self, layer_name, return_points=False, partition_max_order=16):
1835
+ """Create a rectangle inscribed inside a padstack instance pad.
1836
+
1837
+ The rectangle is fully inscribed in the pad and has the maximum area.
1838
+ It is necessary to specify the layer on which the rectangle will be created.
1839
+
1840
+ Parameters
1841
+ ----------
1842
+ layer_name : str
1843
+ Name of the layer on which to create the polygon.
1844
+ return_points : bool, optional
1845
+ If `True` does not create the rectangle and just returns a list containing the rectangle vertices.
1846
+ Default is `False`.
1847
+ partition_max_order : float, optional
1848
+ Order of the lattice partition used to find the quasi-lattice polygon that approximates ``polygon``.
1849
+ Default is ``16``.
1850
+
1851
+ Returns
1852
+ -------
1853
+ bool, List, :class:`pyedb.dotnet.edb_core.edb_data.primitives.EDBPrimitives`
1854
+ Polygon when successful, ``False`` when failed, list of list if `return_points=True`.
1855
+
1856
+ Examples
1857
+ --------
1858
+ >>> from pyedb import Edb
1859
+ >>> edbapp = Edb("myaedbfolder", edbversion="2021.2")
1860
+ >>> edb_layout = edbapp.modeler
1861
+ >>> list_of_padstack_instances = list(edbapp.padstacks.instances.values())
1862
+ >>> padstack_inst = list_of_padstack_instances[0]
1863
+ >>> padstack_inst.create_rectangle_in_pad("TOP")
1864
+ """
1865
+
1866
+ padstack_center = self.position
1867
+ rotation = self.rotation # in radians
1868
+ padstack_name = self.padstack_definition
1869
+ try:
1870
+ padstack = self._pedb.padstacks.definitions[padstack_name]
1871
+ except KeyError: # pragma: no cover
1872
+ return False
1873
+ try:
1874
+ padstack_pad = padstack.pad_by_layer[layer_name]
1875
+ except KeyError: # pragma: no cover
1876
+ try:
1877
+ padstack_pad = padstack.pad_by_layer[padstack.via_start_layer]
1878
+ except KeyError: # pragma: no cover
1879
+ return False
1880
+
1881
+ pad_shape = padstack_pad.geometry_type
1882
+ params = padstack_pad.parameters_values
1883
+ polygon_data = padstack_pad.polygon_data
1884
+
1885
+ def _rotate(p):
1886
+ x = p[0] * math.cos(rotation) - p[1] * math.sin(rotation)
1887
+ y = p[0] * math.sin(rotation) + p[1] * math.cos(rotation)
1888
+ return [x, y]
1889
+
1890
+ def _translate(p):
1891
+ x = p[0] + padstack_center[0]
1892
+ y = p[1] + padstack_center[1]
1893
+ return [x, y]
1894
+
1895
+ rect = None
1896
+
1897
+ if pad_shape == 1:
1898
+ # Circle
1899
+ diameter = params[0]
1900
+ r = diameter * 0.5
1901
+ p1 = [r, 0.0]
1902
+ p2 = [0.0, r]
1903
+ p3 = [-r, 0.0]
1904
+ p4 = [0.0, -r]
1905
+ rect = [_translate(p1), _translate(p2), _translate(p3), _translate(p4)]
1906
+ elif pad_shape == 2:
1907
+ # Square
1908
+ square_size = params[0]
1909
+ s2 = square_size * 0.5
1910
+ p1 = [s2, s2]
1911
+ p2 = [-s2, s2]
1912
+ p3 = [-s2, -s2]
1913
+ p4 = [s2, -s2]
1914
+ rect = [
1915
+ _translate(_rotate(p1)),
1916
+ _translate(_rotate(p2)),
1917
+ _translate(_rotate(p3)),
1918
+ _translate(_rotate(p4)),
1919
+ ]
1920
+ elif pad_shape == 3:
1921
+ # Rectangle
1922
+ x_size = float(params[0])
1923
+ y_size = float(params[1])
1924
+ sx2 = x_size * 0.5
1925
+ sy2 = y_size * 0.5
1926
+ p1 = [sx2, sy2]
1927
+ p2 = [-sx2, sy2]
1928
+ p3 = [-sx2, -sy2]
1929
+ p4 = [sx2, -sy2]
1930
+ rect = [
1931
+ _translate(_rotate(p1)),
1932
+ _translate(_rotate(p2)),
1933
+ _translate(_rotate(p3)),
1934
+ _translate(_rotate(p4)),
1935
+ ]
1936
+ elif pad_shape == 4:
1937
+ # Oval
1938
+ x_size = params[0]
1939
+ y_size = params[1]
1940
+ corner_radius = float(params[2])
1941
+ if corner_radius >= min(x_size, y_size):
1942
+ r = min(x_size, y_size)
1943
+ else:
1944
+ r = corner_radius
1945
+ sx = x_size * 0.5 - r
1946
+ sy = y_size * 0.5 - r
1947
+ k = r / math.sqrt(2)
1948
+ p1 = [sx + k, sy + k]
1949
+ p2 = [-sx - k, sy + k]
1950
+ p3 = [-sx - k, -sy - k]
1951
+ p4 = [sx + k, -sy - k]
1952
+ rect = [
1953
+ _translate(_rotate(p1)),
1954
+ _translate(_rotate(p2)),
1955
+ _translate(_rotate(p3)),
1956
+ _translate(_rotate(p4)),
1957
+ ]
1958
+ elif pad_shape == 5:
1959
+ # Bullet
1960
+ x_size = params[0]
1961
+ y_size = params[1]
1962
+ corner_radius = params[2]
1963
+ if corner_radius >= min(x_size, y_size):
1964
+ r = min(x_size, y_size)
1965
+ else:
1966
+ r = corner_radius
1967
+ sx = x_size * 0.5 - r
1968
+ sy = y_size * 0.5 - r
1969
+ k = r / math.sqrt(2)
1970
+ p1 = [sx + k, sy + k]
1971
+ p2 = [-x_size * 0.5, sy + k]
1972
+ p3 = [-x_size * 0.5, -sy - k]
1973
+ p4 = [sx + k, -sy - k]
1974
+ rect = [
1975
+ _translate(_rotate(p1)),
1976
+ _translate(_rotate(p2)),
1977
+ _translate(_rotate(p3)),
1978
+ _translate(_rotate(p4)),
1979
+ ]
1980
+ elif pad_shape == 6:
1981
+ # N-Sided Polygon
1982
+ size = params[0]
1983
+ num_sides = params[1]
1984
+ ext_radius = size * 0.5
1985
+ apothem = ext_radius * math.cos(math.pi / num_sides)
1986
+ p1 = [apothem, 0.0]
1987
+ p2 = [0.0, apothem]
1988
+ p3 = [-apothem, 0.0]
1989
+ p4 = [0.0, -apothem]
1990
+ rect = [
1991
+ _translate(_rotate(p1)),
1992
+ _translate(_rotate(p2)),
1993
+ _translate(_rotate(p3)),
1994
+ _translate(_rotate(p4)),
1995
+ ]
1996
+ elif pad_shape == 0 and polygon_data is not None:
1997
+ # Polygon
1998
+ points = []
1999
+ i = 0
2000
+ while i < polygon_data.edb_api.Count:
2001
+ point = polygon_data.edb_api.GetPoint(i)
2002
+ i += 1
2003
+ if point.IsArc():
2004
+ continue
2005
+ else:
2006
+ points.append([point.X.ToDouble(), point.Y.ToDouble()])
2007
+ xpoly, ypoly = zip(*points)
2008
+ polygon = [list(xpoly), list(ypoly)]
2009
+ rectangles = GeometryOperators.find_largest_rectangle_inside_polygon(
2010
+ polygon, partition_max_order=partition_max_order
2011
+ )
2012
+ rect = rectangles[0]
2013
+ for i in range(4):
2014
+ rect[i] = _translate(_rotate(rect[i]))
2015
+
2016
+ if rect is None or len(rect) != 4:
2017
+ return False
2018
+ path = self._pedb.modeler.Shape("polygon", points=rect)
2019
+ pdata = self._pedb.modeler.shape_to_polygon_data(path)
2020
+ new_rect = []
2021
+ for point in pdata.Points:
2022
+ p_transf = self._edb_padstackinstance.GetComponent().GetTransform().TransformPoint(point)
2023
+ new_rect.append([p_transf.X.ToDouble(), p_transf.Y.ToDouble()])
2024
+ if return_points:
2025
+ return new_rect
2026
+ else:
2027
+ path = self._pedb.modeler.Shape("polygon", points=new_rect)
2028
+ created_polygon = self._pedb.modeler.create_polygon(path, layer_name)
2029
+ return created_polygon
2030
+
2031
+ @pyedb_function_handler()
2032
+ def get_connected_object_id_set(self):
2033
+ """Produce a list of all geometries physically connected to a given layout object.
2034
+
2035
+ Returns
2036
+ -------
2037
+ list
2038
+ Found connected objects IDs with Layout object.
2039
+ """
2040
+ layoutInst = self._edb_padstackinstance.GetLayout().GetLayoutInstance()
2041
+ layoutObjInst = self.object_instance
2042
+ return [loi.GetLayoutObj().GetId() for loi in layoutInst.GetConnectedObjects(layoutObjInst).Items]
2043
+
2044
+ @pyedb_function_handler()
2045
+ def get_reference_pins(self, reference_net="GND", search_radius=5e-3, max_limit=0, component_only=True):
2046
+ """Search for reference pins using given criteria.
2047
+
2048
+ Parameters
2049
+ ----------
2050
+ reference_net : str, optional
2051
+ Reference net. The default is ``"GND"``.
2052
+ search_radius : float, optional
2053
+ Search radius for finding padstack instances. The default is ``5e-3``.
2054
+ max_limit : int, optional
2055
+ Maximum limit for the padstack instances found. The default is ``0``, in which
2056
+ case no limit is applied. The maximum limit value occurs on the nearest
2057
+ reference pins from the positive one that is found.
2058
+ component_only : bool, optional
2059
+ Whether to limit the search to component padstack instances only. The
2060
+ default is ``True``. When ``False``, the search is extended to the entire layout.
2061
+
2062
+ Returns
2063
+ -------
2064
+ list
2065
+ List of :class:`dotnet.edb_core.edb_data.padstacks_data.EDBPadstackInstance`.
2066
+
2067
+ Examples
2068
+ --------
2069
+ >>> edbapp = Edb("target_path")
2070
+ >>> pin = edbapp.components.instances["J5"].pins["19"]
2071
+ >>> reference_pins = pin.get_reference_pins(reference_net="GND", search_radius=5e-3, max_limit=0,
2072
+ >>> component_only=True)
2073
+ """
2074
+ return self._pedb.padstacks.get_reference_pins(
2075
+ positive_pin=self,
2076
+ reference_net=reference_net,
2077
+ search_radius=search_radius,
2078
+ max_limit=max_limit,
2079
+ component_only=component_only,
2080
+ )