pyedb 0.56.0__py3-none-any.whl → 0.58.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 (110) hide show
  1. pyedb/__init__.py +1 -1
  2. pyedb/configuration/cfg_data.py +3 -0
  3. pyedb/configuration/cfg_pin_groups.py +2 -0
  4. pyedb/configuration/cfg_terminals.py +232 -0
  5. pyedb/configuration/configuration.py +146 -3
  6. pyedb/dotnet/clr_module.py +1 -2
  7. pyedb/dotnet/database/Variables.py +30 -22
  8. pyedb/dotnet/database/cell/hierarchy/component.py +2 -8
  9. pyedb/dotnet/database/cell/layout.py +5 -1
  10. pyedb/dotnet/database/cell/primitive/primitive.py +2 -2
  11. pyedb/dotnet/database/cell/terminal/bundle_terminal.py +12 -0
  12. pyedb/dotnet/database/cell/terminal/pingroup_terminal.py +1 -1
  13. pyedb/dotnet/database/cell/terminal/terminal.py +38 -0
  14. pyedb/dotnet/database/components.py +15 -19
  15. pyedb/dotnet/database/dotnet/database.py +1 -0
  16. pyedb/dotnet/database/edb_data/control_file.py +19 -8
  17. pyedb/dotnet/database/edb_data/nets_data.py +3 -3
  18. pyedb/dotnet/database/edb_data/padstacks_data.py +39 -14
  19. pyedb/dotnet/database/edb_data/ports.py +0 -25
  20. pyedb/dotnet/database/edb_data/primitives_data.py +3 -3
  21. pyedb/dotnet/database/edb_data/raptor_x_simulation_setup_data.py +18 -19
  22. pyedb/dotnet/database/edb_data/simulation_configuration.py +3 -3
  23. pyedb/dotnet/database/edb_data/sources.py +21 -2
  24. pyedb/dotnet/database/general.py +1 -6
  25. pyedb/dotnet/database/hfss.py +9 -8
  26. pyedb/dotnet/database/layout_validation.py +14 -3
  27. pyedb/dotnet/database/materials.py +1 -3
  28. pyedb/dotnet/database/modeler.py +7 -3
  29. pyedb/dotnet/database/nets.py +27 -19
  30. pyedb/dotnet/database/padstack.py +4 -2
  31. pyedb/dotnet/database/sim_setup_data/io/siwave.py +54 -1
  32. pyedb/dotnet/database/siwave.py +4 -3
  33. pyedb/dotnet/database/stackup.py +55 -58
  34. pyedb/dotnet/database/utilities/heatsink.py +0 -1
  35. pyedb/dotnet/database/utilities/hfss_simulation_setup.py +81 -0
  36. pyedb/dotnet/database/utilities/simulation_setup.py +7 -5
  37. pyedb/dotnet/database/utilities/siwave_cpa_simulation_setup.py +1 -0
  38. pyedb/dotnet/database/utilities/siwave_simulation_setup.py +264 -13
  39. pyedb/dotnet/edb.py +65 -47
  40. pyedb/exceptions.py +1 -2
  41. pyedb/extensions/create_cell_array.py +67 -49
  42. pyedb/generic/data_handlers.py +13 -23
  43. pyedb/generic/design_types.py +9 -35
  44. pyedb/generic/filesystem.py +4 -2
  45. pyedb/generic/general_methods.py +28 -41
  46. pyedb/generic/plot.py +8 -23
  47. pyedb/generic/process.py +78 -10
  48. pyedb/grpc/database/_typing.py +0 -0
  49. pyedb/grpc/database/components.py +14 -13
  50. pyedb/grpc/database/control_file.py +27 -40
  51. pyedb/grpc/database/definition/materials.py +1 -1
  52. pyedb/grpc/database/definition/package_def.py +6 -3
  53. pyedb/grpc/database/definition/padstack_def.py +14 -12
  54. pyedb/grpc/database/hfss.py +1 -4
  55. pyedb/grpc/database/hierarchy/component.py +5 -13
  56. pyedb/grpc/database/hierarchy/pingroup.py +16 -3
  57. pyedb/grpc/database/layers/layer.py +1 -2
  58. pyedb/grpc/database/layers/stackup_layer.py +42 -19
  59. pyedb/grpc/database/layout/layout.py +43 -27
  60. pyedb/grpc/database/layout/voltage_regulator.py +6 -1
  61. pyedb/grpc/database/layout_validation.py +5 -2
  62. pyedb/grpc/database/modeler.py +254 -252
  63. pyedb/grpc/database/net/differential_pair.py +9 -2
  64. pyedb/grpc/database/net/extended_net.py +24 -9
  65. pyedb/grpc/database/net/net.py +14 -5
  66. pyedb/grpc/database/net/net_class.py +24 -7
  67. pyedb/grpc/database/nets.py +11 -43
  68. pyedb/grpc/database/padstacks.py +67 -119
  69. pyedb/grpc/database/primitive/bondwire.py +3 -67
  70. pyedb/grpc/database/primitive/circle.py +42 -3
  71. pyedb/grpc/database/primitive/padstack_instance.py +58 -31
  72. pyedb/grpc/database/primitive/path.py +160 -11
  73. pyedb/grpc/database/primitive/polygon.py +73 -7
  74. pyedb/grpc/database/primitive/primitive.py +2 -2
  75. pyedb/grpc/database/primitive/rectangle.py +105 -4
  76. pyedb/grpc/database/simulation_setup/hfss_general_settings.py +0 -2
  77. pyedb/grpc/database/simulation_setup/hfss_settings_options.py +0 -4
  78. pyedb/grpc/database/simulation_setup/hfss_simulation_setup.py +79 -0
  79. pyedb/grpc/database/simulation_setup/siwave_cpa_simulation_setup.py +1 -0
  80. pyedb/grpc/database/simulation_setup/sweep_data.py +1 -3
  81. pyedb/grpc/database/siwave.py +6 -13
  82. pyedb/grpc/database/source_excitations.py +46 -63
  83. pyedb/grpc/database/stackup.py +55 -60
  84. pyedb/grpc/database/terminal/bundle_terminal.py +10 -3
  85. pyedb/grpc/database/terminal/padstack_instance_terminal.py +9 -11
  86. pyedb/grpc/database/terminal/pingroup_terminal.py +8 -1
  87. pyedb/grpc/database/terminal/point_terminal.py +30 -0
  88. pyedb/grpc/database/terminal/terminal.py +35 -10
  89. pyedb/grpc/database/utility/heat_sink.py +0 -1
  90. pyedb/grpc/database/utility/hfss_extent_info.py +2 -2
  91. pyedb/grpc/database/utility/xml_control_file.py +19 -8
  92. pyedb/grpc/edb.py +63 -32
  93. pyedb/grpc/edb_init.py +1 -0
  94. pyedb/ipc2581/ecad/cad_data/layer_feature.py +6 -2
  95. pyedb/ipc2581/ecad/cad_data/step.py +1 -1
  96. pyedb/ipc2581/ipc2581.py +8 -7
  97. pyedb/libraries/common.py +3 -4
  98. pyedb/libraries/rf_libraries/base_functions.py +7 -16
  99. pyedb/libraries/rf_libraries/planar_antennas.py +3 -21
  100. pyedb/misc/aedtlib_personalib_install.py +2 -2
  101. pyedb/misc/downloads.py +19 -3
  102. pyedb/misc/misc.py +5 -2
  103. pyedb/misc/siw_feature_config/emc_rule_checker_settings.py +3 -2
  104. pyedb/misc/siw_feature_config/xtalk_scan/scan_config.py +0 -1
  105. pyedb/misc/utilities.py +0 -1
  106. pyedb/modeler/geometry_operators.py +3 -2
  107. {pyedb-0.56.0.dist-info → pyedb-0.58.0.dist-info}/METADATA +6 -7
  108. {pyedb-0.56.0.dist-info → pyedb-0.58.0.dist-info}/RECORD +110 -108
  109. {pyedb-0.56.0.dist-info → pyedb-0.58.0.dist-info}/WHEEL +0 -0
  110. {pyedb-0.56.0.dist-info → pyedb-0.58.0.dist-info}/licenses/LICENSE +0 -0
@@ -23,20 +23,17 @@
23
23
  """
24
24
  This module contains these classes: `EdbLayout` and `Shape`.
25
25
  """
26
+
26
27
  import math
27
- from typing import Any, Dict, List, Optional, Union
28
+ from typing import Any, Dict, Iterable, List, Optional, Union
28
29
 
29
- from ansys.edb.core.geometry.arc_data import ArcData as GrpcArcData
30
30
  from ansys.edb.core.geometry.point_data import PointData as GrpcPointData
31
31
  from ansys.edb.core.geometry.polygon_data import (
32
- PolygonSenseType as GrpcPolygonSenseType,
32
+ PolygonData as GrpcPolygonData,
33
33
  )
34
- from ansys.edb.core.geometry.polygon_data import PolygonData as GrpcPolygonData
35
34
  from ansys.edb.core.hierarchy.pin_group import PinGroup as GrpcPinGroup
36
- from ansys.edb.core.inner.exceptions import InvalidArgumentException
37
35
  from ansys.edb.core.primitive.bondwire import BondwireType as GrpcBondwireType
38
- from ansys.edb.core.primitive.path import PathCornerType as GrpcPathCornerType
39
- from ansys.edb.core.primitive.path import PathEndCapType as GrpcPathEndCapType
36
+ from ansys.edb.core.primitive.path import PathCornerType as GrpcPathCornerType, PathEndCapType as GrpcPathEndCapType
40
37
  from ansys.edb.core.primitive.rectangle import (
41
38
  RectangleRepresentationType as GrpcRectangleRepresentationType,
42
39
  )
@@ -51,6 +48,25 @@ from pyedb.grpc.database.utility.layout_statistics import LayoutStatistics
51
48
  from pyedb.grpc.database.utility.value import Value
52
49
 
53
50
 
51
+ def normalize_pairs(points: Iterable[float]) -> List[List[float]]:
52
+ """
53
+ Convert any reasonable point description into [[x1, y1], [x2, y2], …]
54
+ """
55
+ pts = list(points)
56
+ if not pts: # empty input
57
+ return []
58
+
59
+ # Detect flat vs nested
60
+ if isinstance(pts[0], (list, tuple)):
61
+ # already nested – just ensure every item is a *list* (not tuple)
62
+ return [list(pair) for pair in pts]
63
+ else:
64
+ # flat list – chunk into pairs
65
+ if len(pts) % 2:
66
+ raise ValueError("Odd number of coordinates supplied")
67
+ return [[pts[i], pts[i + 1]] for i in range(0, len(pts), 2)]
68
+
69
+
54
70
  class Modeler(object):
55
71
  """Manages EDB methods for primitives management accessible from `Edb.modeler`.
56
72
 
@@ -61,7 +77,7 @@ class Modeler(object):
61
77
  >>> edb_layout = edbapp.modeler
62
78
  """
63
79
 
64
- def __getitem__(self, name: Union[str, int]) -> Optional[Primitive]:
80
+ def __getitem__(self, name: Union[str, int]) -> Primitive:
65
81
  """Get a primitive by name or ID.
66
82
 
67
83
  Parameters
@@ -71,7 +87,7 @@ class Modeler(object):
71
87
 
72
88
  Returns
73
89
  -------
74
- :class:`pyedb.dotnet.database.cell.hierarchy.component.EDBComponent` or None
90
+ :class:`pyedb.grpc.database.primitive.primitive.Primitive`
75
91
  Primitive instance if found, None otherwise.
76
92
 
77
93
  Raises
@@ -79,21 +95,151 @@ class Modeler(object):
79
95
  TypeError
80
96
  If name is not str or int.
81
97
  """
82
- for i in self.primitives:
83
- if (
84
- (isinstance(name, str) and i.aedt_name == name)
85
- or (isinstance(name, str) and i.aedt_name == name.replace("__", "_"))
86
- or (isinstance(name, int) and i.id == name)
87
- ):
88
- return i
89
- self._pedb.logger.error("Primitive not found.")
90
- return
98
+
99
+ if isinstance(name, int):
100
+ return self._primitives.get(name)
101
+ return self.primitives_by_name.get(name)
91
102
 
92
103
  def __init__(self, p_edb) -> None:
93
104
  """Initialize Modeler instance."""
94
105
  self._pedb = p_edb
95
- self.__primitives = []
96
- self.__primitives_by_layer = {}
106
+ # Core cache
107
+ self._primitives: dict[str, Primitive] = {}
108
+
109
+ # Lazy indexes
110
+ self._primitives_by_name: dict[str, Primitive] | None = None
111
+ self._primitives_by_net: dict[str, list[Primitive]] | None = None
112
+ self._primitives_by_layer: dict[str, list[Primitive]] | None = None
113
+ self._primitives_by_layer_and_net: Dict[str, Dict[str, List[Primitive]]] | None = None
114
+
115
+ # ============================================================
116
+
117
+ # Cache management
118
+ # ============================================================
119
+
120
+ def _reload_all(self):
121
+ """Force reload of all primitives and reset indexes."""
122
+ self._primitives = {p.edb_uid: p for p in self._pedb.layout.primitives}
123
+ self._primitives_by_name = None
124
+ self._primitives_by_net = None
125
+ self._primitives_by_layer = None
126
+ self._primitives_by_layer_and_net = None
127
+
128
+ def _add_primitive(self, prim: Any):
129
+ """Add primitive wrapper to caches."""
130
+ self._primitives[prim.edb_uid] = prim
131
+ if self._primitives_by_name is not None:
132
+ self._primitives_by_name[prim.aedt_name] = prim
133
+ if self._primitives_by_net is not None and hasattr(prim, "net"):
134
+ self._primitives_by_net.setdefault(prim.net, []).append(prim)
135
+ if hasattr(prim, "layer"):
136
+ if self._primitives_by_layer is not None and prim.layer_name:
137
+ self._primitives_by_layer.setdefault(prim.layer_name, []).append(prim)
138
+
139
+ def _remove_primitive(self, prim: Primitive):
140
+ """Remove primitive wrapper from all caches efficiently and safely."""
141
+ uid = prim.edb_uid
142
+
143
+ # 1. Remove from primary cache
144
+ self._primitives.pop(uid, None)
145
+
146
+ # 2. Remove from name cache if initialized
147
+ if self._primitives_by_name is not None:
148
+ self._primitives_by_name.pop(prim.aedt_name, None)
149
+
150
+ # 3. Remove from net cache if initialized
151
+ if self._primitives_by_net is not None and hasattr(prim, "net") and not prim.net.is_null:
152
+ net_name = prim.net.name
153
+ net_prims = self._primitives_by_net.get(net_name)
154
+ if net_prims:
155
+ try:
156
+ net_prims.remove(prim)
157
+ except ValueError:
158
+ pass # Not found, skip
159
+ if not net_prims:
160
+ self._primitives_by_net.pop(net_name, None)
161
+
162
+ # 4. Remove from layer cache if initialized
163
+ if self._primitives_by_layer is not None and hasattr(prim, "layer") and prim.layer_name:
164
+ layer_name = prim.layer.name
165
+ layer_prims = self._primitives_by_layer.get(layer_name)
166
+ if layer_prims:
167
+ try:
168
+ layer_prims.remove(prim)
169
+ except ValueError:
170
+ pass
171
+ if not layer_prims:
172
+ self._primitives_by_layer.pop(layer_name, None)
173
+
174
+ # 5. Remove from layer+net cache if initialized
175
+ if self._primitives_by_layer_and_net is not None:
176
+ if hasattr(prim, "layer") and hasattr(prim, "net") and not prim.net.is_null:
177
+ layer_name = prim.layer.name
178
+ net_name = prim.net.name
179
+ layer_dict = self._primitives_by_layer_and_net.get(layer_name)
180
+ if layer_dict:
181
+ net_list = layer_dict.get(net_name)
182
+ if net_list:
183
+ try:
184
+ net_list.remove(prim)
185
+ except ValueError:
186
+ pass
187
+ if not net_list:
188
+ layer_dict.pop(net_name, None)
189
+ if not layer_dict:
190
+ self._primitives_by_layer_and_net.pop(layer_name, None)
191
+
192
+ @property
193
+ def primitives(self) -> list[Primitive]:
194
+ if not self._primitives:
195
+ self._reload_all()
196
+ return list(self._primitives.values())
197
+
198
+ @property
199
+ def primitives_by_name(self):
200
+ if self._primitives_by_name is None:
201
+ self._primitives_by_name = {p.aedt_name: p for p in self.primitives}
202
+ return self._primitives_by_name
203
+
204
+ @property
205
+ def primitives_by_net(self):
206
+ if self._primitives_by_net is None:
207
+ d = {}
208
+ for p in self.primitives:
209
+ if hasattr(p, "net"):
210
+ d.setdefault(p.net.name, []).append(p)
211
+ self._primitives_by_net = d
212
+ return self._primitives_by_net
213
+
214
+ @property
215
+ def primitives_by_layer(self):
216
+ if self._primitives_by_layer is None:
217
+ d = {}
218
+ for p in self.primitives:
219
+ if p.layer_name:
220
+ d.setdefault(p.layer_name, []).append(p)
221
+ self._primitives_by_layer = d
222
+ return self._primitives_by_layer
223
+
224
+ @property
225
+ def primitives_by_layer_and_net(self) -> Dict[str, Dict[str, List[Primitive]]]:
226
+ """Return all primitives indexed first by layer, then by net.
227
+
228
+ Returns
229
+ -------
230
+ dict
231
+ Nested dictionary: layer -> net -> list[Primitive]
232
+ """
233
+ if self._primitives_by_layer_and_net is None:
234
+ idx: Dict[str, Dict[str, List[Primitive]]] = {}
235
+ for prim in self.primitives:
236
+ if not prim.layer_name or not hasattr(prim, "net") or prim.net.is_null:
237
+ continue
238
+ layer = prim.layer_name
239
+ net = prim.net.name
240
+ idx.setdefault(layer, {}).setdefault(net, []).append(prim)
241
+ self._primitives_by_layer_and_net = idx
242
+ return self._primitives_by_layer_and_net
97
243
 
98
244
  @property
99
245
  def _edb(self) -> Any:
@@ -211,17 +357,6 @@ class Modeler(object):
211
357
  else:
212
358
  return False
213
359
 
214
- @property
215
- def primitives(self) -> List[Primitive]:
216
- """All primitives in the layout.
217
-
218
- Returns
219
- -------
220
- list
221
- List of :class:`pyedb.dotnet.database.edb_data.primitives_data.Primitive` objects.
222
- """
223
- return self._pedb.layout.primitives
224
-
225
360
  @property
226
361
  def polygons_by_layer(self) -> Dict[str, List[Primitive]]:
227
362
  """Primitives organized by layer names.
@@ -231,47 +366,13 @@ class Modeler(object):
231
366
  dict
232
367
  Dictionary where keys are layer names and values are lists of polygons.
233
368
  """
234
- _primitives_by_layer = {}
369
+ polygon_by_layer = {}
235
370
  for lay in self.layers:
236
- _primitives_by_layer[lay] = self.get_polygons_by_layer(lay)
237
- return _primitives_by_layer
238
-
239
- @property
240
- def primitives_by_net(self) -> Dict[str, List[Primitive]]:
241
- """Primitives organized by net names.
242
-
243
- Returns
244
- -------
245
- dict
246
- Dictionary where keys are net names and values are lists of primitives.
247
- """
248
- _prim_by_net = {}
249
- for net, net_obj in self._pedb.nets.nets.items():
250
- _prim_by_net[net] = [i for i in net_obj.primitives]
251
- return _prim_by_net
252
-
253
- @property
254
- def primitives_by_layer(self) -> Dict[str, List[Primitive]]:
255
- """Primitives organized by layer names.
256
-
257
- Returns
258
- -------
259
- dict
260
- Dictionary where keys are layer names and values are lists of primitives.
261
- """
262
- _primitives_by_layer = {}
263
- for lay in self.layers:
264
- _primitives_by_layer[lay] = []
265
- for lay in self._pedb.stackup.non_stackup_layers:
266
- _primitives_by_layer[lay] = []
267
- for i in self._layout.primitives:
268
- try:
269
- lay = i.layer.name
270
- if lay in _primitives_by_layer:
271
- _primitives_by_layer[lay].append(i)
272
- except (InvalidArgumentException, AttributeError):
273
- pass
274
- return _primitives_by_layer
371
+ if lay in self.primitives_by_layer:
372
+ polygon_by_layer[lay] = [prim for prim in self.primitives_by_layer[lay] if prim.type == "polygon"]
373
+ else:
374
+ polygon_by_layer[lay] = []
375
+ return polygon_by_layer
275
376
 
276
377
  @property
277
378
  def rectangles(self) -> List[Rectangle]:
@@ -332,15 +433,10 @@ class Modeler(object):
332
433
  list
333
434
  List of polygon objects.
334
435
  """
335
- objinst = []
336
- for el in self.polygons:
337
- if el.layer.name == layer_name:
338
- if not el.net.is_null:
339
- if net_list and el.net.name in net_list:
340
- objinst.append(el)
341
- else:
342
- objinst.append(el)
343
- return objinst
436
+ polygons = self.polygons_by_layer.get(layer_name, [])
437
+ if net_list:
438
+ polygons = [p for p in polygons if p.net_name in net_list]
439
+ return polygons
344
440
 
345
441
  def get_primitive_by_layer_and_point(
346
442
  self,
@@ -603,7 +699,8 @@ class Modeler(object):
603
699
  else:
604
700
  corner_style = GrpcPathCornerType.MITER
605
701
  _points = []
606
- if isinstance(points, list):
702
+ if isinstance(points, (list, tuple)):
703
+ points = normalize_pairs(points)
607
704
  for pt in points:
608
705
  _pt = []
609
706
  for coord in pt:
@@ -617,7 +714,7 @@ class Modeler(object):
617
714
  polygon_data = points
618
715
  else:
619
716
  raise TypeError("Points must be a list of points or a PolygonData object.")
620
- path = Path.create(
717
+ path = Path(self._pedb).create(
621
718
  layout=self._active_layout,
622
719
  layer=layer_name,
623
720
  net=net,
@@ -634,7 +731,7 @@ class Modeler(object):
634
731
 
635
732
  def create_trace(
636
733
  self,
637
- path_list: Union[List[List[float]], GrpcPolygonData],
734
+ path_list: Union[Iterable[float], GrpcPolygonData],
638
735
  layer_name: str,
639
736
  width: float = 1,
640
737
  net_name: str = "",
@@ -646,8 +743,9 @@ class Modeler(object):
646
743
 
647
744
  Parameters
648
745
  ----------
649
- path_list : list
650
- List of [x,y] points.
746
+ path_list : Iterable
747
+ List of points [x,y] or [[x, y], ...]
748
+ or [(x, y)...].
651
749
  layer_name : str
652
750
  Layer name.
653
751
  width : float, optional
@@ -676,7 +774,7 @@ class Modeler(object):
676
774
  end_cap_style=end_cap_style,
677
775
  corner_style=corner_style,
678
776
  )
679
-
777
+ self._add_primitive(primitive) # update cache
680
778
  return primitive
681
779
 
682
780
  def create_polygon(
@@ -723,16 +821,21 @@ class Modeler(object):
723
821
  for void in voids:
724
822
  if isinstance(void, list):
725
823
  void_polygon_data = GrpcPolygonData(points=void)
824
+ elif isinstance(void, GrpcPolygonData):
825
+ void_polygon_data = void
726
826
  else:
727
827
  void_polygon_data = void.polygon_data
728
828
  if not void_polygon_data.points:
729
829
  self._logger.error("Failed to create void polygon data")
730
830
  return False
731
831
  polygon_data.holes.append(void_polygon_data)
732
- polygon = Polygon.create(layout=self._active_layout, layer=layer_name, net=net, polygon_data=polygon_data)
832
+ polygon = Polygon(self._pedb, None).create(
833
+ layout=self._active_layout, layer=layer_name, net=net, polygon_data=polygon_data
834
+ )
733
835
  if polygon.is_null or polygon_data is False: # pragma: no cover
734
836
  self._logger.error("Null polygon created")
735
837
  return False
838
+ self._add_primitive(polygon)
736
839
  return Polygon(self._pedb, polygon)
737
840
 
738
841
  def create_rectangle(
@@ -780,12 +883,11 @@ class Modeler(object):
780
883
  """
781
884
  edb_net = self._pedb.nets.find_or_create_net(net_name)
782
885
  if representation_type == "lower_left_upper_right":
783
- rep_type = GrpcRectangleRepresentationType.LOWER_LEFT_UPPER_RIGHT
784
- rect = Rectangle.create(
886
+ rect = Rectangle(self._pedb).create(
785
887
  layout=self._active_layout,
786
888
  layer=layer_name,
787
889
  net=edb_net,
788
- rep_type=rep_type,
890
+ rep_type=representation_type,
789
891
  param1=Value(lower_left_point[0]),
790
892
  param2=Value(lower_left_point[1]),
791
893
  param3=Value(upper_right_point[0]),
@@ -809,7 +911,7 @@ class Modeler(object):
809
911
  height = Value(width)
810
912
  else:
811
913
  height = Value(width)
812
- rect = Rectangle.create(
914
+ rect = Rectangle(self._pedb).create(
813
915
  layout=self._active_layout,
814
916
  layer=layer_name,
815
917
  net=edb_net,
@@ -822,7 +924,8 @@ class Modeler(object):
822
924
  rotation=Value(rotation),
823
925
  )
824
926
  if not rect.is_null:
825
- return Rectangle(self._pedb, rect)
927
+ self._add_primitive(rect)
928
+ return rect
826
929
  return False
827
930
 
828
931
  def create_circle(
@@ -850,7 +953,7 @@ class Modeler(object):
850
953
  """
851
954
  edb_net = self._pedb.nets.find_or_create_net(net_name)
852
955
 
853
- circle = Circle.create(
956
+ circle = Circle(self._pedb).create(
854
957
  layout=self._active_layout,
855
958
  layer=layer_name,
856
959
  net=edb_net,
@@ -859,7 +962,8 @@ class Modeler(object):
859
962
  radius=Value(radius),
860
963
  )
861
964
  if not circle.is_null:
862
- return Circle(self._pedb, circle)
965
+ self._add_primitive(circle)
966
+ return circle
863
967
  return False
864
968
 
865
969
  def delete_primitives(self, net_names: Union[str, List[str]]) -> bool:
@@ -952,120 +1056,6 @@ class Modeler(object):
952
1056
  void_circle.delete()
953
1057
  return True
954
1058
 
955
- @staticmethod
956
- @staticmethod
957
- def add_void(shape: "Primitive", void_shape: Union["Primitive", List["Primitive"]]) -> bool:
958
- """Add void to shape.
959
-
960
- Parameters
961
- ----------
962
- shape : :class:`pyedb.dotnet.database.edb_data.primitives_data.Primitive`
963
- Main shape.
964
- void_shape : list or :class:`pyedb.dotnet.database.edb_data.primitives_data.Primitive`
965
- Void shape(s).
966
-
967
- Returns
968
- -------
969
- bool
970
- True if successful, False otherwise.
971
- """
972
- if not isinstance(void_shape, list):
973
- void_shape = [void_shape]
974
- for void in void_shape:
975
- if isinstance(void, Primitive):
976
- shape._edb_object.add_void(void)
977
- flag = True
978
- else:
979
- shape._edb_object.add_void(void)
980
- flag = True
981
- if not flag:
982
- return flag
983
- return True
984
-
985
- def _createPolygonDataFromPolygon(self, shape):
986
- points = shape.points
987
- if not self._validatePoint(points[0]):
988
- self._logger.error("Error validating point.")
989
- return None
990
- arcs = []
991
- is_parametric = False
992
- for i in range(len(points) - 1):
993
- if i == 0:
994
- startPoint = points[-1]
995
- endPoint = points[i]
996
- else:
997
- startPoint = points[i - 1]
998
- endPoint = points[i]
999
-
1000
- if not self._validatePoint(endPoint):
1001
- return None
1002
- startPoint = [Value(i) for i in startPoint]
1003
- endPoint = [Value(i) for i in endPoint]
1004
- if len(endPoint) == 2:
1005
- is_parametric = (
1006
- is_parametric
1007
- or startPoint[0].is_parametric
1008
- or startPoint[1].is_parametric
1009
- or endPoint[0].is_parametric
1010
- or endPoint[1].is_parametric
1011
- )
1012
- arc = GrpcArcData(
1013
- GrpcPointData([startPoint[0], startPoint[1]]), GrpcPointData([endPoint[0], endPoint[1]])
1014
- )
1015
- arcs.append(arc)
1016
- elif len(endPoint) == 3:
1017
- is_parametric = (
1018
- is_parametric
1019
- or startPoint[0].is_parametric
1020
- or startPoint[1].is_parametric
1021
- or endPoint[0].is_parametric
1022
- or endPoint[1].is_parametric
1023
- or endPoint[2].is_parametric
1024
- )
1025
- arc = GrpcArcData(
1026
- GrpcPointData([startPoint[0], startPoint[1]]),
1027
- GrpcPointData([endPoint[0], endPoint[1]]),
1028
- kwarg={"height": endPoint[2]},
1029
- )
1030
- arcs.append(arc)
1031
- elif len(endPoint) == 5:
1032
- is_parametric = (
1033
- is_parametric
1034
- or startPoint[0].is_parametric
1035
- or startPoint[1].is_parametric
1036
- or endPoint[0].is_parametric
1037
- or endPoint[1].is_parametric
1038
- or endPoint[3].is_parametric
1039
- or endPoint[4].is_parametric
1040
- )
1041
- if endPoint[2].is_cw:
1042
- rotationDirection = GrpcPolygonSenseType.SENSE_CW
1043
- elif endPoint[2].is_ccw:
1044
- rotationDirection = GrpcPolygonSenseType.SENSE_CCW
1045
- else:
1046
- self._logger.error("Invalid rotation direction %s is specified.", endPoint[2])
1047
- return None
1048
- arc = GrpcArcData(
1049
- GrpcPointData(startPoint),
1050
- GrpcPointData(endPoint),
1051
- )
1052
- # arc.direction = rotationDirection,
1053
- # arc.center = GrpcPointData([endPoint[3], endPoint[4]]),
1054
- arcs.append(arc)
1055
- polygon = GrpcPolygonData(arcs=arcs)
1056
- if not is_parametric:
1057
- return polygon
1058
- else:
1059
- k = 0
1060
- for pt in points:
1061
- point = [Value(i) for i in pt]
1062
- new_points = GrpcPointData(point)
1063
- if len(point) > 2:
1064
- k += 1
1065
- polygon.set_point(k, new_points)
1066
- k += 1
1067
- return polygon
1068
-
1069
1059
  def _validatePoint(self, point, allowArcs=True):
1070
1060
  if len(point) == 2:
1071
1061
  if not isinstance(point[0], (int, float, str)):
@@ -1113,17 +1103,6 @@ class Modeler(object):
1113
1103
  self._logger.error("Arc point descriptor has incorrect number of elements (%s)", len(point))
1114
1104
  return False
1115
1105
 
1116
- def _createPolygonDataFromRectangle(self, shape):
1117
- # if not self._validatePoint(shape.pointA, False) or not self._validatePoint(shape.pointB, False):
1118
- # return None
1119
- # pointA = GrpcPointData(pointA[0]), self._get_edb_value(shape.pointA[1])
1120
- # )
1121
- # pointB = self._edb.Geometry.PointData(
1122
- # self._get_edb_value(shape.pointB[0]), self._get_edb_value(shape.pointB[1])
1123
- # )
1124
- # return self._edb.geometry.polygon_data.create_from_bbox((pointA, pointB))
1125
- pass
1126
-
1127
1106
  def parametrize_trace_width(
1128
1107
  self,
1129
1108
  nets_name: Union[str, List[str]],
@@ -1207,39 +1186,31 @@ class Modeler(object):
1207
1186
  all_voids = []
1208
1187
  list_polygon_data = []
1209
1188
  delete_list = []
1210
- if lay in list(self.polygons_by_layer.keys()):
1211
- for poly in self.polygons_by_layer[lay]:
1212
- poly = poly
1213
- if not poly.net.name in list(poly_by_nets.keys()):
1214
- if poly.net.name:
1215
- poly_by_nets[poly.net.name] = [poly]
1216
- else:
1217
- if poly.net.name:
1218
- poly_by_nets[poly.net.name].append(poly)
1219
- for net in poly_by_nets:
1189
+ for poly in self.polygons_by_layer.get(lay, []):
1190
+ if poly.net_name:
1191
+ poly_by_nets.setdefault(poly.net_name, []).append(poly)
1192
+ for net, polys in poly_by_nets.items():
1220
1193
  if net in net_names_list or not net_names_list:
1221
- for i in poly_by_nets[net]:
1222
- list_polygon_data.append(i.polygon_data)
1223
- delete_list.append(i)
1224
- all_voids.append(i.voids)
1225
- a = GrpcPolygonData.unite(list_polygon_data)
1226
- for item in a:
1227
- for v in all_voids:
1228
- for void in v:
1229
- if item.intersection_type(void.polygon_data) == 2:
1230
- item.add_hole(void.polygon_data)
1194
+ for p in polys:
1195
+ list_polygon_data.append(p.polygon_data)
1196
+ delete_list.append(p)
1197
+ all_voids.extend(p.voids)
1198
+ united = GrpcPolygonData.unite(list_polygon_data)
1199
+ for item in united:
1200
+ for void in all_voids:
1201
+ if item.intersection_type(void.polygon_data) == 2:
1202
+ item.add_hole(void.polygon_data)
1231
1203
  self.create_polygon(item, layer_name=lay, voids=[], net_name=net)
1232
- for v in all_voids:
1233
- for void in v:
1234
- for poly in poly_by_nets[net]: # pragma no cover
1235
- if void.polygon_data.intersection_type(poly.polygon_data).value >= 2:
1236
- try:
1237
- id = delete_list.index(poly)
1238
- except ValueError:
1239
- id = -1
1240
- if id >= 0:
1241
- delete_list.pop(id)
1242
- for poly in delete_list:
1204
+ for void in all_voids:
1205
+ for poly in poly_by_nets[net]: # pragma no cover
1206
+ if void.polygon_data.intersection_type(poly.polygon_data).value >= 2:
1207
+ try:
1208
+ id = delete_list.index(poly)
1209
+ except ValueError:
1210
+ id = -1
1211
+ if id >= 0:
1212
+ delete_list.pop(id)
1213
+ for poly in list(set(delete_list)):
1243
1214
  poly.delete()
1244
1215
 
1245
1216
  if delete_padstack_gemometries:
@@ -1268,7 +1239,7 @@ class Modeler(object):
1268
1239
  new_poly = poly.polygon_data.defeature(tol=tolerance)
1269
1240
  if not new_poly.points:
1270
1241
  self._pedb.logger.error(
1271
- f"Defeaturing on polygon {poly.id} returned empty polygon, tolerance threshold " f"might too large. "
1242
+ f"Defeaturing on polygon {poly.id} returned empty polygon, tolerance threshold might too large. "
1272
1243
  )
1273
1244
  return False
1274
1245
  poly.polygon_data = new_poly
@@ -1431,7 +1402,9 @@ class Modeler(object):
1431
1402
  end_context=end_cell_inst,
1432
1403
  start_context=start_cell_inst,
1433
1404
  )
1434
- return Bondwire(self._pedb, bw)
1405
+ bondwire = Bondwire(self._pedb, bw)
1406
+ self._add_primitive(bondwire)
1407
+ return bondwire
1435
1408
 
1436
1409
  def create_pin_group(
1437
1410
  self,
@@ -1502,3 +1475,32 @@ class Modeler(object):
1502
1475
  if net_obj:
1503
1476
  obj.net = net_obj[0]
1504
1477
  return self._pedb.siwave.pin_groups[name]
1478
+
1479
+ @staticmethod
1480
+ def add_void(shape: "Primitive", void_shape: Union["Primitive", List["Primitive"]]) -> bool:
1481
+ """Add void to shape.
1482
+
1483
+ Parameters
1484
+ ----------
1485
+ shape : :class:`pyedb.dotnet.database.edb_data.primitives_data.Primitive`
1486
+ Main shape.
1487
+ void_shape : list or :class:`pyedb.dotnet.database.edb_data.primitives_data.Primitive`
1488
+ Void shape(s).
1489
+
1490
+ Returns
1491
+ -------
1492
+ bool
1493
+ True if successful, False otherwise.
1494
+ """
1495
+ if not isinstance(void_shape, list):
1496
+ void_shape = [void_shape]
1497
+ for void in void_shape:
1498
+ if isinstance(void, Primitive):
1499
+ shape._edb_object.add_void(void)
1500
+ flag = True
1501
+ else:
1502
+ shape._edb_object.add_void(void)
1503
+ flag = True
1504
+ if not flag:
1505
+ return flag
1506
+ return True