Best method to scale rotors?
swiftcoder opened this issue · 2 comments
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 :)
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.
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");
}