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$

2 Answers 2

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$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .