Skip to content

Commit 992de40

Browse files
committed
Fix Issue #586 translate/rotate
1 parent ce0d99a commit 992de40

File tree

3 files changed

+61
-10
lines changed

3 files changed

+61
-10
lines changed

docs/moving_objects.rst

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -113,15 +113,15 @@ Transformation a.k.a. Translation and Rotation
113113
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
114114

115115
.. note::
116-
These methods don't work in the same way as the previous methods in that they don't just change
117-
the object's internal :class:`~geometry.Location` but transform the base object itself which
118-
is quite slow and potentially problematic.
116+
These methods have an optional ``transform`` parameter which allows the user to transform the base
117+
object itself which is quite slow and potentially problematic as opposed to just changing the
118+
object's internal :class:`~geometry.Location`.
119119

120120
- **Translation:** Move a shape relative to its current position.
121121

122122
.. code-block:: build123d
123123
124-
relocated_shape = shape.translate(x, y, z)
124+
relocated_shape = shape.translate((x, y, z))
125125
126126
- **Rotation:** Rotate a shape around a specified axis by a given angle.
127127

src/build123d/topology/shape_core.py

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1711,22 +1711,31 @@ def relocate(self, loc: Location):
17111711
self.wrapped = tcast(TOPODS, downcast(builder.Shape()))
17121712
self.wrapped.Location(loc.wrapped)
17131713

1714-
def rotate(self, axis: Axis, angle: float) -> Self:
1714+
def rotate(self, axis: Axis, angle: float, transform: bool = False) -> Self:
17151715
"""rotate a copy
17161716
17171717
Rotates a shape around an axis.
17181718
17191719
Args:
17201720
axis (Axis): rotation Axis
17211721
angle (float): angle to rotate, in degrees
1722+
transform (bool): regenerate the shape instead of just changing its location.
1723+
Defaults to False.
17221724
17231725
Returns:
17241726
a copy of the shape, rotated
17251727
"""
1728+
if self._wrapped is None: # For backwards compatibility
1729+
return self
1730+
17261731
transformation = gp_Trsf()
17271732
transformation.SetRotation(axis.wrapped, angle * DEG2RAD)
17281733

1729-
return self._apply_transform(transformation)
1734+
if transform:
1735+
rotated_self = self._apply_transform(transformation)
1736+
else:
1737+
rotated_self = self.moved(Location(TopLoc_Location(transformation)))
1738+
return rotated_self
17301739

17311740
def scale(self, factor: float) -> Self:
17321741
"""Scales this shape through a transformation.
@@ -2239,20 +2248,28 @@ def transformed(
22392248
t_o.SetTranslation(Vector(offset).wrapped)
22402249
return self._apply_transform(t_o * t_rx * t_ry * t_rz)
22412250

2242-
def translate(self, vector: VectorLike) -> Self:
2251+
def translate(self, vector: VectorLike, transform: bool = False) -> Self:
22432252
"""Translates this shape through a transformation.
22442253
22452254
Args:
2246-
vector: VectorLike:
2255+
vector (VectorLike): relative movement vector
2256+
transform (bool): regenerate the shape instead of just changing its location
2257+
Defaults to False.
22472258
22482259
Returns:
2249-
2260+
object with a relative move applied
22502261
"""
2262+
if self._wrapped is None: # For backwards compatibility
2263+
return self
22512264

22522265
transformation = gp_Trsf()
22532266
transformation.SetTranslation(Vector(vector).wrapped)
22542267

2255-
return self._apply_transform(transformation)
2268+
if transform:
2269+
self_translated = self._apply_transform(transformation)
2270+
else:
2271+
self_translated = self.moved(Location(TopLoc_Location(transformation)))
2272+
return self_translated
22562273

22572274
def wire(self) -> Wire | None:
22582275
"""Return the Wire"""

tests/test_direct_api/test_shape.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828

2929
# Always equal to any other object, to test that __eq__ cooperation is working
3030
import unittest
31+
import math
3132
from random import uniform
3233
from unittest.mock import PropertyMock, patch
3334

@@ -634,6 +635,39 @@ def test_empty_selectors(self):
634635
self.assertIsNone(Vertex(1, 1, 1).solid())
635636
self.assertIsNone(Vertex(1, 1, 1).compound())
636637

638+
def test_rotate(self):
639+
line = Edge.make_line((0, 0), (1, 0))
640+
rotated_line = line.rotate(Axis((1, 0, 0), (0, 0, 1)), 45)
641+
root_2o2 = math.sqrt(2) / 2
642+
self.assertAlmostEqual(rotated_line @ 0, (1 - root_2o2, -root_2o2))
643+
self.assertAlmostEqual(rotated_line @ 1, (1, 0))
644+
self.assertTrue(line.wrapped.IsPartner(rotated_line.wrapped))
645+
646+
rotated_line = line.rotate(Axis((1, 0, 0), (0, 0, 1)), 45, transform=True)
647+
self.assertAlmostEqual(rotated_line @ 0, (1 - root_2o2, -root_2o2))
648+
self.assertAlmostEqual(rotated_line @ 1, (1, 0))
649+
self.assertFalse(line.wrapped.IsPartner(rotated_line.wrapped))
650+
651+
line._wrapped = None
652+
rotated_line = line.rotate(Axis((1, 0, 0), (0, 0, 1)), 45)
653+
self.assertIsNone(rotated_line._wrapped)
654+
655+
def test_translate(self):
656+
line = Edge.make_line((0, 0), (1, 0))
657+
translated_line = line.translate((0, 1, 0))
658+
self.assertAlmostEqual(translated_line @ 0, (0, 1, 0))
659+
self.assertAlmostEqual(translated_line @ 1, (1, 1, 0))
660+
self.assertTrue(line.wrapped.IsPartner(translated_line.wrapped))
661+
662+
translated_line = line.translate((0, 1, 0), transform=True)
663+
self.assertAlmostEqual(translated_line @ 0, (0, 1, 0))
664+
self.assertAlmostEqual(translated_line @ 1, (1, 1, 0))
665+
self.assertFalse(line.wrapped.IsPartner(translated_line.wrapped))
666+
667+
line._wrapped = None
668+
translated_line = line.translate((0, 1, 0))
669+
self.assertIsNone(translated_line._wrapped)
670+
637671

638672
class TestGlobalLocation(unittest.TestCase):
639673
def test_global_location_hierarchy(self):

0 commit comments

Comments
 (0)