pyedb 0.55.0__py3-none-any.whl → 0.57.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 (107) hide show
  1. pyedb/__init__.py +1 -1
  2. pyedb/configuration/cfg_data.py +3 -0
  3. pyedb/configuration/cfg_operations.py +2 -2
  4. pyedb/configuration/cfg_ports_sources.py +1 -1
  5. pyedb/configuration/cfg_terminals.py +232 -0
  6. pyedb/configuration/configuration.py +146 -3
  7. pyedb/dotnet/clr_module.py +1 -2
  8. pyedb/dotnet/database/Variables.py +56 -41
  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 +55 -52
  15. pyedb/dotnet/database/dotnet/database.py +1 -0
  16. pyedb/dotnet/database/edb_data/control_file.py +6 -3
  17. pyedb/dotnet/database/edb_data/nets_data.py +3 -3
  18. pyedb/dotnet/database/edb_data/padstacks_data.py +5 -2
  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/hfss.py +9 -8
  24. pyedb/dotnet/database/layout_validation.py +6 -3
  25. pyedb/dotnet/database/materials.py +1 -3
  26. pyedb/dotnet/database/modeler.py +7 -3
  27. pyedb/dotnet/database/nets.py +27 -19
  28. pyedb/dotnet/database/padstack.py +91 -2
  29. pyedb/dotnet/database/sim_setup_data/io/siwave.py +1 -1
  30. pyedb/dotnet/database/siwave.py +4 -3
  31. pyedb/dotnet/database/stackup.py +50 -26
  32. pyedb/dotnet/database/utilities/heatsink.py +0 -1
  33. pyedb/dotnet/database/utilities/simulation_setup.py +7 -5
  34. pyedb/dotnet/database/utilities/siwave_cpa_simulation_setup.py +1 -0
  35. pyedb/dotnet/database/utilities/siwave_simulation_setup.py +5 -2
  36. pyedb/dotnet/edb.py +41 -36
  37. pyedb/exceptions.py +1 -2
  38. pyedb/extensions/create_cell_array.py +408 -0
  39. pyedb/generic/data_handlers.py +17 -28
  40. pyedb/generic/design_types.py +25 -38
  41. pyedb/generic/filesystem.py +9 -4
  42. pyedb/generic/general_methods.py +6 -7
  43. pyedb/generic/plot.py +2 -2
  44. pyedb/generic/settings.py +4 -0
  45. pyedb/grpc/database/_typing.py +0 -0
  46. pyedb/grpc/database/components.py +30 -11
  47. pyedb/grpc/database/control_file.py +14 -35
  48. pyedb/grpc/database/definition/materials.py +1 -1
  49. pyedb/grpc/database/definition/package_def.py +6 -3
  50. pyedb/grpc/database/definition/padstack_def.py +4 -7
  51. pyedb/grpc/database/hfss.py +1 -4
  52. pyedb/grpc/database/hierarchy/component.py +3 -4
  53. pyedb/grpc/database/hierarchy/pingroup.py +16 -3
  54. pyedb/grpc/database/layers/layer.py +1 -2
  55. pyedb/grpc/database/layers/stackup_layer.py +42 -19
  56. pyedb/grpc/database/layout/layout.py +117 -28
  57. pyedb/grpc/database/layout/voltage_regulator.py +6 -1
  58. pyedb/grpc/database/layout_validation.py +7 -4
  59. pyedb/grpc/database/modeler.py +241 -256
  60. pyedb/grpc/database/net/differential_pair.py +9 -2
  61. pyedb/grpc/database/net/extended_net.py +24 -9
  62. pyedb/grpc/database/net/net.py +14 -5
  63. pyedb/grpc/database/net/net_class.py +24 -7
  64. pyedb/grpc/database/nets.py +11 -43
  65. pyedb/grpc/database/padstacks.py +92 -16
  66. pyedb/grpc/database/primitive/bondwire.py +3 -67
  67. pyedb/grpc/database/primitive/circle.py +42 -3
  68. pyedb/grpc/database/primitive/padstack_instance.py +17 -19
  69. pyedb/grpc/database/primitive/path.py +154 -5
  70. pyedb/grpc/database/primitive/polygon.py +75 -9
  71. pyedb/grpc/database/primitive/primitive.py +2 -2
  72. pyedb/grpc/database/primitive/rectangle.py +105 -4
  73. pyedb/grpc/database/simulation_setup/hfss_general_settings.py +0 -2
  74. pyedb/grpc/database/simulation_setup/hfss_settings_options.py +0 -4
  75. pyedb/grpc/database/simulation_setup/siwave_cpa_simulation_setup.py +4 -2
  76. pyedb/grpc/database/simulation_setup/sweep_data.py +1 -3
  77. pyedb/grpc/database/siwave.py +6 -13
  78. pyedb/grpc/database/source_excitations.py +49 -57
  79. pyedb/grpc/database/stackup.py +50 -27
  80. pyedb/grpc/database/terminal/bundle_terminal.py +10 -3
  81. pyedb/grpc/database/terminal/pingroup_terminal.py +8 -1
  82. pyedb/grpc/database/terminal/terminal.py +19 -8
  83. pyedb/grpc/database/utility/heat_sink.py +0 -1
  84. pyedb/grpc/database/utility/hfss_extent_info.py +2 -2
  85. pyedb/grpc/database/utility/value.py +1 -0
  86. pyedb/grpc/database/utility/xml_control_file.py +6 -3
  87. pyedb/grpc/edb.py +33 -24
  88. pyedb/grpc/edb_init.py +1 -0
  89. pyedb/grpc/rpc_session.py +4 -3
  90. pyedb/ipc2581/ecad/cad_data/layer_feature.py +6 -2
  91. pyedb/ipc2581/ecad/cad_data/step.py +1 -1
  92. pyedb/ipc2581/ipc2581.py +8 -7
  93. pyedb/libraries/common.py +3 -4
  94. pyedb/libraries/rf_libraries/base_functions.py +7 -16
  95. pyedb/libraries/rf_libraries/planar_antennas.py +3 -21
  96. pyedb/misc/downloads.py +1 -0
  97. pyedb/misc/misc.py +5 -2
  98. pyedb/misc/siw_feature_config/emc_rule_checker_settings.py +1 -1
  99. pyedb/misc/utilities.py +0 -1
  100. pyedb/modeler/geometry_operators.py +9 -8
  101. pyedb/siwave.py +4 -6
  102. pyedb/siwave_core/__init__.py +0 -0
  103. pyedb/siwave_core/cpa/__init__.py +0 -0
  104. {pyedb-0.55.0.dist-info → pyedb-0.57.0.dist-info}/METADATA +3 -3
  105. {pyedb-0.55.0.dist-info → pyedb-0.57.0.dist-info}/RECORD +107 -102
  106. {pyedb-0.55.0.dist-info → pyedb-0.57.0.dist-info}/WHEEL +0 -0
  107. {pyedb-0.55.0.dist-info → pyedb-0.57.0.dist-info}/licenses/LICENSE +0 -0
@@ -23,20 +23,20 @@
23
23
  """
24
24
  This module contains these classes: `EdbLayout` and `Shape`.
25
25
  """
26
+
26
27
  import math
27
28
  from typing import Any, Dict, List, Optional, Union
28
29
 
29
30
  from ansys.edb.core.geometry.arc_data import ArcData as GrpcArcData
30
31
  from ansys.edb.core.geometry.point_data import PointData as GrpcPointData
31
32
  from ansys.edb.core.geometry.polygon_data import (
33
+ PolygonData as GrpcPolygonData,
32
34
  PolygonSenseType as GrpcPolygonSenseType,
33
35
  )
34
- from ansys.edb.core.geometry.polygon_data import PolygonData as GrpcPolygonData
35
36
  from ansys.edb.core.hierarchy.pin_group import PinGroup as GrpcPinGroup
36
37
  from ansys.edb.core.inner.exceptions import InvalidArgumentException
37
38
  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
39
+ from ansys.edb.core.primitive.path import PathCornerType as GrpcPathCornerType, PathEndCapType as GrpcPathEndCapType
40
40
  from ansys.edb.core.primitive.rectangle import (
41
41
  RectangleRepresentationType as GrpcRectangleRepresentationType,
42
42
  )
@@ -61,7 +61,7 @@ class Modeler(object):
61
61
  >>> edb_layout = edbapp.modeler
62
62
  """
63
63
 
64
- def __getitem__(self, name: Union[str, int]) -> Optional[Primitive]:
64
+ def __getitem__(self, name: Union[str, int]) -> Primitive:
65
65
  """Get a primitive by name or ID.
66
66
 
67
67
  Parameters
@@ -71,7 +71,7 @@ class Modeler(object):
71
71
 
72
72
  Returns
73
73
  -------
74
- :class:`pyedb.dotnet.database.cell.hierarchy.component.EDBComponent` or None
74
+ :class:`pyedb.grpc.database.primitive.primitive.Primitive`
75
75
  Primitive instance if found, None otherwise.
76
76
 
77
77
  Raises
@@ -79,21 +79,151 @@ class Modeler(object):
79
79
  TypeError
80
80
  If name is not str or int.
81
81
  """
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
82
+
83
+ if isinstance(name, int):
84
+ return self._primitives.get(name)
85
+ return self.primitives_by_name.get(name)
91
86
 
92
87
  def __init__(self, p_edb) -> None:
93
88
  """Initialize Modeler instance."""
94
89
  self._pedb = p_edb
95
- self.__primitives = []
96
- self.__primitives_by_layer = {}
90
+ # Core cache
91
+ self._primitives: dict[str, Primitive] = {}
92
+
93
+ # Lazy indexes
94
+ self._primitives_by_name: dict[str, Primitive] | None = None
95
+ self._primitives_by_net: dict[str, list[Primitive]] | None = None
96
+ self._primitives_by_layer: dict[str, list[Primitive]] | None = None
97
+ self._primitives_by_layer_and_net: Dict[str, Dict[str, List[Primitive]]] | None = None
98
+
99
+ # ============================================================
100
+
101
+ # Cache management
102
+ # ============================================================
103
+
104
+ def _reload_all(self):
105
+ """Force reload of all primitives and reset indexes."""
106
+ self._primitives = {p.edb_uid: p for p in self._pedb.layout.primitives}
107
+ self._primitives_by_name = None
108
+ self._primitives_by_net = None
109
+ self._primitives_by_layer = None
110
+ self._primitives_by_layer_and_net = None
111
+
112
+ def _add_primitive(self, prim: Any):
113
+ """Add primitive wrapper to caches."""
114
+ self._primitives[prim.edb_uid] = prim
115
+ if self._primitives_by_name is not None:
116
+ self._primitives_by_name[prim.aedt_name] = prim
117
+ if self._primitives_by_net is not None and hasattr(prim, "net"):
118
+ self._primitives_by_net.setdefault(prim.net, []).append(prim)
119
+ if hasattr(prim, "layer"):
120
+ if self._primitives_by_layer is not None and prim.layer_name:
121
+ self._primitives_by_layer.setdefault(prim.layer_name, []).append(prim)
122
+
123
+ def _remove_primitive(self, prim: Primitive):
124
+ """Remove primitive wrapper from all caches efficiently and safely."""
125
+ uid = prim.edb_uid
126
+
127
+ # 1. Remove from primary cache
128
+ self._primitives.pop(uid, None)
129
+
130
+ # 2. Remove from name cache if initialized
131
+ if self._primitives_by_name is not None:
132
+ self._primitives_by_name.pop(prim.aedt_name, None)
133
+
134
+ # 3. Remove from net cache if initialized
135
+ if self._primitives_by_net is not None and hasattr(prim, "net") and not prim.net.is_null:
136
+ net_name = prim.net.name
137
+ net_prims = self._primitives_by_net.get(net_name)
138
+ if net_prims:
139
+ try:
140
+ net_prims.remove(prim)
141
+ except ValueError:
142
+ pass # Not found, skip
143
+ if not net_prims:
144
+ self._primitives_by_net.pop(net_name, None)
145
+
146
+ # 4. Remove from layer cache if initialized
147
+ if self._primitives_by_layer is not None and hasattr(prim, "layer") and prim.layer_name:
148
+ layer_name = prim.layer.name
149
+ layer_prims = self._primitives_by_layer.get(layer_name)
150
+ if layer_prims:
151
+ try:
152
+ layer_prims.remove(prim)
153
+ except ValueError:
154
+ pass
155
+ if not layer_prims:
156
+ self._primitives_by_layer.pop(layer_name, None)
157
+
158
+ # 5. Remove from layer+net cache if initialized
159
+ if self._primitives_by_layer_and_net is not None:
160
+ if hasattr(prim, "layer") and hasattr(prim, "net") and not prim.net.is_null:
161
+ layer_name = prim.layer.name
162
+ net_name = prim.net.name
163
+ layer_dict = self._primitives_by_layer_and_net.get(layer_name)
164
+ if layer_dict:
165
+ net_list = layer_dict.get(net_name)
166
+ if net_list:
167
+ try:
168
+ net_list.remove(prim)
169
+ except ValueError:
170
+ pass
171
+ if not net_list:
172
+ layer_dict.pop(net_name, None)
173
+ if not layer_dict:
174
+ self._primitives_by_layer_and_net.pop(layer_name, None)
175
+
176
+ @property
177
+ def primitives(self) -> list[Primitive]:
178
+ if not self._primitives:
179
+ self._reload_all()
180
+ return list(self._primitives.values())
181
+
182
+ @property
183
+ def primitives_by_name(self):
184
+ if self._primitives_by_name is None:
185
+ self._primitives_by_name = {p.aedt_name: p for p in self.primitives}
186
+ return self._primitives_by_name
187
+
188
+ @property
189
+ def primitives_by_net(self):
190
+ if self._primitives_by_net is None:
191
+ d = {}
192
+ for p in self.primitives:
193
+ if hasattr(p, "net"):
194
+ d.setdefault(p.net.name, []).append(p)
195
+ self._primitives_by_net = d
196
+ return self._primitives_by_net
197
+
198
+ @property
199
+ def primitives_by_layer(self):
200
+ if self._primitives_by_layer is None:
201
+ d = {}
202
+ for p in self.primitives:
203
+ if p.layer_name:
204
+ d.setdefault(p.layer_name, []).append(p)
205
+ self._primitives_by_layer = d
206
+ return self._primitives_by_layer
207
+
208
+ @property
209
+ def primitives_by_layer_and_net(self) -> Dict[str, Dict[str, List[Primitive]]]:
210
+ """Return all primitives indexed first by layer, then by net.
211
+
212
+ Returns
213
+ -------
214
+ dict
215
+ Nested dictionary: layer -> net -> list[Primitive]
216
+ """
217
+ if self._primitives_by_layer_and_net is None:
218
+ idx: Dict[str, Dict[str, List[Primitive]]] = {}
219
+ for prim in self.primitives:
220
+ if not prim.layer_name or not hasattr(prim, "net") or prim.net.is_null:
221
+ continue
222
+ layer = prim.layer_name
223
+ net = prim.net.name
224
+ idx.setdefault(layer, {}).setdefault(net, []).append(prim)
225
+ self._primitives_by_layer_and_net = idx
226
+ return self._primitives_by_layer_and_net
97
227
 
98
228
  @property
99
229
  def _edb(self) -> Any:
@@ -211,17 +341,6 @@ class Modeler(object):
211
341
  else:
212
342
  return False
213
343
 
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
344
  @property
226
345
  def polygons_by_layer(self) -> Dict[str, List[Primitive]]:
227
346
  """Primitives organized by layer names.
@@ -231,47 +350,13 @@ class Modeler(object):
231
350
  dict
232
351
  Dictionary where keys are layer names and values are lists of polygons.
233
352
  """
234
- _primitives_by_layer = {}
235
- 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 = {}
353
+ polygon_by_layer = {}
263
354
  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
355
+ if lay in self.primitives_by_layer:
356
+ polygon_by_layer[lay] = [prim for prim in self.primitives_by_layer[lay] if prim.type == "polygon"]
357
+ else:
358
+ polygon_by_layer[lay] = []
359
+ return polygon_by_layer
275
360
 
276
361
  @property
277
362
  def rectangles(self) -> List[Rectangle]:
@@ -332,15 +417,10 @@ class Modeler(object):
332
417
  list
333
418
  List of polygon objects.
334
419
  """
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
420
+ polygons = self.polygons_by_layer.get(layer_name, [])
421
+ if net_list:
422
+ polygons = [p for p in polygons if p.net_name in net_list]
423
+ return polygons
344
424
 
345
425
  def get_primitive_by_layer_and_point(
346
426
  self,
@@ -603,18 +683,21 @@ class Modeler(object):
603
683
  else:
604
684
  corner_style = GrpcPathCornerType.MITER
605
685
  _points = []
606
- for pt in points:
607
- _pt = []
608
- for coord in pt:
609
- coord = Value(coord, self._pedb.active_cell)
610
- _pt.append(coord)
611
- _points.append(_pt)
612
- points = _points
613
-
614
- width = Value(width, self._pedb.active_cell)
615
-
616
- polygon_data = GrpcPolygonData(points=[GrpcPointData(i) for i in points])
617
- path = Path.create(
686
+ if isinstance(points, list):
687
+ for pt in points:
688
+ _pt = []
689
+ for coord in pt:
690
+ coord = Value(coord, self._pedb.active_cell)
691
+ _pt.append(coord)
692
+ _points.append(_pt)
693
+ points = _points
694
+ width = Value(width, self._pedb.active_cell)
695
+ polygon_data = GrpcPolygonData(points)
696
+ elif isinstance(points, GrpcPolygonData):
697
+ polygon_data = points
698
+ else:
699
+ raise TypeError("Points must be a list of points or a PolygonData object.")
700
+ path = Path(self._pedb).create(
618
701
  layout=self._active_layout,
619
702
  layer=layer_name,
620
703
  net=net,
@@ -631,7 +714,7 @@ class Modeler(object):
631
714
 
632
715
  def create_trace(
633
716
  self,
634
- path_list: List[List[float]],
717
+ path_list: Union[List[List[float]], GrpcPolygonData],
635
718
  layer_name: str,
636
719
  width: float = 1,
637
720
  net_name: str = "",
@@ -673,7 +756,7 @@ class Modeler(object):
673
756
  end_cap_style=end_cap_style,
674
757
  corner_style=corner_style,
675
758
  )
676
-
759
+ self._add_primitive(primitive) # update cache
677
760
  return primitive
678
761
 
679
762
  def create_polygon(
@@ -726,10 +809,13 @@ class Modeler(object):
726
809
  self._logger.error("Failed to create void polygon data")
727
810
  return False
728
811
  polygon_data.holes.append(void_polygon_data)
729
- polygon = Polygon.create(layout=self._active_layout, layer=layer_name, net=net, polygon_data=polygon_data)
812
+ polygon = Polygon(self._pedb, None).create(
813
+ layout=self._active_layout, layer=layer_name, net=net, polygon_data=polygon_data
814
+ )
730
815
  if polygon.is_null or polygon_data is False: # pragma: no cover
731
816
  self._logger.error("Null polygon created")
732
817
  return False
818
+ self._add_primitive(polygon)
733
819
  return Polygon(self._pedb, polygon)
734
820
 
735
821
  def create_rectangle(
@@ -777,12 +863,11 @@ class Modeler(object):
777
863
  """
778
864
  edb_net = self._pedb.nets.find_or_create_net(net_name)
779
865
  if representation_type == "lower_left_upper_right":
780
- rep_type = GrpcRectangleRepresentationType.LOWER_LEFT_UPPER_RIGHT
781
- rect = Rectangle.create(
866
+ rect = Rectangle(self._pedb).create(
782
867
  layout=self._active_layout,
783
868
  layer=layer_name,
784
869
  net=edb_net,
785
- rep_type=rep_type,
870
+ rep_type=representation_type,
786
871
  param1=Value(lower_left_point[0]),
787
872
  param2=Value(lower_left_point[1]),
788
873
  param3=Value(upper_right_point[0]),
@@ -806,7 +891,7 @@ class Modeler(object):
806
891
  height = Value(width)
807
892
  else:
808
893
  height = Value(width)
809
- rect = Rectangle.create(
894
+ rect = Rectangle(self._pedb).create(
810
895
  layout=self._active_layout,
811
896
  layer=layer_name,
812
897
  net=edb_net,
@@ -819,7 +904,8 @@ class Modeler(object):
819
904
  rotation=Value(rotation),
820
905
  )
821
906
  if not rect.is_null:
822
- return Rectangle(self._pedb, rect)
907
+ self._add_primitive(rect)
908
+ return rect
823
909
  return False
824
910
 
825
911
  def create_circle(
@@ -847,7 +933,7 @@ class Modeler(object):
847
933
  """
848
934
  edb_net = self._pedb.nets.find_or_create_net(net_name)
849
935
 
850
- circle = Circle.create(
936
+ circle = Circle(self._pedb).create(
851
937
  layout=self._active_layout,
852
938
  layer=layer_name,
853
939
  net=edb_net,
@@ -856,7 +942,8 @@ class Modeler(object):
856
942
  radius=Value(radius),
857
943
  )
858
944
  if not circle.is_null:
859
- return Circle(self._pedb, circle)
945
+ self._add_primitive(circle)
946
+ return circle
860
947
  return False
861
948
 
862
949
  def delete_primitives(self, net_names: Union[str, List[str]]) -> bool:
@@ -949,120 +1036,6 @@ class Modeler(object):
949
1036
  void_circle.delete()
950
1037
  return True
951
1038
 
952
- @staticmethod
953
- @staticmethod
954
- def add_void(shape: "Primitive", void_shape: Union["Primitive", List["Primitive"]]) -> bool:
955
- """Add void to shape.
956
-
957
- Parameters
958
- ----------
959
- shape : :class:`pyedb.dotnet.database.edb_data.primitives_data.Primitive`
960
- Main shape.
961
- void_shape : list or :class:`pyedb.dotnet.database.edb_data.primitives_data.Primitive`
962
- Void shape(s).
963
-
964
- Returns
965
- -------
966
- bool
967
- True if successful, False otherwise.
968
- """
969
- if not isinstance(void_shape, list):
970
- void_shape = [void_shape]
971
- for void in void_shape:
972
- if isinstance(void, Primitive):
973
- shape._edb_object.add_void(void)
974
- flag = True
975
- else:
976
- shape._edb_object.add_void(void)
977
- flag = True
978
- if not flag:
979
- return flag
980
- return True
981
-
982
- def _createPolygonDataFromPolygon(self, shape):
983
- points = shape.points
984
- if not self._validatePoint(points[0]):
985
- self._logger.error("Error validating point.")
986
- return None
987
- arcs = []
988
- is_parametric = False
989
- for i in range(len(points) - 1):
990
- if i == 0:
991
- startPoint = points[-1]
992
- endPoint = points[i]
993
- else:
994
- startPoint = points[i - 1]
995
- endPoint = points[i]
996
-
997
- if not self._validatePoint(endPoint):
998
- return None
999
- startPoint = [Value(i) for i in startPoint]
1000
- endPoint = [Value(i) for i in endPoint]
1001
- if len(endPoint) == 2:
1002
- is_parametric = (
1003
- is_parametric
1004
- or startPoint[0].is_parametric
1005
- or startPoint[1].is_parametric
1006
- or endPoint[0].is_parametric
1007
- or endPoint[1].is_parametric
1008
- )
1009
- arc = GrpcArcData(
1010
- GrpcPointData([startPoint[0], startPoint[1]]), GrpcPointData([endPoint[0], endPoint[1]])
1011
- )
1012
- arcs.append(arc)
1013
- elif len(endPoint) == 3:
1014
- is_parametric = (
1015
- is_parametric
1016
- or startPoint[0].is_parametric
1017
- or startPoint[1].is_parametric
1018
- or endPoint[0].is_parametric
1019
- or endPoint[1].is_parametric
1020
- or endPoint[2].is_parametric
1021
- )
1022
- arc = GrpcArcData(
1023
- GrpcPointData([startPoint[0], startPoint[1]]),
1024
- GrpcPointData([endPoint[0], endPoint[1]]),
1025
- kwarg={"height": endPoint[2]},
1026
- )
1027
- arcs.append(arc)
1028
- elif len(endPoint) == 5:
1029
- is_parametric = (
1030
- is_parametric
1031
- or startPoint[0].is_parametric
1032
- or startPoint[1].is_parametric
1033
- or endPoint[0].is_parametric
1034
- or endPoint[1].is_parametric
1035
- or endPoint[3].is_parametric
1036
- or endPoint[4].is_parametric
1037
- )
1038
- if endPoint[2].is_cw:
1039
- rotationDirection = GrpcPolygonSenseType.SENSE_CW
1040
- elif endPoint[2].is_ccw:
1041
- rotationDirection = GrpcPolygonSenseType.SENSE_CCW
1042
- else:
1043
- self._logger.error("Invalid rotation direction %s is specified.", endPoint[2])
1044
- return None
1045
- arc = GrpcArcData(
1046
- GrpcPointData(startPoint),
1047
- GrpcPointData(endPoint),
1048
- )
1049
- # arc.direction = rotationDirection,
1050
- # arc.center = GrpcPointData([endPoint[3], endPoint[4]]),
1051
- arcs.append(arc)
1052
- polygon = GrpcPolygonData(arcs=arcs)
1053
- if not is_parametric:
1054
- return polygon
1055
- else:
1056
- k = 0
1057
- for pt in points:
1058
- point = [Value(i) for i in pt]
1059
- new_points = GrpcPointData(point)
1060
- if len(point) > 2:
1061
- k += 1
1062
- polygon.set_point(k, new_points)
1063
- k += 1
1064
- return polygon
1065
-
1066
1039
  def _validatePoint(self, point, allowArcs=True):
1067
1040
  if len(point) == 2:
1068
1041
  if not isinstance(point[0], (int, float, str)):
@@ -1110,17 +1083,6 @@ class Modeler(object):
1110
1083
  self._logger.error("Arc point descriptor has incorrect number of elements (%s)", len(point))
1111
1084
  return False
1112
1085
 
1113
- def _createPolygonDataFromRectangle(self, shape):
1114
- # if not self._validatePoint(shape.pointA, False) or not self._validatePoint(shape.pointB, False):
1115
- # return None
1116
- # pointA = GrpcPointData(pointA[0]), self._get_edb_value(shape.pointA[1])
1117
- # )
1118
- # pointB = self._edb.Geometry.PointData(
1119
- # self._get_edb_value(shape.pointB[0]), self._get_edb_value(shape.pointB[1])
1120
- # )
1121
- # return self._edb.geometry.polygon_data.create_from_bbox((pointA, pointB))
1122
- pass
1123
-
1124
1086
  def parametrize_trace_width(
1125
1087
  self,
1126
1088
  nets_name: Union[str, List[str]],
@@ -1204,39 +1166,31 @@ class Modeler(object):
1204
1166
  all_voids = []
1205
1167
  list_polygon_data = []
1206
1168
  delete_list = []
1207
- if lay in list(self.polygons_by_layer.keys()):
1208
- for poly in self.polygons_by_layer[lay]:
1209
- poly = poly
1210
- if not poly.net.name in list(poly_by_nets.keys()):
1211
- if poly.net.name:
1212
- poly_by_nets[poly.net.name] = [poly]
1213
- else:
1214
- if poly.net.name:
1215
- poly_by_nets[poly.net.name].append(poly)
1216
- for net in poly_by_nets:
1169
+ for poly in self.polygons_by_layer.get(lay, []):
1170
+ if poly.net_name:
1171
+ poly_by_nets.setdefault(poly.net_name, []).append(poly)
1172
+ for net, polys in poly_by_nets.items():
1217
1173
  if net in net_names_list or not net_names_list:
1218
- for i in poly_by_nets[net]:
1219
- list_polygon_data.append(i.polygon_data)
1220
- delete_list.append(i)
1221
- all_voids.append(i.voids)
1222
- a = GrpcPolygonData.unite(list_polygon_data)
1223
- for item in a:
1224
- for v in all_voids:
1225
- for void in v:
1226
- if item.intersection_type(void.polygon_data) == 2:
1227
- item.add_hole(void.polygon_data)
1174
+ for p in polys:
1175
+ list_polygon_data.append(p.polygon_data)
1176
+ delete_list.append(p)
1177
+ all_voids.extend(p.voids)
1178
+ united = GrpcPolygonData.unite(list_polygon_data)
1179
+ for item in united:
1180
+ for void in all_voids:
1181
+ if item.intersection_type(void.polygon_data) == 2:
1182
+ item.add_hole(void.polygon_data)
1228
1183
  self.create_polygon(item, layer_name=lay, voids=[], net_name=net)
1229
- for v in all_voids:
1230
- for void in v:
1231
- for poly in poly_by_nets[net]: # pragma no cover
1232
- if void.polygon_data.intersection_type(poly.polygon_data).value >= 2:
1233
- try:
1234
- id = delete_list.index(poly)
1235
- except ValueError:
1236
- id = -1
1237
- if id >= 0:
1238
- delete_list.pop(id)
1239
- for poly in delete_list:
1184
+ for void in all_voids:
1185
+ for poly in poly_by_nets[net]: # pragma no cover
1186
+ if void.polygon_data.intersection_type(poly.polygon_data).value >= 2:
1187
+ try:
1188
+ id = delete_list.index(poly)
1189
+ except ValueError:
1190
+ id = -1
1191
+ if id >= 0:
1192
+ delete_list.pop(id)
1193
+ for poly in list(set(delete_list)):
1240
1194
  poly.delete()
1241
1195
 
1242
1196
  if delete_padstack_gemometries:
@@ -1265,7 +1219,7 @@ class Modeler(object):
1265
1219
  new_poly = poly.polygon_data.defeature(tol=tolerance)
1266
1220
  if not new_poly.points:
1267
1221
  self._pedb.logger.error(
1268
- f"Defeaturing on polygon {poly.id} returned empty polygon, tolerance threshold " f"might too large. "
1222
+ f"Defeaturing on polygon {poly.id} returned empty polygon, tolerance threshold might too large. "
1269
1223
  )
1270
1224
  return False
1271
1225
  poly.polygon_data = new_poly
@@ -1428,7 +1382,9 @@ class Modeler(object):
1428
1382
  end_context=end_cell_inst,
1429
1383
  start_context=start_cell_inst,
1430
1384
  )
1431
- return Bondwire(self._pedb, bw)
1385
+ bondwire = Bondwire(self._pedb, bw)
1386
+ self._add_primitive(bondwire)
1387
+ return bondwire
1432
1388
 
1433
1389
  def create_pin_group(
1434
1390
  self,
@@ -1499,3 +1455,32 @@ class Modeler(object):
1499
1455
  if net_obj:
1500
1456
  obj.net = net_obj[0]
1501
1457
  return self._pedb.siwave.pin_groups[name]
1458
+
1459
+ @staticmethod
1460
+ def add_void(shape: "Primitive", void_shape: Union["Primitive", List["Primitive"]]) -> bool:
1461
+ """Add void to shape.
1462
+
1463
+ Parameters
1464
+ ----------
1465
+ shape : :class:`pyedb.dotnet.database.edb_data.primitives_data.Primitive`
1466
+ Main shape.
1467
+ void_shape : list or :class:`pyedb.dotnet.database.edb_data.primitives_data.Primitive`
1468
+ Void shape(s).
1469
+
1470
+ Returns
1471
+ -------
1472
+ bool
1473
+ True if successful, False otherwise.
1474
+ """
1475
+ if not isinstance(void_shape, list):
1476
+ void_shape = [void_shape]
1477
+ for void in void_shape:
1478
+ if isinstance(void, Primitive):
1479
+ shape._edb_object.add_void(void)
1480
+ flag = True
1481
+ else:
1482
+ shape._edb_object.add_void(void)
1483
+ flag = True
1484
+ if not flag:
1485
+ return flag
1486
+ return True