Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Best method to scale rotors? #105

Open
swiftcoder opened this issue Jan 16, 2021 · 2 comments
Open

Best method to scale rotors? #105

swiftcoder opened this issue Jan 16, 2021 · 2 comments
Labels
enhancement New feature or request help wanted Extra attention is needed

Comments

@swiftcoder
Copy link

swiftcoder commented Jan 16, 2021

It's often really useful to be able to take fractions of a rotation, or multiples. I believe this should be equivalent to slerping the rotor with the identity rotor, but I'd love a gut check on that from someone who groks rotors better than I do.

i.e. does something like this make sense for scaling a rotation?

fn scale_rotation_by(rotor: Rotor3, factor: f32) -> Rotor3 {
  Rotor3::identity().slerp(rotor, factor)
}

Assuming that does work, any thoughts on adding methods to the rotor types for this sort of thing? I had initially assumed that the multiplication operator would be wired up to perform scaling, but that does not appear to be the case :)

@fu5ha
Copy link
Owner

fu5ha commented May 21, 2021

Sorry for the late response on this. You should be able to multiply rotor.s by some factor and then renormalize the rotor to scale the rotation. You can think of a rotor as:

  • A bivector part, which describes the bivector inside which the rotation will occur.
  • A scalar part, which describes how much rotation will be applied within that bivector.

This isn't a perfect solution as usually you only want a rotor to describe an actual rotation part of up to 180 degrees, at which point you would then flip the bivector and go back down from 180 degrees to 0 until you get to 360 degrees and flip again (since you need the rotor to always be unit length, increasing the scalar part will decrease the absolute value of the components of the bivector to keep the total length to 1 upon normalization).

I'm actually not sure what the best solution is here, should look at some prior art in terms of what people do to solve this with quaternions.

@fu5ha fu5ha added enhancement New feature or request help wanted Extra attention is needed labels May 21, 2021
@thenlevy
Copy link
Contributor

It's often really useful to be able to take fractions of a rotation, or multiples. I believe this should be equivalent to slerping the rotor with the identity rotor, but I'd love a gut check on that from someone who groks rotors better than I do.

i.e. does something like this make sense for scaling a rotation?

fn scale_rotation_by(rotor: Rotor3, factor: f32) -> Rotor3 {
  Rotor3::identity().slerp(rotor, factor)
}

This should work if 0 <= factor <= 1.

Here is an other solution that should work for arbitrary factor:

A normalized can be written in the form

rotor = Rotor3 {
s: (theta/2).cos()
bv: (theta/2).sin() * plane
}

where plane is a normalized bivector.

To scale the angle, one must take the rotor

scaled_rotor = Rotor3 {
s: (scale * theta/2).cos()
bv: (scale * theta/2).sin() * plane
}

This can currently be done by using the function Rotor3::into_angle_plane as demonstrated by this example

use ultraviolet::*; 

fn main() {
    use std::f32::consts::PI;

    let axis = Vec3::new(0.42, 0.123, 0.789).normalized(); //aribitrary rotation axis
    let plane = Bivec3::from_normalized_axis(axis).normalized();
    let angle = PI / 10.;

    // rotation of angle pi/10 on the axis;
    let rotation_1 = Rotor3::from_angle_plane(angle, plane);

    let fraction = 0.234; //arbitrary factor between 0 and 1

    let scaled_rotor_1 = Rotor3::from_angle_plane(angle * fraction, plane);

    let scaled_rotor_2 = Rotor3::slerp(&Rotor3::identity(), rotation_1, fraction);
    assert!((scaled_rotor_1.s - scaled_rotor_2.s).abs() < 1e-5);
    assert!((scaled_rotor_1.bv - scaled_rotor_2.bv).mag() < 1e-5);

    let (angle, axis) = rotation_1.into_angle_plane();

    let scaled_rotor_3 = Rotor3::from_angle_plane(fraction * angle, axis).normalized();
    assert!((scaled_rotor_1.s - scaled_rotor_3.s).abs() < 1e-5);
    assert!((scaled_rotor_1.bv - scaled_rotor_3.bv).mag() < 1e-5);

    println!("Success");
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request help wanted Extra attention is needed
Projects
None yet
Development

No branches or pull requests

3 participants