compas icon indicating copy to clipboard operation
compas copied to clipboard

Spherical Linear Interpolation Function (slerp) for Frames

Open yck011522 opened this issue 2 years ago • 5 comments
trafficstars

Feature Request

In order to develop robotic motion planners, I want a slerp function between two frames so that I can create interpolated frames between two frames that have not only positional differences but also orientation differences.

Details

Is your feature request related to a problem? Please describe. Given two frames with different origin positions and orientations. I want to interpolate between them linearly, controlled by a single parameter. Given a series of uniformly spaced parameters, the resulting set of interpolated Frames should have equal distances (origin points) and natural-looking gradual orientation change.

Describe the solution you'd like

I would imagine a function signature like this: Frame.slerp_interpolation(start_frame, end_frame, parameter) -> Frame where: parameter is a float between 0.0 and 1.0

Additional context I do not know how this is done properly, but I believe animation software has algorithms like this where the position and orientation of the Frames are interpolated separately and combined later. The origin position can be a simple interpolation and the orientation is interpolated by slerp in quaternion representation. https://en.wikipedia.org/wiki/Slerp

yck011522 avatar Nov 09 '23 09:11 yck011522

https://docs.unity3d.com/ScriptReference/Quaternion.Slerp.html

Maybe this provides some idea about the slerp function

https://github.com/Unity-Technologies/UnityCsReference/blob/d0e1a5b25e8d3c8e1b4e6baf0073032d97254a0c/Editor/Mono/Utils/MathUtils.cs#L222-L262

yck011522 avatar Nov 09 '23 09:11 yck011522

https://splines.readthedocs.io/en/latest/rotation/slerp.html

This webpage explains the importance of Slerp having the property of constant angular velocity.

yck011522 avatar Nov 09 '23 09:11 yck011522

@yck011522 this can be useful for slerp:

t - [0.0, 1.0]

 def interpolate_frames(frame0, frame1, t):
                        """
                        Interpolate smoothly between two frames using Slerp and Lerp.

                        Parameters:
                            frame0 (Frame): The starting frame.
                            frame1 (Frame): The ending frame.
                            t (float): Interpolation parameter between 0 and 1.

                        Returns:
                            Frame: The interpolated frame.
                        """
                        # Perform linear interpolation for the position (point) component
                        point = Point(*frame0.point) * (1 - t) + Point(*frame1.point) * t

                        # Perform spherical linear interpolation (Slerp) for the orientation (quaternion) component
                        q0 = Quaternion.from_frame(frame0)
                        q1 = Quaternion.from_frame(frame1)

                        def interpolate_quaternion(q0, q1, t):
                            # Perform subtraction: q1 - q0
                            q_diff = Quaternion(q1.w - q0.w, q1.x - q0.x, q1.y - q0.y, q1.z - q0.z)

                            # Perform scaling: t * (q1 - q0)
                            q_scaled = Quaternion(q_diff.w * t, q_diff.x * t, q_diff.y * t, q_diff.z * t)

                            # Perform addition: q0 + t * (q1 - q0)
                            interpolated_quaternion = Quaternion(
                                q0.w + q_scaled.w, q0.x + q_scaled.x, q0.y + q_scaled.y, q0.z + q_scaled.z
                            )

                            return interpolated_quaternion

                        interpolated_quaternion = interpolate_quaternion(q0, q1, t)  # q0 * (1 - t) + q1 * t

                        # Convert the interpolated quaternion back to a frame
                        point = Point(*frame0.point) * (1 - t) + Point(*frame1.point) * t
                        interpolated_frame = Frame.from_quaternion(interpolated_quaternion, point)

                        return interpolated_frame

petrasvestartas avatar Nov 14 '23 15:11 petrasvestartas

Thank you @petrasvestartas I'll test it out in the compas_fab context. But probably it would be good if this feature gets into compas core too.

yck011522 avatar Nov 15 '23 10:11 yck011522

scipy has slerp: https://docs.scipy.org/doc/scipy/reference/generated/scipy.spatial.transform.Slerp.html https://docs.scipy.org/doc/scipy/reference/generated/scipy.spatial.geometric_slerp.html

romanarust avatar Nov 16 '23 09:11 romanarust

@tomvanmele what's your take: @romanarust' suggestion of building on top of scipy.spatial || @petrasvestartas implementation as per above?

jf--- avatar Apr 05 '24 09:04 jf---

in general, if we can use something that already exists, we should. and since we stopped caring about IronPython, there is no need to make a pure Python version...

tomvanmele avatar Apr 05 '24 09:04 tomvanmele

ah, thanks. given that scipy is a dependency in requirements.txt, then that seems the right call.

jf--- avatar Apr 06 '24 14:04 jf---

Thanks all for the effort.

yck011522 avatar Apr 07 '24 04:04 yck011522