pyedb 0.38.0__py3-none-any.whl → 0.39.1__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.
- pyedb/__init__.py +1 -1
- pyedb/common/nets.py +53 -139
- pyedb/configuration/cfg_components.py +1 -1
- pyedb/configuration/cfg_general.py +4 -2
- pyedb/configuration/cfg_modeler.py +1 -1
- pyedb/configuration/cfg_package_definition.py +1 -1
- pyedb/configuration/cfg_padstacks.py +1 -1
- pyedb/configuration/cfg_ports_sources.py +56 -23
- pyedb/configuration/configuration.py +18 -1
- pyedb/dotnet/{application → database}/Variables.py +21 -21
- pyedb/dotnet/{edb_core → database}/cell/connectable.py +5 -5
- pyedb/dotnet/{edb_core → database}/cell/hierarchy/component.py +11 -11
- pyedb/dotnet/{edb_core → database}/cell/hierarchy/hierarchy_obj.py +1 -1
- pyedb/dotnet/{edb_core → database}/cell/hierarchy/model.py +1 -1
- pyedb/dotnet/{edb_core → database}/cell/layout.py +17 -17
- pyedb/dotnet/{edb_core → database}/cell/layout_obj.py +3 -3
- pyedb/dotnet/{edb_core → database}/cell/primitive/bondwire.py +1 -1
- pyedb/dotnet/{edb_core → database}/cell/primitive/path.py +4 -4
- pyedb/dotnet/{edb_core → database}/cell/primitive/primitive.py +14 -14
- pyedb/dotnet/{edb_core → database}/cell/terminal/bundle_terminal.py +2 -2
- pyedb/dotnet/{edb_core → database}/cell/terminal/edge_terminal.py +4 -4
- pyedb/dotnet/{edb_core → database}/cell/terminal/padstack_instance_terminal.py +2 -2
- pyedb/dotnet/{edb_core → database}/cell/terminal/pingroup_terminal.py +2 -2
- pyedb/dotnet/{edb_core → database}/cell/terminal/point_terminal.py +2 -2
- pyedb/dotnet/{edb_core → database}/cell/terminal/terminal.py +11 -11
- pyedb/dotnet/{edb_core → database}/cell/voltage_regulator.py +2 -2
- pyedb/dotnet/{edb_core → database}/components.py +101 -124
- pyedb/dotnet/{edb_core → database}/definition/component_def.py +5 -5
- pyedb/dotnet/{edb_core → database}/definition/component_model.py +1 -1
- pyedb/dotnet/{edb_core → database}/definition/definition_obj.py +1 -1
- pyedb/dotnet/{edb_core → database}/definition/definitions.py +2 -2
- pyedb/dotnet/{edb_core → database}/definition/package_def.py +4 -4
- pyedb/dotnet/{edb_core → database}/dotnet/database.py +8 -8
- pyedb/dotnet/{edb_core → database}/dotnet/primitive.py +9 -9
- pyedb/dotnet/{edb_core → database}/edb_data/control_file.py +12 -12
- pyedb/dotnet/{edb_core → database}/edb_data/hfss_extent_info.py +7 -7
- pyedb/dotnet/{edb_core → database}/edb_data/nets_data.py +10 -13
- pyedb/dotnet/{edb_core → database}/edb_data/padstacks_data.py +16 -16
- pyedb/dotnet/{edb_core → database}/edb_data/ports.py +4 -4
- pyedb/dotnet/{edb_core → database}/edb_data/primitives_data.py +5 -5
- pyedb/dotnet/{edb_core → database}/edb_data/raptor_x_simulation_setup_data.py +4 -4
- pyedb/dotnet/{edb_core → database}/edb_data/simulation_configuration.py +10 -10
- pyedb/dotnet/{edb_core → database}/edb_data/sources.py +4 -4
- pyedb/dotnet/{edb_core → database}/edb_data/variables.py +1 -1
- pyedb/dotnet/{edb_core → database}/geometry/polygon_data.py +4 -4
- pyedb/dotnet/{edb_core → database}/hfss.py +8 -8
- pyedb/dotnet/{edb_core → database}/layout_obj_instance.py +1 -1
- pyedb/dotnet/{edb_core → database}/layout_validation.py +2 -2
- pyedb/dotnet/{edb_core → database}/materials.py +23 -8
- pyedb/dotnet/{edb_core → database}/modeler.py +27 -27
- pyedb/dotnet/{edb_core → database}/net_class.py +8 -8
- pyedb/dotnet/{edb_core → database}/nets.py +12 -12
- pyedb/dotnet/{edb_core → database}/padstack.py +15 -15
- pyedb/dotnet/{edb_core → database}/sim_setup_data/data/mesh_operation.py +1 -1
- pyedb/dotnet/{edb_core → database}/sim_setup_data/data/settings.py +3 -3
- pyedb/dotnet/{edb_core → database}/sim_setup_data/data/sim_setup_info.py +2 -2
- pyedb/dotnet/{edb_core → database}/sim_setup_data/data/simulation_settings.py +1 -1
- pyedb/dotnet/{edb_core → database}/sim_setup_data/data/siw_dc_ir_settings.py +1 -1
- pyedb/dotnet/{edb_core → database}/sim_setup_data/data/sweep_data.py +1 -1
- pyedb/dotnet/{edb_core → database}/siwave.py +10 -10
- pyedb/dotnet/{edb_core → database}/stackup.py +12 -12
- pyedb/dotnet/{edb_core → database}/utilities/hfss_simulation_setup.py +15 -15
- pyedb/dotnet/{edb_core → database}/utilities/obj_base.py +1 -1
- pyedb/dotnet/{edb_core → database}/utilities/simulation_setup.py +3 -3
- pyedb/dotnet/{edb_core → database}/utilities/siwave_simulation_setup.py +6 -6
- pyedb/dotnet/edb.py +117 -112
- pyedb/generic/design_types.py +26 -19
- pyedb/generic/general_methods.py +1 -1
- pyedb/generic/plot.py +0 -2
- pyedb/grpc/database/__init__.py +1 -0
- pyedb/grpc/database/components.py +2354 -0
- pyedb/grpc/database/control_file.py +1277 -0
- pyedb/grpc/database/definition/component_def.py +218 -0
- pyedb/grpc/database/definition/component_model.py +39 -0
- pyedb/grpc/database/definition/component_pin.py +32 -0
- pyedb/grpc/database/definition/materials.py +1207 -0
- pyedb/grpc/database/definition/n_port_component_model.py +34 -0
- pyedb/grpc/database/definition/package_def.py +227 -0
- pyedb/grpc/database/definition/padstack_def.py +842 -0
- pyedb/grpc/database/definitions.py +70 -0
- pyedb/grpc/database/general.py +43 -0
- pyedb/grpc/database/geometry/__init__.py +0 -0
- pyedb/grpc/database/geometry/arc_data.py +93 -0
- pyedb/grpc/database/geometry/point_3d_data.py +79 -0
- pyedb/grpc/database/geometry/point_data.py +30 -0
- pyedb/grpc/database/geometry/polygon_data.py +133 -0
- pyedb/grpc/database/hfss.py +1279 -0
- pyedb/grpc/database/hierarchy/__init__.py +0 -0
- pyedb/grpc/database/hierarchy/component.py +1301 -0
- pyedb/grpc/database/hierarchy/model.py +31 -0
- pyedb/grpc/database/hierarchy/netlist_model.py +30 -0
- pyedb/grpc/database/hierarchy/pin_pair_model.py +128 -0
- pyedb/grpc/database/hierarchy/pingroup.py +245 -0
- pyedb/grpc/database/hierarchy/s_parameter_model.py +33 -0
- pyedb/grpc/database/hierarchy/spice_model.py +48 -0
- pyedb/grpc/database/layers/__init__.py +0 -0
- pyedb/grpc/database/layers/layer.py +57 -0
- pyedb/grpc/database/layers/stackup_layer.py +410 -0
- pyedb/grpc/database/layout/__init__.py +0 -0
- pyedb/grpc/database/layout/cell.py +30 -0
- pyedb/grpc/database/layout/layout.py +196 -0
- pyedb/grpc/database/layout/voltage_regulator.py +149 -0
- pyedb/grpc/database/layout_validation.py +319 -0
- pyedb/grpc/database/modeler.py +1468 -0
- pyedb/grpc/database/net/__init__.py +0 -0
- pyedb/grpc/database/net/differential_pair.py +138 -0
- pyedb/grpc/database/net/extended_net.py +340 -0
- pyedb/grpc/database/net/net.py +198 -0
- pyedb/grpc/database/net/net_class.py +93 -0
- pyedb/grpc/database/nets.py +633 -0
- pyedb/grpc/database/padstacks.py +1500 -0
- pyedb/grpc/database/ports/__init__.py +0 -0
- pyedb/grpc/database/ports/ports.py +396 -0
- pyedb/grpc/database/primitive/__init__.py +3 -0
- pyedb/grpc/database/primitive/bondwire.py +181 -0
- pyedb/grpc/database/primitive/circle.py +75 -0
- pyedb/grpc/database/primitive/padstack_instance.py +1116 -0
- pyedb/grpc/database/primitive/path.py +346 -0
- pyedb/grpc/database/primitive/polygon.py +276 -0
- pyedb/grpc/database/primitive/primitive.py +739 -0
- pyedb/grpc/database/primitive/rectangle.py +146 -0
- pyedb/grpc/database/simulation_setup/__init__.py +0 -0
- pyedb/grpc/database/simulation_setup/adaptive_frequency.py +33 -0
- pyedb/grpc/database/simulation_setup/hfss_advanced_meshing_settings.py +32 -0
- pyedb/grpc/database/simulation_setup/hfss_advanced_settings.py +59 -0
- pyedb/grpc/database/simulation_setup/hfss_dcr_settings.py +35 -0
- pyedb/grpc/database/simulation_setup/hfss_general_settings.py +61 -0
- pyedb/grpc/database/simulation_setup/hfss_settings_options.py +78 -0
- pyedb/grpc/database/simulation_setup/hfss_simulation_settings.py +118 -0
- pyedb/grpc/database/simulation_setup/hfss_simulation_setup.py +355 -0
- pyedb/grpc/database/simulation_setup/hfss_solver_settings.py +34 -0
- pyedb/grpc/database/simulation_setup/mesh_operation.py +34 -0
- pyedb/grpc/database/simulation_setup/raptor_x_advanced_settings.py +34 -0
- pyedb/grpc/database/simulation_setup/raptor_x_general_settings.py +33 -0
- pyedb/grpc/database/simulation_setup/raptor_x_simulation_settings.py +64 -0
- pyedb/grpc/database/simulation_setup/raptor_x_simulation_setup.py +125 -0
- pyedb/grpc/database/simulation_setup/siwave_dcir_simulation_setup.py +34 -0
- pyedb/grpc/database/simulation_setup/siwave_simulation_setup.py +119 -0
- pyedb/grpc/database/simulation_setup/sweep_data.py +32 -0
- pyedb/grpc/database/siwave.py +1023 -0
- pyedb/grpc/database/source_excitations.py +2572 -0
- pyedb/grpc/database/stackup.py +2574 -0
- pyedb/grpc/database/terminal/__init__.py +0 -0
- pyedb/grpc/database/terminal/bundle_terminal.py +218 -0
- pyedb/grpc/database/terminal/edge_terminal.py +51 -0
- pyedb/grpc/database/terminal/padstack_instance_terminal.py +171 -0
- pyedb/grpc/database/terminal/pingroup_terminal.py +162 -0
- pyedb/grpc/database/terminal/point_terminal.py +99 -0
- pyedb/grpc/database/terminal/terminal.py +470 -0
- pyedb/grpc/database/utility/__init__.py +3 -0
- pyedb/grpc/database/utility/constants.py +25 -0
- pyedb/grpc/database/utility/heat_sink.py +124 -0
- pyedb/grpc/database/utility/hfss_extent_info.py +448 -0
- pyedb/grpc/database/utility/layout_statistics.py +277 -0
- pyedb/grpc/database/utility/rlc.py +80 -0
- pyedb/grpc/database/utility/simulation_configuration.py +3305 -0
- pyedb/grpc/database/utility/sources.py +388 -0
- pyedb/grpc/database/utility/sweep_data_distribution.py +83 -0
- pyedb/grpc/database/utility/xml_control_file.py +1277 -0
- pyedb/grpc/edb.py +4152 -0
- pyedb/grpc/edb_init.py +481 -0
- pyedb/grpc/rpc_session.py +177 -0
- pyedb/ipc2581/ecad/cad_data/assembly_drawing.py +3 -2
- pyedb/ipc2581/ecad/cad_data/feature.py +4 -3
- pyedb/ipc2581/ecad/cad_data/layer_feature.py +32 -20
- pyedb/ipc2581/ecad/cad_data/outline.py +3 -2
- pyedb/ipc2581/ecad/cad_data/package.py +4 -3
- pyedb/ipc2581/ecad/cad_data/path.py +82 -31
- pyedb/ipc2581/ecad/cad_data/polygon.py +122 -60
- pyedb/ipc2581/ecad/cad_data/profile.py +13 -12
- pyedb/ipc2581/ecad/cad_data/step.py +53 -21
- pyedb/ipc2581/ipc2581.py +47 -49
- pyedb/modeler/geometry_operators.py +1 -1
- {pyedb-0.38.0.dist-info → pyedb-0.39.1.dist-info}/METADATA +5 -2
- pyedb-0.39.1.dist-info/RECORD +288 -0
- pyedb-0.38.0.dist-info/RECORD +0 -195
- /pyedb/dotnet/{edb_core → database}/__init__.py +0 -0
- /pyedb/dotnet/{application → database/cell}/__init__.py +0 -0
- /pyedb/dotnet/{edb_core/cell → database/cell/hierarchy}/__init__.py +0 -0
- /pyedb/dotnet/{edb_core → database}/cell/hierarchy/netlist_model.py +0 -0
- /pyedb/dotnet/{edb_core → database}/cell/hierarchy/pin_pair_model.py +0 -0
- /pyedb/dotnet/{edb_core → database}/cell/hierarchy/s_parameter_model.py +0 -0
- /pyedb/dotnet/{edb_core → database}/cell/hierarchy/spice_model.py +0 -0
- /pyedb/dotnet/{edb_core → database}/cell/primitive/__init__.py +0 -0
- /pyedb/dotnet/{edb_core/cell/hierarchy → database/cell/terminal}/__init__.py +0 -0
- /pyedb/dotnet/{edb_core/cell/terminal → database/definition}/__init__.py +0 -0
- /pyedb/dotnet/{edb_core/definition → database/dotnet}/__init__.py +0 -0
- /pyedb/dotnet/{edb_core/dotnet → database/edb_data}/__init__.py +0 -0
- /pyedb/dotnet/{edb_core → database}/edb_data/design_options.py +0 -0
- /pyedb/dotnet/{edb_core → database}/edb_data/edbvalue.py +0 -0
- /pyedb/dotnet/{edb_core → database}/edb_data/layer_data.py +0 -0
- /pyedb/dotnet/{edb_core → database}/edb_data/utilities.py +0 -0
- /pyedb/dotnet/{edb_core → database}/general.py +0 -0
- /pyedb/dotnet/{edb_core/edb_data → database/geometry}/__init__.py +0 -0
- /pyedb/dotnet/{edb_core → database}/geometry/point_data.py +0 -0
- /pyedb/dotnet/{edb_core → database}/sim_setup_data/__init__.py +0 -0
- /pyedb/dotnet/{edb_core → database}/sim_setup_data/data/__init__.py +0 -0
- /pyedb/dotnet/{edb_core → database}/sim_setup_data/data/adaptive_frequency_data.py +0 -0
- /pyedb/dotnet/{edb_core/geometry → database/sim_setup_data/io}/__init__.py +0 -0
- /pyedb/dotnet/{edb_core → database}/sim_setup_data/io/siwave.py +0 -0
- /pyedb/dotnet/{edb_core → database}/utilities/__init__.py +0 -0
- /pyedb/dotnet/{edb_core → database}/utilities/heatsink.py +0 -0
- /pyedb/{dotnet/edb_core/sim_setup_data/io → grpc/database/definition}/__init__.py +0 -0
- {pyedb-0.38.0.dist-info → pyedb-0.39.1.dist-info}/LICENSE +0 -0
- {pyedb-0.38.0.dist-info → pyedb-0.39.1.dist-info}/WHEEL +0 -0
|
@@ -0,0 +1,346 @@
|
|
|
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 ansys.edb.core.geometry.polygon_data import PolygonData as GrpcPolygonData
|
|
25
|
+
from ansys.edb.core.primitive.primitive import Path as GrpcPath
|
|
26
|
+
from ansys.edb.core.primitive.primitive import PathCornerType as GrpcPatCornerType
|
|
27
|
+
from ansys.edb.core.utility.value import Value as GrpcValue
|
|
28
|
+
|
|
29
|
+
from pyedb.grpc.database.primitive.primitive import Primitive
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class Path(GrpcPath, Primitive):
|
|
33
|
+
def __init__(self, pedb, edb_object):
|
|
34
|
+
GrpcPath.__init__(self, edb_object.msg)
|
|
35
|
+
Primitive.__init__(self, pedb, edb_object)
|
|
36
|
+
self._edb_object = edb_object
|
|
37
|
+
self._pedb = pedb
|
|
38
|
+
|
|
39
|
+
@property
|
|
40
|
+
def width(self):
|
|
41
|
+
"""Path width.
|
|
42
|
+
|
|
43
|
+
Returns
|
|
44
|
+
-------
|
|
45
|
+
float
|
|
46
|
+
Path width or None.
|
|
47
|
+
"""
|
|
48
|
+
return round(super().width.value, 9)
|
|
49
|
+
|
|
50
|
+
@width.setter
|
|
51
|
+
def width(self, value):
|
|
52
|
+
super(Path, self.__class__).width.__set__(self, GrpcValue(value))
|
|
53
|
+
|
|
54
|
+
@property
|
|
55
|
+
def length(self):
|
|
56
|
+
"""Path length in meters.
|
|
57
|
+
|
|
58
|
+
Returns
|
|
59
|
+
-------
|
|
60
|
+
float
|
|
61
|
+
Path length in meters.
|
|
62
|
+
"""
|
|
63
|
+
center_line_arcs = self._edb_object.cast().center_line.arc_data
|
|
64
|
+
path_length = 0.0
|
|
65
|
+
for arc in center_line_arcs:
|
|
66
|
+
path_length += arc.length
|
|
67
|
+
end_cap_style = self.get_end_cap_style()
|
|
68
|
+
if end_cap_style:
|
|
69
|
+
if not end_cap_style[0].value == 1:
|
|
70
|
+
path_length += self.width / 2
|
|
71
|
+
if not end_cap_style[1].value == 1:
|
|
72
|
+
path_length += self.width / 2
|
|
73
|
+
return round(path_length, 9)
|
|
74
|
+
|
|
75
|
+
def add_point(self, x, y, incremental=True):
|
|
76
|
+
"""Add a point at the end of the path.
|
|
77
|
+
|
|
78
|
+
Parameters
|
|
79
|
+
----------
|
|
80
|
+
x: str, int, float
|
|
81
|
+
X coordinate.
|
|
82
|
+
y: str, in, float
|
|
83
|
+
Y coordinate.
|
|
84
|
+
incremental: bool
|
|
85
|
+
Add point incrementally. If True, coordinates of the added point is incremental to the last point.
|
|
86
|
+
The default value is ``True``.
|
|
87
|
+
|
|
88
|
+
Returns
|
|
89
|
+
-------
|
|
90
|
+
bool
|
|
91
|
+
"""
|
|
92
|
+
if incremental:
|
|
93
|
+
points = self.center_line
|
|
94
|
+
points.append([x, y])
|
|
95
|
+
points = GrpcPolygonData(points=points)
|
|
96
|
+
GrpcPath.create(
|
|
97
|
+
layout=self.layout,
|
|
98
|
+
layer=self.layer,
|
|
99
|
+
net=self.net,
|
|
100
|
+
)
|
|
101
|
+
self.center_line = points
|
|
102
|
+
return True
|
|
103
|
+
|
|
104
|
+
def clone(self):
|
|
105
|
+
"""Clone a primitive object with keeping same definition and location.
|
|
106
|
+
|
|
107
|
+
Returns
|
|
108
|
+
-------
|
|
109
|
+
bool
|
|
110
|
+
``True`` when successful, ``False`` when failed.
|
|
111
|
+
"""
|
|
112
|
+
mapping = {
|
|
113
|
+
"round": GrpcPatCornerType.ROUND,
|
|
114
|
+
"mitter": GrpcPatCornerType.MITER,
|
|
115
|
+
"sharp": GrpcPatCornerType.SHARP,
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
cloned_path = GrpcPath.create(
|
|
119
|
+
layout=self._pedb.active_layout,
|
|
120
|
+
layer=self.layer,
|
|
121
|
+
net=self.net,
|
|
122
|
+
width=GrpcValue(self.width),
|
|
123
|
+
end_cap1=self.get_end_cap_style()[0],
|
|
124
|
+
end_cap2=self.get_end_cap_style()[1],
|
|
125
|
+
corner_style=mapping[self.corner_style],
|
|
126
|
+
points=GrpcPolygonData(self.center_line),
|
|
127
|
+
)
|
|
128
|
+
if not cloned_path.is_null:
|
|
129
|
+
return Path(self._pedb, cloned_path)
|
|
130
|
+
|
|
131
|
+
#
|
|
132
|
+
|
|
133
|
+
def create_edge_port(
|
|
134
|
+
self,
|
|
135
|
+
name,
|
|
136
|
+
position="End",
|
|
137
|
+
port_type="Wave",
|
|
138
|
+
reference_layer=None,
|
|
139
|
+
horizontal_extent_factor=5,
|
|
140
|
+
vertical_extent_factor=3,
|
|
141
|
+
pec_launch_width="0.01mm",
|
|
142
|
+
):
|
|
143
|
+
"""
|
|
144
|
+
|
|
145
|
+
Parameters
|
|
146
|
+
----------
|
|
147
|
+
name : str
|
|
148
|
+
Name of the port.
|
|
149
|
+
position : str, optional
|
|
150
|
+
Position of the port. The default is ``"End"``, in which case the port is created at the end of the trace.
|
|
151
|
+
Options are ``"Start"`` and ``"End"``.
|
|
152
|
+
port_type : str, optional
|
|
153
|
+
Type of the port. The default is ``"Wave"``, in which case a wave port is created. Options are ``"Wave"``
|
|
154
|
+
and ``"Gap"``.
|
|
155
|
+
reference_layer : str, optional
|
|
156
|
+
Name of the references layer. The default is ``None``. Only available for gap port.
|
|
157
|
+
horizontal_extent_factor : int, optional
|
|
158
|
+
Horizontal extent factor of the wave port. The default is ``5``.
|
|
159
|
+
vertical_extent_factor : int, optional
|
|
160
|
+
Vertical extent factor of the wave port. The default is ``3``.
|
|
161
|
+
pec_launch_width : float, str, optional
|
|
162
|
+
Perfect electrical conductor width of the wave port. The default is ``"0.01mm"``.
|
|
163
|
+
|
|
164
|
+
Returns
|
|
165
|
+
-------
|
|
166
|
+
:class:`GapPort <pyedb.grpc.database.ports.port.GapPort>`
|
|
167
|
+
|
|
168
|
+
Examples
|
|
169
|
+
--------
|
|
170
|
+
>>> edbapp = pyedb.dotnet.Edb("myproject.aedb")
|
|
171
|
+
>>> sig = appedb.modeler.create_trace([[0, 0], ["9mm", 0]], "TOP", "1mm", "SIG", "Flat", "Flat")
|
|
172
|
+
>>> sig.create_edge_port("pcb_port", "end", "Wave", None, 8, 8)
|
|
173
|
+
|
|
174
|
+
"""
|
|
175
|
+
center_line = self.center_line
|
|
176
|
+
pos = center_line[-1] if position.lower() == "end" else center_line[0]
|
|
177
|
+
|
|
178
|
+
# if port_type.lower() == "wave":
|
|
179
|
+
# return self._pedb.hfss.create_wave_port(
|
|
180
|
+
# self.id, pos, name, 50, horizontal_extent_factor, vertical_extent_factor, pec_launch_width
|
|
181
|
+
# )
|
|
182
|
+
# else:
|
|
183
|
+
return self._pedb.hfss.create_edge_port_vertical(
|
|
184
|
+
self.id,
|
|
185
|
+
pos,
|
|
186
|
+
name,
|
|
187
|
+
50,
|
|
188
|
+
reference_layer,
|
|
189
|
+
hfss_type=port_type,
|
|
190
|
+
horizontal_extent_factor=horizontal_extent_factor,
|
|
191
|
+
vertical_extent_factor=vertical_extent_factor,
|
|
192
|
+
pec_launch_width=pec_launch_width,
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
def create_via_fence(self, distance, gap, padstack_name, net_name="GND"):
|
|
196
|
+
"""Create via fences on both sides of the trace.
|
|
197
|
+
|
|
198
|
+
Parameters
|
|
199
|
+
----------
|
|
200
|
+
distance: str, float
|
|
201
|
+
Distance between via fence and trace center line.
|
|
202
|
+
gap: str, float
|
|
203
|
+
Gap between vias.
|
|
204
|
+
padstack_name: str
|
|
205
|
+
Name of the via padstack.
|
|
206
|
+
net_name: str, optional
|
|
207
|
+
Name of the net.
|
|
208
|
+
|
|
209
|
+
"""
|
|
210
|
+
|
|
211
|
+
def getAngle(v1, v2): # pragma: no cover
|
|
212
|
+
v1_mag = math.sqrt(v1[0] ** 2 + v1[1] ** 2)
|
|
213
|
+
v2_mag = math.sqrt(v2[0] ** 2 + v2[1] ** 2)
|
|
214
|
+
dotsum = v1[0] * v2[0] + v1[1] * v2[1]
|
|
215
|
+
if v1[0] * v2[1] - v1[1] * v2[0] > 0:
|
|
216
|
+
scale = 1
|
|
217
|
+
else:
|
|
218
|
+
scale = -1
|
|
219
|
+
dtheta = scale * math.acos(dotsum / (v1_mag * v2_mag))
|
|
220
|
+
|
|
221
|
+
return dtheta
|
|
222
|
+
|
|
223
|
+
def get_locations(line, gap): # pragma: no cover
|
|
224
|
+
location = [line[0]]
|
|
225
|
+
residual = 0
|
|
226
|
+
|
|
227
|
+
for n in range(len(line) - 1):
|
|
228
|
+
x0, y0 = line[n]
|
|
229
|
+
x1, y1 = line[n + 1]
|
|
230
|
+
length = math.sqrt((x1 - x0) ** 2 + (y1 - y0) ** 2)
|
|
231
|
+
dx, dy = (x1 - x0) / length, (y1 - y0) / length
|
|
232
|
+
x = x0 - dx * residual
|
|
233
|
+
y = y0 - dy * residual
|
|
234
|
+
length = length + residual
|
|
235
|
+
while length >= gap:
|
|
236
|
+
x += gap * dx
|
|
237
|
+
y += gap * dy
|
|
238
|
+
location.append((x, y))
|
|
239
|
+
length -= gap
|
|
240
|
+
|
|
241
|
+
residual = length
|
|
242
|
+
return location
|
|
243
|
+
|
|
244
|
+
def get_parallet_lines(pts, distance): # pragma: no cover
|
|
245
|
+
leftline = []
|
|
246
|
+
rightline = []
|
|
247
|
+
|
|
248
|
+
x0, y0 = pts[0]
|
|
249
|
+
x1, y1 = pts[1]
|
|
250
|
+
vector = (x1 - x0, y1 - y0)
|
|
251
|
+
orientation1 = getAngle((1, 0), vector)
|
|
252
|
+
|
|
253
|
+
leftturn = orientation1 + math.pi / 2
|
|
254
|
+
righrturn = orientation1 - math.pi / 2
|
|
255
|
+
leftPt = (x0 + distance * math.cos(leftturn), y0 + distance * math.sin(leftturn))
|
|
256
|
+
leftline.append(leftPt)
|
|
257
|
+
rightPt = (x0 + distance * math.cos(righrturn), y0 + distance * math.sin(righrturn))
|
|
258
|
+
rightline.append(rightPt)
|
|
259
|
+
|
|
260
|
+
for n in range(1, len(pts) - 1):
|
|
261
|
+
x0, y0 = pts[n - 1]
|
|
262
|
+
x1, y1 = pts[n]
|
|
263
|
+
x2, y2 = pts[n + 1]
|
|
264
|
+
|
|
265
|
+
v1 = (x1 - x0, y1 - y0)
|
|
266
|
+
v2 = (x2 - x1, y2 - y1)
|
|
267
|
+
dtheta = getAngle(v1, v2)
|
|
268
|
+
orientation1 = getAngle((1, 0), v1)
|
|
269
|
+
|
|
270
|
+
leftturn = orientation1 + dtheta / 2 + math.pi / 2
|
|
271
|
+
righrturn = orientation1 + dtheta / 2 - math.pi / 2
|
|
272
|
+
|
|
273
|
+
distance2 = distance / math.sin((math.pi - dtheta) / 2)
|
|
274
|
+
leftPt = (x1 + distance2 * math.cos(leftturn), y1 + distance2 * math.sin(leftturn))
|
|
275
|
+
leftline.append(leftPt)
|
|
276
|
+
rightPt = (x1 + distance2 * math.cos(righrturn), y1 + distance2 * math.sin(righrturn))
|
|
277
|
+
rightline.append(rightPt)
|
|
278
|
+
|
|
279
|
+
x0, y0 = pts[-2]
|
|
280
|
+
x1, y1 = pts[-1]
|
|
281
|
+
|
|
282
|
+
vector = (x1 - x0, y1 - y0)
|
|
283
|
+
orientation1 = getAngle((1, 0), vector)
|
|
284
|
+
leftturn = orientation1 + math.pi / 2
|
|
285
|
+
righrturn = orientation1 - math.pi / 2
|
|
286
|
+
leftPt = (x1 + distance * math.cos(leftturn), y1 + distance * math.sin(leftturn))
|
|
287
|
+
leftline.append(leftPt)
|
|
288
|
+
rightPt = (x1 + distance * math.cos(righrturn), y1 + distance * math.sin(righrturn))
|
|
289
|
+
rightline.append(rightPt)
|
|
290
|
+
return leftline, rightline
|
|
291
|
+
|
|
292
|
+
distance = GrpcValue(distance).value
|
|
293
|
+
gap = GrpcValue(gap).value
|
|
294
|
+
center_line = self.center_line
|
|
295
|
+
leftline, rightline = get_parallet_lines(center_line, distance)
|
|
296
|
+
for x, y in get_locations(rightline, gap) + get_locations(leftline, gap):
|
|
297
|
+
self._pedb.padstacks.place([x, y], padstack_name, net_name=net_name)
|
|
298
|
+
|
|
299
|
+
@property
|
|
300
|
+
def center_line(self):
|
|
301
|
+
"""Path center line
|
|
302
|
+
|
|
303
|
+
Returns
|
|
304
|
+
-------
|
|
305
|
+
List[float]
|
|
306
|
+
|
|
307
|
+
"""
|
|
308
|
+
return self.get_center_line()
|
|
309
|
+
|
|
310
|
+
def get_center_line(self):
|
|
311
|
+
"""Retrieve center line points list.
|
|
312
|
+
|
|
313
|
+
Returns
|
|
314
|
+
-------
|
|
315
|
+
List[List[float, float]].
|
|
316
|
+
|
|
317
|
+
"""
|
|
318
|
+
return [[pt.x.value, pt.y.value] for pt in super().center_line.points]
|
|
319
|
+
|
|
320
|
+
# def set_center_line(self, value):
|
|
321
|
+
# if isinstance(value, list):
|
|
322
|
+
# points = [GrpcPointData(i) for i in value]
|
|
323
|
+
# polygon_data = GrpcPolygonData(points, False)
|
|
324
|
+
# super(Path, self.__class__).polygon_data.__set__(self, polygon_data)
|
|
325
|
+
|
|
326
|
+
@property
|
|
327
|
+
def corner_style(self):
|
|
328
|
+
"""Path's corner style as string.
|
|
329
|
+
|
|
330
|
+
Returns
|
|
331
|
+
-------
|
|
332
|
+
str
|
|
333
|
+
Values supported for the setter `"round"`, `"mitter"`, `"sharp"`
|
|
334
|
+
|
|
335
|
+
"""
|
|
336
|
+
return super().corner_style.name.lower()
|
|
337
|
+
|
|
338
|
+
@corner_style.setter
|
|
339
|
+
def corner_style(self, corner_type):
|
|
340
|
+
if isinstance(corner_type, str):
|
|
341
|
+
mapping = {
|
|
342
|
+
"round": GrpcPatCornerType.ROUND,
|
|
343
|
+
"mitter": GrpcPatCornerType.MITER,
|
|
344
|
+
"sharp": GrpcPatCornerType.SHARP,
|
|
345
|
+
}
|
|
346
|
+
self.corner_style = mapping[corner_type]
|
|
@@ -0,0 +1,276 @@
|
|
|
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
|
+
|
|
23
|
+
|
|
24
|
+
import math
|
|
25
|
+
|
|
26
|
+
from ansys.edb.core.geometry.point_data import PointData as GrpcPointData
|
|
27
|
+
from ansys.edb.core.geometry.polygon_data import PolygonData as GrpcPolygonData
|
|
28
|
+
from ansys.edb.core.primitive.primitive import Polygon as GrpcPolygon
|
|
29
|
+
from ansys.edb.core.utility.value import Value as GrpcValue
|
|
30
|
+
|
|
31
|
+
from pyedb.grpc.database.primitive.primitive import Primitive
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class Polygon(GrpcPolygon, Primitive):
|
|
35
|
+
def __init__(self, pedb, edb_object):
|
|
36
|
+
GrpcPolygon.__init__(self, edb_object.msg)
|
|
37
|
+
Primitive.__init__(self, pedb, edb_object)
|
|
38
|
+
self._pedb = pedb
|
|
39
|
+
|
|
40
|
+
@property
|
|
41
|
+
def type(self):
|
|
42
|
+
"""Primitive type.
|
|
43
|
+
|
|
44
|
+
Return
|
|
45
|
+
------
|
|
46
|
+
str
|
|
47
|
+
Polygon type.
|
|
48
|
+
|
|
49
|
+
"""
|
|
50
|
+
return self.primitive_type.name.lower()
|
|
51
|
+
|
|
52
|
+
@property
|
|
53
|
+
def has_self_intersections(self):
|
|
54
|
+
"""Check if Polygon has self intersections.
|
|
55
|
+
|
|
56
|
+
Returns
|
|
57
|
+
-------
|
|
58
|
+
bool
|
|
59
|
+
"""
|
|
60
|
+
return self.polygon_data.has_self_intersections()
|
|
61
|
+
|
|
62
|
+
def fix_self_intersections(self):
|
|
63
|
+
"""Remove self intersections if they exist.
|
|
64
|
+
|
|
65
|
+
Returns
|
|
66
|
+
-------
|
|
67
|
+
List[:class:`Polygon <ansys.edb.core.primitive.primitive.Polygon>`]
|
|
68
|
+
All new polygons created from the removal operation.
|
|
69
|
+
|
|
70
|
+
"""
|
|
71
|
+
new_polys = []
|
|
72
|
+
if self.has_self_intersections:
|
|
73
|
+
new_polygons = self.polygon_data.remove_self_intersections()
|
|
74
|
+
self.polygon_data = new_polygons[0]
|
|
75
|
+
for p in new_polygons[1:]:
|
|
76
|
+
cloned_poly = self.create(
|
|
77
|
+
layout=self._pedb.active_layout, layer=self.layer.name, net=self.net, polygon_data=p
|
|
78
|
+
)
|
|
79
|
+
new_polys.append(cloned_poly)
|
|
80
|
+
return new_polys
|
|
81
|
+
|
|
82
|
+
def clone(self):
|
|
83
|
+
"""Duplicate polygon.
|
|
84
|
+
|
|
85
|
+
Returns
|
|
86
|
+
-------
|
|
87
|
+
:class:`Polygon <ansys.edb.core.primitive.primitive.Polygon>`
|
|
88
|
+
Cloned polygon.
|
|
89
|
+
|
|
90
|
+
"""
|
|
91
|
+
polygon_data = self.polygon_data
|
|
92
|
+
duplicated_polygon = self.create(
|
|
93
|
+
layout=self._pedb.active_layout, layer=self.layer, net=self.net, polygon_data=polygon_data
|
|
94
|
+
)
|
|
95
|
+
for void in self.voids:
|
|
96
|
+
duplicated_polygon.add_void(void)
|
|
97
|
+
return duplicated_polygon
|
|
98
|
+
|
|
99
|
+
def duplicate_across_layers(self, layers):
|
|
100
|
+
"""Duplicate across layer a primitive object.
|
|
101
|
+
|
|
102
|
+
Parameters:
|
|
103
|
+
|
|
104
|
+
layers: list
|
|
105
|
+
list of str, with layer names
|
|
106
|
+
|
|
107
|
+
Returns
|
|
108
|
+
-------
|
|
109
|
+
bool
|
|
110
|
+
``True`` when successful, ``False`` when failed.
|
|
111
|
+
"""
|
|
112
|
+
for layer in layers:
|
|
113
|
+
if layer in self._pedb.stackup.layers:
|
|
114
|
+
duplicate_polygon = self.create(
|
|
115
|
+
layout=self._pedb.active_layout, layer=layer, net=self.net.name, polygon_data=self.polygon_data
|
|
116
|
+
)
|
|
117
|
+
if duplicate_polygon:
|
|
118
|
+
for void in self.voids:
|
|
119
|
+
duplicate_void = self.create(
|
|
120
|
+
layout=self._pedb.active_layout,
|
|
121
|
+
layer=layer,
|
|
122
|
+
net=self.net.name,
|
|
123
|
+
polygon_data=void.cast().polygon_data,
|
|
124
|
+
)
|
|
125
|
+
duplicate_polygon.add_void(duplicate_void)
|
|
126
|
+
else:
|
|
127
|
+
return False
|
|
128
|
+
return True
|
|
129
|
+
|
|
130
|
+
def move(self, vector):
|
|
131
|
+
"""Move polygon along a vector.
|
|
132
|
+
|
|
133
|
+
Parameters
|
|
134
|
+
----------
|
|
135
|
+
vector : List of float or str [x,y].
|
|
136
|
+
|
|
137
|
+
Returns
|
|
138
|
+
-------
|
|
139
|
+
bool
|
|
140
|
+
``True`` when successful, ``False`` when failed.
|
|
141
|
+
|
|
142
|
+
Examples
|
|
143
|
+
--------
|
|
144
|
+
>>> edbapp = ansys.aedt.core.Edb("myproject.aedb")
|
|
145
|
+
>>> top_layer_polygon = [poly for poly in edbapp.modeler.polygons if poly.layer_name == "Top Layer"]
|
|
146
|
+
>>> for polygon in top_layer_polygon:
|
|
147
|
+
>>> polygon.move(vector=["2mm", "100um"])
|
|
148
|
+
"""
|
|
149
|
+
if vector and isinstance(vector, list) and len(vector) == 2:
|
|
150
|
+
_vector = [GrpcValue(pt).value for pt in vector]
|
|
151
|
+
self.polygon_data = self.polygon_data.move(_vector)
|
|
152
|
+
return True
|
|
153
|
+
return False
|
|
154
|
+
|
|
155
|
+
def scale(self, factor, center=None):
|
|
156
|
+
"""Scales the polygon relative to a center point by a factor.
|
|
157
|
+
|
|
158
|
+
Parameters
|
|
159
|
+
----------
|
|
160
|
+
factor : float
|
|
161
|
+
Scaling factor.
|
|
162
|
+
center : List of float or str [x,y], optional
|
|
163
|
+
If None scaling is done from polygon center.
|
|
164
|
+
|
|
165
|
+
Returns
|
|
166
|
+
-------
|
|
167
|
+
bool
|
|
168
|
+
``True`` when successful, ``False`` when failed.
|
|
169
|
+
"""
|
|
170
|
+
if not isinstance(factor, str):
|
|
171
|
+
factor = float(factor)
|
|
172
|
+
if not center:
|
|
173
|
+
center = self.polygon_data.bounding_circle()[0]
|
|
174
|
+
if center:
|
|
175
|
+
self.polygon_data = self.polygon_data.scale(factor, center)
|
|
176
|
+
return True
|
|
177
|
+
else:
|
|
178
|
+
self._pedb.logger.error(f"Failed to evaluate center on primitive {self.id}")
|
|
179
|
+
elif isinstance(center, list) and len(center) == 2:
|
|
180
|
+
center = GrpcPointData([GrpcValue(center[0]), GrpcValue(center[1])])
|
|
181
|
+
self.polygon_data = self.polygon_data.scale(factor, center)
|
|
182
|
+
return True
|
|
183
|
+
return False
|
|
184
|
+
|
|
185
|
+
def rotate(self, angle, center=None):
|
|
186
|
+
"""Rotate polygon around a center point by an angle.
|
|
187
|
+
|
|
188
|
+
Parameters
|
|
189
|
+
----------
|
|
190
|
+
angle : float
|
|
191
|
+
Value of the rotation angle in degree.
|
|
192
|
+
center : List of float or str [x,y], optional
|
|
193
|
+
If None rotation is done from polygon center.
|
|
194
|
+
|
|
195
|
+
Returns
|
|
196
|
+
-------
|
|
197
|
+
bool
|
|
198
|
+
``True`` when successful, ``False`` when failed.
|
|
199
|
+
|
|
200
|
+
Examples
|
|
201
|
+
--------
|
|
202
|
+
>>> edbapp = ansys.aedt.core.Edb("myproject.aedb")
|
|
203
|
+
>>> top_layer_polygon = [poly for poly in edbapp.modeler.polygons if poly.layer_name == "Top Layer"]
|
|
204
|
+
>>> for polygon in top_layer_polygon:
|
|
205
|
+
>>> polygon.rotate(angle=45)
|
|
206
|
+
"""
|
|
207
|
+
if angle:
|
|
208
|
+
if not center:
|
|
209
|
+
center = self.polygon_data.bounding_circle()[0]
|
|
210
|
+
if center:
|
|
211
|
+
self.polygon_data = self.polygon_data.rotate(angle * math.pi / 180, center)
|
|
212
|
+
return True
|
|
213
|
+
elif isinstance(center, list) and len(center) == 2:
|
|
214
|
+
self.polygon_data = self.polygon_data.rotate(angle * math.pi / 180, center)
|
|
215
|
+
return True
|
|
216
|
+
return False
|
|
217
|
+
|
|
218
|
+
def move_layer(self, layer):
|
|
219
|
+
"""Move polygon to given layer.
|
|
220
|
+
|
|
221
|
+
Parameters
|
|
222
|
+
----------
|
|
223
|
+
layer : str
|
|
224
|
+
layer name.
|
|
225
|
+
|
|
226
|
+
Returns
|
|
227
|
+
-------
|
|
228
|
+
bool
|
|
229
|
+
``True`` when successful, ``False`` when failed.
|
|
230
|
+
"""
|
|
231
|
+
if layer and isinstance(layer, str) and layer in self._pedb.stackup.signal_layers:
|
|
232
|
+
self.layer = self._pedb.stackup.layers[layer]
|
|
233
|
+
return True
|
|
234
|
+
return False
|
|
235
|
+
|
|
236
|
+
def in_polygon(
|
|
237
|
+
self,
|
|
238
|
+
point_data,
|
|
239
|
+
include_partial=True,
|
|
240
|
+
):
|
|
241
|
+
"""Check if padstack Instance is in given polygon data.
|
|
242
|
+
|
|
243
|
+
Parameters
|
|
244
|
+
----------
|
|
245
|
+
point_data : PointData Object or list of float
|
|
246
|
+
include_partial : bool, optional
|
|
247
|
+
Whether to include partial intersecting instances. The default is ``True``.
|
|
248
|
+
|
|
249
|
+
Returns
|
|
250
|
+
-------
|
|
251
|
+
bool
|
|
252
|
+
``True`` when successful, ``False`` when failed.
|
|
253
|
+
"""
|
|
254
|
+
int_val = 1 if self.polygon_data.is_inside(GrpcPointData(point_data)) else 0
|
|
255
|
+
if int_val == 0:
|
|
256
|
+
return False
|
|
257
|
+
else:
|
|
258
|
+
int_val = self.polygon_data.intersection_type(GrpcPolygonData(point_data))
|
|
259
|
+
# Intersection type:
|
|
260
|
+
# 0 = objects do not intersect
|
|
261
|
+
# 1 = this object fully inside other (no common contour points)
|
|
262
|
+
# 2 = other object fully inside this
|
|
263
|
+
# 3 = common contour points 4 = undefined intersection
|
|
264
|
+
if int_val == 0:
|
|
265
|
+
return False
|
|
266
|
+
elif include_partial:
|
|
267
|
+
return True
|
|
268
|
+
elif int_val < 3:
|
|
269
|
+
return True
|
|
270
|
+
else:
|
|
271
|
+
return False
|
|
272
|
+
|
|
273
|
+
def add_void(self, polygon):
|
|
274
|
+
if isinstance(polygon, list):
|
|
275
|
+
polygon = self._pedb.modeler.create_polygon(points=polygon, layer_name=self.layer.name)
|
|
276
|
+
return self._edb_object.add_void(polygon._edb_object)
|