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,1397 @@
1
+ import math
2
+
3
+ from pyedb.dotnet.edb_core.dotnet.database import NetDotNet
4
+ from pyedb.dotnet.edb_core.dotnet.primitive import (
5
+ BondwireDotNet,
6
+ CircleDotNet,
7
+ PathDotNet,
8
+ PolygonDataDotNet,
9
+ PolygonDotNet,
10
+ RectangleDotNet,
11
+ TextDotNet,
12
+ )
13
+ from pyedb.dotnet.edb_core.edb_data.connectable import Connectable
14
+ from pyedb.dotnet.edb_core.general import convert_py_list_to_net_list
15
+ from pyedb.generic.general_methods import pyedb_function_handler
16
+ from pyedb.modeler.geometry_operators import GeometryOperators
17
+
18
+
19
+ def cast(raw_primitive, core_app):
20
+ """Cast the primitive object to correct concrete type.
21
+
22
+ Returns
23
+ -------
24
+ Primitive
25
+ """
26
+ if isinstance(raw_primitive, RectangleDotNet):
27
+ return EdbRectangle(raw_primitive.prim_obj, core_app)
28
+ elif isinstance(raw_primitive, PolygonDotNet):
29
+ return EdbPolygon(raw_primitive.prim_obj, core_app)
30
+ elif isinstance(raw_primitive, PathDotNet):
31
+ return EdbPath(raw_primitive.prim_obj, core_app)
32
+ elif isinstance(raw_primitive, BondwireDotNet):
33
+ return EdbBondwire(raw_primitive.prim_obj, core_app)
34
+ elif isinstance(raw_primitive, TextDotNet):
35
+ return EdbText(raw_primitive.prim_obj, core_app)
36
+ elif isinstance(raw_primitive, CircleDotNet):
37
+ return EdbCircle(raw_primitive.prim_obj, core_app)
38
+ else:
39
+ try:
40
+ prim_type = raw_primitive.GetPrimitiveType()
41
+ if prim_type == prim_type.Rectangle:
42
+ return EdbRectangle(raw_primitive, core_app)
43
+ elif prim_type == prim_type.Polygon:
44
+ return EdbPolygon(raw_primitive, core_app)
45
+ elif prim_type == prim_type.Path:
46
+ return EdbPath(raw_primitive, core_app)
47
+ elif prim_type == prim_type.Bondwire:
48
+ return EdbBondwire(raw_primitive, core_app)
49
+ elif prim_type == prim_type.Text:
50
+ return EdbText(raw_primitive, core_app)
51
+ elif prim_type == prim_type.Circle:
52
+ return EdbCircle(raw_primitive, core_app)
53
+ else:
54
+ return None
55
+ except:
56
+ return None
57
+
58
+
59
+ class EDBPrimitivesMain(Connectable):
60
+ """Manages EDB functionalities for a primitives.
61
+ It Inherits EDB Object properties.
62
+
63
+ Examples
64
+ --------
65
+ >>> from pyedb import Edb
66
+ >>> edb = Edb(myedb, edbversion="2021.2")
67
+ >>> edb_prim = edb.modeler.primitives[0]
68
+ >>> edb_prim.is_void # Class Property
69
+ >>> edb_prim.IsVoid() # EDB Object Property
70
+ """
71
+
72
+ def __init__(self, raw_primitive, core_app):
73
+ super().__init__(core_app, raw_primitive)
74
+ self._app = self._pedb
75
+ self._core_stackup = core_app.stackup
76
+ self._core_net = core_app.nets
77
+ self.primitive_object = self._edb_object
78
+
79
+ @property
80
+ def type(self):
81
+ """Return the type of the primitive.
82
+ Allowed outputs are ``"Circle"``, ``"Rectangle"``,``"Polygon"``,``"Path"`` or ``"Bondwire"``.
83
+
84
+ Returns
85
+ -------
86
+ str
87
+ """
88
+ try:
89
+ return self._edb_object.GetPrimitiveType().ToString()
90
+ except AttributeError: # pragma: no cover
91
+ return ""
92
+
93
+ @property
94
+ def net_name(self):
95
+ """Get or Set the primitive net name.
96
+
97
+ Returns
98
+ -------
99
+ str
100
+ """
101
+ return self.net.GetName()
102
+
103
+ @net_name.setter
104
+ def net_name(self, name):
105
+ if isinstance(name, str):
106
+ net = self._app.nets.nets[name].net_object
107
+ self.primitive_object.SetNet(net)
108
+ else:
109
+ try:
110
+ if isinstance(name, str):
111
+ self.net = name
112
+ elif isinstance(name, NetDotNet):
113
+ self.net = name.name
114
+ except: # pragma: no cover
115
+ self._app.logger.error("Failed to set net name.")
116
+
117
+ @property
118
+ def layer(self):
119
+ """Get the primitive edb layer object."""
120
+ try:
121
+ return self.primitive_object.GetLayer()
122
+ except AttributeError: # pragma: no cover
123
+ return None
124
+
125
+ @property
126
+ def layer_name(self):
127
+ """Get or Set the primitive layer name.
128
+
129
+ Returns
130
+ -------
131
+ str
132
+ """
133
+ try:
134
+ return self.layer.GetName()
135
+ except AttributeError: # pragma: no cover
136
+ return None
137
+
138
+ @layer_name.setter
139
+ def layer_name(self, val):
140
+ if isinstance(val, str) and val in list(self._core_stackup.layers.keys()):
141
+ lay = self._core_stackup.layers["TOP"]._edb_layer
142
+ if lay:
143
+ self.primitive_object.SetLayer(lay)
144
+ else:
145
+ raise AttributeError("Layer {} not found in layer".format(val))
146
+ elif isinstance(val, type(self._core_stackup.layers["TOP"])):
147
+ try:
148
+ self.primitive_object.SetLayer(val._edb_layer)
149
+ except:
150
+ raise AttributeError("Failed to assign new layer on primitive.")
151
+ else:
152
+ raise AttributeError("Invalid input value")
153
+
154
+ @property
155
+ def is_void(self):
156
+ """Either if the primitive is a void or not.
157
+
158
+ Returns
159
+ -------
160
+ bool
161
+ """
162
+ try:
163
+ return self._edb_object.IsVoid()
164
+ except AttributeError: # pragma: no cover
165
+ return None
166
+
167
+ def get_connected_objects(self):
168
+ """Get connected objects.
169
+
170
+ Returns
171
+ -------
172
+ list
173
+ """
174
+ return self._pedb.get_connected_objects(self._layout_obj_instance)
175
+
176
+
177
+ class EDBPrimitives(EDBPrimitivesMain):
178
+ """Manages EDB functionalities for a primitives.
179
+ It Inherits EDB Object properties.
180
+
181
+ Examples
182
+ --------
183
+ >>> from pyedb import Edb
184
+ >>> edb = Edb(myedb, edbversion="2021.2")
185
+ >>> edb_prim = edb.modeler.primitives[0]
186
+ >>> edb_prim.is_void # Class Property
187
+ >>> edb_prim.IsVoid() # EDB Object Property
188
+ """
189
+
190
+ def __init__(self, raw_primitive, core_app):
191
+ EDBPrimitivesMain.__init__(self, raw_primitive, core_app)
192
+
193
+ @pyedb_function_handler()
194
+ def area(self, include_voids=True):
195
+ """Return the total area.
196
+
197
+ Parameters
198
+ ----------
199
+ include_voids : bool, optional
200
+ Either if the voids have to be included in computation.
201
+ The default value is ``True``.
202
+
203
+ Returns
204
+ -------
205
+ float
206
+ """
207
+ area = self.primitive_object.GetPolygonData().Area()
208
+ if include_voids:
209
+ for el in self.primitive_object.Voids:
210
+ area -= el.GetPolygonData().Area()
211
+ return area
212
+
213
+ @property
214
+ def is_negative(self):
215
+ """Determine whether this primitive is negative.
216
+
217
+ Returns
218
+ -------
219
+ bool
220
+ True if it is negative, False otherwise.
221
+ """
222
+ return self.primitive_object.GetIsNegative()
223
+
224
+ @is_negative.setter
225
+ def is_negative(self, value):
226
+ self.primitive_object.SetIsNegative(value)
227
+
228
+ @staticmethod
229
+ def _eval_arc_points(p1, p2, h, n=6, tol=1e-12):
230
+ """Get the points of the arc
231
+
232
+ Parameters
233
+ ----------
234
+ p1 : list
235
+ Arc starting point.
236
+ p2 : list
237
+ Arc ending point.
238
+ h : float
239
+ Arc height.
240
+ n : int
241
+ Number of points to generate along the arc.
242
+ tol : float
243
+ Geometric tolerance.
244
+
245
+ Returns
246
+ -------
247
+ list, list
248
+ Points generated along the arc.
249
+ """
250
+ # fmt: off
251
+ if abs(h) < tol:
252
+ return [], []
253
+ elif h > 0:
254
+ reverse = False
255
+ x1 = p1[0]
256
+ y1 = p1[1]
257
+ x2 = p2[0]
258
+ y2 = p2[1]
259
+ else:
260
+ reverse = True
261
+ x1 = p2[0]
262
+ y1 = p2[1]
263
+ x2 = p1[0]
264
+ y2 = p1[1]
265
+ h *= -1
266
+ xa = (x2 - x1) / 2
267
+ ya = (y2 - y1) / 2
268
+ xo = x1 + xa
269
+ yo = y1 + ya
270
+ a = math.sqrt(xa ** 2 + ya ** 2)
271
+ if a < tol:
272
+ return [], []
273
+ r = (a ** 2) / (2 * h) + h / 2
274
+ if abs(r - a) < tol:
275
+ b = 0
276
+ th = 2 * math.asin(1) # chord angle
277
+ else:
278
+ b = math.sqrt(r ** 2 - a ** 2)
279
+ th = 2 * math.asin(a / r) # chord angle
280
+
281
+ # center of the circle
282
+ xc = xo + b * ya / a
283
+ yc = yo - b * xa / a
284
+
285
+ alpha = math.atan2((y1 - yc), (x1 - xc))
286
+ xr = []
287
+ yr = []
288
+ for i in range(n):
289
+ i += 1
290
+ dth = (float(i) / (n + 1)) * th
291
+ xi = xc + r * math.cos(alpha - dth)
292
+ yi = yc + r * math.sin(alpha - dth)
293
+ xr.append(xi)
294
+ yr.append(yi)
295
+
296
+ if reverse:
297
+ xr.reverse()
298
+ yr.reverse()
299
+ # fmt: on
300
+ return xr, yr
301
+
302
+ def _get_points_for_plot(self, my_net_points, num):
303
+ """
304
+ Get the points to be plotted.
305
+ """
306
+ # fmt: off
307
+ x = []
308
+ y = []
309
+ for i, point in enumerate(my_net_points):
310
+ if not self.is_arc(point):
311
+ x.append(point.X.ToDouble())
312
+ y.append(point.Y.ToDouble())
313
+ # i += 1
314
+ else:
315
+ arc_h = point.GetArcHeight().ToDouble()
316
+ p1 = [my_net_points[i - 1].X.ToDouble(), my_net_points[i - 1].Y.ToDouble()]
317
+ if i + 1 < len(my_net_points):
318
+ p2 = [my_net_points[i + 1].X.ToDouble(), my_net_points[i + 1].Y.ToDouble()]
319
+ else:
320
+ p2 = [my_net_points[0].X.ToDouble(), my_net_points[0].Y.ToDouble()]
321
+ x_arc, y_arc = self._eval_arc_points(p1, p2, arc_h, num)
322
+ x.extend(x_arc)
323
+ y.extend(y_arc)
324
+ # i += 1
325
+ # fmt: on
326
+ return x, y
327
+
328
+ @property
329
+ def bbox(self):
330
+ """Return the primitive bounding box points. Lower left corner, upper right corner.
331
+
332
+ Returns
333
+ -------
334
+ list
335
+ [lower_left x, lower_left y, upper right x, upper right y]
336
+
337
+ """
338
+ bbox = self.polygon_data.edb_api.GetBBox()
339
+ return [bbox.Item1.X.ToDouble(), bbox.Item1.Y.ToDouble(), bbox.Item2.X.ToDouble(), bbox.Item2.Y.ToDouble()]
340
+
341
+ @property
342
+ def center(self):
343
+ """Return the primitive bounding box center coordinate.
344
+
345
+ Returns
346
+ -------
347
+ list
348
+ [x, y]
349
+
350
+ """
351
+ bbox = self.bbox
352
+ return [(bbox[0] + bbox[2]) / 2, (bbox[1] + bbox[3]) / 2]
353
+
354
+ @pyedb_function_handler()
355
+ def is_arc(self, point):
356
+ """Either if a point is an arc or not.
357
+
358
+ Returns
359
+ -------
360
+ bool
361
+ """
362
+ return point.IsArc()
363
+
364
+ @pyedb_function_handler()
365
+ def get_connected_object_id_set(self):
366
+ """Produce a list of all geometries physically connected to a given layout object.
367
+
368
+ Returns
369
+ -------
370
+ list
371
+ Found connected objects IDs with Layout object.
372
+ """
373
+ layoutInst = self.primitive_object.GetLayout().GetLayoutInstance()
374
+ layoutObjInst = layoutInst.GetLayoutObjInstance(self.primitive_object, None) # 2nd arg was []
375
+ return [loi.GetLayoutObj().GetId() for loi in layoutInst.GetConnectedObjects(layoutObjInst).Items]
376
+
377
+ @pyedb_function_handler()
378
+ def convert_to_polygon(self):
379
+ """Convert path to polygon.
380
+
381
+ Returns
382
+ -------
383
+ Converted polygon.
384
+
385
+ """
386
+ if self.type == "Path":
387
+ polygon_data = self.primitive_object.GetPolygonData()
388
+ polygon = self._app.modeler.create_polygon(polygon_data, self.layer_name, [], self.net_name)
389
+ self.primitive_object.Delete()
390
+ return polygon
391
+
392
+ @pyedb_function_handler()
393
+ def subtract(self, primitives):
394
+ """Subtract active primitive with one or more primitives.
395
+
396
+ Parameters
397
+ ----------
398
+ primitives : :class:`dotnet.edb_core.edb_data.EDBPrimitives` or EDB PolygonData or EDB Primitive or list
399
+
400
+ Returns
401
+ -------
402
+ List of :class:`dotnet.edb_core.edb_data.EDBPrimitives`
403
+ """
404
+ poly = self.primitive_object.GetPolygonData()
405
+ if not isinstance(primitives, list):
406
+ primitives = [primitives]
407
+ primi_polys = []
408
+ voids_of_prims = []
409
+ for prim in primitives:
410
+ if isinstance(prim, EDBPrimitives):
411
+ primi_polys.append(prim.primitive_object.GetPolygonData())
412
+ for void in prim.voids:
413
+ voids_of_prims.append(void.polygon_data.edb_api)
414
+ else:
415
+ try:
416
+ primi_polys.append(prim.GetPolygonData())
417
+ except:
418
+ primi_polys.append(prim)
419
+ for v in self.voids[:]:
420
+ primi_polys.append(v.polygon_data.edb_api)
421
+ primi_polys = poly.Unite(convert_py_list_to_net_list(primi_polys))
422
+ p_to_sub = poly.Unite(convert_py_list_to_net_list([poly] + voids_of_prims))
423
+ list_poly = poly.Subtract(p_to_sub, primi_polys)
424
+ new_polys = []
425
+ if list_poly:
426
+ for p in list_poly:
427
+ if p.IsNull():
428
+ continue
429
+ new_polys.append(
430
+ cast(
431
+ self._app.modeler.create_polygon(p, self.layer_name, net_name=self.net_name, voids=[]),
432
+ self._app,
433
+ )
434
+ )
435
+ self.delete()
436
+ for prim in primitives:
437
+ if isinstance(prim, EDBPrimitives):
438
+ prim.delete()
439
+ else:
440
+ try:
441
+ prim.Delete()
442
+ except AttributeError:
443
+ continue
444
+ return new_polys
445
+
446
+ @pyedb_function_handler()
447
+ def intersect(self, primitives):
448
+ """Intersect active primitive with one or more primitives.
449
+
450
+ Parameters
451
+ ----------
452
+ primitives : :class:`dotnet.edb_core.edb_data.EDBPrimitives` or EDB PolygonData or EDB Primitive or list
453
+
454
+ Returns
455
+ -------
456
+ List of :class:`dotnet.edb_core.edb_data.EDBPrimitives`
457
+ """
458
+ poly = self.primitive_object.GetPolygonData()
459
+ if not isinstance(primitives, list):
460
+ primitives = [primitives]
461
+ primi_polys = []
462
+ for prim in primitives:
463
+ if isinstance(prim, EDBPrimitives):
464
+ primi_polys.append(prim.primitive_object.GetPolygonData())
465
+ else:
466
+ try:
467
+ primi_polys.append(prim.GetPolygonData())
468
+ except:
469
+ primi_polys.append(prim)
470
+ list_poly = poly.Intersect(convert_py_list_to_net_list([poly]), convert_py_list_to_net_list(primi_polys))
471
+ new_polys = []
472
+ if list_poly:
473
+ voids = self.voids
474
+ for p in list_poly:
475
+ if p.IsNull():
476
+ continue
477
+ list_void = []
478
+ void_to_subtract = []
479
+ if voids:
480
+ for void in voids:
481
+ void_pdata = void.prim_obj.GetPolygonData()
482
+ int_data2 = p.GetIntersectionType(void_pdata)
483
+ if int_data2 > 2 or int_data2 == 1:
484
+ void_to_subtract.append(void_pdata)
485
+ elif int_data2 == 2:
486
+ list_void.append(void_pdata)
487
+ if void_to_subtract:
488
+ polys_cleans = p.Subtract(
489
+ convert_py_list_to_net_list(p), convert_py_list_to_net_list(void_to_subtract)
490
+ )
491
+ for polys_clean in polys_cleans:
492
+ if not polys_clean.IsNull():
493
+ void_to_append = [v for v in list_void if polys_clean.GetIntersectionType(v) == 2]
494
+ new_polys.append(
495
+ cast(
496
+ self._app.modeler.create_polygon(
497
+ polys_clean, self.layer_name, net_name=self.net_name, voids=void_to_append
498
+ ),
499
+ self._app,
500
+ )
501
+ )
502
+ else:
503
+ new_polys.append(
504
+ cast(
505
+ self._app.modeler.create_polygon(
506
+ p, self.layer_name, net_name=self.net_name, voids=list_void
507
+ ),
508
+ self._app,
509
+ )
510
+ )
511
+ else:
512
+ new_polys.append(
513
+ cast(
514
+ self._app.modeler.create_polygon(
515
+ p, self.layer_name, net_name=self.net_name, voids=list_void
516
+ ),
517
+ self._app,
518
+ )
519
+ )
520
+ self.delete()
521
+ for prim in primitives:
522
+ if isinstance(prim, EDBPrimitives):
523
+ prim.delete()
524
+ else:
525
+ try:
526
+ prim.Delete()
527
+ except AttributeError:
528
+ continue
529
+ return new_polys
530
+
531
+ @pyedb_function_handler()
532
+ def unite(self, primitives):
533
+ """Unite active primitive with one or more primitives.
534
+
535
+ Parameters
536
+ ----------
537
+ primitives : :class:`dotnet.edb_core.edb_data.EDBPrimitives` or EDB PolygonData or EDB Primitive or list
538
+
539
+ Returns
540
+ -------
541
+ List of :class:`dotnet.edb_core.edb_data.EDBPrimitives`
542
+ """
543
+ poly = self.primitive_object.GetPolygonData()
544
+ if not isinstance(primitives, list):
545
+ primitives = [primitives]
546
+ primi_polys = []
547
+ for prim in primitives:
548
+ if isinstance(prim, EDBPrimitives):
549
+ primi_polys.append(prim.primitive_object.GetPolygonData())
550
+ else:
551
+ try:
552
+ primi_polys.append(prim.GetPolygonData())
553
+ except:
554
+ primi_polys.append(prim)
555
+ list_poly = poly.Unite(convert_py_list_to_net_list([poly] + primi_polys))
556
+ new_polys = []
557
+ if list_poly:
558
+ voids = self.voids
559
+ for p in list_poly:
560
+ if p.IsNull():
561
+ continue
562
+ list_void = []
563
+ if voids:
564
+ for void in voids:
565
+ void_pdata = void.primitive_object.GetPolygonData()
566
+ int_data2 = p.GetIntersectionType(void_pdata)
567
+ if int_data2 > 1:
568
+ list_void.append(void_pdata)
569
+ new_polys.append(
570
+ cast(
571
+ self._app.modeler.create_polygon(p, self.layer_name, net_name=self.net_name, voids=list_void),
572
+ self._app,
573
+ )
574
+ )
575
+ self.delete()
576
+ for prim in primitives:
577
+ if isinstance(prim, EDBPrimitives):
578
+ prim.delete()
579
+ else:
580
+ try:
581
+ prim.Delete()
582
+ except AttributeError:
583
+ continue
584
+ return new_polys
585
+
586
+ @pyedb_function_handler()
587
+ def intersection_type(self, primitive):
588
+ """Get intersection type between actual primitive and another primitive or polygon data.
589
+
590
+ Parameters
591
+ ----------
592
+ primitive : :class:`pyaeedt.edb_core.edb_data.primitives_data.EDBPrimitives` or `PolygonData`
593
+
594
+ Returns
595
+ -------
596
+ int
597
+ Intersection type:
598
+ 0 - objects do not intersect,
599
+ 1 - this object fully inside other (no common contour points),
600
+ 2 - other object fully inside this,
601
+ 3 - common contour points,
602
+ 4 - undefined intersection.
603
+ """
604
+ poly = primitive
605
+ try:
606
+ poly = primitive.polygon_data
607
+ except AttributeError:
608
+ pass
609
+ return int(self.polygon_data.edb_api.GetIntersectionType(poly.edb_api))
610
+
611
+ @pyedb_function_handler()
612
+ def is_intersecting(self, primitive):
613
+ """Check if actual primitive and another primitive or polygon data intesects.
614
+
615
+ Parameters
616
+ ----------
617
+ primitive : :class:`pyaeedt.edb_core.edb_data.primitives_data.EDBPrimitives` or `PolygonData`
618
+
619
+ Returns
620
+ -------
621
+ bool
622
+ """
623
+ return True if self.intersection_type(primitive) >= 1 else False
624
+
625
+ @pyedb_function_handler()
626
+ def get_closest_point(self, point):
627
+ """Get the closest point of the primitive to the input data.
628
+
629
+ Parameters
630
+ ----------
631
+ point : list of float or PointData
632
+
633
+ Returns
634
+ -------
635
+ list of float
636
+ """
637
+ if isinstance(point, (list, tuple)):
638
+ point = self._app.edb_api.geometry.point_data(self._app.edb_value(point[0]), self._app.edb_value(point[1]))
639
+
640
+ p0 = self.polygon_data.edb_api.GetClosestPoint(point)
641
+ return [p0.X.ToDouble(), p0.Y.ToDouble()]
642
+
643
+ @pyedb_function_handler()
644
+ def get_closest_arc_midpoint(self, point):
645
+ """Get the closest arc midpoint of the primitive to the input data.
646
+
647
+ Parameters
648
+ ----------
649
+ point : list of float or PointData
650
+
651
+ Returns
652
+ -------
653
+ list of float
654
+ """
655
+ if isinstance(point, self._app.edb_api.geometry.geometry.PointData):
656
+ point = [point.X.ToDouble(), point.Y.ToDouble()]
657
+ dist = 1e12
658
+ out = None
659
+ for arc in self.arcs:
660
+ mid_point = arc.mid_point
661
+ mid_point = [mid_point.X.ToDouble(), mid_point.Y.ToDouble()]
662
+ if GeometryOperators.points_distance(mid_point, point) < dist:
663
+ out = arc.mid_point
664
+ dist = GeometryOperators.points_distance(mid_point, point)
665
+ return [out.X.ToDouble(), out.Y.ToDouble()]
666
+
667
+ @property
668
+ def arcs(self):
669
+ """Get the Primitive Arc Data."""
670
+ arcs = [EDBArcs(self, i) for i in self.polygon_data.arcs]
671
+ return arcs
672
+
673
+ @property
674
+ def longest_arc(self):
675
+ """Get the longest arc."""
676
+ len = 0
677
+ arc = None
678
+ for i in self.arcs:
679
+ if i.is_segment and i.length > len:
680
+ arc = i
681
+ len = i.length
682
+ return arc
683
+
684
+ @property
685
+ def shortest_arc(self):
686
+ """Get the longest arc."""
687
+ len = 1e12
688
+ arc = None
689
+ for i in self.arcs:
690
+ if i.is_segment and i.length < len:
691
+ arc = i
692
+ len = i.length
693
+ return arc
694
+
695
+
696
+ class EdbPath(EDBPrimitives, PathDotNet):
697
+ def __init__(self, raw_primitive, core_app):
698
+ EDBPrimitives.__init__(self, raw_primitive, core_app)
699
+ PathDotNet.__init__(self, self._app, raw_primitive)
700
+
701
+ @property
702
+ def width(self):
703
+ """Path width.
704
+
705
+ Returns
706
+ -------
707
+ float
708
+ Path width or None.
709
+ """
710
+ if self.type == "Path":
711
+ return self.primitive_object.GetWidth()
712
+ return
713
+
714
+ @width.setter
715
+ def width(self, value):
716
+ if self.type == "Path":
717
+ if isinstance(value, (int, str, float)):
718
+ self.primitive_object.SetWidth(self._app.edb_value(value))
719
+ else:
720
+ self.primitive_object.SetWidth(value)
721
+
722
+ @property
723
+ def length(self):
724
+ """Path length in meters.
725
+
726
+ Returns
727
+ -------
728
+ float
729
+ Path length in meters.
730
+ """
731
+ center_line_arcs = list(self.center_line.GetArcData())
732
+ path_length = 0.0
733
+ for arc in center_line_arcs:
734
+ path_length += arc.GetLength()
735
+ if self.end_cap_style[0]:
736
+ if not self.end_cap_style[1].value__ == 1:
737
+ path_length += self.width / 2
738
+ if not self.end_cap_style[2].value__ == 1:
739
+ path_length += self.width / 2
740
+ return path_length
741
+
742
+ @pyedb_function_handler()
743
+ def add_point(self, x, y, incremental=False):
744
+ """Add a point at the end of the path.
745
+
746
+ Parameters
747
+ ----------
748
+ x: str, int, float
749
+ X coordinate.
750
+ y: str, in, float
751
+ Y coordinate.
752
+ incremental: bool
753
+ Add point incrementally. If True, coordinates of the added point is incremental to the last point.
754
+ The default value is ``False``.
755
+
756
+ Returns
757
+ -------
758
+ bool
759
+ """
760
+ center_line = PolygonDataDotNet(self._pedb, self._edb_object.GetCenterLine())
761
+ center_line.add_point(x, y, incremental)
762
+ return self._edb_object.SetCenterLine(center_line.edb_api)
763
+
764
+ @pyedb_function_handler()
765
+ def get_center_line(self, to_string=False):
766
+ """Get the center line of the trace.
767
+
768
+ Parameters
769
+ ----------
770
+ to_string : bool, optional
771
+ Type of return. The default is ``"False"``.
772
+
773
+ Returns
774
+ -------
775
+ list
776
+
777
+ """
778
+ if to_string:
779
+ return [[p.X.ToString(), p.Y.ToString()] for p in list(self.primitive_object.GetCenterLine().Points)]
780
+ else:
781
+ return [[p.X.ToDouble(), p.Y.ToDouble()] for p in list(self.primitive_object.GetCenterLine().Points)]
782
+
783
+ @pyedb_function_handler()
784
+ def clone(self):
785
+ """Clone a primitive object with keeping same definition and location.
786
+
787
+ Returns
788
+ -------
789
+ bool
790
+ ``True`` when successful, ``False`` when failed.
791
+ """
792
+ center_line = self.center_line
793
+ width = self.width
794
+ corner_style = self.corner_style
795
+ end_cap_style = self.end_cap_style
796
+ cloned_path = self._app.edb_api.cell.primitive.path.create(
797
+ self._app.active_layout,
798
+ self.layer_name,
799
+ self.net,
800
+ width,
801
+ end_cap_style[1],
802
+ end_cap_style[2],
803
+ corner_style,
804
+ center_line,
805
+ )
806
+ if cloned_path:
807
+ return cloned_path
808
+
809
+ # @pyedb_function_handler()
810
+ @pyedb_function_handler()
811
+ def create_edge_port(
812
+ self,
813
+ name,
814
+ position="End",
815
+ port_type="Wave",
816
+ reference_layer=None,
817
+ horizontal_extent_factor=5,
818
+ vertical_extent_factor=3,
819
+ pec_launch_width="0.01mm",
820
+ ):
821
+ """
822
+
823
+ Parameters
824
+ ----------
825
+ name : str
826
+ Name of the port.
827
+ position : str, optional
828
+ Position of the port. The default is ``"End"``, in which case the port is created at the end of the trace.
829
+ Options are ``"Start"`` and ``"End"``.
830
+ port_type : str, optional
831
+ Type of the port. The default is ``"Wave"``, in which case a wave port is created. Options are ``"Wave"``
832
+ and ``"Gap"``.
833
+ reference_layer : str, optional
834
+ Name of the references layer. The default is ``None``. Only available for gap port.
835
+ horizontal_extent_factor : int, optional
836
+ Horizontal extent factor of the wave port. The default is ``5``.
837
+ vertical_extent_factor : int, optional
838
+ Vertical extent factor of the wave port. The default is ``3``.
839
+ pec_launch_width : float, str, optional
840
+ Perfect electrical conductor width of the wave port. The default is ``"0.01mm"``.
841
+
842
+ Returns
843
+ -------
844
+ :class:`dotnet.edb_core.edb_data.sources.ExcitationPorts`
845
+
846
+ Examples
847
+ --------
848
+ >>> edbapp = pyedb.dotnet.Edb("myproject.aedb")
849
+ >>> sig = appedb.modeler.create_trace([[0, 0], ["9mm", 0]], "TOP", "1mm", "SIG", "Flat", "Flat")
850
+ >>> sig.create_edge_port("pcb_port", "end", "Wave", None, 8, 8)
851
+
852
+ """
853
+ center_line = self.get_center_line()
854
+ pos = center_line[-1] if position.lower() == "end" else center_line[0]
855
+
856
+ if port_type.lower() == "wave":
857
+ return self._app.hfss.create_wave_port(
858
+ self.id, pos, name, 50, horizontal_extent_factor, vertical_extent_factor, pec_launch_width
859
+ )
860
+ else:
861
+ return self._app.hfss.create_edge_port_vertical(self.id, pos, name, 50, reference_layer)
862
+
863
+ @pyedb_function_handler()
864
+ def create_via_fence(self, distance, gap, padstack_name):
865
+ """Create via fences on both sides of the trace.
866
+
867
+ Parameters
868
+ ----------
869
+ distance: str, float
870
+ Distance between via fence and trace center line.
871
+ gap: str, float
872
+ Gap between vias.
873
+ padstack_name: str
874
+ Name of the via padstack.
875
+
876
+ Returns
877
+ -------
878
+ """
879
+
880
+ def getAngle(v1, v2): # pragma: no cover
881
+ v1_mag = math.sqrt(v1[0] ** 2 + v1[1] ** 2)
882
+ v2_mag = math.sqrt(v2[0] ** 2 + v2[1] ** 2)
883
+ dotsum = v1[0] * v2[0] + v1[1] * v2[1]
884
+ if v1[0] * v2[1] - v1[1] * v2[0] > 0:
885
+ scale = 1
886
+ else:
887
+ scale = -1
888
+ dtheta = scale * math.acos(dotsum / (v1_mag * v2_mag))
889
+
890
+ return dtheta
891
+
892
+ def getLocations(line, gap): # pragma: no cover
893
+ location = [line[0]]
894
+ residual = 0
895
+
896
+ for n in range(len(line) - 1):
897
+ x0, y0 = line[n]
898
+ x1, y1 = line[n + 1]
899
+ length = math.sqrt((x1 - x0) ** 2 + (y1 - y0) ** 2)
900
+ dx, dy = (x1 - x0) / length, (y1 - y0) / length
901
+ x = x0 - dx * residual
902
+ y = y0 - dy * residual
903
+ length = length + residual
904
+ while length >= gap:
905
+ x += gap * dx
906
+ y += gap * dy
907
+ location.append((x, y))
908
+ length -= gap
909
+
910
+ residual = length
911
+ return location
912
+
913
+ def getParalletLines(pts, distance): # pragma: no cover
914
+ leftline = []
915
+ rightline = []
916
+
917
+ x0, y0 = pts[0]
918
+ x1, y1 = pts[1]
919
+ vector = (x1 - x0, y1 - y0)
920
+ orientation1 = getAngle((1, 0), vector)
921
+
922
+ leftturn = orientation1 + math.pi / 2
923
+ righrturn = orientation1 - math.pi / 2
924
+ leftPt = (x0 + distance * math.cos(leftturn), y0 + distance * math.sin(leftturn))
925
+ leftline.append(leftPt)
926
+ rightPt = (x0 + distance * math.cos(righrturn), y0 + distance * math.sin(righrturn))
927
+ rightline.append(rightPt)
928
+
929
+ for n in range(1, len(pts) - 1):
930
+ x0, y0 = pts[n - 1]
931
+ x1, y1 = pts[n]
932
+ x2, y2 = pts[n + 1]
933
+
934
+ v1 = (x1 - x0, y1 - y0)
935
+ v2 = (x2 - x1, y2 - y1)
936
+ dtheta = getAngle(v1, v2)
937
+ orientation1 = getAngle((1, 0), v1)
938
+
939
+ leftturn = orientation1 + dtheta / 2 + math.pi / 2
940
+ righrturn = orientation1 + dtheta / 2 - math.pi / 2
941
+
942
+ distance2 = distance / math.sin((math.pi - dtheta) / 2)
943
+ leftPt = (x1 + distance2 * math.cos(leftturn), y1 + distance2 * math.sin(leftturn))
944
+ leftline.append(leftPt)
945
+ rightPt = (x1 + distance2 * math.cos(righrturn), y1 + distance2 * math.sin(righrturn))
946
+ rightline.append(rightPt)
947
+
948
+ x0, y0 = pts[-2]
949
+ x1, y1 = pts[-1]
950
+
951
+ vector = (x1 - x0, y1 - y0)
952
+ orientation1 = getAngle((1, 0), vector)
953
+ leftturn = orientation1 + math.pi / 2
954
+ righrturn = orientation1 - math.pi / 2
955
+ leftPt = (x1 + distance * math.cos(leftturn), y1 + distance * math.sin(leftturn))
956
+ leftline.append(leftPt)
957
+ rightPt = (x1 + distance * math.cos(righrturn), y1 + distance * math.sin(righrturn))
958
+ rightline.append(rightPt)
959
+ return leftline, rightline
960
+
961
+ distance = self._pedb.edb_value(distance).ToDouble()
962
+ gap = self._pedb.edb_value(gap).ToDouble()
963
+ center_line = self.get_center_line()
964
+ leftline, rightline = getParalletLines(center_line, distance)
965
+ for x, y in getLocations(rightline, gap) + getLocations(leftline, gap):
966
+ self._pedb.padstacks.place([x, y], padstack_name)
967
+
968
+
969
+ class EdbRectangle(EDBPrimitives, RectangleDotNet):
970
+ def __init__(self, raw_primitive, core_app):
971
+ EDBPrimitives.__init__(self, raw_primitive, core_app)
972
+ RectangleDotNet.__init__(self, self._app, raw_primitive)
973
+
974
+
975
+ class EdbCircle(EDBPrimitives, CircleDotNet):
976
+ def __init__(self, raw_primitive, core_app):
977
+ EDBPrimitives.__init__(self, raw_primitive, core_app)
978
+ CircleDotNet.__init__(self, self._app, raw_primitive)
979
+
980
+
981
+ class EdbPolygon(EDBPrimitives, PolygonDotNet):
982
+ def __init__(self, raw_primitive, core_app):
983
+ EDBPrimitives.__init__(self, raw_primitive, core_app)
984
+ PolygonDotNet.__init__(self, self._app, raw_primitive)
985
+
986
+ @pyedb_function_handler()
987
+ def clone(self):
988
+ """Clone a primitive object with keeping same definition and location.
989
+
990
+ Returns
991
+ -------
992
+ bool
993
+ ``True`` when successful, ``False`` when failed.
994
+ """
995
+ cloned_poly = self._app.edb_api.cell.primitive.polygon.create(
996
+ self._app.active_layout, self.layer_name, self.net, self.polygon_data.edb_api
997
+ )
998
+ if cloned_poly:
999
+ for void in self.voids:
1000
+ cloned_void = self._app.edb_api.cell.primitive.polygon.create(
1001
+ self._app.active_layout, self.layer_name, self.net, void.polygon_data.edb_api
1002
+ )
1003
+ # cloned_void
1004
+ cloned_poly.prim_obj.AddVoid(cloned_void.prim_obj)
1005
+ return cloned_poly
1006
+ return False
1007
+
1008
+ @pyedb_function_handler
1009
+ def move(self, vector):
1010
+ """Move polygon along a vector.
1011
+
1012
+ Parameters
1013
+ ----------
1014
+ vector : List of float or str [x,y].
1015
+
1016
+ Returns
1017
+ -------
1018
+ bool
1019
+ ``True`` when successful, ``False`` when failed.
1020
+
1021
+ Examples
1022
+ --------
1023
+ >>> edbapp = pyaedt.Edb("myproject.aedb")
1024
+ >>> top_layer_polygon = [poly for poly in edbapp.modeler.polygons if poly.layer_name == "Top Layer"]
1025
+ >>> for polygon in top_layer_polygon:
1026
+ >>> polygon.move(vector=["2mm", "100um"])
1027
+ """
1028
+ if vector and isinstance(vector, list) and len(vector) == 2:
1029
+ _vector = self._edb.Geometry.PointData(
1030
+ self._edb.Utility.Value(vector[0]), self._edb.Utility.Value(vector[1])
1031
+ )
1032
+ polygon_data = self._edb.Geometry.PolygonData.CreateFromArcs(self.polygon_data.edb_api.GetArcData(), True)
1033
+ polygon_data.Move(_vector)
1034
+ return self.api_object.SetPolygonData(polygon_data)
1035
+ return False
1036
+
1037
+ @pyedb_function_handler
1038
+ def rotate(self, angle, center=None):
1039
+ """Rotate polygon around a center point by an angle.
1040
+
1041
+ Parameters
1042
+ ----------
1043
+ angle : float
1044
+ Value of the rotation angle in degree.
1045
+ center : List of float or str [x,y], optional
1046
+ If None rotation is done from polygon center.
1047
+
1048
+ Returns
1049
+ -------
1050
+ bool
1051
+ ``True`` when successful, ``False`` when failed.
1052
+
1053
+ Examples
1054
+ --------
1055
+ >>> edbapp = pyaedt.Edb("myproject.aedb")
1056
+ >>> top_layer_polygon = [poly for poly in edbapp.modeler.polygons if poly.layer_name == "Top Layer"]
1057
+ >>> for polygon in top_layer_polygon:
1058
+ >>> polygon.rotate(angle=45)
1059
+ """
1060
+ if angle:
1061
+ polygon_data = self._edb.Geometry.PolygonData.CreateFromArcs(self.polygon_data.edb_api.GetArcData(), True)
1062
+ if not center:
1063
+ center = polygon_data.GetBoundingCircleCenter()
1064
+ if center:
1065
+ polygon_data.Rotate(angle * math.pi / 180, center)
1066
+ return self.api_object.SetPolygonData(polygon_data)
1067
+ elif isinstance(center, list) and len(center) == 2:
1068
+ center = self._edb.Geometry.PointData(
1069
+ self._edb.Utility.Value(center[0]), self._edb.Utility.Value(center[1])
1070
+ )
1071
+ polygon_data.Rotate(angle * math.pi / 180, center)
1072
+ return self.api_object.SetPolygonData(polygon_data)
1073
+ return False
1074
+
1075
+ @pyedb_function_handler
1076
+ def scale(self, factor, center=None):
1077
+ """Scales the polygon relative to a center point by a factor.
1078
+
1079
+ Parameters
1080
+ ----------
1081
+ factor : float
1082
+ Scaling factor.
1083
+ center : List of float or str [x,y], optional
1084
+ If None scaling is done from polygon center.
1085
+
1086
+ Returns
1087
+ -------
1088
+ bool
1089
+ ``True`` when successful, ``False`` when failed.
1090
+
1091
+ Examples
1092
+ --------
1093
+ >>> edbapp = pyaedt.Edb("myproject.aedb")
1094
+ >>> top_layer_polygon = [poly for poly in edbapp.modeler.polygons if poly.layer_name == "Top Layer"]
1095
+ >>> for polygon in top_layer_polygon:
1096
+ >>> polygon.scale(factor=2)
1097
+ """
1098
+ if not isinstance(factor, str):
1099
+ factor = float(factor)
1100
+ polygon_data = self._edb.Geometry.PolygonData.CreateFromArcs(self.polygon_data.edb_api.GetArcData(), True)
1101
+ if not center:
1102
+ center = polygon_data.GetBoundingCircleCenter()
1103
+ if center:
1104
+ polygon_data.Scale(factor, center)
1105
+ return self.api_object.SetPolygonData(polygon_data)
1106
+ elif isinstance(center, list) and len(center) == 2:
1107
+ center = self._edb.Geometry.PointData(
1108
+ self._edb.Utility.Value(center[0]), self._edb.Utility.Value(center[1])
1109
+ )
1110
+ polygon_data.Scale(factor, center)
1111
+ return self.api_object.SetPolygonData(polygon_data)
1112
+ return False
1113
+
1114
+ @pyedb_function_handler
1115
+ def move_layer(self, layer):
1116
+ """Move polygon to given layer.
1117
+
1118
+ Parameters
1119
+ ----------
1120
+ layer : str
1121
+ layer name.
1122
+
1123
+ Returns
1124
+ -------
1125
+ bool
1126
+ ``True`` when successful, ``False`` when failed.
1127
+ """
1128
+ if layer and isinstance(layer, str) and layer in self._pedb.stackup.signal_layers:
1129
+ polygon_data = self._edb.Geometry.PolygonData.CreateFromArcs(self.polygon_data.edb_api.GetArcData(), True)
1130
+ moved_polygon = self._pedb.modeler.create_polygon(
1131
+ main_shape=polygon_data, net_name=self.net_name, layer_name=layer
1132
+ )
1133
+ if moved_polygon:
1134
+ self.delete()
1135
+ return True
1136
+ return False
1137
+
1138
+ @pyedb_function_handler()
1139
+ def in_polygon(
1140
+ self,
1141
+ point_data,
1142
+ include_partial=True,
1143
+ ):
1144
+ """Check if padstack Instance is in given polygon data.
1145
+
1146
+ Parameters
1147
+ ----------
1148
+ point_data : PointData Object or list of float
1149
+ include_partial : bool, optional
1150
+ Whether to include partial intersecting instances. The default is ``True``.
1151
+
1152
+ Returns
1153
+ -------
1154
+ bool
1155
+ ``True`` when successful, ``False`` when failed.
1156
+ """
1157
+ if isinstance(point_data, list):
1158
+ point_data = self._app.edb_api.geometry.point_data(
1159
+ self._app.edb_value(point_data[0]), self._app.edb_value(point_data[1])
1160
+ )
1161
+ int_val = int(self.polygon_data.edb_api.PointInPolygon(point_data))
1162
+
1163
+ # Intersection type:
1164
+ # 0 = objects do not intersect
1165
+ # 1 = this object fully inside other (no common contour points)
1166
+ # 2 = other object fully inside this
1167
+ # 3 = common contour points 4 = undefined intersection
1168
+ if int_val == 0:
1169
+ return False
1170
+ elif include_partial:
1171
+ return True
1172
+ elif int_val < 3:
1173
+ return True
1174
+ else:
1175
+ return False
1176
+
1177
+ # @pyedb_function_handler()
1178
+ # def add_void(self, point_list):
1179
+ # """Add a void to current primitive.
1180
+ #
1181
+ # Parameters
1182
+ # ----------
1183
+ # point_list : list or :class:`dotnet.edb_core.edb_data.primitives_data.EDBPrimitives` or EDB Primitive Object
1184
+ # Point list in the format of `[[x1,y1], [x2,y2],..,[xn,yn]]`.
1185
+ #
1186
+ # Returns
1187
+ # -------
1188
+ # bool
1189
+ # ``True`` if successful, either ``False``.
1190
+ # """
1191
+ # if isinstance(point_list, list):
1192
+ # plane = self._app.modeler.Shape("polygon", points=point_list)
1193
+ # _poly = self._app.modeler.shape_to_polygon_data(plane)
1194
+ # if _poly is None or _poly.IsNull() or _poly is False:
1195
+ # self._logger.error("Failed to create void polygon data")
1196
+ # return False
1197
+ # prim = self._app.edb_api.cell.primitive.polygon.create(
1198
+ # self._app.active_layout, self.layer_name, self.primitive_object.GetNet(), _poly
1199
+ # )
1200
+ # elif isinstance(point_list, EDBPrimitives):
1201
+ # prim = point_list.primitive_object
1202
+ # else:
1203
+ # prim = point_list
1204
+ # return self.add_void(prim)
1205
+
1206
+
1207
+ class EdbText(EDBPrimitivesMain, TextDotNet):
1208
+ def __init__(self, raw_primitive, core_app):
1209
+ EDBPrimitives.__init__(self, raw_primitive, core_app)
1210
+ TextDotNet.__init__(self, self._app, raw_primitive)
1211
+
1212
+
1213
+ class EdbBondwire(EDBPrimitivesMain, BondwireDotNet):
1214
+ def __init__(self, raw_primitive, core_app):
1215
+ EDBPrimitives.__init__(self, raw_primitive, core_app)
1216
+ BondwireDotNet.__init__(self, self._app, raw_primitive)
1217
+
1218
+
1219
+ class EDBArcs(object):
1220
+ """Manages EDB Arc Data functionalities.
1221
+ It Inherits EDB primitives arcs properties.
1222
+
1223
+ Examples
1224
+ --------
1225
+ >>> from pyedb import Edb
1226
+ >>> edb = Edb(myedb, edbversion="2021.2")
1227
+ >>> prim_arcs = edb.modeler.primitives[0].arcs
1228
+ >>> prim_arcs.center # arc center
1229
+ >>> prim_arcs.points # arc point list
1230
+ >>> prim_arcs.mid_point # arc mid point
1231
+ """
1232
+
1233
+ def __init__(self, app, arc):
1234
+ self._app = app
1235
+ self.arc_object = arc
1236
+
1237
+ @property
1238
+ def start(self):
1239
+ """Get the coordinates of the starting point.
1240
+
1241
+ Returns
1242
+ -------
1243
+ list
1244
+ List containing the X and Y coordinates of the starting point.
1245
+
1246
+
1247
+ Examples
1248
+ --------
1249
+ >>> appedb = Edb(fpath, edbversion="2023.2")
1250
+ >>> start_coordinate = appedb.nets["V1P0_S0"].primitives[0].arcs[0].start
1251
+ >>> print(start_coordinate)
1252
+ [x_value, y_value]
1253
+ """
1254
+ point = self.arc_object.Start
1255
+ return [point.X.ToDouble(), point.Y.ToDouble()]
1256
+
1257
+ @property
1258
+ def end(self):
1259
+ """Get the coordinates of the ending point.
1260
+
1261
+ Returns
1262
+ -------
1263
+ list
1264
+ List containing the X and Y coordinates of the ending point.
1265
+
1266
+ Examples
1267
+ --------
1268
+ >>> appedb = Edb(fpath, edbversion="2023.2")
1269
+ >>> end_coordinate = appedb.nets["V1P0_S0"].primitives[0].arcs[0].end
1270
+ """
1271
+ point = self.arc_object.End
1272
+ return [point.X.ToDouble(), point.Y.ToDouble()]
1273
+
1274
+ @property
1275
+ def height(self):
1276
+ """Get the height of the arc.
1277
+
1278
+ Returns
1279
+ -------
1280
+ float
1281
+ Height of the arc.
1282
+
1283
+
1284
+ Examples
1285
+ --------
1286
+ >>> appedb = Edb(fpath, edbversion="2023.2")
1287
+ >>> arc_height = appedb.nets["V1P0_S0"].primitives[0].arcs[0].height
1288
+ """
1289
+ return self.arc_object.Height
1290
+
1291
+ @property
1292
+ def center(self):
1293
+ """Arc center.
1294
+
1295
+ Returns
1296
+ -------
1297
+ list
1298
+ """
1299
+ cent = self.arc_object.GetCenter()
1300
+ return [cent.X.ToDouble(), cent.Y.ToDouble()]
1301
+
1302
+ @property
1303
+ def length(self):
1304
+ """Arc length.
1305
+
1306
+ Returns
1307
+ -------
1308
+ float
1309
+ """
1310
+ return self.arc_object.GetLength()
1311
+
1312
+ @property
1313
+ def mid_point(self):
1314
+ """Arc mid point.
1315
+
1316
+ Returns
1317
+ -------
1318
+ float
1319
+ """
1320
+ return self.arc_object.GetMidPoint()
1321
+
1322
+ @property
1323
+ def radius(self):
1324
+ """Arc radius.
1325
+
1326
+ Returns
1327
+ -------
1328
+ float
1329
+ """
1330
+ return self.arc_object.GetRadius()
1331
+
1332
+ @property
1333
+ def is_segment(self):
1334
+ """Either if it is a straight segment or not.
1335
+
1336
+ Returns
1337
+ -------
1338
+ bool
1339
+ """
1340
+ return self.arc_object.IsSegment()
1341
+
1342
+ @property
1343
+ def is_point(self):
1344
+ """Either if it is a point or not.
1345
+
1346
+ Returns
1347
+ -------
1348
+ bool
1349
+ """
1350
+ return self.arc_object.IsPoint()
1351
+
1352
+ @property
1353
+ def is_ccw(self):
1354
+ """Test whether arc is counter clockwise.
1355
+
1356
+ Returns
1357
+ -------
1358
+ bool
1359
+ """
1360
+ return self.arc_object.IsCCW()
1361
+
1362
+ @property
1363
+ def points_raw(self):
1364
+ """Return a list of Edb points.
1365
+
1366
+ Returns
1367
+ -------
1368
+ list
1369
+ Edb Points.
1370
+ """
1371
+ return list(self.arc_object.GetPointData())
1372
+
1373
+ @property
1374
+ def points(self, arc_segments=6):
1375
+ """Return the list of points with arcs converted to segments.
1376
+
1377
+ Parameters
1378
+ ----------
1379
+ arc_segments : int
1380
+ Number of facets to convert an arc. Default is `6`.
1381
+
1382
+ Returns
1383
+ -------
1384
+ list, list
1385
+ x and y list of points.
1386
+ """
1387
+ try:
1388
+ my_net_points = self.points_raw
1389
+ xt, yt = self._app._get_points_for_plot(my_net_points, arc_segments)
1390
+ if not xt:
1391
+ return []
1392
+ x, y = GeometryOperators.orient_polygon(xt, yt, clockwise=True)
1393
+ return x, y
1394
+ except:
1395
+ x = []
1396
+ y = []
1397
+ return x, y