Transform.as
ActionScript source for Creating low-poly sphere using easing, 218 lines. Raw file
//----- Transform
function Transform()
{
this.p = [0, 0, 0]
this.q = [0, 0, 1, 0]
this.qi = true // Identity quaternion flag (if true, no rotation calculation necessary)
this.pi = true // Zero translation flag (p is zero)
}
//---- setPosition
Transform.prototype.setPosition = function( x, y, z )
{
this.p = [x, y, z]
this.pi = false
}
//---- addPosition
Transform.prototype.addPosition = function( x, y, z )
{
this.p[0] += x
this.p[1] += y
this.p[2] += z
this.pi = false
}
//---- setRotation
Transform.prototype.setRotation = function( x, y, z, r )
{
// Normalise & create quaternion
var s = Math.sin(r/2);
var d = s / Math.sqrt( x*x + y*y + z*z )
this.q = [x*d, y*d, z*d, Math.cos(r/2) ]
this.qi = false
}
//---- addRotation
// This could be made more efficient by explicitly doing the calculation
Transform.prototype.addRotation = function( x, y, z, r )
{
var a = this.copy()
this.setRotation( x, y, z, r )
a.setPosition( 0, 0, 0 )
// Combine with existing rotation
this.combine( a )
}
//---- combine
// does this times z
// The new transformation is done on things first, before the original
// TODO: CombineEx( x, y, z, r ) to save us making a transform in addRotation
Transform.prototype.combine = function( z )
{
// Combine quaternions
var a = this.q
var b = z.q
var dp = a[0]*b[0] + a[1]*b[1] + a[2]*b[2] // Dot (scalar) product
var cp =
[
a[1]*b[2]-a[2]*b[1],
a[2]*b[0]-a[0]*b[2],
a[0]*b[1]-a[1]*b[0]
] // Cross (vector) product
// Combine transformations
var tmp = [0,0,0]
this.transformPoint( z.p, tmp )
this.p = tmp
this.q =
[
b[0]*a[3] + a[0]*b[3] + cp[0],
b[1]*a[3] + a[1]*b[3] + cp[1],
b[2]*a[3] + a[2]*b[3] + cp[2],
a[3]*b[3] - dp
]
this.pi = false
this.qi = false
}
//---- copy
Transform.prototype.copy = function( )
{
var d = new Transform()
d.p[0] = this.p[0]
d.p[1] = this.p[1]
d.p[2] = this.p[2]
d.q = [ this.q[0], this.q[1], this.q[2], this.q[3] ]
d.pi = this.pi
d.qi = this.qi
return d
}
//---- transformPoint
Transform.prototype.transformPoint = function( s, d )
{
//trace( "now "+this.q )
var r1 = s[0]
var r2 = s[1]
var r3 = s[2]
var cx = this.q[0]
var cy = this.q[1]
var cz = this.q[2]
var cw = this.q[3]
//trace( this.q )
// Rotate by q then translate by p
d[0] = this.p[0] + r1*(1-2*(cy*cy+cz*cz)) + r2*(2*cx*cy-2*cw*cz) + r3*(2*cw*cy+2*cx*cz);
d[1] = this.p[1] + r1*(2*cx*cy+2*cw*cz) + r2*(1-2*(cx*cx + cz*cz)) + r3*((-2)*cw*cx+2*cy*cz);
d[2] = this.p[2] + r1*((-2)*cw*cy + 2*cx*cz) + r2*(2*cw*cx+2*cy*cz) + r3*(1-2*(cx*cx + cy*cy));
// trace( "tP: ("+s[0]+", "+s[1]+", "+s[2]+") -> ("+d[0]+", "+d[1]+", "+d[2]+")" )
}
//---- transformNormal
// rotates the given vector but does not translate it
// For working out directions or normals in the space (from the point of view) of the object
Transform.prototype.transformNormal = function( s, d )
{
var r1 = s[0]
var r2 = s[1]
var r3 = s[2]
var cx = this.q[0]
var cy = this.q[1]
var cz = this.q[2]
var cw = this.q[3]
// Rotate by q
d[0] = r1*(1-2*(cy*cy+cz*cz)) + r2*(2*cx*cy-2*cw*cz) + r3*(2*cw*cy+2*cx*cz);
d[1] = r1*(2*cx*cy+2*cw*cz) + r2*(1-2*(cx*cx + cz*cz)) + r3*((-2)*cw*cx+2*cy*cz);
d[2] = r1*((-2)*cw*cy + 2*cx*cz) + r2*(2*cw*cx+2*cy*cz) + r3*(1-2*(cx*cx + cy*cy));
}
//---- transformNormalInv
// rotates the given vector but does not translate it
// For working out directions or normals in the space (from the point of view) of the object
// Does the inverse rotation
Transform.prototype.transformNormalInv = function( s, d )
{
var r1 = s[0]
var r2 = s[1]
var r3 = s[2]
var cx = -this.q[0]
var cy = -this.q[1]
var cz = -this.q[2]
var cw = this.q[3]
// Rotate by q
d[0] = r1*(1-2*(cy*cy+cz*cz)) + r2*(2*cx*cy-2*cw*cz) + r3*(2*cw*cy+2*cx*cz);
d[1] = r1*(2*cx*cy+2*cw*cz) + r2*(1-2*(cx*cx + cz*cz)) + r3*((-2)*cw*cx+2*cy*cz);
d[2] = r1*((-2)*cw*cy + 2*cx*cz) + r2*(2*cw*cx+2*cy*cz) + r3*(1-2*(cx*cx + cy*cy));
}
//---- pointZAxis
Transform.prototype.pointZAxis = function( x, y, z )
{
var d = 1.0 / Math.sqrt( x*x + y*y + z*z )
this.setRotation( y*d, -x*d, 0, -Math.acos( z*d ) )
}