The quaternion for the shortest rotation from vector r1 to vector r2 i.e., q = sqrt(r2*r1'), normalized. If r1 and r2 are antiparallel, then the result is ambiguous; a normal vector will be returned, and a warning will be issued.
(cls, r1, r2)
| 4379 | |
| 4380 | @classmethod |
| 4381 | def rotate_from_to(cls, r1, r2): |
| 4382 | """ |
| 4383 | The quaternion for the shortest rotation from vector r1 to vector r2 |
| 4384 | i.e., q = sqrt(r2*r1'), normalized. |
| 4385 | If r1 and r2 are antiparallel, then the result is ambiguous; |
| 4386 | a normal vector will be returned, and a warning will be issued. |
| 4387 | """ |
| 4388 | k = np.cross(r1, r2) |
| 4389 | nk = np.linalg.norm(k) |
| 4390 | th = np.arctan2(nk, np.dot(r1, r2)) |
| 4391 | th /= 2 |
| 4392 | if nk == 0: # r1 and r2 are parallel or anti-parallel |
| 4393 | if np.dot(r1, r2) < 0: |
| 4394 | warnings.warn("Rotation defined by anti-parallel vectors is ambiguous") |
| 4395 | k = np.zeros(3) |
| 4396 | k[np.argmin(r1*r1)] = 1 # basis vector most perpendicular to r1-r2 |
| 4397 | k = np.cross(r1, k) |
| 4398 | k = k / np.linalg.norm(k) # unit vector normal to r1-r2 |
| 4399 | q = cls(0, k) |
| 4400 | else: |
| 4401 | q = cls(1, [0, 0, 0]) # = 1, no rotation |
| 4402 | else: |
| 4403 | q = cls(np.cos(th), k*np.sin(th)/nk) |
| 4404 | return q |
| 4405 | |
| 4406 | @classmethod |
| 4407 | def from_cardan_angles(cls, elev, azim, roll): |