6
$\begingroup$

How to do this?

Below is my particular use case and attempt to solve the problem:


Consider Z_axis = (0,0,1) and an arbitrary point also on the unit sphere v.

You can imagine the arc on the surface of the sphere from Z_axis to v.

I wish to create v' by extending the arc by 10%.

How can I do this from Python?

Here is as far as I have got:

unit_v = v.normalized()
rot_axis = Z_axis.cross(unit_v)

...will give a vector perpendicular to rotation plane, and

theta = arcsin( abs(rot_axis) ) # <-- some potential problem with positive and negative angles here I think

...will return the angle.

So I was just need to rotate unit_v by theta' = 0.1*theta around rot_axis

How do I do this?

I can construct a Quaternion Q representing the rotation:

w = cos( theta'/2 )
x,y,z = sin( theta'/2 ) * rot_axis.normalized()

Q = Quaternion(( w,x,y,z ))

and then:

unit_v' = unit_v.rotate(Q)
v' = abs(v) * unit_v'

Is this correct, and is there a cleaner way?

(ref: http://www.essentialmath.com/GDC2013/GDC13_quaternions_final.pdf)

$\endgroup$
9
$\begingroup$

Blender 2.71 (or any recent build) has Vector.slerp (spherical linear interpolation) which accepts values outside 0-1

So you can do:

a = Vector((1, 0, 0))
b = Vector((0, 1, 0))
c = a.slerp(b, 0.5)  # half way

To over rotate 10% do:

c = a.slerp(b, 1.1)

Note, this feature is not included in a stable release yet (but 2.71 will include it).

$\endgroup$
3
$\begingroup$

As @ideasman42 said you can use slerp for the rotation in coming releases, but until then, I think Quaternions are a good solution.
However if you want to rotate a large number of points, rotation matrices is faster. Rotating a point p using a quaternion q works as follows:

(0,p') = q * (0,p) * q^

where (0,p) is a quaternion with a w value of 0 and the x, y and z value of p and q^ is the conjugated quaternion of q. * denotes the quaternion multiplication.
This is what quaternion multiplication looks like if broken into bits:

q1*q2 = (w1,x1,y1,z1)*(w2,x2,y2,z2)
      = ( w1*w2-x1*x2-y1*y2-z1*z2 ,
          w1*x2+x1*w2+y1*z2-z1*y2 ,
          w1*y2+y1*w2+z1*x2-x1*z2 ,
          w1*z2+z1*w2+x1*y2-y1*x2  )

Both quaternion multiplications internally need 16 floatingpoint multiplications and 12 floatingpoint additions (seeing subtractions as additions with negative numbers).

Total cost:
32 multiplications
24 additions

Rotating a point using a rotation matrix as follows:

p' = R * p

where R is the rotation matrix and * denotes the matrix multiplication. Note that p is a column vector.
Even if Blender imbeds the rotation matrix in a 4x4 transformation matrix and uses 4D homogenuous points in the calculation this results in less computation steps:

      |r11 r12 r13 r14|   |px|   |r11*px+r12*py+r13*pz+r14*pw|
R*p = |r21 r22 r23 r24| * |py| = |r21*px+r22*py+r23*pz+r24*pw|
      |r31 r32 r33 r34|   |pz|   |r31*px+r32*py+r33*pz+r34*pw|
      |r41 r42 r43 r44|   |pw|   |r41*px+r42*py+r43*pz+r44*pw|

Total cost:
16 multiplications
12 additions

If Blender internally only uses 3x3 matrices and normal 3D points the calculations get even more performant (9 multiplications and 6 additions).

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.