Merge pull request #50 from bernhard-42/location_changes

Location changes
This commit is contained in:
gumyr 2022-11-19 13:07:58 -05:00 committed by GitHub
commit ee8ed88cd9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 124 additions and 35 deletions

View file

@ -148,6 +148,7 @@ from OCP.gp import (
gp_Dir2d,
gp_Elips,
gp_EulerSequence,
gp_Quaternion,
gp_GTrsf,
gp_Lin,
gp_Pln,
@ -1021,42 +1022,58 @@ class Location:
@overload
def __init__(self) -> None: # pragma: no cover
# Empty location with not rotation or translation with respect to the original location.
"Empty location with not rotation or translation with respect to the original location."
...
@overload
def __init__(self, translation: VectorLike) -> None: # pragma: no cover
# Location with translation with respect to the original location.
def __init__(self, location: "Location") -> None: # pragma: no cover
"Location with another given location."
...
@overload
def __init__(
self, translation: VectorLike, angle: float = 0
) -> None: # pragma: no cover
"""Location with translation with respect to the original location.
If angle != 0 then the location includes a rotation around z-axis by angle"""
...
@overload
def __init__(
self, translation: VectorLike, rotation: RotationLike = None
) -> None: # pragma: no cover
"""Location with translation with respect to the original location.
If rotation is not None then the location includes the rotation (see also Rotation class)"""
...
@overload
def __init__(self, plane: Plane) -> None: # pragma: no cover
# Location corresponding to the location of the Plane.
"Location corresponding to the location of the Plane."
...
@overload
def __init__(
self, plane: Plane, plane_offset: VectorLike
) -> None: # pragma: no cover
# Location corresponding to the angular location of the Plane with translation plane_offset.
"Location corresponding to the angular location of the Plane with translation plane_offset."
...
@overload
def __init__(self, top_loc: TopLoc_Location) -> None: # pragma: no cover
# Location wrapping the low-level TopLoc_Location object t
"Location wrapping the low-level TopLoc_Location object t"
...
@overload
def __init__(self, gp_trsf: gp_Trsf) -> None: # pragma: no cover
# Location wrapping the low-level gp_Trsf object t
"Location wrapping the low-level gp_Trsf object t"
...
@overload
def __init__(
self, translation: VectorLike, axis: VectorLike, angle: float
) -> None: # pragma: no cover
# Location with translation t and rotation around axis by angle
# with respect to the original location."""
"""Location with translation t and rotation around axis by angle
with respect to the original location."""
...
def __init__(self, *args):
@ -1065,6 +1082,7 @@ class Location:
if len(args) == 0:
pass
elif len(args) == 1:
translation = args[0]
@ -1078,6 +1096,9 @@ class Location:
)
transform.SetTransformation(coordinate_system)
transform.Invert()
elif isinstance(args[0], Location):
self.wrapped = translation.wrapped
return
elif isinstance(translation, TopLoc_Location):
self.wrapped = translation
return
@ -1085,15 +1106,33 @@ class Location:
transform = translation
else:
raise TypeError("Unexpected parameters")
elif len(args) == 2:
translation, origin = args
coordinate_system = gp_Ax3(
Vector(origin).to_pnt(),
translation.z_dir.to_dir(),
translation.x_dir.to_dir(),
)
transform.SetTransformation(coordinate_system)
transform.Invert()
if isinstance(args[0], (Vector, tuple)):
if isinstance(args[1], (Vector, tuple)):
rotation = [radians(a) for a in args[1]]
q = gp_Quaternion()
q.SetEulerAngles(gp_EulerSequence.gp_Intrinsic_XYZ, *rotation)
transform.SetRotation(q)
elif isinstance(args[0], (Vector, tuple)) and isinstance(
args[1], (int, float)
):
angle = radians(args[1])
q = gp_Quaternion()
q.SetEulerAngles(gp_EulerSequence.gp_Intrinsic_XYZ, 0, 0, angle)
transform.SetRotation(q)
# set translation part after setting rotation (if exists)
transform.SetTranslationPart(Vector(args[0]).wrapped)
else:
translation, origin = args
coordinate_system = gp_Ax3(
Vector(origin).to_pnt(),
translation.z_dir.to_dir(),
translation.x_dir.to_dir(),
)
transform.SetTransformation(coordinate_system)
transform.Invert()
else:
translation, axis, angle = args
transform.SetRotation(
@ -1123,9 +1162,11 @@ class Location:
rot = transformation.GetRotation()
rv_trans = (trans.X(), trans.Y(), trans.Z())
rv_rot = rot.GetEulerAngles(gp_EulerSequence.gp_Extrinsic_XYZ)
rv_rot = [
degrees(a) for a in rot.GetEulerAngles(gp_EulerSequence.gp_Intrinsic_XYZ)
]
return rv_trans, rv_rot
return rv_trans, tuple(rv_rot)
def __repr__(self):
"""To String
@ -1136,7 +1177,7 @@ class Location:
Location as String
"""
position_str = ", ".join((f"{v:.2f}" for v in self.to_tuple()[0]))
orientation_str = ", ".join((f"{180*v/pi:.2f}" for v in self.to_tuple()[1]))
orientation_str = ", ".join((f"{v:.2f}" for v in self.to_tuple()[1]))
return f"(p=({position_str}), o=({orientation_str}))"
def __str__(self):
@ -1148,7 +1189,7 @@ class Location:
Location as String
"""
position_str = ", ".join((f"{v:.2f}" for v in self.to_tuple()[0]))
orientation_str = ", ".join((f"{180*v/pi:.2f}" for v in self.to_tuple()[1]))
orientation_str = ", ".join((f"{v:.2f}" for v in self.to_tuple()[1]))
return f"Location: (position=({position_str}), orientation=({orientation_str}))"
@ -1160,14 +1201,16 @@ class Rotation(Location):
self.about_y = about_y
self.about_z = about_z
# Compute rotation matrix.
rot_x = gp_Trsf()
rot_x.SetRotation(gp_Ax1(gp_Pnt(0, 0, 0), gp_Dir(1, 0, 0)), radians(about_x))
rot_y = gp_Trsf()
rot_y.SetRotation(gp_Ax1(gp_Pnt(0, 0, 0), gp_Dir(0, 1, 0)), radians(about_y))
rot_z = gp_Trsf()
rot_z.SetRotation(gp_Ax1(gp_Pnt(0, 0, 0), gp_Dir(0, 0, 1)), radians(about_z))
super().__init__(rot_x * rot_y * rot_z)
q = gp_Quaternion()
q.SetEulerAngles(
gp_EulerSequence.gp_Intrinsic_XYZ,
radians(about_x),
radians(about_y),
radians(about_z),
)
t = gp_Trsf()
t.SetRotationPart(q)
super().__init__(t)
#:TypeVar("RotationLike"): Three tuple of angles about x, y, z or Rotation

View file

@ -13,6 +13,8 @@ from OCP.gp import (
gp_Trsf,
gp_Ax1,
gp_Dir,
gp_Quaternion,
gp_EulerSequence,
)
from OCP.BRepBuilderAPI import BRepBuilderAPI_MakeEdge
@ -414,19 +416,65 @@ class TestCadObjects(unittest.TestCase):
with self.assertRaises(TypeError):
Location("xy_plane")
# Test that the computed rotation matrix and intrinsic euler angles return the same
about_x = uniform(-2 * math.pi, 2 * math.pi)
about_y = uniform(-2 * math.pi, 2 * math.pi)
about_z = uniform(-2 * math.pi, 2 * math.pi)
rot_x = gp_Trsf()
rot_x.SetRotation(gp_Ax1(gp_Pnt(0, 0, 0), gp_Dir(1, 0, 0)), about_x)
rot_y = gp_Trsf()
rot_y.SetRotation(gp_Ax1(gp_Pnt(0, 0, 0), gp_Dir(0, 1, 0)), about_y)
rot_z = gp_Trsf()
rot_z.SetRotation(gp_Ax1(gp_Pnt(0, 0, 0), gp_Dir(0, 0, 1)), about_z)
loc1 = Location(rot_x * rot_y * rot_z)
q = gp_Quaternion()
q.SetEulerAngles(
gp_EulerSequence.gp_Intrinsic_XYZ,
about_x,
about_y,
about_z,
)
t = gp_Trsf()
t.SetRotationPart(q)
loc2 = Location(t)
self.assertTupleAlmostEquals(loc1.to_tuple()[0], loc2.to_tuple()[0], 6)
self.assertTupleAlmostEquals(loc1.to_tuple()[1], loc2.to_tuple()[1], 6)
loc1 = Location((1, 2), 34)
self.assertTupleAlmostEquals(loc1.to_tuple()[0], (1, 2, 0), 6)
self.assertTupleAlmostEquals(loc1.to_tuple()[1], (0, 0, 34), 6)
rot_angles = (-115.00, 35.00, -135.00)
loc2 = Location((1, 2, 3), rot_angles)
self.assertTupleAlmostEquals(loc2.to_tuple()[0], (1, 2, 3), 6)
self.assertTupleAlmostEquals(loc2.to_tuple()[1], rot_angles, 6)
loc3 = Location(loc2)
self.assertTupleAlmostEquals(loc3.to_tuple()[0], (1, 2, 3), 6)
self.assertTupleAlmostEquals(loc3.to_tuple()[1], rot_angles, 6)
def test_location_repr_and_str(self):
self.assertEqual(
repr(Location()), "(p=(0.00, 0.00, 0.00), o=(0.00, -0.00, 0.00))"
repr(Location()), "(p=(0.00, 0.00, 0.00), o=(-0.00, 0.00, -0.00))"
)
self.assertEqual(
str(Location()),
"Location: (position=(0.00, 0.00, 0.00), orientation=(0.00, -0.00, 0.00))",
"Location: (position=(0.00, 0.00, 0.00), orientation=(-0.00, 0.00, -0.00))",
)
loc = Location((1, 2, 3), (33, 45, 67))
self.assertEqual(
str(loc),
"Location: (position=(1.00, 2.00, 3.00), orientation=(33.00, 45.00, 67.00))",
)
def test_location_inverted(self):
loc = Location(Plane.XZ)
self.assertTupleAlmostEquals(
loc.inverse().orientation.to_tuple(), (-math.pi / 2, 0, 0), 6
loc.inverse().orientation.to_tuple(), (-90, 0, 0), 6
)
def test_edge_wrapper_radius(self):
@ -1288,9 +1336,7 @@ class TestAxis(unittest.TestCase):
x_location = Axis.X.to_location()
self.assertTrue(isinstance(x_location, Location))
self.assertTupleAlmostEquals(x_location.position.to_tuple(), (0, 0, 0), 5)
self.assertTupleAlmostEquals(
x_location.orientation.to_tuple(), (-math.pi, -math.pi / 2, 0), 5
)
self.assertTupleAlmostEquals(x_location.orientation.to_tuple(), (0, 90, 180), 5)
def test_axis_to_plane(self):
x_plane = Axis.X.to_plane()