Skip to content

Commit

Permalink
Merge branch 'main' into release/0.4
Browse files Browse the repository at this point in the history
  • Loading branch information
maxcapodi78 authored and maxcapodi78 committed Mar 9, 2022
2 parents e0072c4 + 7876ead commit 3abf581
Show file tree
Hide file tree
Showing 15 changed files with 226 additions and 76 deletions.
2 changes: 1 addition & 1 deletion _unittest/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ def my_teardown(self):
oDesktop = sys.modules["__main__"].oDesktop
except Exception as e:
oDesktop = None
if oDesktop:
if oDesktop and not settings.non_graphical:
oDesktop.ClearMessages("", "", 3)
for edbapp in self.edbapps[::-1]:
try:
Expand Down
Binary file modified _unittest/example_models/Galileo_edb.aedb/edb.def
Binary file not shown.
37 changes: 23 additions & 14 deletions _unittest/test_00_EDB.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@

try:
import pytest
except ImportError:
import unittest.mock
except ImportError: # pragma: no cover
import _unittest_ironpython.conf_unittest as pytest


Expand Down Expand Up @@ -44,6 +45,17 @@ def test_00_export_ipc2581(self):
self.edbapp.export_to_ipc2581(ipc_path, "mm")
assert os.path.exists(ipc_path)

if not is_ironpython:
# Test the export_to_ipc2581 method when IPC8521.ExportIPC2581FromLayout raises an exception internally.
with unittest.mock.patch("pyaedt.Edb.edblib", new_callable=unittest.mock.PropertyMock) as edblib_mock:
Edb.edblib.IPC8521 = unittest.mock.Mock()
Edb.edblib.IPC8521.IPCExporter = unittest.mock.Mock()
Edb.edblib.IPC8521.IPCExporter.ExportIPC2581FromLayout = unittest.mock.Mock(
side_effect=Exception("Exception for testing raised in ExportIPC2581FromLayout.")
)

assert not self.edbapp.export_to_ipc2581(os.path.exists(ipc_path))

def test_01_find_by_name(self):
comp = self.edbapp.core_components.get_component_by_name("J1")
assert comp is not None
Expand Down Expand Up @@ -475,21 +487,17 @@ def test_55b_create_cutout(self):
assert self.edbapp.create_cutout(["A0_N", "A0_P"], ["GND"], output_aedb_path=output, open_cutout_at_end=False)
assert os.path.exists(os.path.join(output, "edb.def"))
bounding = self.edbapp.get_bounding_box()

cutout_line_x = 41
cutout_line_y = 30
points = [[bounding[0][0], bounding[0][1]]]
points.append([bounding[0][0], bounding[0][1] + (bounding[1][1] - bounding[0][1]) / 10])
points.append(
[
bounding[0][0] + (bounding[0][1] - bounding[0][0]) / 10,
bounding[0][1] + (bounding[1][1] - bounding[0][1]) / 10,
]
)
points.append([bounding[0][0] + (bounding[0][1] - bounding[0][0]) / 10, bounding[0][1]])
points.append([cutout_line_x, bounding[0][1]])
points.append([cutout_line_x, cutout_line_y])
points.append([bounding[0][0], cutout_line_y])
points.append([bounding[0][0], bounding[0][1]])
output = os.path.join(self.local_scratch.path, "cutout2.aedb")

assert self.edbapp.create_cutout_on_point_list(
points, nets_to_include=["GND"], output_aedb_path=output, open_cutout_at_end=False
points, nets_to_include=["GND", "V3P3_S0"], output_aedb_path=output, open_cutout_at_end=False
)
assert os.path.exists(os.path.join(output, "edb.def"))

Expand Down Expand Up @@ -708,16 +716,17 @@ def test_79_get_placement_vector(self):
hosting_component_pin2="A4",
)
assert result
assert abs(rotation - math.pi / 2) < 1e-9
assert abs(abs(rotation) - math.pi / 2) < 1e-9
assert solder_ball_height == 0.00033
assert len(vector) == 2
result, vector, rotation, solder_ball_height = self.edbapp.core_components.get_component_placement_vector(
mounted_component=mounted_cmp,
hosting_component=hosting_cmp,
mounted_component_pin1="A10",
mounted_component_pin2="A12",
hosting_component_pin1="A4",
hosting_component_pin2="A2",
hosting_component_pin1="A2",
hosting_component_pin2="A4",
flipped=True,
)
assert result
assert abs(rotation + math.pi / 2) < 1e-9
Expand Down
1 change: 1 addition & 0 deletions _unittest/test_00_downloads.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,4 @@ def test_download_antenna_sherlock(self):

def test_download_wfp(self):
assert self.examples.download_edb_merge_utility()
assert self.examples.download_edb_merge_utility(True)
58 changes: 58 additions & 0 deletions _unittest/test_08_Primitives3D.py
Original file line number Diff line number Diff line change
Expand Up @@ -1156,3 +1156,61 @@ def test_76_check_value_type(self):
assert boolean2
assert isinstance(resolve3, float)
assert not boolean3

@pyaedt_unittest_check_desktop_error
def test_77_create_helix(self):

udp1 = [0, 0, 0]
udp2 = [5, 0, 0]
udp3 = [10, 5, 0]
udp4 = [15, 3, 0]
polyline = self.aedtapp.modeler.create_polyline(
[udp1, udp2, udp3, udp4], cover_surface=False, name="helix_polyline"
)

helix_right_turn = self.aedtapp.modeler.create_helix(
polyline_name="helix_polyline",
position=[0, 0, 0],
x_start_dir=0,
y_start_dir=1.0,
z_start_dir=1.0,
num_thread=1,
right_hand=True,
radius_increment=0.0,
thread=1.0,
)

assert helix_right_turn.object_units == "mm"

# Test left turn without providing argument value for default parameters.
udp1 = [-45, 0, 0]
udp2 = [-50, 0, 0]
udp3 = [-105, 5, 0]
udp4 = [-110, 3, 0]
polyline_left = self.aedtapp.modeler.create_polyline(
[udp1, udp2, udp3, udp4], cover_surface=False, name="helix_polyline_left"
)

assert self.aedtapp.modeler.create_helix(
polyline_name="helix_polyline_left",
position=[0, 0, 0],
x_start_dir=1.0,
y_start_dir=1.0,
z_start_dir=1.0,
right_hand=False,
)

# Test that an exception is raised if the name of the polyline is not provided.
# We can't use with.pytest.raises pattern bellow because IronPython does not support pytest.
try:
self.aedtapp.modeler.create_helix(
polyline_name="",
position=[0, 0, 0],
x_start_dir=1.0,
y_start_dir=1.0,
z_start_dir=1.0,
)
except ValueError as exc_info:
assert "The name of the polyline cannot be an empty string." in str(exc_info.args[0])
else:
assert False
8 changes: 6 additions & 2 deletions examples/00-EDB/07_WPF_Merge_Utility.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@

from pyaedt.examples.downloads import download_edb_merge_utility

python_file = download_edb_merge_utility()

python_file = download_edb_merge_utility(force_download=True)
desktop_version = "2022.1"

######################################################################
# Python Script execution
Expand All @@ -35,3 +35,7 @@
#
# The json file contains default settings that can be used in any other project to automatically
# load all settings.
# The following command line can be unchecked and launched from python interpreter.

# from pyaedt.generic.toolkit import launch
# launch(python_file, specified_version=desktop_version, new_desktop_session=False, autosave=False)
7 changes: 5 additions & 2 deletions pyaedt/desktop.py
Original file line number Diff line number Diff line change
Expand Up @@ -284,21 +284,24 @@ def __init__(
self._main.pyaedt_version = pyaedtversion
self._main.interpreter_ver = _pythonver
self._main.student_version = student_version
settings.non_graphical = non_graphical
if is_ironpython:
self._main.isoutsideDesktop = False
else:
self._main.isoutsideDesktop = True
self.release_on_exit = True
self.logfile = None
if "oDesktop" in dir():
if "oDesktop" in dir(): # pragma: no cover
self.release_on_exit = False
self._main.oDesktop = oDesktop
elif "oDesktop" in dir(self._main) and self._main.oDesktop is not None:
settings.aedt_version = oDesktop.GetVersion()[0:6]
elif "oDesktop" in dir(self._main) and self._main.oDesktop is not None: # pragma: no cover
self.release_on_exit = False
else:
if "oDesktop" in dir(self._main):
del self._main.oDesktop
self._main.student_version, version_key, version = self._set_version(specified_version, student_version)
settings.aedt_version = version
if _com == "ironpython": # pragma: no cover
print("Launching PyAEDT outside AEDT with IronPython.")
self._init_ironpython(non_graphical, new_desktop_session, version)
Expand Down
65 changes: 37 additions & 28 deletions pyaedt/edb.py
Original file line number Diff line number Diff line change
Expand Up @@ -517,16 +517,19 @@ def export_to_ipc2581(self, ipc_path=None, units="millimeter"):
ipc_path = self.edbpath[:-4] + "xml"
self.logger.info("Export IPC 2581 is starting. This operation can take a while...")
start = time.time()
result = self.edblib.IPC8521.IPCExporter.ExportIPC2581FromLayout(
self.active_layout, self.edbversion, ipc_path, units.lower()
)
end = time.time() - start
if result:
self.logger.info("Export IPC 2581 completed in %s sec.", end)
self.logger.info("File saved as %s", ipc_path)
return ipc_path
self.logger.info("Error Exporting IPC 2581.")
return False
try:
result = self.edblib.IPC8521.IPCExporter.ExportIPC2581FromLayout(
self.active_layout, self.edbversion, ipc_path, units.lower()
)
end = time.time() - start
if result:
self.logger.info("Export IPC 2581 completed in %s sec.", end)
self.logger.info("File saved as %s", ipc_path)
return ipc_path
except Exception as e:
self.logger.info("Error Exporting IPC 2581.")
self.logger.info(str(e))
return False

def edb_exception(self, ex_value, tb_data):
"""Write the trace stack to AEDT when a Python error occurs.
Expand Down Expand Up @@ -1068,33 +1071,39 @@ def create_cutout_on_point_list(
else:
_ref_nets.append(self.core_nets.nets[_ref].net_object) # pragma: no cover
# TODO check and insert via check on polygon intersection
circle_voids = [void_circle for void_circle in self.core_primitives.circles if void_circle.is_void]
voids = [p for p in self.core_primitives.circles if p.is_void]
voids2 = [p for p in self.core_primitives.polygons if p.is_void]
voids.extend(voids2)
voids_to_add = []
for circle in circle_voids:
for circle in voids:
if polygonData.GetIntersectionType(circle.primitive_object.GetPolygonData()) >= 3:
voids_to_add.append(circle)

_netsClip = convert_py_list_to_net_list(_ref_nets)
net_signals = List[type(_ref_nets[0])]()
# Create new cutout cell/design
_cutout = self.active_cell.CutOut(net_signals, _netsClip, polygonData)

layout = _cutout.GetLayout()
for void_circle in voids_to_add:
layout = _cutout.GetLayout()
if is_ironpython: # pragma: no cover
res, center_x, center_y, radius = void_circle.primitive_object.GetParameters()
else:
res, center_x, center_y, radius = void_circle.primitive_object.GetParameters(0.0, 0.0, 0.0)
cloned_circle = self.edb.Cell.Primitive.Circle.Create(
layout,
void_circle.layer_name,
void_circle.net,
self.edb_value(center_x),
self.edb_value(center_y),
self.edb_value(radius),
)
cloned_circle.SetIsNegative(True)

if void_circle.type == "Circle":
if is_ironpython: # pragma: no cover
res, center_x, center_y, radius = void_circle.primitive_object.GetParameters()
else:
res, center_x, center_y, radius = void_circle.primitive_object.GetParameters(0.0, 0.0, 0.0)
cloned_circle = self.edb.Cell.Primitive.Circle.Create(
layout,
void_circle.layer_name,
void_circle.net,
self.edb_value(center_x),
self.edb_value(center_y),
self.edb_value(radius),
)
cloned_circle.SetIsNegative(True)
elif void_circle.type == "Polygon":
cloned_polygon = self.edb.Cell.Primitive.Polygon.Create(
layout, void_circle.layer_name, void_circle.net, void_circle.primitive_object.GetPolygonData()
)
cloned_polygon.SetIsNegative(True)
layers = self.core_stackup.stackup_layers.signal_layers
for layer in list(layers.keys()):
layer_primitves = self.core_primitives.get_primitives(layer_name=layer)
Expand Down
2 changes: 2 additions & 0 deletions pyaedt/edb_core/EDB_Data.py
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,8 @@ def is_void(self):
-------
bool
"""
if not hasattr(self.primitive_object, "IsVoid"):
return False
return self.primitive_object.IsVoid()

@staticmethod
Expand Down
32 changes: 16 additions & 16 deletions pyaedt/edb_core/components.py
Original file line number Diff line number Diff line change
Expand Up @@ -406,6 +406,7 @@ def get_component_placement_vector(
mounted_component_pin2,
hosting_component_pin1,
hosting_component_pin2,
flipped=False,
):
"""Get the placement vector between 2 components.
Expand All @@ -423,6 +424,8 @@ def get_component_placement_vector(
Hosted component Pin 1 name.
hosting_component_pin2 : str
Hosted component Pin 2 name.
flipped : bool, optional
Either if the mounted component will be flipped or not.
Returns
-------
Expand Down Expand Up @@ -454,43 +457,40 @@ def get_component_placement_vector(
if mounted_component_pin1:
m_pin1 = self._get_edb_pin_from_pin_name(mounted_component, mounted_component_pin1)
m_pin1_pos = self.get_pin_position(m_pin1)
m_pin1_pos_3d = [m_pin1_pos[0], m_pin1_pos[1], 0]
if mounted_component_pin2:
m_pin2 = self._get_edb_pin_from_pin_name(mounted_component, mounted_component_pin2)
m_pin2_pos = self.get_pin_position(m_pin2)
m_pin2_pos_3d = [m_pin2_pos[0], m_pin2_pos[1], 0]

if hosting_component_pin1:
h_pin1 = self._get_edb_pin_from_pin_name(hosting_component, hosting_component_pin1)
h_pin1_pos = self.get_pin_position(h_pin1)
h_pin1_pos_3d = [h_pin1_pos[0], h_pin1_pos[1], 0]

if hosting_component_pin2:
h_pin2 = self._get_edb_pin_from_pin_name(hosting_component, hosting_component_pin2)
h_pin2_pos = self.get_pin_position(h_pin2)
h_pin2_pos_3d = [h_pin2_pos[0], h_pin2_pos[1], 0]
#
vector = [h_pin1_pos[0] - m_pin1_pos[0], h_pin1_pos[1] - m_pin1_pos[1]]
vector1 = GeometryOperators.v_points(m_pin1_pos_3d, m_pin2_pos_3d)
vector2 = GeometryOperators.v_points(h_pin1_pos_3d, h_pin2_pos_3d)

rotation = GeometryOperators.v_angle(vector1, vector2)
if abs(rotation - math.pi / 2) < 1e-9 and vector1[0] * vector2[1] + vector1[1] * vector2[0] < 0:
rotation = -1 * math.pi / 2
vector1 = GeometryOperators.v_points(m_pin1_pos, m_pin2_pos)
vector2 = GeometryOperators.v_points(h_pin1_pos, h_pin2_pos)
multiplier = 1
if flipped:
multiplier = -1
vector1[1] = multiplier * vector1[1]

rotation = GeometryOperators.v_angle_sign_2D(vector1, vector2, False)
if rotation != 0.0:
layinst = mounted_component.GetLayout().GetLayoutInstance()
cmpinst = layinst.GetLayoutObjInstance(mounted_component, None)
center = cmpinst.GetCenter()
center_double = [center.X.ToDouble(), center.Y.ToDouble(), 0]
vector_center = GeometryOperators.v_points(center_double, m_pin1_pos_3d)
x_v2 = vector_center[0] * math.cos(rotation) + vector_center[1] * math.sin(rotation)
y_v2 = -1 * vector_center[0] * math.sin(rotation) + vector_center[1] * math.cos(rotation)
new_vector = [x_v2 + center_double[0], y_v2 + center_double[1], 0]
center_double = [center.X.ToDouble(), center.Y.ToDouble()]
vector_center = GeometryOperators.v_points(center_double, m_pin1_pos)
x_v2 = vector_center[0] * math.cos(rotation) + multiplier * vector_center[1] * math.sin(rotation)
y_v2 = -1 * vector_center[0] * math.sin(rotation) + multiplier * vector_center[1] * math.cos(rotation)
new_vector = [x_v2 + center_double[0], y_v2 + center_double[1]]
vector = [h_pin1_pos[0] - new_vector[0], h_pin1_pos[1] - new_vector[1]]

if vector:
solder_ball_height = self.get_solder_ball_height(mounted_component)
# self.set_solder_ball(component=mounted_component, sball_height=solder_ball_height)
return True, vector, rotation, solder_ball_height
self._logger.warning("Failed to compute vector.")
return False, [0, 0], 0, 0
Expand Down
Loading

0 comments on commit 3abf581

Please sign in to comment.