Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix JernArc not always co-planar with input plane #644

Merged
merged 10 commits into from
Jun 23, 2024
27 changes: 21 additions & 6 deletions src/build123d/geometry.py
Original file line number Diff line number Diff line change
Expand Up @@ -465,13 +465,28 @@ def to_dir(self) -> gp_Dir:
"""Convert to OCCT gp_Dir object"""
return gp_Dir(self.wrapped.XYZ())

def transform(self, affine_transform: Matrix) -> Vector:
"""Apply affine transformation"""
# to gp_Pnt to obey build123d transformation convention (in OCP.vectors do not translate)
pnt = self.to_pnt()
pnt_t = pnt.Transformed(affine_transform.wrapped.Trsf())
def transform(self, affine_transform: Matrix, is_direction: bool = False) -> Vector:
"""Apply affine transformation

return Vector(gp_Vec(pnt_t.XYZ()))
Args:
affine_transform (Matrix): affine transformation matrix
is_direction (bool, optional): Should self be transformed as a vector or direction?
Defaults to False (vector)

Returns:
Vector: transformed vector
"""
if not is_direction:
# to gp_Pnt to obey build123d transformation convention (in OCP.vectors do not translate)
pnt = self.to_pnt()
pnt_t = pnt.Transformed(affine_transform.wrapped.Trsf())
return_value = Vector(gp_Vec(pnt_t.XYZ()))
else:
# to gp_Dir for transformation of "direction vectors" (no translation or scaling)
dir = self.to_dir()
dir_t = dir.Transformed(affine_transform.wrapped.Trsf())
return_value = Vector(gp_Vec(dir_t.XYZ()))
return return_value

def rotate(self, axis: Axis, angle: float) -> Vector:
"""Rotate about axis
Expand Down
2 changes: 1 addition & 1 deletion src/build123d/objects_curve.py
Original file line number Diff line number Diff line change
Expand Up @@ -579,12 +579,12 @@ def __init__(

start = WorkplaneList.localize(start)
self.start = start
start_tangent = WorkplaneList.localize(tangent).normalized()
if context is None:
jern_workplane = Plane.XY
else:
jern_workplane = copy.copy(WorkplaneList._get_context().workplanes[0])
jern_workplane.origin = start
start_tangent = Vector(tangent).transform(jern_workplane.reverse_transform, is_direction=True)

arc_direction = copysign(1.0, arc_size)
self.center_point = start + start_tangent.rotate(
Expand Down
21 changes: 18 additions & 3 deletions tests/test_build_line.py
Original file line number Diff line number Diff line change
Expand Up @@ -206,9 +206,24 @@ def test_intersecting_line(self):

def test_jern_arc(self):
with BuildLine() as jern:
JernArc((1, 0), (0, 1), 1, 90)
self.assertTupleAlmostEquals((jern.edges()[0] @ 1).to_tuple(), (0, 1, 0), 5)

j1 = JernArc((1, 0), (0, 1), 1, 90)
self.assertTupleAlmostEquals((jern.line @ 1).to_tuple(), (0, 1, 0), 5)
self.assertAlmostEqual(j1.radius, 1)
self.assertAlmostEqual(j1.length, pi/2)

with BuildLine(Plane.XY.offset(1)) as offset_l:
off1 = JernArc((1, 0), (0, 1), 1, 90)
self.assertTupleAlmostEquals((offset_l.line @ 1).to_tuple(), (0, 1, 1), 5)
self.assertAlmostEqual(off1.radius, 1)
self.assertAlmostEqual(off1.length, pi/2)

plane_iso = Plane(origin=(0, 0, 0), x_dir=(1, 1, 0), z_dir=(1, -1, 1))
with BuildLine(plane_iso) as iso_l:
iso1 = JernArc((0, 0), (0, 1), 1, 180)
self.assertTupleAlmostEquals((iso_l.line @ 1).to_tuple(), (-sqrt(2), -sqrt(2), 0), 5)
self.assertAlmostEqual(iso1.radius, 1)
self.assertAlmostEqual(iso1.length, pi)

with BuildLine() as l:
l1 = JernArc(start=(0, 0, 0), tangent=(1, 0, 0), radius=1, arc_size=360)
self.assertTrue(l1.is_closed)
Expand Down
21 changes: 21 additions & 0 deletions tests/test_direct_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -3688,6 +3688,27 @@ def test_hash(self):
self.assertEqual(len(vectors), 4)
self.assertEqual(len(unique_vectors), 3)

def test_vector_transform(self):
a = Vector(1, 2, 3)
pxy = Plane.XY
pxy_o1 = Plane.XY.offset(1)
self.assertEqual(a.transform(pxy.forward_transform, is_direction=False), a)
self.assertEqual(
a.transform(pxy.forward_transform, is_direction=True), a.normalized()
)
self.assertEqual(
a.transform(pxy_o1.forward_transform, is_direction=False), Vector(1, 2, 2)
)
self.assertEqual(
a.transform(pxy_o1.forward_transform, is_direction=True), a.normalized()
)
self.assertEqual(
a.transform(pxy_o1.reverse_transform, is_direction=False), Vector(1, 2, 4)
)
self.assertEqual(
a.transform(pxy_o1.reverse_transform, is_direction=True), a.normalized()
)

def test_intersect(self):
v1 = Vector(1, 2, 3)
self.assertVectorAlmostEquals(v1 & Vector(1, 2, 3), (1, 2, 3), 5)
Expand Down
Loading