pyedb 0.23.0__py3-none-any.whl → 0.24.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 (33) hide show
  1. pyedb/__init__.py +1 -1
  2. pyedb/dotnet/edb.py +35 -33
  3. pyedb/dotnet/edb_core/cell/hierarchy/hierarchy_obj.py +11 -0
  4. pyedb/dotnet/edb_core/cell/layout.py +30 -23
  5. pyedb/dotnet/edb_core/cell/layout_obj.py +0 -9
  6. pyedb/dotnet/edb_core/cell/primitive/__init__.py +3 -0
  7. pyedb/dotnet/edb_core/cell/{primitive.py → primitive/bondwire.py} +1 -146
  8. pyedb/dotnet/edb_core/cell/primitive/path.py +351 -0
  9. pyedb/dotnet/edb_core/cell/primitive/primitive.py +895 -0
  10. pyedb/dotnet/edb_core/cell/terminal/bundle_terminal.py +0 -4
  11. pyedb/dotnet/edb_core/cell/terminal/edge_terminal.py +1 -1
  12. pyedb/dotnet/edb_core/components.py +12 -5
  13. pyedb/dotnet/edb_core/dotnet/database.py +1 -23
  14. pyedb/dotnet/edb_core/dotnet/primitive.py +3 -139
  15. pyedb/dotnet/edb_core/edb_data/nets_data.py +1 -11
  16. pyedb/dotnet/edb_core/edb_data/padstacks_data.py +10 -24
  17. pyedb/dotnet/edb_core/edb_data/primitives_data.py +56 -868
  18. pyedb/dotnet/edb_core/geometry/polygon_data.py +43 -0
  19. pyedb/dotnet/edb_core/hfss.py +26 -22
  20. pyedb/dotnet/edb_core/layout_validation.py +3 -3
  21. pyedb/dotnet/edb_core/modeler.py +64 -81
  22. pyedb/dotnet/edb_core/nets.py +5 -4
  23. pyedb/dotnet/edb_core/padstack.py +12 -13
  24. pyedb/dotnet/edb_core/siwave.py +1 -1
  25. pyedb/dotnet/edb_core/stackup.py +3 -3
  26. pyedb/ipc2581/ecad/cad_data/layer_feature.py +1 -1
  27. pyedb/ipc2581/ecad/cad_data/polygon.py +2 -2
  28. pyedb/ipc2581/ecad/cad_data/step.py +2 -2
  29. pyedb/siwave.py +99 -0
  30. {pyedb-0.23.0.dist-info → pyedb-0.24.0.dist-info}/METADATA +2 -2
  31. {pyedb-0.23.0.dist-info → pyedb-0.24.0.dist-info}/RECORD +33 -30
  32. {pyedb-0.23.0.dist-info → pyedb-0.24.0.dist-info}/LICENSE +0 -0
  33. {pyedb-0.23.0.dist-info → pyedb-0.24.0.dist-info}/WHEEL +0 -0
@@ -0,0 +1,895 @@
1
+ # Copyright (C) 2023 - 2024 ANSYS, Inc. and/or its affiliates.
2
+ # SPDX-License-Identifier: MIT
3
+ #
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the "Software"), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in all
13
+ # copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ # SOFTWARE.
22
+ import math
23
+
24
+ from pyedb.dotnet.edb_core.cell.connectable import Connectable
25
+ from pyedb.dotnet.edb_core.general import convert_py_list_to_net_list
26
+ from pyedb.dotnet.edb_core.geometry.polygon_data import PolygonData
27
+ from pyedb.modeler.geometry_operators import GeometryOperators
28
+
29
+
30
+ class Primitive(Connectable):
31
+ """Manages EDB functionalities for a primitives.
32
+ It inherits EDB Object properties.
33
+
34
+ Examples
35
+ --------
36
+ >>> from pyedb import Edb
37
+ >>> edb = Edb(myedb, edbversion="2021.2")
38
+ >>> edb_prim = edb.modeler.primitives[0]
39
+ >>> edb_prim.is_void # Class Property
40
+ >>> edb_prim.IsVoid() # EDB Object Property
41
+ """
42
+
43
+ def __init__(self, pedb, edb_object):
44
+ super().__init__(pedb, edb_object)
45
+ self._app = self._pedb
46
+ self._core_stackup = pedb.stackup
47
+ self._core_net = pedb.nets
48
+ self.primitive_object = self._edb_object
49
+
50
+ bondwire_type = self._pedb._edb.Cell.Primitive.BondwireType
51
+ self._bondwire_type = {
52
+ "invalid": bondwire_type.Invalid,
53
+ "apd": bondwire_type.ApdBondwire,
54
+ "jedec_4": bondwire_type.Jedec4Bondwire,
55
+ "jedec_5": bondwire_type.Jedec5Bondwire,
56
+ "num_of_bondwire_type": bondwire_type.NumOfBondwireType,
57
+ }
58
+ bondwire_cross_section_type = self._pedb._edb.Cell.Primitive.BondwireCrossSectionType
59
+ self._bondwire_cross_section_type = {
60
+ "invalid": bondwire_cross_section_type.Invalid,
61
+ "round": bondwire_cross_section_type.BondwireRound,
62
+ "rectangle": bondwire_cross_section_type.BondwireRectangle,
63
+ }
64
+
65
+ @property
66
+ def type(self):
67
+ """Return the type of the primitive.
68
+
69
+ Expected output is among ``"Circle"``, ``"Rectangle"``,``"Polygon"``,``"Path"`` or ``"Bondwire"``.
70
+
71
+ Returns
72
+ -------
73
+ str
74
+ """
75
+ try:
76
+ return self._edb_object.GetPrimitiveType().ToString()
77
+ except AttributeError: # pragma: no cover
78
+ return ""
79
+
80
+ @property
81
+ def primitive_type(self):
82
+ """Return the type of the primitive.
83
+
84
+ Expected output is among ``"circle"``, ``"rectangle"``,``"polygon"``,``"path"`` or ``"bondwire"``.
85
+
86
+ Returns
87
+ -------
88
+ str
89
+ """
90
+ return self._edb_object.GetPrimitiveType().ToString().lower()
91
+
92
+ @property
93
+ def net_name(self):
94
+ """Get the primitive net name.
95
+
96
+ Returns
97
+ -------
98
+ str
99
+ """
100
+ return self.net.name
101
+
102
+ @net_name.setter
103
+ def net_name(self, name):
104
+ if isinstance(name, str):
105
+ net = self._app.nets.nets[name].net_object
106
+ self.primitive_object.SetNet(net)
107
+ else:
108
+ try:
109
+ self.net = name.name
110
+ except: # pragma: no cover
111
+ self._app.logger.error("Failed to set net name.")
112
+
113
+ @property
114
+ def layer(self):
115
+ """Get the primitive edb layer object."""
116
+ layer_name = self._edb_object.GetLayer().GetName()
117
+ return self._pedb.stackup.all_layers[layer_name]
118
+
119
+ @property
120
+ def layer_name(self):
121
+ """Get the primitive layer name.
122
+
123
+ Returns
124
+ -------
125
+ str
126
+ """
127
+ try:
128
+ return self.layer.name
129
+ except (KeyError, AttributeError): # pragma: no cover
130
+ return None
131
+
132
+ @layer_name.setter
133
+ def layer_name(self, val):
134
+ layer_list = list(self._core_stackup.layers.keys())
135
+ if isinstance(val, str) and val in layer_list:
136
+ layer = self._core_stackup.layers[val]._edb_layer
137
+ if layer:
138
+ self.primitive_object.SetLayer(layer)
139
+ else:
140
+ raise AttributeError("Layer {} not found.".format(val))
141
+ elif isinstance(val, type(self._core_stackup.layers[layer_list[0]])):
142
+ try:
143
+ self.primitive_object.SetLayer(val._edb_layer)
144
+ except:
145
+ raise AttributeError("Failed to assign new layer on primitive.")
146
+ else:
147
+ raise AttributeError("Invalid input value")
148
+
149
+ @property
150
+ def is_void(self):
151
+ """Either if the primitive is a void or not.
152
+
153
+ Returns
154
+ -------
155
+ bool
156
+ """
157
+ return self._edb_object.IsVoid()
158
+
159
+ def get_connected_objects(self):
160
+ """Get connected objects.
161
+
162
+ Returns
163
+ -------
164
+ list
165
+ """
166
+ return self._pedb.get_connected_objects(self._layout_obj_instance)
167
+
168
+ def area(self, include_voids=True):
169
+ """Return the total area.
170
+
171
+ Parameters
172
+ ----------
173
+ include_voids : bool, optional
174
+ Either if the voids have to be included in computation.
175
+ The default value is ``True``.
176
+
177
+ Returns
178
+ -------
179
+ float
180
+ """
181
+ area = self._edb_object.GetPolygonData().Area()
182
+ if include_voids:
183
+ for el in self._edb_object.Voids:
184
+ area -= el.GetPolygonData().Area()
185
+ return area
186
+
187
+ @property
188
+ def is_negative(self):
189
+ """Determine whether this primitive is negative.
190
+
191
+ Returns
192
+ -------
193
+ bool
194
+ True if it is negative, False otherwise.
195
+ """
196
+ return self._edb_object.GetIsNegative()
197
+
198
+ @is_negative.setter
199
+ def is_negative(self, value):
200
+ self._edb_object.SetIsNegative(value)
201
+
202
+ @staticmethod
203
+ def _eval_arc_points(p1, p2, h, n=6, tol=1e-12):
204
+ """Get the points of the arc
205
+
206
+ Parameters
207
+ ----------
208
+ p1 : list
209
+ Arc starting point.
210
+ p2 : list
211
+ Arc ending point.
212
+ h : float
213
+ Arc height.
214
+ n : int
215
+ Number of points to generate along the arc.
216
+ tol : float
217
+ Geometric tolerance.
218
+
219
+ Returns
220
+ -------
221
+ list, list
222
+ Points generated along the arc.
223
+ """
224
+ # fmt: off
225
+ if abs(h) < tol:
226
+ return [], []
227
+ elif h > 0:
228
+ reverse = False
229
+ x1 = p1[0]
230
+ y1 = p1[1]
231
+ x2 = p2[0]
232
+ y2 = p2[1]
233
+ else:
234
+ reverse = True
235
+ x1 = p2[0]
236
+ y1 = p2[1]
237
+ x2 = p1[0]
238
+ y2 = p1[1]
239
+ h *= -1
240
+ xa = (x2 - x1) / 2
241
+ ya = (y2 - y1) / 2
242
+ xo = x1 + xa
243
+ yo = y1 + ya
244
+ a = math.sqrt(xa ** 2 + ya ** 2)
245
+ if a < tol:
246
+ return [], []
247
+ r = (a ** 2) / (2 * h) + h / 2
248
+ if abs(r - a) < tol:
249
+ b = 0
250
+ th = 2 * math.asin(1) # chord angle
251
+ else:
252
+ b = math.sqrt(r ** 2 - a ** 2)
253
+ th = 2 * math.asin(a / r) # chord angle
254
+
255
+ # center of the circle
256
+ xc = xo + b * ya / a
257
+ yc = yo - b * xa / a
258
+
259
+ alpha = math.atan2((y1 - yc), (x1 - xc))
260
+ xr = []
261
+ yr = []
262
+ for i in range(n):
263
+ i += 1
264
+ dth = (float(i) / (n + 1)) * th
265
+ xi = xc + r * math.cos(alpha - dth)
266
+ yi = yc + r * math.sin(alpha - dth)
267
+ xr.append(xi)
268
+ yr.append(yi)
269
+
270
+ if reverse:
271
+ xr.reverse()
272
+ yr.reverse()
273
+ # fmt: on
274
+ return xr, yr
275
+
276
+ def _get_points_for_plot(self, my_net_points, num):
277
+ """
278
+ Get the points to be plotted.
279
+ """
280
+ # fmt: off
281
+ x = []
282
+ y = []
283
+ for i, point in enumerate(my_net_points):
284
+ if not self.is_arc(point):
285
+ x.append(point.X.ToDouble())
286
+ y.append(point.Y.ToDouble())
287
+ # i += 1
288
+ else:
289
+ arc_h = point.GetArcHeight().ToDouble()
290
+ p1 = [my_net_points[i - 1].X.ToDouble(), my_net_points[i - 1].Y.ToDouble()]
291
+ if i + 1 < len(my_net_points):
292
+ p2 = [my_net_points[i + 1].X.ToDouble(), my_net_points[i + 1].Y.ToDouble()]
293
+ else:
294
+ p2 = [my_net_points[0].X.ToDouble(), my_net_points[0].Y.ToDouble()]
295
+ x_arc, y_arc = self._eval_arc_points(p1, p2, arc_h, num)
296
+ x.extend(x_arc)
297
+ y.extend(y_arc)
298
+ # i += 1
299
+ # fmt: on
300
+ return x, y
301
+
302
+ @property
303
+ def center(self):
304
+ """Return the primitive bounding box center coordinate.
305
+
306
+ Returns
307
+ -------
308
+ list
309
+ [x, y]
310
+
311
+ """
312
+ bbox = self.bbox
313
+ return [(bbox[0] + bbox[2]) / 2, (bbox[1] + bbox[3]) / 2]
314
+
315
+ def is_arc(self, point):
316
+ """Either if a point is an arc or not.
317
+
318
+ Returns
319
+ -------
320
+ bool
321
+ """
322
+ return point.IsArc()
323
+
324
+ def get_connected_object_id_set(self):
325
+ """Produce a list of all geometries physically connected to a given layout object.
326
+
327
+ Returns
328
+ -------
329
+ list
330
+ Found connected objects IDs with Layout object.
331
+ """
332
+ layoutInst = self._edb_object.GetLayout().GetLayoutInstance()
333
+ layoutObjInst = layoutInst.GetLayoutObjInstance(self._edb_object, None) # 2nd arg was []
334
+ return [loi.GetLayoutObj().GetId() for loi in layoutInst.GetConnectedObjects(layoutObjInst).Items]
335
+
336
+ @property
337
+ def bbox(self):
338
+ """Return the primitive bounding box points. Lower left corner, upper right corner.
339
+
340
+ Returns
341
+ -------
342
+ list
343
+ [lower_left x, lower_left y, upper right x, upper right y]
344
+
345
+ """
346
+ bbox = self.polygon_data._edb_object.GetBBox()
347
+ return [bbox.Item1.X.ToDouble(), bbox.Item1.Y.ToDouble(), bbox.Item2.X.ToDouble(), bbox.Item2.Y.ToDouble()]
348
+
349
+ def convert_to_polygon(self):
350
+ """Convert path to polygon.
351
+
352
+ Returns
353
+ -------
354
+ bool, :class:`dotnet.edb_core.edb_data.primitives.EDBPrimitives`
355
+ Polygon when successful, ``False`` when failed.
356
+
357
+ """
358
+ if self.type == "Path":
359
+ polygon_data = self._edb_object.GetPolygonData()
360
+ polygon = self._app.modeler.create_polygon(polygon_data, self.layer_name, [], self.net_name)
361
+ self._edb_object.Delete()
362
+ return polygon
363
+ else:
364
+ return False
365
+
366
+ def intersection_type(self, primitive):
367
+ """Get intersection type between actual primitive and another primitive or polygon data.
368
+
369
+ Parameters
370
+ ----------
371
+ primitive : :class:`pyaeedt.edb_core.edb_data.primitives_data.EDBPrimitives` or `PolygonData`
372
+
373
+ Returns
374
+ -------
375
+ int
376
+ Intersection type:
377
+ 0 - objects do not intersect,
378
+ 1 - this object fully inside other (no common contour points),
379
+ 2 - other object fully inside this,
380
+ 3 - common contour points,
381
+ 4 - undefined intersection.
382
+ """
383
+ poly = primitive
384
+ try:
385
+ poly = primitive.polygon_data
386
+ except AttributeError:
387
+ pass
388
+ return int(self.polygon_data._edb_object.GetIntersectionType(poly._edb_object))
389
+
390
+ def is_intersecting(self, primitive):
391
+ """Check if actual primitive and another primitive or polygon data intesects.
392
+
393
+ Parameters
394
+ ----------
395
+ primitive : :class:`pyaeedt.edb_core.edb_data.primitives_data.EDBPrimitives` or `PolygonData`
396
+
397
+ Returns
398
+ -------
399
+ bool
400
+ """
401
+ return True if self.intersection_type(primitive) >= 1 else False
402
+
403
+ def get_closest_point(self, point):
404
+ """Get the closest point of the primitive to the input data.
405
+
406
+ Parameters
407
+ ----------
408
+ point : list of float or PointData
409
+
410
+ Returns
411
+ -------
412
+ list of float
413
+ """
414
+ if isinstance(point, (list, tuple)):
415
+ point = self._app.edb_api.geometry.point_data(self._app.edb_value(point[0]), self._app.edb_value(point[1]))
416
+
417
+ p0 = self.polygon_data._edb_object.GetClosestPoint(point)
418
+ return [p0.X.ToDouble(), p0.Y.ToDouble()]
419
+
420
+ @property
421
+ def arcs(self):
422
+ """Get the Primitive Arc Data."""
423
+ return self.polygon_data.arcs
424
+
425
+ @property
426
+ def longest_arc(self):
427
+ """Get the longest arc."""
428
+ len = 0
429
+ arc = None
430
+ for i in self.arcs:
431
+ if i.is_segment and i.length > len:
432
+ arc = i
433
+ len = i.length
434
+ return arc
435
+
436
+ def subtract(self, primitives):
437
+ """Subtract active primitive with one or more primitives.
438
+
439
+ Parameters
440
+ ----------
441
+ primitives : :class:`dotnet.edb_core.edb_data.EDBPrimitives` or EDB PolygonData or EDB Primitive or list
442
+
443
+ Returns
444
+ -------
445
+ List of :class:`dotnet.edb_core.edb_data.EDBPrimitives`
446
+ """
447
+ poly = self.primitive_object.GetPolygonData()
448
+ if not isinstance(primitives, list):
449
+ primitives = [primitives]
450
+ primi_polys = []
451
+ voids_of_prims = []
452
+ for prim in primitives:
453
+ if isinstance(prim, Primitive):
454
+ primi_polys.append(prim.primitive_object.GetPolygonData())
455
+ for void in prim.voids:
456
+ voids_of_prims.append(void.polygon_data._edb_object)
457
+ else:
458
+ try:
459
+ primi_polys.append(prim.GetPolygonData())
460
+ except:
461
+ primi_polys.append(prim)
462
+ for v in self.voids[:]:
463
+ primi_polys.append(v.polygon_data._edb_object)
464
+ primi_polys = poly.Unite(convert_py_list_to_net_list(primi_polys))
465
+ p_to_sub = poly.Unite(convert_py_list_to_net_list([poly] + voids_of_prims))
466
+ list_poly = poly.Subtract(p_to_sub, primi_polys)
467
+ new_polys = []
468
+ if list_poly:
469
+ for p in list_poly:
470
+ if p.IsNull():
471
+ continue
472
+ new_polys.append(
473
+ self._app.modeler.create_polygon(p, self.layer_name, net_name=self.net_name, voids=[]),
474
+ )
475
+ self.delete()
476
+ for prim in primitives:
477
+ if isinstance(prim, Primitive):
478
+ prim.delete()
479
+ else:
480
+ try:
481
+ prim.Delete()
482
+ except AttributeError:
483
+ continue
484
+ return new_polys
485
+
486
+ def intersect(self, primitives):
487
+ """Intersect active primitive with one or more primitives.
488
+
489
+ Parameters
490
+ ----------
491
+ primitives : :class:`dotnet.edb_core.edb_data.EDBPrimitives` or EDB PolygonData or EDB Primitive or list
492
+
493
+ Returns
494
+ -------
495
+ List of :class:`dotnet.edb_core.edb_data.EDBPrimitives`
496
+ """
497
+ poly = self._edb_object.GetPolygonData()
498
+ if not isinstance(primitives, list):
499
+ primitives = [primitives]
500
+ primi_polys = []
501
+ for prim in primitives:
502
+ if isinstance(prim, Primitive):
503
+ primi_polys.append(prim.primitive_object.GetPolygonData())
504
+ else:
505
+ primi_polys.append(prim._edb_object.GetPolygonData())
506
+ # primi_polys.append(prim)
507
+ list_poly = poly.Intersect(convert_py_list_to_net_list([poly]), convert_py_list_to_net_list(primi_polys))
508
+ new_polys = []
509
+ if list_poly:
510
+ voids = self.voids
511
+ for p in list_poly:
512
+ if p.IsNull():
513
+ continue
514
+ list_void = []
515
+ void_to_subtract = []
516
+ if voids:
517
+ for void in voids:
518
+ void_pdata = void._edb_object.GetPolygonData()
519
+ int_data2 = p.GetIntersectionType(void_pdata)
520
+ if int_data2 > 2 or int_data2 == 1:
521
+ void_to_subtract.append(void_pdata)
522
+ elif int_data2 == 2:
523
+ list_void.append(void_pdata)
524
+ if void_to_subtract:
525
+ polys_cleans = p.Subtract(
526
+ convert_py_list_to_net_list(p), convert_py_list_to_net_list(void_to_subtract)
527
+ )
528
+ for polys_clean in polys_cleans:
529
+ if not polys_clean.IsNull():
530
+ void_to_append = [v for v in list_void if polys_clean.GetIntersectionType(v) == 2]
531
+ new_polys.append(
532
+ self._app.modeler.create_polygon(
533
+ polys_clean, self.layer_name, net_name=self.net_name, voids=void_to_append
534
+ )
535
+ )
536
+ else:
537
+ new_polys.append(
538
+ self._app.modeler.create_polygon(
539
+ p, self.layer_name, net_name=self.net_name, voids=list_void
540
+ )
541
+ )
542
+ else:
543
+ new_polys.append(
544
+ self._app.modeler.create_polygon(p, self.layer_name, net_name=self.net_name, voids=list_void)
545
+ )
546
+ self.delete()
547
+ for prim in primitives:
548
+ if isinstance(prim, Primitive):
549
+ prim.delete()
550
+ else:
551
+ try:
552
+ prim.Delete()
553
+ except AttributeError:
554
+ continue
555
+ return new_polys
556
+
557
+ def unite(self, primitives):
558
+ """Unite active primitive with one or more primitives.
559
+
560
+ Parameters
561
+ ----------
562
+ primitives : :class:`dotnet.edb_core.edb_data.EDBPrimitives` or EDB PolygonData or EDB Primitive or list
563
+
564
+ Returns
565
+ -------
566
+ List of :class:`dotnet.edb_core.edb_data.EDBPrimitives`
567
+ """
568
+ poly = self._edb_object.GetPolygonData()
569
+ if not isinstance(primitives, list):
570
+ primitives = [primitives]
571
+ primi_polys = []
572
+ for prim in primitives:
573
+ if isinstance(prim, Primitive):
574
+ primi_polys.append(prim.primitive_object.GetPolygonData())
575
+ else:
576
+ try:
577
+ primi_polys.append(prim.GetPolygonData())
578
+ except:
579
+ primi_polys.append(prim)
580
+ list_poly = poly.Unite(convert_py_list_to_net_list([poly] + primi_polys))
581
+ new_polys = []
582
+ if list_poly:
583
+ voids = self.voids
584
+ for p in list_poly:
585
+ if p.IsNull():
586
+ continue
587
+ list_void = []
588
+ if voids:
589
+ for void in voids:
590
+ void_pdata = void.primitive_object.GetPolygonData()
591
+ int_data2 = p.GetIntersectionType(void_pdata)
592
+ if int_data2 > 1:
593
+ list_void.append(void_pdata)
594
+ new_polys.append(
595
+ self._app.modeler.create_polygon(p, self.layer_name, net_name=self.net_name, voids=list_void),
596
+ )
597
+ self.delete()
598
+ for prim in primitives:
599
+ if isinstance(prim, Primitive):
600
+ prim.delete()
601
+ else:
602
+ try:
603
+ prim.Delete()
604
+ except AttributeError:
605
+ continue
606
+ return new_polys
607
+
608
+ def get_closest_arc_midpoint(self, point):
609
+ """Get the closest arc midpoint of the primitive to the input data.
610
+
611
+ Parameters
612
+ ----------
613
+ point : list of float or PointData
614
+
615
+ Returns
616
+ -------
617
+ list of float
618
+ """
619
+ if isinstance(point, self._app.edb_api.geometry.geometry.PointData):
620
+ point = [point.X.ToDouble(), point.Y.ToDouble()]
621
+ dist = 1e12
622
+ out = None
623
+ for arc in self.arcs:
624
+ mid_point = arc.mid_point
625
+ mid_point = [mid_point.X.ToDouble(), mid_point.Y.ToDouble()]
626
+ if GeometryOperators.points_distance(mid_point, point) < dist:
627
+ out = arc.mid_point
628
+ dist = GeometryOperators.points_distance(mid_point, point)
629
+ return [out.X.ToDouble(), out.Y.ToDouble()]
630
+
631
+ @property
632
+ def voids(self):
633
+ """:obj:`list` of :class:`Primitive <ansys.edb.primitive.Primitive>`: List of void\
634
+ primitive objects inside the primitive.
635
+
636
+ Read-Only.
637
+ """
638
+ return [self._pedb.layout.find_object_by_id(void.GetId()) for void in self._edb_object.Voids]
639
+
640
+ @property
641
+ def shortest_arc(self):
642
+ """Get the longest arc."""
643
+ len = 1e12
644
+ arc = None
645
+ for i in self.arcs:
646
+ if i.is_segment and i.length < len:
647
+ arc = i
648
+ len = i.length
649
+ return arc
650
+
651
+ @property
652
+ def aedt_name(self):
653
+ """Name to be visualized in AEDT.
654
+
655
+ Returns
656
+ -------
657
+ str
658
+ Name.
659
+ """
660
+ from System import String
661
+
662
+ val = String("")
663
+
664
+ _, name = self._edb_object.GetProductProperty(self._pedb._edb.ProductId.Designer, 1, val)
665
+ name = str(name).strip("'")
666
+ if name == "":
667
+ if str(self.primitive_type) == "Path":
668
+ ptype = "line"
669
+ elif str(self.primitive_type) == "Rectangle":
670
+ ptype = "rect"
671
+ elif str(self.primitive_type) == "Polygon":
672
+ ptype = "poly"
673
+ elif str(self.primitive_type) == "Bondwire":
674
+ ptype = "bwr"
675
+ else:
676
+ ptype = str(self.primitive_type).lower()
677
+ name = "{}_{}".format(ptype, self.id)
678
+ self._edb_object.SetProductProperty(self._pedb._edb.ProductId.Designer, 1, name)
679
+ return name
680
+
681
+ @aedt_name.setter
682
+ def aedt_name(self, value):
683
+ self._edb_object.SetProductProperty(self._pedb._edb.ProductId.Designer, 1, value)
684
+
685
+ @property
686
+ def polygon_data(self):
687
+ """:class:`pyedb.dotnet.edb_core.dotnet.database.PolygonDataDotNet`: Outer contour of the Polygon object."""
688
+ return PolygonData(self._pedb, self._edb_object.GetPolygonData())
689
+
690
+ @polygon_data.setter
691
+ def polygon_data(self, poly):
692
+ self._edb_object.SetPolygonData(poly._edb_object)
693
+
694
+ def add_void(self, point_list):
695
+ """Add a void to current primitive.
696
+
697
+ Parameters
698
+ ----------
699
+ point_list : list or :class:`pyedb.dotnet.edb_core.edb_data.primitives_data.EDBPrimitives` \
700
+ or EDB Primitive Object. Point list in the format of `[[x1,y1], [x2,y2],..,[xn,yn]]`.
701
+
702
+ Returns
703
+ -------
704
+ bool
705
+ ``True`` if successful, either ``False``.
706
+ """
707
+ if isinstance(point_list, list):
708
+ plane = self._pedb.modeler.Shape("polygon", points=point_list)
709
+ _poly = self._pedb.modeler.shape_to_polygon_data(plane)
710
+ if _poly is None or _poly.IsNull() or _poly is False:
711
+ self._logger.error("Failed to create void polygon data")
712
+ return False
713
+ point_list = self._pedb.modeler.create_polygon(
714
+ _poly, layer_name=self.layer_name, net_name=self.net.name
715
+ )._edb_object
716
+ elif "_edb_object" in dir(point_list):
717
+ point_list = point_list._edb_object
718
+ elif "primitive_obj" in dir(point_list):
719
+ point_list = point_list.primitive_obj
720
+ return self._edb_object.AddVoid(point_list)
721
+
722
+ @property
723
+ def api_class(self):
724
+ return self._pedb._edb.Cell.Primitive
725
+
726
+ def set_hfss_prop(self, material, solve_inside):
727
+ """Set HFSS properties.
728
+
729
+ Parameters
730
+ ----------
731
+ material : str
732
+ Material property name to be set.
733
+ solve_inside : bool
734
+ Whether to do solve inside.
735
+ """
736
+ self._edb_object.SetHfssProp(material, solve_inside)
737
+
738
+ @property
739
+ def has_voids(self):
740
+ """:obj:`bool`: If a primitive has voids inside.
741
+
742
+ Read-Only.
743
+ """
744
+ return self._edb_object.HasVoids()
745
+
746
+ @property
747
+ def owner(self):
748
+ """:class:`Primitive <ansys.edb.primitive.Primitive>`: Owner of the primitive object.
749
+
750
+ Read-Only.
751
+ """
752
+ pid = self._edb_object.GetOwner().GetId()
753
+ return self._pedb.layout.self.find_object_by_id(pid)
754
+
755
+ @property
756
+ def is_parameterized(self):
757
+ """:obj:`bool`: Primitive's parametrization.
758
+
759
+ Read-Only.
760
+ """
761
+ return self._edb_object.IsParameterized()
762
+
763
+ def get_hfss_prop(self):
764
+ """
765
+ Get HFSS properties.
766
+
767
+ Returns
768
+ -------
769
+ material : str
770
+ Material property name.
771
+ solve_inside : bool
772
+ If solve inside.
773
+ """
774
+ material = ""
775
+ solve_inside = True
776
+ self._edb_object.GetHfssProp(material, solve_inside)
777
+ return material, solve_inside
778
+
779
+ def remove_hfss_prop(self):
780
+ """Remove HFSS properties."""
781
+ self._edb_object.RemoveHfssProp()
782
+
783
+ @property
784
+ def is_zone_primitive(self):
785
+ """:obj:`bool`: If primitive object is a zone.
786
+
787
+ Read-Only.
788
+ """
789
+ return self._edb_object.IsZonePrimitive()
790
+
791
+ @property
792
+ def can_be_zone_primitive(self):
793
+ """:obj:`bool`: If a primitive can be a zone.
794
+
795
+ Read-Only.
796
+ """
797
+ return True
798
+
799
+ def make_zone_primitive(self, zone_id):
800
+ """Make primitive a zone primitive with a zone specified by the provided id.
801
+
802
+ Parameters
803
+ ----------
804
+ zone_id : int
805
+ Id of zone primitive will use.
806
+
807
+ """
808
+ self._edb_object.MakeZonePrimitive(zone_id)
809
+
810
+ def points(self, arc_segments=6):
811
+ """Return the list of points with arcs converted to segments.
812
+
813
+ Parameters
814
+ ----------
815
+ arc_segments : int
816
+ Number of facets to convert an arc. Default is `6`.
817
+
818
+ Returns
819
+ -------
820
+ tuple
821
+ The tuple contains 2 lists made of X and Y points coordinates.
822
+ """
823
+ my_net_points = list(self._edb_object.GetPolygonData().Points)
824
+ xt, yt = self._get_points_for_plot(my_net_points, arc_segments)
825
+ if not xt:
826
+ return []
827
+ x, y = GeometryOperators.orient_polygon(xt, yt, clockwise=True)
828
+ return x, y
829
+
830
+ def points_raw(self):
831
+ """Return a list of Edb points.
832
+
833
+ Returns
834
+ -------
835
+ list
836
+ Edb Points.
837
+ """
838
+ points = []
839
+ my_net_points = list(self._edb_object.GetPolygonData().Points)
840
+ for point in my_net_points:
841
+ points.append(point)
842
+ return points
843
+
844
+ def expand(self, offset=0.001, tolerance=1e-12, round_corners=True, maximum_corner_extension=0.001):
845
+ """Expand the polygon shape by an absolute value in all direction.
846
+ Offset can be negative for negative expansion.
847
+
848
+ Parameters
849
+ ----------
850
+ offset : float, optional
851
+ Offset value in meters.
852
+ tolerance : float, optional
853
+ Tolerance in meters.
854
+ round_corners : bool, optional
855
+ Whether to round corners or not.
856
+ If True, use rounded corners in the expansion otherwise use straight edges (can be degenerate).
857
+ maximum_corner_extension : float, optional
858
+ The maximum corner extension (when round corners are not used) at which point the corner is clipped.
859
+ """
860
+ return self.polygon_data.expand(offset, tolerance, round_corners, maximum_corner_extension)
861
+
862
+ def scale(self, factor, center=None):
863
+ """Scales the polygon relative to a center point by a factor.
864
+
865
+ Parameters
866
+ ----------
867
+ factor : float
868
+ Scaling factor.
869
+ center : List of float or str [x,y], optional
870
+ If None scaling is done from polygon center.
871
+
872
+ Returns
873
+ -------
874
+ bool
875
+ ``True`` when successful, ``False`` when failed.
876
+ """
877
+ if not isinstance(factor, str):
878
+ factor = float(factor)
879
+ polygon_data = self.polygon_data.create_from_arcs(self.polygon_data._edb_object.GetArcData(), True)
880
+ if not center:
881
+ center = self.polygon_data._edb_object.GetBoundingCircleCenter()
882
+ if center:
883
+ polygon_data._edb_object.Scale(factor, center)
884
+ self.polygon_data = polygon_data
885
+ return True
886
+ else:
887
+ self._pedb.logger.error(f"Failed to evaluate center on primitive {self.id}")
888
+ elif isinstance(center, list) and len(center) == 2:
889
+ center = self._edb.Geometry.PointData(
890
+ self._edb.Utility.Value(center[0]), self._edb.Utility.Value(center[1])
891
+ )
892
+ polygon_data._edb_object.Scale(factor, center)
893
+ self.polygon_data = polygon_data
894
+ return True
895
+ return False