Skip to content

Add methods for swing-twist decomposition to Quat #536

@cactusdualcore

Description

@cactusdualcore

I ran into a problem where I wanted to decompose a rotation into a part which rotates around a specified axis and perpendicular to it. This can be done using the swing-twist decomposition of quaternions.

I now implemented an alternative solution to my problem, but I think this library would still profit from this feature.

I implemented a crude function to do this for me based on this stackoverflow question.

/// Decompose the rotation on to 2 parts.
///
/// 1. Twist - rotation around the "direction" vector
/// 2. Swing - rotation around axis that is perpendicular to "direction" vector
///
/// The rotation can be composed back by
/// `rotation = swing * twist`.
/// Order matters!
///
/// has singularity in case of swing_rotation close to 180 degrees rotation.
/// if the input quaternion is of non-unit length, the outputs are non-unit as well
/// otherwise, outputs are both unit
fn swing_twist_decomposition(rotation: Quat, axis: Dir3) -> Option<(Quat, Quat)> {
    let rotation_axis = rotation.xyz();
    let projection = rotation_axis.project_onto(*axis);

    let twist = {
        let maybe_flipped_twist = Quat::from_vec4(projection.extend(rotation.w));
        if rotation_axis.dot(projection) < 0.0 {
            -maybe_flipped_twist
        } else {
            maybe_flipped_twist
        }
    };

    if twist.length_squared() != 0.0 {
        let swing = rotation * twist.conjugate();
        Some((twist.normalize(), swing))
    } else {
        None
    }
}

The above code is fully written by me, but the mechanism was adapted from a StackOverflow answer.
I have no clues about licensing here. If I am legally allowed, I'd like to give up any rights to the code.

There seem to be many resources on this topic online.
I have neither thoroughly tested nor benchmarked the above snipped and I assume it requires more polish. If desired, I could try putting together a PR for a full implementation?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions