@@ -148,6 +148,34 @@ def test_so3_apply_throws_assertion_error_if_wrong_shape(self):
148148 with self .assertRaises (AssertionError ):
149149 rot .apply (vec )
150150
151+ def test_so3_clamp (self ):
152+ # Clamping with the default RPY limits (+- infinity) means the SO3 should remain unchanged.
153+ rot = SO3 .from_rpy_radians (roll = np .pi , pitch = 0 , yaw = - np .pi )
154+ self .assertEqual (rot , rot .clamp ())
155+
156+ original_rpy = rot .as_rpy_radians ()
157+
158+ # Test clamping the roll.
159+ clamped_rot = rot .clamp (roll_radians = (0 , 1 ))
160+ clamped_rpy = clamped_rot .as_rpy_radians ()
161+ self .assertAlmostEqual (clamped_rpy .roll , 1 )
162+ self .assertAlmostEqual (clamped_rpy .pitch , original_rpy .pitch )
163+ self .assertAlmostEqual (clamped_rpy .yaw , original_rpy .yaw )
164+
165+ # Test clamping the pitch.
166+ clamped_rot = rot .clamp (pitch_radians = (1 , 2 ))
167+ clamped_rpy = clamped_rot .as_rpy_radians ()
168+ self .assertAlmostEqual (clamped_rpy .roll , original_rpy .roll )
169+ self .assertAlmostEqual (clamped_rpy .pitch , 1 )
170+ self .assertAlmostEqual (clamped_rpy .yaw , original_rpy .yaw )
171+
172+ # Test clamping the yaw.
173+ clamped_rot = rot .clamp (yaw_radians = (np .pi , 2 * np .pi ))
174+ clamped_rpy = clamped_rot .as_rpy_radians ()
175+ self .assertAlmostEqual (clamped_rpy .roll , original_rpy .roll )
176+ self .assertAlmostEqual (clamped_rpy .pitch , original_rpy .pitch )
177+ self .assertAlmostEqual (clamped_rpy .yaw , np .pi )
178+
151179 # SE3.
152180
153181 def test_se3_equality (self ):
@@ -257,6 +285,55 @@ def test_se3_interpolate(self):
257285 start .interpolate (end , alpha = 2.0 )
258286 self .assertIn (expected_error_message , str (cm .exception ))
259287
288+ def test_se3_clamp (self ):
289+ T = SE3 .from_rotation_and_translation (
290+ rotation = SO3 .from_rpy_radians (roll = np .pi , pitch = 0 , yaw = - np .pi ),
291+ translation = np .array ([0 , 1 , 2 ]),
292+ )
293+ original_rpy = T .rotation ().as_rpy_radians ()
294+
295+ # Clamping with the default limits (+- infinity) means the SE3 should remain unchanged.
296+ self .assertEqual (T , T .clamp ())
297+
298+ # Test clamping the x translation.
299+ clamped_T = T .clamp (x_translation = (1 , 2 ))
300+ np .testing .assert_allclose (clamped_T .translation (), np .array ([1 , 1 , 2 ]))
301+ self .assertEqual (clamped_T .rotation (), T .rotation ())
302+
303+ # Test clamping the y translation.
304+ clamped_T = T .clamp (y_translation = (- 1 , 0 ))
305+ np .testing .assert_allclose (clamped_T .translation (), np .array ([0 , 0 , 2 ]))
306+ self .assertEqual (clamped_T .rotation (), T .rotation ())
307+
308+ # Test clamping the z translation.
309+ clamped_T = T .clamp (z_translation = (5 , 10 ))
310+ np .testing .assert_allclose (clamped_T .translation (), np .array ([0 , 1 , 5 ]))
311+ self .assertEqual (clamped_T .rotation (), T .rotation ())
312+
313+ # Test clamping the roll.
314+ clamped_T = T .clamp (roll_radians = (0 , 1 ))
315+ clamped_rpy = clamped_T .rotation ().as_rpy_radians ()
316+ np .testing .assert_equal (clamped_T .translation (), T .translation ())
317+ self .assertAlmostEqual (clamped_rpy .roll , 1 )
318+ self .assertAlmostEqual (clamped_rpy .pitch , original_rpy .pitch )
319+ self .assertAlmostEqual (clamped_rpy .yaw , original_rpy .yaw )
320+
321+ # Test clamping the pitch.
322+ clamped_T = T .clamp (pitch_radians = (1 , 2 ))
323+ clamped_rpy = clamped_T .rotation ().as_rpy_radians ()
324+ np .testing .assert_equal (clamped_T .translation (), T .translation ())
325+ self .assertAlmostEqual (clamped_rpy .roll , original_rpy .roll )
326+ self .assertAlmostEqual (clamped_rpy .pitch , 1 )
327+ self .assertAlmostEqual (clamped_rpy .yaw , original_rpy .yaw )
328+
329+ # Test clamping the yaw.
330+ clamped_T = T .clamp (yaw_radians = (np .pi , 2 * np .pi ))
331+ clamped_rpy = clamped_T .rotation ().as_rpy_radians ()
332+ np .testing .assert_equal (clamped_T .translation (), T .translation ())
333+ self .assertAlmostEqual (clamped_rpy .roll , original_rpy .roll )
334+ self .assertAlmostEqual (clamped_rpy .pitch , original_rpy .pitch )
335+ self .assertAlmostEqual (clamped_rpy .yaw , np .pi )
336+
260337
261338if __name__ == "__main__" :
262339 absltest .main ()
0 commit comments