pyedb 0.2.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.
- pyedb/__init__.py +17 -0
- pyedb/dotnet/__init__.py +0 -0
- pyedb/dotnet/application/Variables.py +2261 -0
- pyedb/dotnet/application/__init__.py +0 -0
- pyedb/dotnet/clr_module.py +103 -0
- pyedb/dotnet/edb.py +4237 -0
- pyedb/dotnet/edb_core/__init__.py +1 -0
- pyedb/dotnet/edb_core/cell/__init__.py +0 -0
- pyedb/dotnet/edb_core/cell/hierarchy/__init__.py +0 -0
- pyedb/dotnet/edb_core/cell/hierarchy/model.py +66 -0
- pyedb/dotnet/edb_core/components.py +2669 -0
- pyedb/dotnet/edb_core/configuration.py +423 -0
- pyedb/dotnet/edb_core/definition/__init__.py +0 -0
- pyedb/dotnet/edb_core/definition/component_def.py +166 -0
- pyedb/dotnet/edb_core/definition/component_model.py +30 -0
- pyedb/dotnet/edb_core/definition/definition_obj.py +18 -0
- pyedb/dotnet/edb_core/definition/definitions.py +12 -0
- pyedb/dotnet/edb_core/dotnet/__init__.py +0 -0
- pyedb/dotnet/edb_core/dotnet/database.py +1218 -0
- pyedb/dotnet/edb_core/dotnet/layout.py +238 -0
- pyedb/dotnet/edb_core/dotnet/primitive.py +1517 -0
- pyedb/dotnet/edb_core/edb_data/__init__.py +0 -0
- pyedb/dotnet/edb_core/edb_data/components_data.py +938 -0
- pyedb/dotnet/edb_core/edb_data/connectable.py +113 -0
- pyedb/dotnet/edb_core/edb_data/control_file.py +1268 -0
- pyedb/dotnet/edb_core/edb_data/design_options.py +35 -0
- pyedb/dotnet/edb_core/edb_data/edbvalue.py +45 -0
- pyedb/dotnet/edb_core/edb_data/hfss_extent_info.py +330 -0
- pyedb/dotnet/edb_core/edb_data/hfss_simulation_setup_data.py +1607 -0
- pyedb/dotnet/edb_core/edb_data/layer_data.py +576 -0
- pyedb/dotnet/edb_core/edb_data/nets_data.py +281 -0
- pyedb/dotnet/edb_core/edb_data/obj_base.py +19 -0
- pyedb/dotnet/edb_core/edb_data/padstacks_data.py +2080 -0
- pyedb/dotnet/edb_core/edb_data/ports.py +287 -0
- pyedb/dotnet/edb_core/edb_data/primitives_data.py +1397 -0
- pyedb/dotnet/edb_core/edb_data/simulation_configuration.py +2914 -0
- pyedb/dotnet/edb_core/edb_data/simulation_setup.py +716 -0
- pyedb/dotnet/edb_core/edb_data/siwave_simulation_setup_data.py +1205 -0
- pyedb/dotnet/edb_core/edb_data/sources.py +514 -0
- pyedb/dotnet/edb_core/edb_data/terminals.py +632 -0
- pyedb/dotnet/edb_core/edb_data/utilities.py +148 -0
- pyedb/dotnet/edb_core/edb_data/variables.py +91 -0
- pyedb/dotnet/edb_core/general.py +181 -0
- pyedb/dotnet/edb_core/hfss.py +1646 -0
- pyedb/dotnet/edb_core/layout.py +1244 -0
- pyedb/dotnet/edb_core/layout_validation.py +272 -0
- pyedb/dotnet/edb_core/materials.py +939 -0
- pyedb/dotnet/edb_core/net_class.py +335 -0
- pyedb/dotnet/edb_core/nets.py +1215 -0
- pyedb/dotnet/edb_core/padstack.py +1389 -0
- pyedb/dotnet/edb_core/siwave.py +1427 -0
- pyedb/dotnet/edb_core/stackup.py +2703 -0
- pyedb/edb_logger.py +396 -0
- pyedb/generic/__init__.py +0 -0
- pyedb/generic/constants.py +1063 -0
- pyedb/generic/data_handlers.py +320 -0
- pyedb/generic/design_types.py +104 -0
- pyedb/generic/filesystem.py +150 -0
- pyedb/generic/general_methods.py +1535 -0
- pyedb/generic/plot.py +1840 -0
- pyedb/generic/process.py +285 -0
- pyedb/generic/settings.py +224 -0
- pyedb/ipc2581/__init__.py +0 -0
- pyedb/ipc2581/bom/__init__.py +0 -0
- pyedb/ipc2581/bom/bom.py +21 -0
- pyedb/ipc2581/bom/bom_item.py +32 -0
- pyedb/ipc2581/bom/characteristics.py +37 -0
- pyedb/ipc2581/bom/refdes.py +16 -0
- pyedb/ipc2581/content/__init__.py +0 -0
- pyedb/ipc2581/content/color.py +38 -0
- pyedb/ipc2581/content/content.py +55 -0
- pyedb/ipc2581/content/dictionary_color.py +29 -0
- pyedb/ipc2581/content/dictionary_fill.py +28 -0
- pyedb/ipc2581/content/dictionary_line.py +30 -0
- pyedb/ipc2581/content/entry_color.py +13 -0
- pyedb/ipc2581/content/entry_line.py +14 -0
- pyedb/ipc2581/content/fill.py +15 -0
- pyedb/ipc2581/content/layer_ref.py +10 -0
- pyedb/ipc2581/content/standard_geometries_dictionary.py +72 -0
- pyedb/ipc2581/ecad/__init__.py +0 -0
- pyedb/ipc2581/ecad/cad_data/__init__.py +0 -0
- pyedb/ipc2581/ecad/cad_data/assembly_drawing.py +26 -0
- pyedb/ipc2581/ecad/cad_data/cad_data.py +37 -0
- pyedb/ipc2581/ecad/cad_data/component.py +41 -0
- pyedb/ipc2581/ecad/cad_data/drill.py +30 -0
- pyedb/ipc2581/ecad/cad_data/feature.py +54 -0
- pyedb/ipc2581/ecad/cad_data/layer.py +41 -0
- pyedb/ipc2581/ecad/cad_data/layer_feature.py +151 -0
- pyedb/ipc2581/ecad/cad_data/logical_net.py +32 -0
- pyedb/ipc2581/ecad/cad_data/outline.py +25 -0
- pyedb/ipc2581/ecad/cad_data/package.py +104 -0
- pyedb/ipc2581/ecad/cad_data/padstack_def.py +38 -0
- pyedb/ipc2581/ecad/cad_data/padstack_hole_def.py +24 -0
- pyedb/ipc2581/ecad/cad_data/padstack_instance.py +62 -0
- pyedb/ipc2581/ecad/cad_data/padstack_pad_def.py +26 -0
- pyedb/ipc2581/ecad/cad_data/path.py +89 -0
- pyedb/ipc2581/ecad/cad_data/phy_net.py +80 -0
- pyedb/ipc2581/ecad/cad_data/pin.py +31 -0
- pyedb/ipc2581/ecad/cad_data/polygon.py +169 -0
- pyedb/ipc2581/ecad/cad_data/profile.py +40 -0
- pyedb/ipc2581/ecad/cad_data/stackup.py +31 -0
- pyedb/ipc2581/ecad/cad_data/stackup_group.py +42 -0
- pyedb/ipc2581/ecad/cad_data/stackup_layer.py +21 -0
- pyedb/ipc2581/ecad/cad_data/step.py +275 -0
- pyedb/ipc2581/ecad/cad_header.py +33 -0
- pyedb/ipc2581/ecad/ecad.py +19 -0
- pyedb/ipc2581/ecad/spec.py +46 -0
- pyedb/ipc2581/history_record.py +37 -0
- pyedb/ipc2581/ipc2581.py +387 -0
- pyedb/ipc2581/logistic_header.py +25 -0
- pyedb/misc/__init__.py +0 -0
- pyedb/misc/aedtlib_personalib_install.py +14 -0
- pyedb/misc/downloads.py +322 -0
- pyedb/misc/misc.py +67 -0
- pyedb/misc/pyedb.runtimeconfig.json +13 -0
- pyedb/misc/siw_feature_config/__init__.py +0 -0
- pyedb/misc/siw_feature_config/emc/__init__.py +0 -0
- pyedb/misc/siw_feature_config/emc/component_tags.py +46 -0
- pyedb/misc/siw_feature_config/emc/net_tags.py +37 -0
- pyedb/misc/siw_feature_config/emc/tag_library.py +62 -0
- pyedb/misc/siw_feature_config/emc/xml_generic.py +78 -0
- pyedb/misc/siw_feature_config/emc_rule_checker_settings.py +179 -0
- pyedb/misc/utilities.py +27 -0
- pyedb/modeler/geometry_operators.py +2082 -0
- pyedb-0.2.0.dist-info/LICENSE +21 -0
- pyedb-0.2.0.dist-info/METADATA +208 -0
- pyedb-0.2.0.dist-info/RECORD +128 -0
- pyedb-0.2.0.dist-info/WHEEL +4 -0
|
@@ -0,0 +1,1397 @@
|
|
|
1
|
+
import math
|
|
2
|
+
|
|
3
|
+
from pyedb.dotnet.edb_core.dotnet.database import NetDotNet
|
|
4
|
+
from pyedb.dotnet.edb_core.dotnet.primitive import (
|
|
5
|
+
BondwireDotNet,
|
|
6
|
+
CircleDotNet,
|
|
7
|
+
PathDotNet,
|
|
8
|
+
PolygonDataDotNet,
|
|
9
|
+
PolygonDotNet,
|
|
10
|
+
RectangleDotNet,
|
|
11
|
+
TextDotNet,
|
|
12
|
+
)
|
|
13
|
+
from pyedb.dotnet.edb_core.edb_data.connectable import Connectable
|
|
14
|
+
from pyedb.dotnet.edb_core.general import convert_py_list_to_net_list
|
|
15
|
+
from pyedb.generic.general_methods import pyedb_function_handler
|
|
16
|
+
from pyedb.modeler.geometry_operators import GeometryOperators
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def cast(raw_primitive, core_app):
|
|
20
|
+
"""Cast the primitive object to correct concrete type.
|
|
21
|
+
|
|
22
|
+
Returns
|
|
23
|
+
-------
|
|
24
|
+
Primitive
|
|
25
|
+
"""
|
|
26
|
+
if isinstance(raw_primitive, RectangleDotNet):
|
|
27
|
+
return EdbRectangle(raw_primitive.prim_obj, core_app)
|
|
28
|
+
elif isinstance(raw_primitive, PolygonDotNet):
|
|
29
|
+
return EdbPolygon(raw_primitive.prim_obj, core_app)
|
|
30
|
+
elif isinstance(raw_primitive, PathDotNet):
|
|
31
|
+
return EdbPath(raw_primitive.prim_obj, core_app)
|
|
32
|
+
elif isinstance(raw_primitive, BondwireDotNet):
|
|
33
|
+
return EdbBondwire(raw_primitive.prim_obj, core_app)
|
|
34
|
+
elif isinstance(raw_primitive, TextDotNet):
|
|
35
|
+
return EdbText(raw_primitive.prim_obj, core_app)
|
|
36
|
+
elif isinstance(raw_primitive, CircleDotNet):
|
|
37
|
+
return EdbCircle(raw_primitive.prim_obj, core_app)
|
|
38
|
+
else:
|
|
39
|
+
try:
|
|
40
|
+
prim_type = raw_primitive.GetPrimitiveType()
|
|
41
|
+
if prim_type == prim_type.Rectangle:
|
|
42
|
+
return EdbRectangle(raw_primitive, core_app)
|
|
43
|
+
elif prim_type == prim_type.Polygon:
|
|
44
|
+
return EdbPolygon(raw_primitive, core_app)
|
|
45
|
+
elif prim_type == prim_type.Path:
|
|
46
|
+
return EdbPath(raw_primitive, core_app)
|
|
47
|
+
elif prim_type == prim_type.Bondwire:
|
|
48
|
+
return EdbBondwire(raw_primitive, core_app)
|
|
49
|
+
elif prim_type == prim_type.Text:
|
|
50
|
+
return EdbText(raw_primitive, core_app)
|
|
51
|
+
elif prim_type == prim_type.Circle:
|
|
52
|
+
return EdbCircle(raw_primitive, core_app)
|
|
53
|
+
else:
|
|
54
|
+
return None
|
|
55
|
+
except:
|
|
56
|
+
return None
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class EDBPrimitivesMain(Connectable):
|
|
60
|
+
"""Manages EDB functionalities for a primitives.
|
|
61
|
+
It Inherits EDB Object properties.
|
|
62
|
+
|
|
63
|
+
Examples
|
|
64
|
+
--------
|
|
65
|
+
>>> from pyedb import Edb
|
|
66
|
+
>>> edb = Edb(myedb, edbversion="2021.2")
|
|
67
|
+
>>> edb_prim = edb.modeler.primitives[0]
|
|
68
|
+
>>> edb_prim.is_void # Class Property
|
|
69
|
+
>>> edb_prim.IsVoid() # EDB Object Property
|
|
70
|
+
"""
|
|
71
|
+
|
|
72
|
+
def __init__(self, raw_primitive, core_app):
|
|
73
|
+
super().__init__(core_app, raw_primitive)
|
|
74
|
+
self._app = self._pedb
|
|
75
|
+
self._core_stackup = core_app.stackup
|
|
76
|
+
self._core_net = core_app.nets
|
|
77
|
+
self.primitive_object = self._edb_object
|
|
78
|
+
|
|
79
|
+
@property
|
|
80
|
+
def type(self):
|
|
81
|
+
"""Return the type of the primitive.
|
|
82
|
+
Allowed outputs are ``"Circle"``, ``"Rectangle"``,``"Polygon"``,``"Path"`` or ``"Bondwire"``.
|
|
83
|
+
|
|
84
|
+
Returns
|
|
85
|
+
-------
|
|
86
|
+
str
|
|
87
|
+
"""
|
|
88
|
+
try:
|
|
89
|
+
return self._edb_object.GetPrimitiveType().ToString()
|
|
90
|
+
except AttributeError: # pragma: no cover
|
|
91
|
+
return ""
|
|
92
|
+
|
|
93
|
+
@property
|
|
94
|
+
def net_name(self):
|
|
95
|
+
"""Get or Set the primitive net name.
|
|
96
|
+
|
|
97
|
+
Returns
|
|
98
|
+
-------
|
|
99
|
+
str
|
|
100
|
+
"""
|
|
101
|
+
return self.net.GetName()
|
|
102
|
+
|
|
103
|
+
@net_name.setter
|
|
104
|
+
def net_name(self, name):
|
|
105
|
+
if isinstance(name, str):
|
|
106
|
+
net = self._app.nets.nets[name].net_object
|
|
107
|
+
self.primitive_object.SetNet(net)
|
|
108
|
+
else:
|
|
109
|
+
try:
|
|
110
|
+
if isinstance(name, str):
|
|
111
|
+
self.net = name
|
|
112
|
+
elif isinstance(name, NetDotNet):
|
|
113
|
+
self.net = name.name
|
|
114
|
+
except: # pragma: no cover
|
|
115
|
+
self._app.logger.error("Failed to set net name.")
|
|
116
|
+
|
|
117
|
+
@property
|
|
118
|
+
def layer(self):
|
|
119
|
+
"""Get the primitive edb layer object."""
|
|
120
|
+
try:
|
|
121
|
+
return self.primitive_object.GetLayer()
|
|
122
|
+
except AttributeError: # pragma: no cover
|
|
123
|
+
return None
|
|
124
|
+
|
|
125
|
+
@property
|
|
126
|
+
def layer_name(self):
|
|
127
|
+
"""Get or Set the primitive layer name.
|
|
128
|
+
|
|
129
|
+
Returns
|
|
130
|
+
-------
|
|
131
|
+
str
|
|
132
|
+
"""
|
|
133
|
+
try:
|
|
134
|
+
return self.layer.GetName()
|
|
135
|
+
except AttributeError: # pragma: no cover
|
|
136
|
+
return None
|
|
137
|
+
|
|
138
|
+
@layer_name.setter
|
|
139
|
+
def layer_name(self, val):
|
|
140
|
+
if isinstance(val, str) and val in list(self._core_stackup.layers.keys()):
|
|
141
|
+
lay = self._core_stackup.layers["TOP"]._edb_layer
|
|
142
|
+
if lay:
|
|
143
|
+
self.primitive_object.SetLayer(lay)
|
|
144
|
+
else:
|
|
145
|
+
raise AttributeError("Layer {} not found in layer".format(val))
|
|
146
|
+
elif isinstance(val, type(self._core_stackup.layers["TOP"])):
|
|
147
|
+
try:
|
|
148
|
+
self.primitive_object.SetLayer(val._edb_layer)
|
|
149
|
+
except:
|
|
150
|
+
raise AttributeError("Failed to assign new layer on primitive.")
|
|
151
|
+
else:
|
|
152
|
+
raise AttributeError("Invalid input value")
|
|
153
|
+
|
|
154
|
+
@property
|
|
155
|
+
def is_void(self):
|
|
156
|
+
"""Either if the primitive is a void or not.
|
|
157
|
+
|
|
158
|
+
Returns
|
|
159
|
+
-------
|
|
160
|
+
bool
|
|
161
|
+
"""
|
|
162
|
+
try:
|
|
163
|
+
return self._edb_object.IsVoid()
|
|
164
|
+
except AttributeError: # pragma: no cover
|
|
165
|
+
return None
|
|
166
|
+
|
|
167
|
+
def get_connected_objects(self):
|
|
168
|
+
"""Get connected objects.
|
|
169
|
+
|
|
170
|
+
Returns
|
|
171
|
+
-------
|
|
172
|
+
list
|
|
173
|
+
"""
|
|
174
|
+
return self._pedb.get_connected_objects(self._layout_obj_instance)
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
class EDBPrimitives(EDBPrimitivesMain):
|
|
178
|
+
"""Manages EDB functionalities for a primitives.
|
|
179
|
+
It Inherits EDB Object properties.
|
|
180
|
+
|
|
181
|
+
Examples
|
|
182
|
+
--------
|
|
183
|
+
>>> from pyedb import Edb
|
|
184
|
+
>>> edb = Edb(myedb, edbversion="2021.2")
|
|
185
|
+
>>> edb_prim = edb.modeler.primitives[0]
|
|
186
|
+
>>> edb_prim.is_void # Class Property
|
|
187
|
+
>>> edb_prim.IsVoid() # EDB Object Property
|
|
188
|
+
"""
|
|
189
|
+
|
|
190
|
+
def __init__(self, raw_primitive, core_app):
|
|
191
|
+
EDBPrimitivesMain.__init__(self, raw_primitive, core_app)
|
|
192
|
+
|
|
193
|
+
@pyedb_function_handler()
|
|
194
|
+
def area(self, include_voids=True):
|
|
195
|
+
"""Return the total area.
|
|
196
|
+
|
|
197
|
+
Parameters
|
|
198
|
+
----------
|
|
199
|
+
include_voids : bool, optional
|
|
200
|
+
Either if the voids have to be included in computation.
|
|
201
|
+
The default value is ``True``.
|
|
202
|
+
|
|
203
|
+
Returns
|
|
204
|
+
-------
|
|
205
|
+
float
|
|
206
|
+
"""
|
|
207
|
+
area = self.primitive_object.GetPolygonData().Area()
|
|
208
|
+
if include_voids:
|
|
209
|
+
for el in self.primitive_object.Voids:
|
|
210
|
+
area -= el.GetPolygonData().Area()
|
|
211
|
+
return area
|
|
212
|
+
|
|
213
|
+
@property
|
|
214
|
+
def is_negative(self):
|
|
215
|
+
"""Determine whether this primitive is negative.
|
|
216
|
+
|
|
217
|
+
Returns
|
|
218
|
+
-------
|
|
219
|
+
bool
|
|
220
|
+
True if it is negative, False otherwise.
|
|
221
|
+
"""
|
|
222
|
+
return self.primitive_object.GetIsNegative()
|
|
223
|
+
|
|
224
|
+
@is_negative.setter
|
|
225
|
+
def is_negative(self, value):
|
|
226
|
+
self.primitive_object.SetIsNegative(value)
|
|
227
|
+
|
|
228
|
+
@staticmethod
|
|
229
|
+
def _eval_arc_points(p1, p2, h, n=6, tol=1e-12):
|
|
230
|
+
"""Get the points of the arc
|
|
231
|
+
|
|
232
|
+
Parameters
|
|
233
|
+
----------
|
|
234
|
+
p1 : list
|
|
235
|
+
Arc starting point.
|
|
236
|
+
p2 : list
|
|
237
|
+
Arc ending point.
|
|
238
|
+
h : float
|
|
239
|
+
Arc height.
|
|
240
|
+
n : int
|
|
241
|
+
Number of points to generate along the arc.
|
|
242
|
+
tol : float
|
|
243
|
+
Geometric tolerance.
|
|
244
|
+
|
|
245
|
+
Returns
|
|
246
|
+
-------
|
|
247
|
+
list, list
|
|
248
|
+
Points generated along the arc.
|
|
249
|
+
"""
|
|
250
|
+
# fmt: off
|
|
251
|
+
if abs(h) < tol:
|
|
252
|
+
return [], []
|
|
253
|
+
elif h > 0:
|
|
254
|
+
reverse = False
|
|
255
|
+
x1 = p1[0]
|
|
256
|
+
y1 = p1[1]
|
|
257
|
+
x2 = p2[0]
|
|
258
|
+
y2 = p2[1]
|
|
259
|
+
else:
|
|
260
|
+
reverse = True
|
|
261
|
+
x1 = p2[0]
|
|
262
|
+
y1 = p2[1]
|
|
263
|
+
x2 = p1[0]
|
|
264
|
+
y2 = p1[1]
|
|
265
|
+
h *= -1
|
|
266
|
+
xa = (x2 - x1) / 2
|
|
267
|
+
ya = (y2 - y1) / 2
|
|
268
|
+
xo = x1 + xa
|
|
269
|
+
yo = y1 + ya
|
|
270
|
+
a = math.sqrt(xa ** 2 + ya ** 2)
|
|
271
|
+
if a < tol:
|
|
272
|
+
return [], []
|
|
273
|
+
r = (a ** 2) / (2 * h) + h / 2
|
|
274
|
+
if abs(r - a) < tol:
|
|
275
|
+
b = 0
|
|
276
|
+
th = 2 * math.asin(1) # chord angle
|
|
277
|
+
else:
|
|
278
|
+
b = math.sqrt(r ** 2 - a ** 2)
|
|
279
|
+
th = 2 * math.asin(a / r) # chord angle
|
|
280
|
+
|
|
281
|
+
# center of the circle
|
|
282
|
+
xc = xo + b * ya / a
|
|
283
|
+
yc = yo - b * xa / a
|
|
284
|
+
|
|
285
|
+
alpha = math.atan2((y1 - yc), (x1 - xc))
|
|
286
|
+
xr = []
|
|
287
|
+
yr = []
|
|
288
|
+
for i in range(n):
|
|
289
|
+
i += 1
|
|
290
|
+
dth = (float(i) / (n + 1)) * th
|
|
291
|
+
xi = xc + r * math.cos(alpha - dth)
|
|
292
|
+
yi = yc + r * math.sin(alpha - dth)
|
|
293
|
+
xr.append(xi)
|
|
294
|
+
yr.append(yi)
|
|
295
|
+
|
|
296
|
+
if reverse:
|
|
297
|
+
xr.reverse()
|
|
298
|
+
yr.reverse()
|
|
299
|
+
# fmt: on
|
|
300
|
+
return xr, yr
|
|
301
|
+
|
|
302
|
+
def _get_points_for_plot(self, my_net_points, num):
|
|
303
|
+
"""
|
|
304
|
+
Get the points to be plotted.
|
|
305
|
+
"""
|
|
306
|
+
# fmt: off
|
|
307
|
+
x = []
|
|
308
|
+
y = []
|
|
309
|
+
for i, point in enumerate(my_net_points):
|
|
310
|
+
if not self.is_arc(point):
|
|
311
|
+
x.append(point.X.ToDouble())
|
|
312
|
+
y.append(point.Y.ToDouble())
|
|
313
|
+
# i += 1
|
|
314
|
+
else:
|
|
315
|
+
arc_h = point.GetArcHeight().ToDouble()
|
|
316
|
+
p1 = [my_net_points[i - 1].X.ToDouble(), my_net_points[i - 1].Y.ToDouble()]
|
|
317
|
+
if i + 1 < len(my_net_points):
|
|
318
|
+
p2 = [my_net_points[i + 1].X.ToDouble(), my_net_points[i + 1].Y.ToDouble()]
|
|
319
|
+
else:
|
|
320
|
+
p2 = [my_net_points[0].X.ToDouble(), my_net_points[0].Y.ToDouble()]
|
|
321
|
+
x_arc, y_arc = self._eval_arc_points(p1, p2, arc_h, num)
|
|
322
|
+
x.extend(x_arc)
|
|
323
|
+
y.extend(y_arc)
|
|
324
|
+
# i += 1
|
|
325
|
+
# fmt: on
|
|
326
|
+
return x, y
|
|
327
|
+
|
|
328
|
+
@property
|
|
329
|
+
def bbox(self):
|
|
330
|
+
"""Return the primitive bounding box points. Lower left corner, upper right corner.
|
|
331
|
+
|
|
332
|
+
Returns
|
|
333
|
+
-------
|
|
334
|
+
list
|
|
335
|
+
[lower_left x, lower_left y, upper right x, upper right y]
|
|
336
|
+
|
|
337
|
+
"""
|
|
338
|
+
bbox = self.polygon_data.edb_api.GetBBox()
|
|
339
|
+
return [bbox.Item1.X.ToDouble(), bbox.Item1.Y.ToDouble(), bbox.Item2.X.ToDouble(), bbox.Item2.Y.ToDouble()]
|
|
340
|
+
|
|
341
|
+
@property
|
|
342
|
+
def center(self):
|
|
343
|
+
"""Return the primitive bounding box center coordinate.
|
|
344
|
+
|
|
345
|
+
Returns
|
|
346
|
+
-------
|
|
347
|
+
list
|
|
348
|
+
[x, y]
|
|
349
|
+
|
|
350
|
+
"""
|
|
351
|
+
bbox = self.bbox
|
|
352
|
+
return [(bbox[0] + bbox[2]) / 2, (bbox[1] + bbox[3]) / 2]
|
|
353
|
+
|
|
354
|
+
@pyedb_function_handler()
|
|
355
|
+
def is_arc(self, point):
|
|
356
|
+
"""Either if a point is an arc or not.
|
|
357
|
+
|
|
358
|
+
Returns
|
|
359
|
+
-------
|
|
360
|
+
bool
|
|
361
|
+
"""
|
|
362
|
+
return point.IsArc()
|
|
363
|
+
|
|
364
|
+
@pyedb_function_handler()
|
|
365
|
+
def get_connected_object_id_set(self):
|
|
366
|
+
"""Produce a list of all geometries physically connected to a given layout object.
|
|
367
|
+
|
|
368
|
+
Returns
|
|
369
|
+
-------
|
|
370
|
+
list
|
|
371
|
+
Found connected objects IDs with Layout object.
|
|
372
|
+
"""
|
|
373
|
+
layoutInst = self.primitive_object.GetLayout().GetLayoutInstance()
|
|
374
|
+
layoutObjInst = layoutInst.GetLayoutObjInstance(self.primitive_object, None) # 2nd arg was []
|
|
375
|
+
return [loi.GetLayoutObj().GetId() for loi in layoutInst.GetConnectedObjects(layoutObjInst).Items]
|
|
376
|
+
|
|
377
|
+
@pyedb_function_handler()
|
|
378
|
+
def convert_to_polygon(self):
|
|
379
|
+
"""Convert path to polygon.
|
|
380
|
+
|
|
381
|
+
Returns
|
|
382
|
+
-------
|
|
383
|
+
Converted polygon.
|
|
384
|
+
|
|
385
|
+
"""
|
|
386
|
+
if self.type == "Path":
|
|
387
|
+
polygon_data = self.primitive_object.GetPolygonData()
|
|
388
|
+
polygon = self._app.modeler.create_polygon(polygon_data, self.layer_name, [], self.net_name)
|
|
389
|
+
self.primitive_object.Delete()
|
|
390
|
+
return polygon
|
|
391
|
+
|
|
392
|
+
@pyedb_function_handler()
|
|
393
|
+
def subtract(self, primitives):
|
|
394
|
+
"""Subtract active primitive with one or more primitives.
|
|
395
|
+
|
|
396
|
+
Parameters
|
|
397
|
+
----------
|
|
398
|
+
primitives : :class:`dotnet.edb_core.edb_data.EDBPrimitives` or EDB PolygonData or EDB Primitive or list
|
|
399
|
+
|
|
400
|
+
Returns
|
|
401
|
+
-------
|
|
402
|
+
List of :class:`dotnet.edb_core.edb_data.EDBPrimitives`
|
|
403
|
+
"""
|
|
404
|
+
poly = self.primitive_object.GetPolygonData()
|
|
405
|
+
if not isinstance(primitives, list):
|
|
406
|
+
primitives = [primitives]
|
|
407
|
+
primi_polys = []
|
|
408
|
+
voids_of_prims = []
|
|
409
|
+
for prim in primitives:
|
|
410
|
+
if isinstance(prim, EDBPrimitives):
|
|
411
|
+
primi_polys.append(prim.primitive_object.GetPolygonData())
|
|
412
|
+
for void in prim.voids:
|
|
413
|
+
voids_of_prims.append(void.polygon_data.edb_api)
|
|
414
|
+
else:
|
|
415
|
+
try:
|
|
416
|
+
primi_polys.append(prim.GetPolygonData())
|
|
417
|
+
except:
|
|
418
|
+
primi_polys.append(prim)
|
|
419
|
+
for v in self.voids[:]:
|
|
420
|
+
primi_polys.append(v.polygon_data.edb_api)
|
|
421
|
+
primi_polys = poly.Unite(convert_py_list_to_net_list(primi_polys))
|
|
422
|
+
p_to_sub = poly.Unite(convert_py_list_to_net_list([poly] + voids_of_prims))
|
|
423
|
+
list_poly = poly.Subtract(p_to_sub, primi_polys)
|
|
424
|
+
new_polys = []
|
|
425
|
+
if list_poly:
|
|
426
|
+
for p in list_poly:
|
|
427
|
+
if p.IsNull():
|
|
428
|
+
continue
|
|
429
|
+
new_polys.append(
|
|
430
|
+
cast(
|
|
431
|
+
self._app.modeler.create_polygon(p, self.layer_name, net_name=self.net_name, voids=[]),
|
|
432
|
+
self._app,
|
|
433
|
+
)
|
|
434
|
+
)
|
|
435
|
+
self.delete()
|
|
436
|
+
for prim in primitives:
|
|
437
|
+
if isinstance(prim, EDBPrimitives):
|
|
438
|
+
prim.delete()
|
|
439
|
+
else:
|
|
440
|
+
try:
|
|
441
|
+
prim.Delete()
|
|
442
|
+
except AttributeError:
|
|
443
|
+
continue
|
|
444
|
+
return new_polys
|
|
445
|
+
|
|
446
|
+
@pyedb_function_handler()
|
|
447
|
+
def intersect(self, primitives):
|
|
448
|
+
"""Intersect active primitive with one or more primitives.
|
|
449
|
+
|
|
450
|
+
Parameters
|
|
451
|
+
----------
|
|
452
|
+
primitives : :class:`dotnet.edb_core.edb_data.EDBPrimitives` or EDB PolygonData or EDB Primitive or list
|
|
453
|
+
|
|
454
|
+
Returns
|
|
455
|
+
-------
|
|
456
|
+
List of :class:`dotnet.edb_core.edb_data.EDBPrimitives`
|
|
457
|
+
"""
|
|
458
|
+
poly = self.primitive_object.GetPolygonData()
|
|
459
|
+
if not isinstance(primitives, list):
|
|
460
|
+
primitives = [primitives]
|
|
461
|
+
primi_polys = []
|
|
462
|
+
for prim in primitives:
|
|
463
|
+
if isinstance(prim, EDBPrimitives):
|
|
464
|
+
primi_polys.append(prim.primitive_object.GetPolygonData())
|
|
465
|
+
else:
|
|
466
|
+
try:
|
|
467
|
+
primi_polys.append(prim.GetPolygonData())
|
|
468
|
+
except:
|
|
469
|
+
primi_polys.append(prim)
|
|
470
|
+
list_poly = poly.Intersect(convert_py_list_to_net_list([poly]), convert_py_list_to_net_list(primi_polys))
|
|
471
|
+
new_polys = []
|
|
472
|
+
if list_poly:
|
|
473
|
+
voids = self.voids
|
|
474
|
+
for p in list_poly:
|
|
475
|
+
if p.IsNull():
|
|
476
|
+
continue
|
|
477
|
+
list_void = []
|
|
478
|
+
void_to_subtract = []
|
|
479
|
+
if voids:
|
|
480
|
+
for void in voids:
|
|
481
|
+
void_pdata = void.prim_obj.GetPolygonData()
|
|
482
|
+
int_data2 = p.GetIntersectionType(void_pdata)
|
|
483
|
+
if int_data2 > 2 or int_data2 == 1:
|
|
484
|
+
void_to_subtract.append(void_pdata)
|
|
485
|
+
elif int_data2 == 2:
|
|
486
|
+
list_void.append(void_pdata)
|
|
487
|
+
if void_to_subtract:
|
|
488
|
+
polys_cleans = p.Subtract(
|
|
489
|
+
convert_py_list_to_net_list(p), convert_py_list_to_net_list(void_to_subtract)
|
|
490
|
+
)
|
|
491
|
+
for polys_clean in polys_cleans:
|
|
492
|
+
if not polys_clean.IsNull():
|
|
493
|
+
void_to_append = [v for v in list_void if polys_clean.GetIntersectionType(v) == 2]
|
|
494
|
+
new_polys.append(
|
|
495
|
+
cast(
|
|
496
|
+
self._app.modeler.create_polygon(
|
|
497
|
+
polys_clean, self.layer_name, net_name=self.net_name, voids=void_to_append
|
|
498
|
+
),
|
|
499
|
+
self._app,
|
|
500
|
+
)
|
|
501
|
+
)
|
|
502
|
+
else:
|
|
503
|
+
new_polys.append(
|
|
504
|
+
cast(
|
|
505
|
+
self._app.modeler.create_polygon(
|
|
506
|
+
p, self.layer_name, net_name=self.net_name, voids=list_void
|
|
507
|
+
),
|
|
508
|
+
self._app,
|
|
509
|
+
)
|
|
510
|
+
)
|
|
511
|
+
else:
|
|
512
|
+
new_polys.append(
|
|
513
|
+
cast(
|
|
514
|
+
self._app.modeler.create_polygon(
|
|
515
|
+
p, self.layer_name, net_name=self.net_name, voids=list_void
|
|
516
|
+
),
|
|
517
|
+
self._app,
|
|
518
|
+
)
|
|
519
|
+
)
|
|
520
|
+
self.delete()
|
|
521
|
+
for prim in primitives:
|
|
522
|
+
if isinstance(prim, EDBPrimitives):
|
|
523
|
+
prim.delete()
|
|
524
|
+
else:
|
|
525
|
+
try:
|
|
526
|
+
prim.Delete()
|
|
527
|
+
except AttributeError:
|
|
528
|
+
continue
|
|
529
|
+
return new_polys
|
|
530
|
+
|
|
531
|
+
@pyedb_function_handler()
|
|
532
|
+
def unite(self, primitives):
|
|
533
|
+
"""Unite active primitive with one or more primitives.
|
|
534
|
+
|
|
535
|
+
Parameters
|
|
536
|
+
----------
|
|
537
|
+
primitives : :class:`dotnet.edb_core.edb_data.EDBPrimitives` or EDB PolygonData or EDB Primitive or list
|
|
538
|
+
|
|
539
|
+
Returns
|
|
540
|
+
-------
|
|
541
|
+
List of :class:`dotnet.edb_core.edb_data.EDBPrimitives`
|
|
542
|
+
"""
|
|
543
|
+
poly = self.primitive_object.GetPolygonData()
|
|
544
|
+
if not isinstance(primitives, list):
|
|
545
|
+
primitives = [primitives]
|
|
546
|
+
primi_polys = []
|
|
547
|
+
for prim in primitives:
|
|
548
|
+
if isinstance(prim, EDBPrimitives):
|
|
549
|
+
primi_polys.append(prim.primitive_object.GetPolygonData())
|
|
550
|
+
else:
|
|
551
|
+
try:
|
|
552
|
+
primi_polys.append(prim.GetPolygonData())
|
|
553
|
+
except:
|
|
554
|
+
primi_polys.append(prim)
|
|
555
|
+
list_poly = poly.Unite(convert_py_list_to_net_list([poly] + primi_polys))
|
|
556
|
+
new_polys = []
|
|
557
|
+
if list_poly:
|
|
558
|
+
voids = self.voids
|
|
559
|
+
for p in list_poly:
|
|
560
|
+
if p.IsNull():
|
|
561
|
+
continue
|
|
562
|
+
list_void = []
|
|
563
|
+
if voids:
|
|
564
|
+
for void in voids:
|
|
565
|
+
void_pdata = void.primitive_object.GetPolygonData()
|
|
566
|
+
int_data2 = p.GetIntersectionType(void_pdata)
|
|
567
|
+
if int_data2 > 1:
|
|
568
|
+
list_void.append(void_pdata)
|
|
569
|
+
new_polys.append(
|
|
570
|
+
cast(
|
|
571
|
+
self._app.modeler.create_polygon(p, self.layer_name, net_name=self.net_name, voids=list_void),
|
|
572
|
+
self._app,
|
|
573
|
+
)
|
|
574
|
+
)
|
|
575
|
+
self.delete()
|
|
576
|
+
for prim in primitives:
|
|
577
|
+
if isinstance(prim, EDBPrimitives):
|
|
578
|
+
prim.delete()
|
|
579
|
+
else:
|
|
580
|
+
try:
|
|
581
|
+
prim.Delete()
|
|
582
|
+
except AttributeError:
|
|
583
|
+
continue
|
|
584
|
+
return new_polys
|
|
585
|
+
|
|
586
|
+
@pyedb_function_handler()
|
|
587
|
+
def intersection_type(self, primitive):
|
|
588
|
+
"""Get intersection type between actual primitive and another primitive or polygon data.
|
|
589
|
+
|
|
590
|
+
Parameters
|
|
591
|
+
----------
|
|
592
|
+
primitive : :class:`pyaeedt.edb_core.edb_data.primitives_data.EDBPrimitives` or `PolygonData`
|
|
593
|
+
|
|
594
|
+
Returns
|
|
595
|
+
-------
|
|
596
|
+
int
|
|
597
|
+
Intersection type:
|
|
598
|
+
0 - objects do not intersect,
|
|
599
|
+
1 - this object fully inside other (no common contour points),
|
|
600
|
+
2 - other object fully inside this,
|
|
601
|
+
3 - common contour points,
|
|
602
|
+
4 - undefined intersection.
|
|
603
|
+
"""
|
|
604
|
+
poly = primitive
|
|
605
|
+
try:
|
|
606
|
+
poly = primitive.polygon_data
|
|
607
|
+
except AttributeError:
|
|
608
|
+
pass
|
|
609
|
+
return int(self.polygon_data.edb_api.GetIntersectionType(poly.edb_api))
|
|
610
|
+
|
|
611
|
+
@pyedb_function_handler()
|
|
612
|
+
def is_intersecting(self, primitive):
|
|
613
|
+
"""Check if actual primitive and another primitive or polygon data intesects.
|
|
614
|
+
|
|
615
|
+
Parameters
|
|
616
|
+
----------
|
|
617
|
+
primitive : :class:`pyaeedt.edb_core.edb_data.primitives_data.EDBPrimitives` or `PolygonData`
|
|
618
|
+
|
|
619
|
+
Returns
|
|
620
|
+
-------
|
|
621
|
+
bool
|
|
622
|
+
"""
|
|
623
|
+
return True if self.intersection_type(primitive) >= 1 else False
|
|
624
|
+
|
|
625
|
+
@pyedb_function_handler()
|
|
626
|
+
def get_closest_point(self, point):
|
|
627
|
+
"""Get the closest point of the primitive to the input data.
|
|
628
|
+
|
|
629
|
+
Parameters
|
|
630
|
+
----------
|
|
631
|
+
point : list of float or PointData
|
|
632
|
+
|
|
633
|
+
Returns
|
|
634
|
+
-------
|
|
635
|
+
list of float
|
|
636
|
+
"""
|
|
637
|
+
if isinstance(point, (list, tuple)):
|
|
638
|
+
point = self._app.edb_api.geometry.point_data(self._app.edb_value(point[0]), self._app.edb_value(point[1]))
|
|
639
|
+
|
|
640
|
+
p0 = self.polygon_data.edb_api.GetClosestPoint(point)
|
|
641
|
+
return [p0.X.ToDouble(), p0.Y.ToDouble()]
|
|
642
|
+
|
|
643
|
+
@pyedb_function_handler()
|
|
644
|
+
def get_closest_arc_midpoint(self, point):
|
|
645
|
+
"""Get the closest arc midpoint of the primitive to the input data.
|
|
646
|
+
|
|
647
|
+
Parameters
|
|
648
|
+
----------
|
|
649
|
+
point : list of float or PointData
|
|
650
|
+
|
|
651
|
+
Returns
|
|
652
|
+
-------
|
|
653
|
+
list of float
|
|
654
|
+
"""
|
|
655
|
+
if isinstance(point, self._app.edb_api.geometry.geometry.PointData):
|
|
656
|
+
point = [point.X.ToDouble(), point.Y.ToDouble()]
|
|
657
|
+
dist = 1e12
|
|
658
|
+
out = None
|
|
659
|
+
for arc in self.arcs:
|
|
660
|
+
mid_point = arc.mid_point
|
|
661
|
+
mid_point = [mid_point.X.ToDouble(), mid_point.Y.ToDouble()]
|
|
662
|
+
if GeometryOperators.points_distance(mid_point, point) < dist:
|
|
663
|
+
out = arc.mid_point
|
|
664
|
+
dist = GeometryOperators.points_distance(mid_point, point)
|
|
665
|
+
return [out.X.ToDouble(), out.Y.ToDouble()]
|
|
666
|
+
|
|
667
|
+
@property
|
|
668
|
+
def arcs(self):
|
|
669
|
+
"""Get the Primitive Arc Data."""
|
|
670
|
+
arcs = [EDBArcs(self, i) for i in self.polygon_data.arcs]
|
|
671
|
+
return arcs
|
|
672
|
+
|
|
673
|
+
@property
|
|
674
|
+
def longest_arc(self):
|
|
675
|
+
"""Get the longest arc."""
|
|
676
|
+
len = 0
|
|
677
|
+
arc = None
|
|
678
|
+
for i in self.arcs:
|
|
679
|
+
if i.is_segment and i.length > len:
|
|
680
|
+
arc = i
|
|
681
|
+
len = i.length
|
|
682
|
+
return arc
|
|
683
|
+
|
|
684
|
+
@property
|
|
685
|
+
def shortest_arc(self):
|
|
686
|
+
"""Get the longest arc."""
|
|
687
|
+
len = 1e12
|
|
688
|
+
arc = None
|
|
689
|
+
for i in self.arcs:
|
|
690
|
+
if i.is_segment and i.length < len:
|
|
691
|
+
arc = i
|
|
692
|
+
len = i.length
|
|
693
|
+
return arc
|
|
694
|
+
|
|
695
|
+
|
|
696
|
+
class EdbPath(EDBPrimitives, PathDotNet):
|
|
697
|
+
def __init__(self, raw_primitive, core_app):
|
|
698
|
+
EDBPrimitives.__init__(self, raw_primitive, core_app)
|
|
699
|
+
PathDotNet.__init__(self, self._app, raw_primitive)
|
|
700
|
+
|
|
701
|
+
@property
|
|
702
|
+
def width(self):
|
|
703
|
+
"""Path width.
|
|
704
|
+
|
|
705
|
+
Returns
|
|
706
|
+
-------
|
|
707
|
+
float
|
|
708
|
+
Path width or None.
|
|
709
|
+
"""
|
|
710
|
+
if self.type == "Path":
|
|
711
|
+
return self.primitive_object.GetWidth()
|
|
712
|
+
return
|
|
713
|
+
|
|
714
|
+
@width.setter
|
|
715
|
+
def width(self, value):
|
|
716
|
+
if self.type == "Path":
|
|
717
|
+
if isinstance(value, (int, str, float)):
|
|
718
|
+
self.primitive_object.SetWidth(self._app.edb_value(value))
|
|
719
|
+
else:
|
|
720
|
+
self.primitive_object.SetWidth(value)
|
|
721
|
+
|
|
722
|
+
@property
|
|
723
|
+
def length(self):
|
|
724
|
+
"""Path length in meters.
|
|
725
|
+
|
|
726
|
+
Returns
|
|
727
|
+
-------
|
|
728
|
+
float
|
|
729
|
+
Path length in meters.
|
|
730
|
+
"""
|
|
731
|
+
center_line_arcs = list(self.center_line.GetArcData())
|
|
732
|
+
path_length = 0.0
|
|
733
|
+
for arc in center_line_arcs:
|
|
734
|
+
path_length += arc.GetLength()
|
|
735
|
+
if self.end_cap_style[0]:
|
|
736
|
+
if not self.end_cap_style[1].value__ == 1:
|
|
737
|
+
path_length += self.width / 2
|
|
738
|
+
if not self.end_cap_style[2].value__ == 1:
|
|
739
|
+
path_length += self.width / 2
|
|
740
|
+
return path_length
|
|
741
|
+
|
|
742
|
+
@pyedb_function_handler()
|
|
743
|
+
def add_point(self, x, y, incremental=False):
|
|
744
|
+
"""Add a point at the end of the path.
|
|
745
|
+
|
|
746
|
+
Parameters
|
|
747
|
+
----------
|
|
748
|
+
x: str, int, float
|
|
749
|
+
X coordinate.
|
|
750
|
+
y: str, in, float
|
|
751
|
+
Y coordinate.
|
|
752
|
+
incremental: bool
|
|
753
|
+
Add point incrementally. If True, coordinates of the added point is incremental to the last point.
|
|
754
|
+
The default value is ``False``.
|
|
755
|
+
|
|
756
|
+
Returns
|
|
757
|
+
-------
|
|
758
|
+
bool
|
|
759
|
+
"""
|
|
760
|
+
center_line = PolygonDataDotNet(self._pedb, self._edb_object.GetCenterLine())
|
|
761
|
+
center_line.add_point(x, y, incremental)
|
|
762
|
+
return self._edb_object.SetCenterLine(center_line.edb_api)
|
|
763
|
+
|
|
764
|
+
@pyedb_function_handler()
|
|
765
|
+
def get_center_line(self, to_string=False):
|
|
766
|
+
"""Get the center line of the trace.
|
|
767
|
+
|
|
768
|
+
Parameters
|
|
769
|
+
----------
|
|
770
|
+
to_string : bool, optional
|
|
771
|
+
Type of return. The default is ``"False"``.
|
|
772
|
+
|
|
773
|
+
Returns
|
|
774
|
+
-------
|
|
775
|
+
list
|
|
776
|
+
|
|
777
|
+
"""
|
|
778
|
+
if to_string:
|
|
779
|
+
return [[p.X.ToString(), p.Y.ToString()] for p in list(self.primitive_object.GetCenterLine().Points)]
|
|
780
|
+
else:
|
|
781
|
+
return [[p.X.ToDouble(), p.Y.ToDouble()] for p in list(self.primitive_object.GetCenterLine().Points)]
|
|
782
|
+
|
|
783
|
+
@pyedb_function_handler()
|
|
784
|
+
def clone(self):
|
|
785
|
+
"""Clone a primitive object with keeping same definition and location.
|
|
786
|
+
|
|
787
|
+
Returns
|
|
788
|
+
-------
|
|
789
|
+
bool
|
|
790
|
+
``True`` when successful, ``False`` when failed.
|
|
791
|
+
"""
|
|
792
|
+
center_line = self.center_line
|
|
793
|
+
width = self.width
|
|
794
|
+
corner_style = self.corner_style
|
|
795
|
+
end_cap_style = self.end_cap_style
|
|
796
|
+
cloned_path = self._app.edb_api.cell.primitive.path.create(
|
|
797
|
+
self._app.active_layout,
|
|
798
|
+
self.layer_name,
|
|
799
|
+
self.net,
|
|
800
|
+
width,
|
|
801
|
+
end_cap_style[1],
|
|
802
|
+
end_cap_style[2],
|
|
803
|
+
corner_style,
|
|
804
|
+
center_line,
|
|
805
|
+
)
|
|
806
|
+
if cloned_path:
|
|
807
|
+
return cloned_path
|
|
808
|
+
|
|
809
|
+
# @pyedb_function_handler()
|
|
810
|
+
@pyedb_function_handler()
|
|
811
|
+
def create_edge_port(
|
|
812
|
+
self,
|
|
813
|
+
name,
|
|
814
|
+
position="End",
|
|
815
|
+
port_type="Wave",
|
|
816
|
+
reference_layer=None,
|
|
817
|
+
horizontal_extent_factor=5,
|
|
818
|
+
vertical_extent_factor=3,
|
|
819
|
+
pec_launch_width="0.01mm",
|
|
820
|
+
):
|
|
821
|
+
"""
|
|
822
|
+
|
|
823
|
+
Parameters
|
|
824
|
+
----------
|
|
825
|
+
name : str
|
|
826
|
+
Name of the port.
|
|
827
|
+
position : str, optional
|
|
828
|
+
Position of the port. The default is ``"End"``, in which case the port is created at the end of the trace.
|
|
829
|
+
Options are ``"Start"`` and ``"End"``.
|
|
830
|
+
port_type : str, optional
|
|
831
|
+
Type of the port. The default is ``"Wave"``, in which case a wave port is created. Options are ``"Wave"``
|
|
832
|
+
and ``"Gap"``.
|
|
833
|
+
reference_layer : str, optional
|
|
834
|
+
Name of the references layer. The default is ``None``. Only available for gap port.
|
|
835
|
+
horizontal_extent_factor : int, optional
|
|
836
|
+
Horizontal extent factor of the wave port. The default is ``5``.
|
|
837
|
+
vertical_extent_factor : int, optional
|
|
838
|
+
Vertical extent factor of the wave port. The default is ``3``.
|
|
839
|
+
pec_launch_width : float, str, optional
|
|
840
|
+
Perfect electrical conductor width of the wave port. The default is ``"0.01mm"``.
|
|
841
|
+
|
|
842
|
+
Returns
|
|
843
|
+
-------
|
|
844
|
+
:class:`dotnet.edb_core.edb_data.sources.ExcitationPorts`
|
|
845
|
+
|
|
846
|
+
Examples
|
|
847
|
+
--------
|
|
848
|
+
>>> edbapp = pyedb.dotnet.Edb("myproject.aedb")
|
|
849
|
+
>>> sig = appedb.modeler.create_trace([[0, 0], ["9mm", 0]], "TOP", "1mm", "SIG", "Flat", "Flat")
|
|
850
|
+
>>> sig.create_edge_port("pcb_port", "end", "Wave", None, 8, 8)
|
|
851
|
+
|
|
852
|
+
"""
|
|
853
|
+
center_line = self.get_center_line()
|
|
854
|
+
pos = center_line[-1] if position.lower() == "end" else center_line[0]
|
|
855
|
+
|
|
856
|
+
if port_type.lower() == "wave":
|
|
857
|
+
return self._app.hfss.create_wave_port(
|
|
858
|
+
self.id, pos, name, 50, horizontal_extent_factor, vertical_extent_factor, pec_launch_width
|
|
859
|
+
)
|
|
860
|
+
else:
|
|
861
|
+
return self._app.hfss.create_edge_port_vertical(self.id, pos, name, 50, reference_layer)
|
|
862
|
+
|
|
863
|
+
@pyedb_function_handler()
|
|
864
|
+
def create_via_fence(self, distance, gap, padstack_name):
|
|
865
|
+
"""Create via fences on both sides of the trace.
|
|
866
|
+
|
|
867
|
+
Parameters
|
|
868
|
+
----------
|
|
869
|
+
distance: str, float
|
|
870
|
+
Distance between via fence and trace center line.
|
|
871
|
+
gap: str, float
|
|
872
|
+
Gap between vias.
|
|
873
|
+
padstack_name: str
|
|
874
|
+
Name of the via padstack.
|
|
875
|
+
|
|
876
|
+
Returns
|
|
877
|
+
-------
|
|
878
|
+
"""
|
|
879
|
+
|
|
880
|
+
def getAngle(v1, v2): # pragma: no cover
|
|
881
|
+
v1_mag = math.sqrt(v1[0] ** 2 + v1[1] ** 2)
|
|
882
|
+
v2_mag = math.sqrt(v2[0] ** 2 + v2[1] ** 2)
|
|
883
|
+
dotsum = v1[0] * v2[0] + v1[1] * v2[1]
|
|
884
|
+
if v1[0] * v2[1] - v1[1] * v2[0] > 0:
|
|
885
|
+
scale = 1
|
|
886
|
+
else:
|
|
887
|
+
scale = -1
|
|
888
|
+
dtheta = scale * math.acos(dotsum / (v1_mag * v2_mag))
|
|
889
|
+
|
|
890
|
+
return dtheta
|
|
891
|
+
|
|
892
|
+
def getLocations(line, gap): # pragma: no cover
|
|
893
|
+
location = [line[0]]
|
|
894
|
+
residual = 0
|
|
895
|
+
|
|
896
|
+
for n in range(len(line) - 1):
|
|
897
|
+
x0, y0 = line[n]
|
|
898
|
+
x1, y1 = line[n + 1]
|
|
899
|
+
length = math.sqrt((x1 - x0) ** 2 + (y1 - y0) ** 2)
|
|
900
|
+
dx, dy = (x1 - x0) / length, (y1 - y0) / length
|
|
901
|
+
x = x0 - dx * residual
|
|
902
|
+
y = y0 - dy * residual
|
|
903
|
+
length = length + residual
|
|
904
|
+
while length >= gap:
|
|
905
|
+
x += gap * dx
|
|
906
|
+
y += gap * dy
|
|
907
|
+
location.append((x, y))
|
|
908
|
+
length -= gap
|
|
909
|
+
|
|
910
|
+
residual = length
|
|
911
|
+
return location
|
|
912
|
+
|
|
913
|
+
def getParalletLines(pts, distance): # pragma: no cover
|
|
914
|
+
leftline = []
|
|
915
|
+
rightline = []
|
|
916
|
+
|
|
917
|
+
x0, y0 = pts[0]
|
|
918
|
+
x1, y1 = pts[1]
|
|
919
|
+
vector = (x1 - x0, y1 - y0)
|
|
920
|
+
orientation1 = getAngle((1, 0), vector)
|
|
921
|
+
|
|
922
|
+
leftturn = orientation1 + math.pi / 2
|
|
923
|
+
righrturn = orientation1 - math.pi / 2
|
|
924
|
+
leftPt = (x0 + distance * math.cos(leftturn), y0 + distance * math.sin(leftturn))
|
|
925
|
+
leftline.append(leftPt)
|
|
926
|
+
rightPt = (x0 + distance * math.cos(righrturn), y0 + distance * math.sin(righrturn))
|
|
927
|
+
rightline.append(rightPt)
|
|
928
|
+
|
|
929
|
+
for n in range(1, len(pts) - 1):
|
|
930
|
+
x0, y0 = pts[n - 1]
|
|
931
|
+
x1, y1 = pts[n]
|
|
932
|
+
x2, y2 = pts[n + 1]
|
|
933
|
+
|
|
934
|
+
v1 = (x1 - x0, y1 - y0)
|
|
935
|
+
v2 = (x2 - x1, y2 - y1)
|
|
936
|
+
dtheta = getAngle(v1, v2)
|
|
937
|
+
orientation1 = getAngle((1, 0), v1)
|
|
938
|
+
|
|
939
|
+
leftturn = orientation1 + dtheta / 2 + math.pi / 2
|
|
940
|
+
righrturn = orientation1 + dtheta / 2 - math.pi / 2
|
|
941
|
+
|
|
942
|
+
distance2 = distance / math.sin((math.pi - dtheta) / 2)
|
|
943
|
+
leftPt = (x1 + distance2 * math.cos(leftturn), y1 + distance2 * math.sin(leftturn))
|
|
944
|
+
leftline.append(leftPt)
|
|
945
|
+
rightPt = (x1 + distance2 * math.cos(righrturn), y1 + distance2 * math.sin(righrturn))
|
|
946
|
+
rightline.append(rightPt)
|
|
947
|
+
|
|
948
|
+
x0, y0 = pts[-2]
|
|
949
|
+
x1, y1 = pts[-1]
|
|
950
|
+
|
|
951
|
+
vector = (x1 - x0, y1 - y0)
|
|
952
|
+
orientation1 = getAngle((1, 0), vector)
|
|
953
|
+
leftturn = orientation1 + math.pi / 2
|
|
954
|
+
righrturn = orientation1 - math.pi / 2
|
|
955
|
+
leftPt = (x1 + distance * math.cos(leftturn), y1 + distance * math.sin(leftturn))
|
|
956
|
+
leftline.append(leftPt)
|
|
957
|
+
rightPt = (x1 + distance * math.cos(righrturn), y1 + distance * math.sin(righrturn))
|
|
958
|
+
rightline.append(rightPt)
|
|
959
|
+
return leftline, rightline
|
|
960
|
+
|
|
961
|
+
distance = self._pedb.edb_value(distance).ToDouble()
|
|
962
|
+
gap = self._pedb.edb_value(gap).ToDouble()
|
|
963
|
+
center_line = self.get_center_line()
|
|
964
|
+
leftline, rightline = getParalletLines(center_line, distance)
|
|
965
|
+
for x, y in getLocations(rightline, gap) + getLocations(leftline, gap):
|
|
966
|
+
self._pedb.padstacks.place([x, y], padstack_name)
|
|
967
|
+
|
|
968
|
+
|
|
969
|
+
class EdbRectangle(EDBPrimitives, RectangleDotNet):
|
|
970
|
+
def __init__(self, raw_primitive, core_app):
|
|
971
|
+
EDBPrimitives.__init__(self, raw_primitive, core_app)
|
|
972
|
+
RectangleDotNet.__init__(self, self._app, raw_primitive)
|
|
973
|
+
|
|
974
|
+
|
|
975
|
+
class EdbCircle(EDBPrimitives, CircleDotNet):
|
|
976
|
+
def __init__(self, raw_primitive, core_app):
|
|
977
|
+
EDBPrimitives.__init__(self, raw_primitive, core_app)
|
|
978
|
+
CircleDotNet.__init__(self, self._app, raw_primitive)
|
|
979
|
+
|
|
980
|
+
|
|
981
|
+
class EdbPolygon(EDBPrimitives, PolygonDotNet):
|
|
982
|
+
def __init__(self, raw_primitive, core_app):
|
|
983
|
+
EDBPrimitives.__init__(self, raw_primitive, core_app)
|
|
984
|
+
PolygonDotNet.__init__(self, self._app, raw_primitive)
|
|
985
|
+
|
|
986
|
+
@pyedb_function_handler()
|
|
987
|
+
def clone(self):
|
|
988
|
+
"""Clone a primitive object with keeping same definition and location.
|
|
989
|
+
|
|
990
|
+
Returns
|
|
991
|
+
-------
|
|
992
|
+
bool
|
|
993
|
+
``True`` when successful, ``False`` when failed.
|
|
994
|
+
"""
|
|
995
|
+
cloned_poly = self._app.edb_api.cell.primitive.polygon.create(
|
|
996
|
+
self._app.active_layout, self.layer_name, self.net, self.polygon_data.edb_api
|
|
997
|
+
)
|
|
998
|
+
if cloned_poly:
|
|
999
|
+
for void in self.voids:
|
|
1000
|
+
cloned_void = self._app.edb_api.cell.primitive.polygon.create(
|
|
1001
|
+
self._app.active_layout, self.layer_name, self.net, void.polygon_data.edb_api
|
|
1002
|
+
)
|
|
1003
|
+
# cloned_void
|
|
1004
|
+
cloned_poly.prim_obj.AddVoid(cloned_void.prim_obj)
|
|
1005
|
+
return cloned_poly
|
|
1006
|
+
return False
|
|
1007
|
+
|
|
1008
|
+
@pyedb_function_handler
|
|
1009
|
+
def move(self, vector):
|
|
1010
|
+
"""Move polygon along a vector.
|
|
1011
|
+
|
|
1012
|
+
Parameters
|
|
1013
|
+
----------
|
|
1014
|
+
vector : List of float or str [x,y].
|
|
1015
|
+
|
|
1016
|
+
Returns
|
|
1017
|
+
-------
|
|
1018
|
+
bool
|
|
1019
|
+
``True`` when successful, ``False`` when failed.
|
|
1020
|
+
|
|
1021
|
+
Examples
|
|
1022
|
+
--------
|
|
1023
|
+
>>> edbapp = pyaedt.Edb("myproject.aedb")
|
|
1024
|
+
>>> top_layer_polygon = [poly for poly in edbapp.modeler.polygons if poly.layer_name == "Top Layer"]
|
|
1025
|
+
>>> for polygon in top_layer_polygon:
|
|
1026
|
+
>>> polygon.move(vector=["2mm", "100um"])
|
|
1027
|
+
"""
|
|
1028
|
+
if vector and isinstance(vector, list) and len(vector) == 2:
|
|
1029
|
+
_vector = self._edb.Geometry.PointData(
|
|
1030
|
+
self._edb.Utility.Value(vector[0]), self._edb.Utility.Value(vector[1])
|
|
1031
|
+
)
|
|
1032
|
+
polygon_data = self._edb.Geometry.PolygonData.CreateFromArcs(self.polygon_data.edb_api.GetArcData(), True)
|
|
1033
|
+
polygon_data.Move(_vector)
|
|
1034
|
+
return self.api_object.SetPolygonData(polygon_data)
|
|
1035
|
+
return False
|
|
1036
|
+
|
|
1037
|
+
@pyedb_function_handler
|
|
1038
|
+
def rotate(self, angle, center=None):
|
|
1039
|
+
"""Rotate polygon around a center point by an angle.
|
|
1040
|
+
|
|
1041
|
+
Parameters
|
|
1042
|
+
----------
|
|
1043
|
+
angle : float
|
|
1044
|
+
Value of the rotation angle in degree.
|
|
1045
|
+
center : List of float or str [x,y], optional
|
|
1046
|
+
If None rotation is done from polygon center.
|
|
1047
|
+
|
|
1048
|
+
Returns
|
|
1049
|
+
-------
|
|
1050
|
+
bool
|
|
1051
|
+
``True`` when successful, ``False`` when failed.
|
|
1052
|
+
|
|
1053
|
+
Examples
|
|
1054
|
+
--------
|
|
1055
|
+
>>> edbapp = pyaedt.Edb("myproject.aedb")
|
|
1056
|
+
>>> top_layer_polygon = [poly for poly in edbapp.modeler.polygons if poly.layer_name == "Top Layer"]
|
|
1057
|
+
>>> for polygon in top_layer_polygon:
|
|
1058
|
+
>>> polygon.rotate(angle=45)
|
|
1059
|
+
"""
|
|
1060
|
+
if angle:
|
|
1061
|
+
polygon_data = self._edb.Geometry.PolygonData.CreateFromArcs(self.polygon_data.edb_api.GetArcData(), True)
|
|
1062
|
+
if not center:
|
|
1063
|
+
center = polygon_data.GetBoundingCircleCenter()
|
|
1064
|
+
if center:
|
|
1065
|
+
polygon_data.Rotate(angle * math.pi / 180, center)
|
|
1066
|
+
return self.api_object.SetPolygonData(polygon_data)
|
|
1067
|
+
elif isinstance(center, list) and len(center) == 2:
|
|
1068
|
+
center = self._edb.Geometry.PointData(
|
|
1069
|
+
self._edb.Utility.Value(center[0]), self._edb.Utility.Value(center[1])
|
|
1070
|
+
)
|
|
1071
|
+
polygon_data.Rotate(angle * math.pi / 180, center)
|
|
1072
|
+
return self.api_object.SetPolygonData(polygon_data)
|
|
1073
|
+
return False
|
|
1074
|
+
|
|
1075
|
+
@pyedb_function_handler
|
|
1076
|
+
def scale(self, factor, center=None):
|
|
1077
|
+
"""Scales the polygon relative to a center point by a factor.
|
|
1078
|
+
|
|
1079
|
+
Parameters
|
|
1080
|
+
----------
|
|
1081
|
+
factor : float
|
|
1082
|
+
Scaling factor.
|
|
1083
|
+
center : List of float or str [x,y], optional
|
|
1084
|
+
If None scaling is done from polygon center.
|
|
1085
|
+
|
|
1086
|
+
Returns
|
|
1087
|
+
-------
|
|
1088
|
+
bool
|
|
1089
|
+
``True`` when successful, ``False`` when failed.
|
|
1090
|
+
|
|
1091
|
+
Examples
|
|
1092
|
+
--------
|
|
1093
|
+
>>> edbapp = pyaedt.Edb("myproject.aedb")
|
|
1094
|
+
>>> top_layer_polygon = [poly for poly in edbapp.modeler.polygons if poly.layer_name == "Top Layer"]
|
|
1095
|
+
>>> for polygon in top_layer_polygon:
|
|
1096
|
+
>>> polygon.scale(factor=2)
|
|
1097
|
+
"""
|
|
1098
|
+
if not isinstance(factor, str):
|
|
1099
|
+
factor = float(factor)
|
|
1100
|
+
polygon_data = self._edb.Geometry.PolygonData.CreateFromArcs(self.polygon_data.edb_api.GetArcData(), True)
|
|
1101
|
+
if not center:
|
|
1102
|
+
center = polygon_data.GetBoundingCircleCenter()
|
|
1103
|
+
if center:
|
|
1104
|
+
polygon_data.Scale(factor, center)
|
|
1105
|
+
return self.api_object.SetPolygonData(polygon_data)
|
|
1106
|
+
elif isinstance(center, list) and len(center) == 2:
|
|
1107
|
+
center = self._edb.Geometry.PointData(
|
|
1108
|
+
self._edb.Utility.Value(center[0]), self._edb.Utility.Value(center[1])
|
|
1109
|
+
)
|
|
1110
|
+
polygon_data.Scale(factor, center)
|
|
1111
|
+
return self.api_object.SetPolygonData(polygon_data)
|
|
1112
|
+
return False
|
|
1113
|
+
|
|
1114
|
+
@pyedb_function_handler
|
|
1115
|
+
def move_layer(self, layer):
|
|
1116
|
+
"""Move polygon to given layer.
|
|
1117
|
+
|
|
1118
|
+
Parameters
|
|
1119
|
+
----------
|
|
1120
|
+
layer : str
|
|
1121
|
+
layer name.
|
|
1122
|
+
|
|
1123
|
+
Returns
|
|
1124
|
+
-------
|
|
1125
|
+
bool
|
|
1126
|
+
``True`` when successful, ``False`` when failed.
|
|
1127
|
+
"""
|
|
1128
|
+
if layer and isinstance(layer, str) and layer in self._pedb.stackup.signal_layers:
|
|
1129
|
+
polygon_data = self._edb.Geometry.PolygonData.CreateFromArcs(self.polygon_data.edb_api.GetArcData(), True)
|
|
1130
|
+
moved_polygon = self._pedb.modeler.create_polygon(
|
|
1131
|
+
main_shape=polygon_data, net_name=self.net_name, layer_name=layer
|
|
1132
|
+
)
|
|
1133
|
+
if moved_polygon:
|
|
1134
|
+
self.delete()
|
|
1135
|
+
return True
|
|
1136
|
+
return False
|
|
1137
|
+
|
|
1138
|
+
@pyedb_function_handler()
|
|
1139
|
+
def in_polygon(
|
|
1140
|
+
self,
|
|
1141
|
+
point_data,
|
|
1142
|
+
include_partial=True,
|
|
1143
|
+
):
|
|
1144
|
+
"""Check if padstack Instance is in given polygon data.
|
|
1145
|
+
|
|
1146
|
+
Parameters
|
|
1147
|
+
----------
|
|
1148
|
+
point_data : PointData Object or list of float
|
|
1149
|
+
include_partial : bool, optional
|
|
1150
|
+
Whether to include partial intersecting instances. The default is ``True``.
|
|
1151
|
+
|
|
1152
|
+
Returns
|
|
1153
|
+
-------
|
|
1154
|
+
bool
|
|
1155
|
+
``True`` when successful, ``False`` when failed.
|
|
1156
|
+
"""
|
|
1157
|
+
if isinstance(point_data, list):
|
|
1158
|
+
point_data = self._app.edb_api.geometry.point_data(
|
|
1159
|
+
self._app.edb_value(point_data[0]), self._app.edb_value(point_data[1])
|
|
1160
|
+
)
|
|
1161
|
+
int_val = int(self.polygon_data.edb_api.PointInPolygon(point_data))
|
|
1162
|
+
|
|
1163
|
+
# Intersection type:
|
|
1164
|
+
# 0 = objects do not intersect
|
|
1165
|
+
# 1 = this object fully inside other (no common contour points)
|
|
1166
|
+
# 2 = other object fully inside this
|
|
1167
|
+
# 3 = common contour points 4 = undefined intersection
|
|
1168
|
+
if int_val == 0:
|
|
1169
|
+
return False
|
|
1170
|
+
elif include_partial:
|
|
1171
|
+
return True
|
|
1172
|
+
elif int_val < 3:
|
|
1173
|
+
return True
|
|
1174
|
+
else:
|
|
1175
|
+
return False
|
|
1176
|
+
|
|
1177
|
+
# @pyedb_function_handler()
|
|
1178
|
+
# def add_void(self, point_list):
|
|
1179
|
+
# """Add a void to current primitive.
|
|
1180
|
+
#
|
|
1181
|
+
# Parameters
|
|
1182
|
+
# ----------
|
|
1183
|
+
# point_list : list or :class:`dotnet.edb_core.edb_data.primitives_data.EDBPrimitives` or EDB Primitive Object
|
|
1184
|
+
# Point list in the format of `[[x1,y1], [x2,y2],..,[xn,yn]]`.
|
|
1185
|
+
#
|
|
1186
|
+
# Returns
|
|
1187
|
+
# -------
|
|
1188
|
+
# bool
|
|
1189
|
+
# ``True`` if successful, either ``False``.
|
|
1190
|
+
# """
|
|
1191
|
+
# if isinstance(point_list, list):
|
|
1192
|
+
# plane = self._app.modeler.Shape("polygon", points=point_list)
|
|
1193
|
+
# _poly = self._app.modeler.shape_to_polygon_data(plane)
|
|
1194
|
+
# if _poly is None or _poly.IsNull() or _poly is False:
|
|
1195
|
+
# self._logger.error("Failed to create void polygon data")
|
|
1196
|
+
# return False
|
|
1197
|
+
# prim = self._app.edb_api.cell.primitive.polygon.create(
|
|
1198
|
+
# self._app.active_layout, self.layer_name, self.primitive_object.GetNet(), _poly
|
|
1199
|
+
# )
|
|
1200
|
+
# elif isinstance(point_list, EDBPrimitives):
|
|
1201
|
+
# prim = point_list.primitive_object
|
|
1202
|
+
# else:
|
|
1203
|
+
# prim = point_list
|
|
1204
|
+
# return self.add_void(prim)
|
|
1205
|
+
|
|
1206
|
+
|
|
1207
|
+
class EdbText(EDBPrimitivesMain, TextDotNet):
|
|
1208
|
+
def __init__(self, raw_primitive, core_app):
|
|
1209
|
+
EDBPrimitives.__init__(self, raw_primitive, core_app)
|
|
1210
|
+
TextDotNet.__init__(self, self._app, raw_primitive)
|
|
1211
|
+
|
|
1212
|
+
|
|
1213
|
+
class EdbBondwire(EDBPrimitivesMain, BondwireDotNet):
|
|
1214
|
+
def __init__(self, raw_primitive, core_app):
|
|
1215
|
+
EDBPrimitives.__init__(self, raw_primitive, core_app)
|
|
1216
|
+
BondwireDotNet.__init__(self, self._app, raw_primitive)
|
|
1217
|
+
|
|
1218
|
+
|
|
1219
|
+
class EDBArcs(object):
|
|
1220
|
+
"""Manages EDB Arc Data functionalities.
|
|
1221
|
+
It Inherits EDB primitives arcs properties.
|
|
1222
|
+
|
|
1223
|
+
Examples
|
|
1224
|
+
--------
|
|
1225
|
+
>>> from pyedb import Edb
|
|
1226
|
+
>>> edb = Edb(myedb, edbversion="2021.2")
|
|
1227
|
+
>>> prim_arcs = edb.modeler.primitives[0].arcs
|
|
1228
|
+
>>> prim_arcs.center # arc center
|
|
1229
|
+
>>> prim_arcs.points # arc point list
|
|
1230
|
+
>>> prim_arcs.mid_point # arc mid point
|
|
1231
|
+
"""
|
|
1232
|
+
|
|
1233
|
+
def __init__(self, app, arc):
|
|
1234
|
+
self._app = app
|
|
1235
|
+
self.arc_object = arc
|
|
1236
|
+
|
|
1237
|
+
@property
|
|
1238
|
+
def start(self):
|
|
1239
|
+
"""Get the coordinates of the starting point.
|
|
1240
|
+
|
|
1241
|
+
Returns
|
|
1242
|
+
-------
|
|
1243
|
+
list
|
|
1244
|
+
List containing the X and Y coordinates of the starting point.
|
|
1245
|
+
|
|
1246
|
+
|
|
1247
|
+
Examples
|
|
1248
|
+
--------
|
|
1249
|
+
>>> appedb = Edb(fpath, edbversion="2023.2")
|
|
1250
|
+
>>> start_coordinate = appedb.nets["V1P0_S0"].primitives[0].arcs[0].start
|
|
1251
|
+
>>> print(start_coordinate)
|
|
1252
|
+
[x_value, y_value]
|
|
1253
|
+
"""
|
|
1254
|
+
point = self.arc_object.Start
|
|
1255
|
+
return [point.X.ToDouble(), point.Y.ToDouble()]
|
|
1256
|
+
|
|
1257
|
+
@property
|
|
1258
|
+
def end(self):
|
|
1259
|
+
"""Get the coordinates of the ending point.
|
|
1260
|
+
|
|
1261
|
+
Returns
|
|
1262
|
+
-------
|
|
1263
|
+
list
|
|
1264
|
+
List containing the X and Y coordinates of the ending point.
|
|
1265
|
+
|
|
1266
|
+
Examples
|
|
1267
|
+
--------
|
|
1268
|
+
>>> appedb = Edb(fpath, edbversion="2023.2")
|
|
1269
|
+
>>> end_coordinate = appedb.nets["V1P0_S0"].primitives[0].arcs[0].end
|
|
1270
|
+
"""
|
|
1271
|
+
point = self.arc_object.End
|
|
1272
|
+
return [point.X.ToDouble(), point.Y.ToDouble()]
|
|
1273
|
+
|
|
1274
|
+
@property
|
|
1275
|
+
def height(self):
|
|
1276
|
+
"""Get the height of the arc.
|
|
1277
|
+
|
|
1278
|
+
Returns
|
|
1279
|
+
-------
|
|
1280
|
+
float
|
|
1281
|
+
Height of the arc.
|
|
1282
|
+
|
|
1283
|
+
|
|
1284
|
+
Examples
|
|
1285
|
+
--------
|
|
1286
|
+
>>> appedb = Edb(fpath, edbversion="2023.2")
|
|
1287
|
+
>>> arc_height = appedb.nets["V1P0_S0"].primitives[0].arcs[0].height
|
|
1288
|
+
"""
|
|
1289
|
+
return self.arc_object.Height
|
|
1290
|
+
|
|
1291
|
+
@property
|
|
1292
|
+
def center(self):
|
|
1293
|
+
"""Arc center.
|
|
1294
|
+
|
|
1295
|
+
Returns
|
|
1296
|
+
-------
|
|
1297
|
+
list
|
|
1298
|
+
"""
|
|
1299
|
+
cent = self.arc_object.GetCenter()
|
|
1300
|
+
return [cent.X.ToDouble(), cent.Y.ToDouble()]
|
|
1301
|
+
|
|
1302
|
+
@property
|
|
1303
|
+
def length(self):
|
|
1304
|
+
"""Arc length.
|
|
1305
|
+
|
|
1306
|
+
Returns
|
|
1307
|
+
-------
|
|
1308
|
+
float
|
|
1309
|
+
"""
|
|
1310
|
+
return self.arc_object.GetLength()
|
|
1311
|
+
|
|
1312
|
+
@property
|
|
1313
|
+
def mid_point(self):
|
|
1314
|
+
"""Arc mid point.
|
|
1315
|
+
|
|
1316
|
+
Returns
|
|
1317
|
+
-------
|
|
1318
|
+
float
|
|
1319
|
+
"""
|
|
1320
|
+
return self.arc_object.GetMidPoint()
|
|
1321
|
+
|
|
1322
|
+
@property
|
|
1323
|
+
def radius(self):
|
|
1324
|
+
"""Arc radius.
|
|
1325
|
+
|
|
1326
|
+
Returns
|
|
1327
|
+
-------
|
|
1328
|
+
float
|
|
1329
|
+
"""
|
|
1330
|
+
return self.arc_object.GetRadius()
|
|
1331
|
+
|
|
1332
|
+
@property
|
|
1333
|
+
def is_segment(self):
|
|
1334
|
+
"""Either if it is a straight segment or not.
|
|
1335
|
+
|
|
1336
|
+
Returns
|
|
1337
|
+
-------
|
|
1338
|
+
bool
|
|
1339
|
+
"""
|
|
1340
|
+
return self.arc_object.IsSegment()
|
|
1341
|
+
|
|
1342
|
+
@property
|
|
1343
|
+
def is_point(self):
|
|
1344
|
+
"""Either if it is a point or not.
|
|
1345
|
+
|
|
1346
|
+
Returns
|
|
1347
|
+
-------
|
|
1348
|
+
bool
|
|
1349
|
+
"""
|
|
1350
|
+
return self.arc_object.IsPoint()
|
|
1351
|
+
|
|
1352
|
+
@property
|
|
1353
|
+
def is_ccw(self):
|
|
1354
|
+
"""Test whether arc is counter clockwise.
|
|
1355
|
+
|
|
1356
|
+
Returns
|
|
1357
|
+
-------
|
|
1358
|
+
bool
|
|
1359
|
+
"""
|
|
1360
|
+
return self.arc_object.IsCCW()
|
|
1361
|
+
|
|
1362
|
+
@property
|
|
1363
|
+
def points_raw(self):
|
|
1364
|
+
"""Return a list of Edb points.
|
|
1365
|
+
|
|
1366
|
+
Returns
|
|
1367
|
+
-------
|
|
1368
|
+
list
|
|
1369
|
+
Edb Points.
|
|
1370
|
+
"""
|
|
1371
|
+
return list(self.arc_object.GetPointData())
|
|
1372
|
+
|
|
1373
|
+
@property
|
|
1374
|
+
def points(self, arc_segments=6):
|
|
1375
|
+
"""Return the list of points with arcs converted to segments.
|
|
1376
|
+
|
|
1377
|
+
Parameters
|
|
1378
|
+
----------
|
|
1379
|
+
arc_segments : int
|
|
1380
|
+
Number of facets to convert an arc. Default is `6`.
|
|
1381
|
+
|
|
1382
|
+
Returns
|
|
1383
|
+
-------
|
|
1384
|
+
list, list
|
|
1385
|
+
x and y list of points.
|
|
1386
|
+
"""
|
|
1387
|
+
try:
|
|
1388
|
+
my_net_points = self.points_raw
|
|
1389
|
+
xt, yt = self._app._get_points_for_plot(my_net_points, arc_segments)
|
|
1390
|
+
if not xt:
|
|
1391
|
+
return []
|
|
1392
|
+
x, y = GeometryOperators.orient_polygon(xt, yt, clockwise=True)
|
|
1393
|
+
return x, y
|
|
1394
|
+
except:
|
|
1395
|
+
x = []
|
|
1396
|
+
y = []
|
|
1397
|
+
return x, y
|