```"""
by K. Urner, 4D Solutions
Modified May 8, 2000:  added __repr__ (tested for Qvector compatibility)
"""

from coords import Vector
import math

class Quaternion:

def __init__(self,s1,v1):
# initialize a Quaternian as [s1,v1]
self.s = float(s1)  # a scalar
self.v = v1         # a Vector

def __repr__(self):
return "Quaternion " + str((self.s,self.v))

return Quaternion(self.s + q1.s, self.v + q1.v)

def __sub__(self,q1):
return Quaternion(self.s - q1.s, self.v - q1.v)

def __neg__(self):
return Quaternion(-self.s, -self.v)

def __mul__(self,q1):
# multiply (self x quaternion q1) --> new quaternion or...
# multiply (self x scalar) --> new quaternion

typearg = type(q1).__name__ # to check argument type

# check for Quaternion type
if (typearg == 'instance'
and q1.__class__.__name__ == 'Quaternion'):
# s1*s2 - v1.v2 where s1 is self.s, v1 is self.v
new_s = self.s * q1.s - self.v.dot(q1.v)
# (v1 x v2) + (s1*v2) + (s2*v1)
new_v = self.v.cross(q1.v) + self.s*q1.v + q1.s*self.v
return Quaternion(new_s, new_v)

# check for scalar type
if typearg in ['int','float','long int']:
return Quaternion(q1*self.s,q1*self.v)

__rmul__ = __mul__

def __div__(self,s1):
# divide self by scalar
return Quaternion(self.s/s1,self.v/s1)

def inv(self):
# inverse of self
return self.conj()/self.norm()

def norm(self):
# norm of self
return self.s**2 + self.v.dot(self.v)

def conj(self):
# conjugate of self
return Quaternion(self.s,-self.v)

def rotate(v1,axis,alpha):
# rotate vector v1 around axis 'X', 'Y' or 'Z', by alpha degrees
qr = rotator(axis,alpha)
# sandwich v1 as a Quaternion's vector part
# between a rotator and its inverse
new_q = qr * Quaternion(0,v1) * qr.inv()
return new_q.v  # return just the vector part

def rotator(axis,alpha):
# return quaternion for rotating around axis
# by alpha degrees
alpha = alpha * math.pi/180.0 # convert to radians
ntuple = (axis=="X",axis=="Y",axis=="Z")
v1 = math.sin(alpha/2.0) * Vector(ntuple)
s1 = math.cos(alpha/2.0)
return Quaternion(s1,v1)
```