
- Added RigidConstraint. - Depricated some methods (get_result, get_constrainedness) and added some new methods (get_solution, get_cluster, get_status). Removed old SelectionConstraint and renamed FunctionConstraint to SelectionConstraint Depricated ClusterSolver2D Small bugfixes in cluster ClusterSolver3D Renamed solvergui directory to workbench Renamed solvertest directory to test
339 lines
13 KiB
Python
339 lines
13 KiB
Python
from includes import *
|
|
import numpy.numarray as Numeric
|
|
from geosolver.matfunc import Vec
|
|
|
|
class Quaternion:
|
|
def __init__(self, x=0.0, y=0.0, z=0.0, w=1.0):
|
|
#self.quaternion = Numeric.array([x, y, z, w])
|
|
self.quaternion = Vec([x, y, z, w])
|
|
# self.matrix = Numeric.zeros([4,4]) $ ununsed! - Rick
|
|
|
|
def __str__(self):
|
|
return "Quaternion "+str(self.quaternion)
|
|
|
|
def __repr__(self):
|
|
return "Quaternion("+str(repr(self.quaternion))+")"
|
|
|
|
def __mul__(self, quat2):
|
|
return Quaternion(self.quaternion[3]*quat2.quaternion[0] + quat2.quaternion[3]*self.quaternion[0] +
|
|
self.quaternion[1]*quat2.quaternion[2] - self.quaternion[2]*quat2.quaternion[1],
|
|
self.quaternion[3]*quat2.quaternion[1] + quat2.quaternion[3]*self.quaternion[1] +
|
|
self.quaternion[2]*quat2.quaternion[0] - self.quaternion[0]*quat2.quaternion[2],
|
|
self.quaternion[3]*quat2.quaternion[2] + quat2.quaternion[3]*self.quaternion[2] +
|
|
self.quaternion[0]*quat2.quaternion[1] - self.quaternion[1] * quat2.quaternion[0],
|
|
self.quaternion[3]*quat2.quaternion[3] - quat2.quaternion[0]*self.quaternion[0] -
|
|
self.quaternion[1]*quat2.quaternion[1] - self.quaternion[2]*quat2.quaternion[2])
|
|
|
|
def getQuaternion(self):
|
|
return self.quaternion
|
|
|
|
def fromDirection(self, vFrom, vTo):
|
|
vFrom = Vec(vFrom)
|
|
vTo = Vec(vTo)
|
|
epsilon = 1E-10
|
|
fromLengthSq = vFrom.normSquared()
|
|
toLengthSq = vTo.normSquared()
|
|
|
|
if (fromLengthSq < epsilon) or (toLengthSq < epsilon):
|
|
self.quaternion[0] = self.quaternion[1] = self.quaternion[2] = 0.0
|
|
self.quaternion[3] = 1.0
|
|
else:
|
|
axis = vTo.cross(vFrom)
|
|
axisLengthSq = axis.normSquared()
|
|
|
|
if axisLengthSq < epsilon:
|
|
if (math.fabs(vFrom[1]) >= math.fabs(vFrom[0])) and (math.fabs(vFrom[2]) >= math.fabs(vFrom[0])):
|
|
axis[0] = 0.0
|
|
axis[1] = -vFrom[2]
|
|
axis[2] = vFrom[0]
|
|
elif (math.fabs(vFrom[0]) >= math.fabs(vFrom[1])) and (math.fabs(vFrom[2]) >= math.fabs(vFrom[1])):
|
|
axis[0] = -vFrom[2]
|
|
axis[1] = 0.0
|
|
axis[2] = vFrom[0]
|
|
else:
|
|
axis[0] = -vFrom[1]
|
|
axis[1] = vFrom[0]
|
|
axis[2] = 0.0
|
|
|
|
squareroot = math.sqrt(axisLengthSq / (fromLengthSq * toLengthSq))
|
|
|
|
if squareroot > 1.0:
|
|
squareroot = 1.0
|
|
elif squareroot < -1.0:
|
|
squareroot = -1.0
|
|
|
|
angle = math.asin(squareroot)
|
|
|
|
if vFrom.dot(vTo) < 0.0:
|
|
angle = math.pi - angle
|
|
|
|
self.fromAxisAngle(axis, angle)
|
|
|
|
def angleBetween(self, vFrom, vTo):
|
|
d = vFrom.dot(vTo)
|
|
axis = vFrom.cross(vTo)
|
|
qw = math.sqrt(vFrom.normSquared()*vTo.normSquared()) + d
|
|
|
|
if qw < 0.0001:
|
|
self.quaternion[0] = -vFrom[2]
|
|
self.quaternion[1] = vFrom[1]
|
|
self.quaternion[2] = vFrom[0]
|
|
self.quaternion[3] = 1.0
|
|
self.normalize()
|
|
else:
|
|
self.quaternion[0] = axis[0]
|
|
self.quaternion[1] = axis[1]
|
|
self.quaternion[2] = axis[2]
|
|
self.quaternion[3] = qw
|
|
self.normalize()
|
|
|
|
def fromAxisAngle(self, axis, angle):
|
|
axisLength = axis.norm()
|
|
if axisLength < 1E-8:
|
|
self.quaternion[0] = 0.0
|
|
self.quaternion[1] = 0.0
|
|
self.quaternion[2] = 0.0
|
|
self.quaternion[3] = 1.0
|
|
else:
|
|
sinHalfAngle = math.sin(angle/2.0)
|
|
self.quaternion[0] = sinHalfAngle * axis[0]/axisLength
|
|
self.quaternion[1] = sinHalfAngle * axis[1]/axisLength
|
|
self.quaternion[2] = sinHalfAngle * axis[2]/axisLength
|
|
self.quaternion[3] = math.cos(angle/2.0)
|
|
|
|
def fromEulerToQuaternion(self, heading, attitude, bank):
|
|
c1 = math.cos(heading/2.0)
|
|
s1 = math.sin(heading/2.0)
|
|
c2 = math.cos(attitude/2.0)
|
|
s2 = math.sin(attitude/2.0)
|
|
c3 = math.cos(bank/2.0)
|
|
s3 = math.sin(bank/2.0)
|
|
c1c2 = c1*c2
|
|
s1s2 = s1*s2
|
|
tempQuat = Quaternion()
|
|
tempQuat.quaternion[3] = c1c2*c3 - s1s2*s3
|
|
tempQuat.quaternion[0] = c1c2*s3 + s1s2*c3
|
|
tempQuat.quaternion[1] = s1*c2*c3 + c1*s2*s3
|
|
tempQuat.quaternion[2] = c1*s2*c3 - s1*c2*s3
|
|
return tempQuat
|
|
|
|
def getAxisAngle(self, quat, axis):
|
|
realQuat = quat.getQuaternion()
|
|
angle = 2.0*math.acos(realQuat[3])
|
|
axis[0] = realQuat[0]
|
|
axis[1] = realQuat[1]
|
|
axis[2] = realQuat[2]
|
|
|
|
sinus = axis.norm()
|
|
if sinus > 1E-8:
|
|
axis[0] /= sinus
|
|
axis[1] /= sinus
|
|
axis[2] /= sinus
|
|
|
|
if angle > math.pi:
|
|
angle = 2.0*math.pi - angle;
|
|
axis = -axis;
|
|
|
|
return math.degrees(angle)
|
|
|
|
def getMatrix(self, matrix):
|
|
quat00 = 2.0 * self.quaternion[0] * self.quaternion[0]
|
|
quat11 = 2.0 * self.quaternion[1] * self.quaternion[1]
|
|
quat22 = 2.0 * self.quaternion[2] * self.quaternion[2]
|
|
|
|
quat01 = 2.0 * self.quaternion[0] * self.quaternion[1]
|
|
quat02 = 2.0 * self.quaternion[0] * self.quaternion[2]
|
|
quat03 = 2.0 * self.quaternion[0] * self.quaternion[3]
|
|
|
|
quat12 = 2.0 * self.quaternion[1] * self.quaternion[2]
|
|
quat13 = 2.0 * self.quaternion[1] * self.quaternion[3]
|
|
|
|
quat23 = 2.0 * self.quaternion[2] * self.quaternion[3]
|
|
|
|
matrix[0][0] = 1.0 - quat11 - quat22
|
|
matrix[1][0] = quat01 - quat23
|
|
matrix[2][0] = quat02 + quat13
|
|
|
|
matrix[0][1] = quat01 + quat23
|
|
matrix[1][1] = 1.0 - quat22 - quat00
|
|
matrix[2][1] = quat12 - quat03
|
|
|
|
matrix[0][2] = quat02 - quat13
|
|
matrix[1][2] = quat12 + quat03
|
|
matrix[2][2] = 1.0 - quat11 - quat00
|
|
|
|
matrix[0][3] = 0.0
|
|
matrix[1][3] = 0.0
|
|
matrix[2][3] = 0.0
|
|
matrix[3][0] = 0.0
|
|
matrix[3][1] = 0.0
|
|
matrix[3][2] = 0.0
|
|
matrix[3][3] = 1.0
|
|
|
|
# Not used - Rick
|
|
#def getMatrixSingle(self, matrix):
|
|
# mat = Numeric.zeros([4,4])
|
|
# self.getMatrix(mat)
|
|
# count = 0
|
|
# for i in range(4):
|
|
# for j in range(4):
|
|
# matrix[count] = mat[i][j]
|
|
# count += 1
|
|
# #print "between:"
|
|
# #print matrix
|
|
|
|
def getRotationMatrix(self, matrix):
|
|
mat = Numeric.identity(4)
|
|
self.getMatrix(mat)
|
|
|
|
for i in range(4):
|
|
for j in range(4):
|
|
matrix[i][j] = mat[j][i]
|
|
|
|
def axis(self):
|
|
result = Vec([self.quaternion[0], self.quaternion[1], self.quaternion[2]])
|
|
sinus = result.norm()
|
|
if sinus > 1E-8:
|
|
result /= sinus
|
|
if math.acos(self.quaternion[3]) <= (math.pi/2.0):
|
|
return result
|
|
else:
|
|
return -result
|
|
|
|
def angle(self):
|
|
angle = 2.0 * math.acos(self.quaternion[3])
|
|
if angle <= math.pi:
|
|
return angle
|
|
else:
|
|
return 2.0*math.pi - angle
|
|
|
|
def rotate(self, vec):
|
|
quat00 = 2.0 * self.quaternion[0] * self.quaternion[0]
|
|
quat11 = 2.0 * self.quaternion[1] * self.quaternion[1]
|
|
quat22 = 2.0 * self.quaternion[2] * self.quaternion[2]
|
|
|
|
quat01 = 2.0 * self.quaternion[0] * self.quaternion[1]
|
|
quat02 = 2.0 * self.quaternion[0] * self.quaternion[2]
|
|
quat03 = 2.0 * self.quaternion[0] * self.quaternion[3]
|
|
|
|
quat12 = 2.0 * self.quaternion[1] * self.quaternion[2]
|
|
quat13 = 2.0 * self.quaternion[1] * self.quaternion[3]
|
|
|
|
quat23 = 2.0 * self.quaternion[2] * self.quaternion[3]
|
|
|
|
rotation = Vec([0.0, 0.0, 0.0])
|
|
rotation[0] = (1.0 - quat11 - quat22)*vec[0] + ( quat01 - quat23)*vec[1] + (quat02 + quat13)*vec[2]
|
|
rotation[1] = ( quat01 + quat23)*vec[0] + (1.0 - quat22 - quat00)*vec[1] + (quat12 - quat03)*vec[2]
|
|
rotation[2] = ( quat02 - quat13)*vec[0] + ( quat12 + quat03)*vec[1] + (1.0 - quat11 - quat00)*vec[2]
|
|
|
|
#print "rot: ", rotation
|
|
return rotation
|
|
|
|
def inverseRotate(self, vec):
|
|
return self.inverse().rotate(vec)
|
|
|
|
def normalize(self):
|
|
magnitude = Numeric.sqrt(self.quaternion[0]*self.quaternion[0] + self.quaternion[1]*self.quaternion[1] + self.quaternion[2]*self.quaternion[2] + self.quaternion[3]*self.quaternion[3])
|
|
for i in range(4):
|
|
self.quaternion[i] /= magnitude
|
|
return magnitude
|
|
|
|
def normalized(self):
|
|
quat = Quaternion()
|
|
magnitude = sqrt(self.quaternion[0]*self.quaternion[0] + self.quaternion[1]*self.quaternion[1] + self.quaternion[2]*self.quaternion[2] + self.quaternion[3]*self.quaternion[3])
|
|
for i in range(4):
|
|
self.quat = self.quaternion[i] / magnitude
|
|
return quat
|
|
|
|
def invert(self):
|
|
self.quaternion[0] = -self.quaternion[0]
|
|
self.quaternion[1] = -self.quaternion[1]
|
|
self.quaternion[2] = -self.quaternion[2]
|
|
|
|
def inverse(self):
|
|
return Quaternion(-self.quaternion[0], -self.quaternion[1], -self.quaternion[2], self.quaternion[3])
|
|
|
|
def dot(self, qA, qB):
|
|
quatA = qA.getQuaternion()
|
|
quatB = qB.getQuaternion()
|
|
return quatA[0] * quatB[0] + quatA[1] * quatB[1] + quatA[2] * quatB[2] + quatA[3] * quatB[3]
|
|
|
|
def slerp(self, qStart, qEnd, alpha, allowFlip=True):
|
|
cosAngle = self.dot(qStart, qEnd)
|
|
c1 = c2 = 0.0
|
|
|
|
if (1.0 - math.fabs(cosAngle)) < 0.01:
|
|
c1 = 1.0 - alpha
|
|
c2 = alpha
|
|
else:
|
|
angle = math.acos(math.fabs(cosAngle))
|
|
sinAngle = math.sin(angle)
|
|
c1 = math.sin(angle * (1.0 - alpha)) / sinAngle
|
|
c2 = math.sin(angle * alpha) / sinAngle
|
|
|
|
if allowFlip and (cosAngle < 0.0):
|
|
c1 = -c1
|
|
|
|
qStartQuat = qStart.getQuaternion()
|
|
qEndQuat = qEnd.getQuaternion()
|
|
return Quaternion(c1 * qStartQuat[0] + c2*qEndQuat[0], c1 * qStartQuat[1] + c2*qEndQuat[1],
|
|
c1 * qStartQuat[2] + c2*qEndQuat[2], c1 * qStartQuat[3] + c2*qEndQuat[3])
|
|
|
|
def setFromRotatedBasis(self, vecX, vecY, vecZ):
|
|
#print "setFromRotatedBases: ",vecX,vecY,vecZ
|
|
m = Numeric.zeros([3,3])
|
|
normX = vecX.norm()
|
|
normY = vecY.norm()
|
|
normZ = vecZ.norm()
|
|
#print "norms: ",normX, normY, normZ
|
|
for i in range(3):
|
|
m[i][0] = vecX[i] / normX
|
|
m[i][1] = vecY[i] / normY
|
|
m[i][2] = vecZ[i] / normZ
|
|
self.setFromRotationMatrix(m)
|
|
|
|
def setFromRotationMatrix(self, matrix):
|
|
#print "setFromRotationMatix: ",matrix
|
|
onePlusTrace = 1.0 + matrix[0][0] + matrix[1][1] + matrix[2][2]
|
|
|
|
if onePlusTrace > 1E-5:
|
|
s = 0.5/math.sqrt(onePlusTrace)
|
|
self.quaternion[0] = (matrix[2][1] - matrix[1][2]) * s
|
|
self.quaternion[1] = (matrix[0][2] - matrix[2][0]) * s
|
|
self.quaternion[2] = (matrix[1][0] - matrix[0][1]) * s
|
|
self.quaternion[3] = 0.25 / s
|
|
|
|
elif (matrix[0][0] > matrix[1][1]) and (matrix[0][0] > matrix[2][2]):
|
|
s = math.sqrt(1.0 + matrix[0][0] - matrix[1][1] - matrix[2][2]) * 2.0
|
|
self.quaternion[0] = 0.25 * s
|
|
self.quaternion[1] = (matrix[0][1] + matrix[1][0]) / s
|
|
self.quaternion[2] = (matrix[0][2] + matrix[2][0]) / s
|
|
self.quaternion[3] = (matrix[1][2] - matrix[2][1]) / s
|
|
|
|
elif matrix[1][1] > matrix[2][2]:
|
|
s = math.sqrt(1.0 + matrix[1][1] - matrix[0][0] - matrix[2][2]) * 2.0
|
|
self.quaternion[0] = (matrix[0][1] + matrix[1][0]) / s
|
|
self.quaternion[1] = 0.25 * s
|
|
self.quaternion[2] = (matrix[1][2] + matrix[2][1]) / s
|
|
self.quaternion[3] = (matrix[0][2] - matrix[2][0]) /s
|
|
|
|
else:
|
|
s = math.sqrt(1.0 + matrix[2][2] - matrix[0][0] - matrix[1][1]) * 2.0
|
|
self.quaternion[0] = (matrix[0][2] + matrix[2][0]) / s
|
|
self.quaternion[1] = (matrix[1][2] + matrix[2][1]) / s
|
|
self.quaternion[2] = 0.25 * s
|
|
self.quaternion[3] = (matrix[0][1] - matrix[1][0]) /s
|
|
|
|
self.normalize()
|
|
#print "quaternion: ", self.quaternion
|
|
|
|
if __name__ == "__main__":
|
|
print "hallo"
|
|
a = Quaternion(3.0, 3.0, 2.0, 1.0)
|
|
#b = Quaternion()
|
|
#c = a.slerp(a, b, 0.3)
|
|
a.normalize()
|
|
print a.getQuaternion()
|
|
|
|
|