Quaternions consisting of scalar, along 1, and vector, with components along i, j, k
| 4315 | |
| 4316 | |
| 4317 | class _Quaternion: |
| 4318 | """ |
| 4319 | Quaternions |
| 4320 | consisting of scalar, along 1, and vector, with components along i, j, k |
| 4321 | """ |
| 4322 | |
| 4323 | def __init__(self, scalar, vector): |
| 4324 | self.scalar = scalar |
| 4325 | self.vector = np.array(vector) |
| 4326 | |
| 4327 | def __neg__(self): |
| 4328 | return self.__class__(-self.scalar, -self.vector) |
| 4329 | |
| 4330 | def __mul__(self, other): |
| 4331 | """ |
| 4332 | Product of two quaternions |
| 4333 | i*i = j*j = k*k = i*j*k = -1 |
| 4334 | Quaternion multiplication can be expressed concisely |
| 4335 | using scalar and vector parts, |
| 4336 | see <https://en.wikipedia.org/wiki/Quaternion#Scalar_and_vector_parts> |
| 4337 | """ |
| 4338 | return self.__class__( |
| 4339 | self.scalar*other.scalar - np.dot(self.vector, other.vector), |
| 4340 | self.scalar*other.vector + self.vector*other.scalar |
| 4341 | + np.cross(self.vector, other.vector)) |
| 4342 | |
| 4343 | def conjugate(self): |
| 4344 | """The conjugate quaternion -(1/2)*(q+i*q*i+j*q*j+k*q*k)""" |
| 4345 | return self.__class__(self.scalar, -self.vector) |
| 4346 | |
| 4347 | @property |
| 4348 | def norm(self): |
| 4349 | """The 2-norm, q*q', a scalar""" |
| 4350 | return self.scalar*self.scalar + np.dot(self.vector, self.vector) |
| 4351 | |
| 4352 | def normalize(self): |
| 4353 | """Scaling such that norm equals 1""" |
| 4354 | n = np.sqrt(self.norm) |
| 4355 | return self.__class__(self.scalar/n, self.vector/n) |
| 4356 | |
| 4357 | def reciprocal(self): |
| 4358 | """The reciprocal, 1/q = q'/(q*q') = q' / norm(q)""" |
| 4359 | n = self.norm |
| 4360 | return self.__class__(self.scalar/n, -self.vector/n) |
| 4361 | |
| 4362 | def __div__(self, other): |
| 4363 | return self*other.reciprocal() |
| 4364 | |
| 4365 | __truediv__ = __div__ |
| 4366 | |
| 4367 | def rotate(self, v): |
| 4368 | # Rotate the vector v by the quaternion q, i.e., |
| 4369 | # calculate (the vector part of) q*v/q |
| 4370 | v = self.__class__(0, v) |
| 4371 | v = self*v/self |
| 4372 | return v.vector |
| 4373 | |
| 4374 | def __eq__(self, other): |
no outgoing calls
no test coverage detected
searching dependent graphs…