pyedb 0.56.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 (99) hide show
  1. pyedb/__init__.py +1 -1
  2. pyedb/configuration/cfg_data.py +3 -0
  3. pyedb/configuration/cfg_terminals.py +232 -0
  4. pyedb/configuration/configuration.py +146 -3
  5. pyedb/dotnet/clr_module.py +1 -2
  6. pyedb/dotnet/database/Variables.py +30 -22
  7. pyedb/dotnet/database/cell/layout.py +5 -1
  8. pyedb/dotnet/database/cell/primitive/primitive.py +2 -2
  9. pyedb/dotnet/database/cell/terminal/bundle_terminal.py +12 -0
  10. pyedb/dotnet/database/cell/terminal/pingroup_terminal.py +1 -1
  11. pyedb/dotnet/database/cell/terminal/terminal.py +38 -0
  12. pyedb/dotnet/database/components.py +14 -16
  13. pyedb/dotnet/database/dotnet/database.py +1 -0
  14. pyedb/dotnet/database/edb_data/control_file.py +6 -3
  15. pyedb/dotnet/database/edb_data/nets_data.py +3 -3
  16. pyedb/dotnet/database/edb_data/padstacks_data.py +5 -2
  17. pyedb/dotnet/database/edb_data/ports.py +0 -25
  18. pyedb/dotnet/database/edb_data/primitives_data.py +3 -3
  19. pyedb/dotnet/database/edb_data/raptor_x_simulation_setup_data.py +18 -19
  20. pyedb/dotnet/database/edb_data/simulation_configuration.py +3 -3
  21. pyedb/dotnet/database/hfss.py +9 -8
  22. pyedb/dotnet/database/layout_validation.py +6 -3
  23. pyedb/dotnet/database/materials.py +1 -3
  24. pyedb/dotnet/database/modeler.py +7 -3
  25. pyedb/dotnet/database/nets.py +27 -19
  26. pyedb/dotnet/database/padstack.py +4 -2
  27. pyedb/dotnet/database/sim_setup_data/io/siwave.py +1 -1
  28. pyedb/dotnet/database/siwave.py +4 -3
  29. pyedb/dotnet/database/stackup.py +50 -26
  30. pyedb/dotnet/database/utilities/heatsink.py +0 -1
  31. pyedb/dotnet/database/utilities/simulation_setup.py +7 -5
  32. pyedb/dotnet/database/utilities/siwave_cpa_simulation_setup.py +1 -0
  33. pyedb/dotnet/database/utilities/siwave_simulation_setup.py +5 -2
  34. pyedb/dotnet/edb.py +39 -34
  35. pyedb/exceptions.py +1 -2
  36. pyedb/extensions/create_cell_array.py +19 -5
  37. pyedb/generic/data_handlers.py +13 -23
  38. pyedb/generic/design_types.py +9 -35
  39. pyedb/generic/filesystem.py +4 -2
  40. pyedb/generic/general_methods.py +4 -5
  41. pyedb/generic/plot.py +2 -2
  42. pyedb/grpc/database/_typing.py +0 -0
  43. pyedb/grpc/database/components.py +7 -8
  44. pyedb/grpc/database/control_file.py +14 -35
  45. pyedb/grpc/database/definition/materials.py +1 -1
  46. pyedb/grpc/database/definition/package_def.py +6 -3
  47. pyedb/grpc/database/definition/padstack_def.py +4 -7
  48. pyedb/grpc/database/hfss.py +1 -4
  49. pyedb/grpc/database/hierarchy/component.py +3 -4
  50. pyedb/grpc/database/hierarchy/pingroup.py +16 -3
  51. pyedb/grpc/database/layers/layer.py +1 -2
  52. pyedb/grpc/database/layers/stackup_layer.py +42 -19
  53. pyedb/grpc/database/layout/layout.py +43 -27
  54. pyedb/grpc/database/layout/voltage_regulator.py +6 -1
  55. pyedb/grpc/database/layout_validation.py +5 -2
  56. pyedb/grpc/database/modeler.py +226 -244
  57. pyedb/grpc/database/net/differential_pair.py +9 -2
  58. pyedb/grpc/database/net/extended_net.py +24 -9
  59. pyedb/grpc/database/net/net.py +14 -5
  60. pyedb/grpc/database/net/net_class.py +24 -7
  61. pyedb/grpc/database/nets.py +11 -43
  62. pyedb/grpc/database/padstacks.py +5 -16
  63. pyedb/grpc/database/primitive/bondwire.py +3 -67
  64. pyedb/grpc/database/primitive/circle.py +42 -3
  65. pyedb/grpc/database/primitive/padstack_instance.py +17 -19
  66. pyedb/grpc/database/primitive/path.py +154 -5
  67. pyedb/grpc/database/primitive/polygon.py +73 -7
  68. pyedb/grpc/database/primitive/primitive.py +2 -2
  69. pyedb/grpc/database/primitive/rectangle.py +105 -4
  70. pyedb/grpc/database/simulation_setup/hfss_general_settings.py +0 -2
  71. pyedb/grpc/database/simulation_setup/hfss_settings_options.py +0 -4
  72. pyedb/grpc/database/simulation_setup/siwave_cpa_simulation_setup.py +1 -0
  73. pyedb/grpc/database/simulation_setup/sweep_data.py +1 -3
  74. pyedb/grpc/database/siwave.py +6 -13
  75. pyedb/grpc/database/source_excitations.py +39 -56
  76. pyedb/grpc/database/stackup.py +50 -27
  77. pyedb/grpc/database/terminal/bundle_terminal.py +10 -3
  78. pyedb/grpc/database/terminal/pingroup_terminal.py +8 -1
  79. pyedb/grpc/database/terminal/terminal.py +19 -8
  80. pyedb/grpc/database/utility/heat_sink.py +0 -1
  81. pyedb/grpc/database/utility/hfss_extent_info.py +2 -2
  82. pyedb/grpc/database/utility/xml_control_file.py +6 -3
  83. pyedb/grpc/edb.py +24 -19
  84. pyedb/grpc/edb_init.py +1 -0
  85. pyedb/ipc2581/ecad/cad_data/layer_feature.py +6 -2
  86. pyedb/ipc2581/ecad/cad_data/step.py +1 -1
  87. pyedb/ipc2581/ipc2581.py +8 -7
  88. pyedb/libraries/common.py +3 -4
  89. pyedb/libraries/rf_libraries/base_functions.py +7 -16
  90. pyedb/libraries/rf_libraries/planar_antennas.py +3 -21
  91. pyedb/misc/downloads.py +1 -0
  92. pyedb/misc/misc.py +5 -2
  93. pyedb/misc/siw_feature_config/emc_rule_checker_settings.py +1 -1
  94. pyedb/misc/utilities.py +0 -1
  95. pyedb/modeler/geometry_operators.py +3 -2
  96. {pyedb-0.56.0.dist-info → pyedb-0.57.0.dist-info}/METADATA +3 -3
  97. {pyedb-0.56.0.dist-info → pyedb-0.57.0.dist-info}/RECORD +99 -97
  98. {pyedb-0.56.0.dist-info → pyedb-0.57.0.dist-info}/WHEEL +0 -0
  99. {pyedb-0.56.0.dist-info → pyedb-0.57.0.dist-info}/licenses/LICENSE +0 -0
@@ -224,8 +224,11 @@ class LayoutValidation:
224
224
  if el.layout_obj.obj_type.value == 0:
225
225
  if not el.is_void:
226
226
  sum += el.area()
227
- except:
228
- pass
227
+ except Exception as e:
228
+ self._pedb._logger.warning(
229
+ f"A(n) {type(e).__name__} error occurred while calculating area "
230
+ f"for element {elem} - Default value of 0 is used: {str(e)}"
231
+ )
229
232
  return sum
230
233
 
231
234
  if order_by_area:
@@ -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,
@@ -617,7 +697,7 @@ class Modeler(object):
617
697
  polygon_data = points
618
698
  else:
619
699
  raise TypeError("Points must be a list of points or a PolygonData object.")
620
- path = Path.create(
700
+ path = Path(self._pedb).create(
621
701
  layout=self._active_layout,
622
702
  layer=layer_name,
623
703
  net=net,
@@ -676,7 +756,7 @@ class Modeler(object):
676
756
  end_cap_style=end_cap_style,
677
757
  corner_style=corner_style,
678
758
  )
679
-
759
+ self._add_primitive(primitive) # update cache
680
760
  return primitive
681
761
 
682
762
  def create_polygon(
@@ -729,10 +809,13 @@ class Modeler(object):
729
809
  self._logger.error("Failed to create void polygon data")
730
810
  return False
731
811
  polygon_data.holes.append(void_polygon_data)
732
- 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
+ )
733
815
  if polygon.is_null or polygon_data is False: # pragma: no cover
734
816
  self._logger.error("Null polygon created")
735
817
  return False
818
+ self._add_primitive(polygon)
736
819
  return Polygon(self._pedb, polygon)
737
820
 
738
821
  def create_rectangle(
@@ -780,12 +863,11 @@ class Modeler(object):
780
863
  """
781
864
  edb_net = self._pedb.nets.find_or_create_net(net_name)
782
865
  if representation_type == "lower_left_upper_right":
783
- rep_type = GrpcRectangleRepresentationType.LOWER_LEFT_UPPER_RIGHT
784
- rect = Rectangle.create(
866
+ rect = Rectangle(self._pedb).create(
785
867
  layout=self._active_layout,
786
868
  layer=layer_name,
787
869
  net=edb_net,
788
- rep_type=rep_type,
870
+ rep_type=representation_type,
789
871
  param1=Value(lower_left_point[0]),
790
872
  param2=Value(lower_left_point[1]),
791
873
  param3=Value(upper_right_point[0]),
@@ -809,7 +891,7 @@ class Modeler(object):
809
891
  height = Value(width)
810
892
  else:
811
893
  height = Value(width)
812
- rect = Rectangle.create(
894
+ rect = Rectangle(self._pedb).create(
813
895
  layout=self._active_layout,
814
896
  layer=layer_name,
815
897
  net=edb_net,
@@ -822,7 +904,8 @@ class Modeler(object):
822
904
  rotation=Value(rotation),
823
905
  )
824
906
  if not rect.is_null:
825
- return Rectangle(self._pedb, rect)
907
+ self._add_primitive(rect)
908
+ return rect
826
909
  return False
827
910
 
828
911
  def create_circle(
@@ -850,7 +933,7 @@ class Modeler(object):
850
933
  """
851
934
  edb_net = self._pedb.nets.find_or_create_net(net_name)
852
935
 
853
- circle = Circle.create(
936
+ circle = Circle(self._pedb).create(
854
937
  layout=self._active_layout,
855
938
  layer=layer_name,
856
939
  net=edb_net,
@@ -859,7 +942,8 @@ class Modeler(object):
859
942
  radius=Value(radius),
860
943
  )
861
944
  if not circle.is_null:
862
- return Circle(self._pedb, circle)
945
+ self._add_primitive(circle)
946
+ return circle
863
947
  return False
864
948
 
865
949
  def delete_primitives(self, net_names: Union[str, List[str]]) -> bool:
@@ -952,120 +1036,6 @@ class Modeler(object):
952
1036
  void_circle.delete()
953
1037
  return True
954
1038
 
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
1039
  def _validatePoint(self, point, allowArcs=True):
1070
1040
  if len(point) == 2:
1071
1041
  if not isinstance(point[0], (int, float, str)):
@@ -1113,17 +1083,6 @@ class Modeler(object):
1113
1083
  self._logger.error("Arc point descriptor has incorrect number of elements (%s)", len(point))
1114
1084
  return False
1115
1085
 
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
1086
  def parametrize_trace_width(
1128
1087
  self,
1129
1088
  nets_name: Union[str, List[str]],
@@ -1207,39 +1166,31 @@ class Modeler(object):
1207
1166
  all_voids = []
1208
1167
  list_polygon_data = []
1209
1168
  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:
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():
1220
1173
  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)
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)
1231
1183
  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:
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)):
1243
1194
  poly.delete()
1244
1195
 
1245
1196
  if delete_padstack_gemometries:
@@ -1268,7 +1219,7 @@ class Modeler(object):
1268
1219
  new_poly = poly.polygon_data.defeature(tol=tolerance)
1269
1220
  if not new_poly.points:
1270
1221
  self._pedb.logger.error(
1271
- 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. "
1272
1223
  )
1273
1224
  return False
1274
1225
  poly.polygon_data = new_poly
@@ -1431,7 +1382,9 @@ class Modeler(object):
1431
1382
  end_context=end_cell_inst,
1432
1383
  start_context=start_cell_inst,
1433
1384
  )
1434
- return Bondwire(self._pedb, bw)
1385
+ bondwire = Bondwire(self._pedb, bw)
1386
+ self._add_primitive(bondwire)
1387
+ return bondwire
1435
1388
 
1436
1389
  def create_pin_group(
1437
1390
  self,
@@ -1502,3 +1455,32 @@ class Modeler(object):
1502
1455
  if net_obj:
1503
1456
  obj.net = net_obj[0]
1504
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
@@ -20,15 +20,18 @@
20
20
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
21
  # SOFTWARE.
22
22
 
23
+ from __future__ import annotations
23
24
 
25
+ from typing import TYPE_CHECKING
26
+
27
+ if TYPE_CHECKING:
28
+ from pyedb.grpc.database.net.net import Net
24
29
  import re
25
30
 
26
31
  from ansys.edb.core.net.differential_pair import (
27
32
  DifferentialPair as GrpcDifferentialPair,
28
33
  )
29
34
 
30
- from pyedb.grpc.database.net.net import Net
31
-
32
35
 
33
36
  class DifferentialPairs:
34
37
  def __init__(self, pedb):
@@ -131,9 +134,13 @@ class DifferentialPair(GrpcDifferentialPair):
131
134
  @property
132
135
  def positive_net(self) -> Net:
133
136
  """Positive Net."""
137
+ from pyedb.grpc.database.net.net import Net
138
+
134
139
  return Net(self._pedb, super().positive_net)
135
140
 
136
141
  @property
137
142
  def negative_net(self) -> Net:
138
143
  """Negative Net."""
144
+ from pyedb.grpc.database.net.net import Net
145
+
139
146
  return Net(self._pedb, super().negative_net)