Skip to content

Commit 4879ea9

Browse files
committed
setters for worldtransformation and frame
1 parent 53b27b5 commit 4879ea9

File tree

3 files changed

+52
-1
lines changed

3 files changed

+52
-1
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
88
## Unreleased
99

1010
### Added
11+
1112
* Implemented `to_points` method in `compas.datastructures.Mesh`, which before raised a `NotImplementedError`.
1213
* Implemented `compute_aabb` method in `compas.datastructures.Datastructure`, which before raised a `NotImplementedError`. Made use of the `compas.geometry.bbox.bounding_box` function.
1314
* Implemented `compute_obb` method in `compas.datastructures.Datastructure`, which before raised a `NotImplementedError`. Made use of the `compas.geometry.bbox_numpy.oriented_bounding_box_numpy` function.
@@ -17,6 +18,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1718
* Added test function `test_to_points` in `test_graph.py`.
1819
* Added test function `test_to_points` in `test_volmesh.py`.
1920
* Added test functions `test_to_points`, `test_compute_aabb`, and `test_compute_obb` in `test_mesh.py`.
21+
* Added setters for `SceneObject.worldtransformation` and `SceneObject.frame`, which automatically handles the parent transformations.
2022

2123
### Changed
2224

src/compas/scene/sceneobject.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,6 @@ def __init__(
9595
color=None, # type: compas.colors.Color | None
9696
opacity=1.0, # type: float
9797
show=True, # type: bool
98-
frame=None, # type: compas.geometry.Frame | None
9998
transformation=None, # type: compas.geometry.Transformation | None
10099
context=None, # type: str | None
101100
**kwargs # type: dict
@@ -157,6 +156,11 @@ def frame(self):
157156
# type: () -> compas.geometry.Frame | None
158157
return Frame.from_transformation(self.worldtransformation)
159158

159+
@frame.setter
160+
def frame(self, frame):
161+
# type: (compas.geometry.Frame) -> None
162+
self.worldtransformation = Transformation.from_frame(frame)
163+
160164
@property
161165
def transformation(self):
162166
# type: () -> compas.geometry.Transformation | None
@@ -183,6 +187,14 @@ def worldtransformation(self):
183187

184188
return worldtransformation
185189

190+
@worldtransformation.setter
191+
def worldtransformation(self, worldtransformation):
192+
# type: (compas.geometry.Transformation) -> None
193+
if isinstance(self.parent, SceneObject):
194+
self.transformation = self.parent.worldtransformation.inverse() * worldtransformation
195+
else:
196+
self.transformation = worldtransformation
197+
186198
@property
187199
def contrastcolor(self):
188200
# type: () -> compas.colors.Color | None

tests/compas/scene/test_scene.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
from compas.geometry import Box
1212
from compas.geometry import Frame
1313
from compas.geometry import Translation
14+
from compas.geometry import Transformation
1415
from compas.scene import Group
1516

1617
@pytest.fixture(autouse=True)
@@ -104,6 +105,42 @@ def test_sceneobject_transform():
104105
assert sceneobj3.frame == Frame([30.0, 20.0, 10.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0])
105106
assert sceneobj3.frame.to_transformation() == Translation.from_vector([30.0, 20.0, 10.0])
106107

108+
def test_sceneobject_frame_and_worldtransformation_setters():
109+
"""Test that frame and worldtransformation setters work correctly."""
110+
scene = Scene()
111+
112+
# Test on root object
113+
root_obj = scene.add(Box())
114+
test_frame = Frame([10.0, 20.0, 30.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0])
115+
root_obj.frame = test_frame
116+
assert root_obj.frame == test_frame
117+
assert root_obj.worldtransformation == Transformation.from_frame(test_frame)
118+
119+
# Test worldtransformation setter on root object
120+
test_transform = Translation.from_vector([5.0, 10.0, 15.0])
121+
root_obj.worldtransformation = test_transform
122+
assert root_obj.worldtransformation == test_transform
123+
assert root_obj.transformation == test_transform
124+
125+
# Test with parent-child relationship
126+
parent_obj = scene.add(Box())
127+
child_obj = scene.add(Box(), parent=parent_obj)
128+
parent_obj.transformation = Translation.from_vector([10.0, 0.0, 0.0])
129+
130+
# Test frame setter with parent
131+
child_frame = Frame([30.0, 20.0, 10.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0])
132+
child_obj.frame = child_frame
133+
assert child_obj.frame == child_frame
134+
expected_local = parent_obj.worldtransformation.inverse() * Transformation.from_frame(child_frame)
135+
assert child_obj.transformation == expected_local
136+
137+
# Test worldtransformation setter with parent
138+
child_world_transform = Translation.from_vector([50.0, 30.0, 20.0])
139+
child_obj.worldtransformation = child_world_transform
140+
assert child_obj.worldtransformation == child_world_transform
141+
expected_local = parent_obj.worldtransformation.inverse() * child_world_transform
142+
assert child_obj.transformation == expected_local
143+
107144
def test_scene_clear():
108145
scene = Scene()
109146
sceneobj1 = scene.add(Box())

0 commit comments

Comments
 (0)