Skip to content

Instantly share code, notes, and snippets.

@jarek-foksa
Created August 24, 2013 11:21
Show Gist options
  • Select an option

  • Save jarek-foksa/6327570 to your computer and use it in GitHub Desktop.

Select an option

Save jarek-foksa/6327570 to your computer and use it in GitHub Desktop.
# @copyright
# © 2012-2013 Jarosław Foksa
{createSVGMatrix} = imports 'utils/dom'
{createSVGTransform} = imports 'utils/transform'
{sin, cos, tan, sqrt, atan2, radToDeg, degToRad, abs, pow, signum} = imports 'utils/math'
# https://github.com/WebKit/webkit/blob/master/Source/WebCore/platform/graphics/transforms/AffineTransform.cpp
# https://dvcs.w3.org/hg/FXTF/raw-file/tip/matrix/index.html
exports matrix =
# | a c e |
# | b d f |
# | 0 0 1 |
a: 1
b: 0
c: 0
d: 1
e: 0
f: 0
init: (@a = 1, @b = 0, @c = 0, @d = 1, @e = 0, @f = 0) ->
return @
initWithSVGMatrix: (svgMatrix) ->
@a = svgMatrix.a
@b = svgMatrix.b
@c = svgMatrix.c
@d = svgMatrix.d
@e = svgMatrix.e
@f = svgMatrix.f
return @
initWithSVGTransform: (svgTransform) ->
@initWithSVGMatrix svgTransform.matrix
return @
copy: ->
copy = matrix.clone().init @a, @b, @c, @d, @e, @f
return copy
# | 1 0 0 |
# | 0 1 0 |
# | 0 0 1 |
reset: ->
@a = 1
@b = 0
@c = 0
@d = 1
@e = 0
@f = 0
# | a c e | | A C E | | a*A+c*B a*C+c*D a*E+c*F |
# | b d f | * | B D F | = | b*A+d*B b*C+d*D b*E+d*F |
# | 0 0 1 | | 0 0 1 | | 0 0 1 |
multiply: (matrix) ->
a = (@a * matrix.a) + (@c * matrix.b)
b = (@b * matrix.a) + (@d * matrix.b)
c = (@a * matrix.c) + (@c * matrix.d)
d = (@b * matrix.c) + (@d * matrix.d)
e = (@a * matrix.e) + (@c * matrix.f) + @e
f = (@b * matrix.e) + (@d * matrix.f) + @f
@a = a
@b = b
@c = c
@d = d
@e = e
@f = f
return @
inverse: ->
if @isInvertible == false
return @
det = @getDeterminant()
a = @d / det
b = -@b / det
c = -@c / det
d = @a / det
e = (@c * @f - @d * @e) / det
f = (@b * @e - @a * @f) / det
@a = a
@b = b
@c = c
@d = d
@e = e
@f = f
return @
translate: (x, y) ->
@e += x
@f += y
return @
translateScaled: (x, y) ->
@e = @e + (x * @a) + (y * @c)
@f = @f + (x * @b) + (y * @d)
return @
scale: (x, y) ->
if y == undefined
y = x
@a = @a * x
@b = @b * x
@c = @c * y
@d = @d * y
return @
flipX: ->
@scale -1, 1
return @
flipY: ->
@scale 1, -1
return @
rotate: (angle, rotX = 0, rotY = 0) ->
angleRad = degToRad angle
cosAngle = cos angleRad
sinAngle = sin angleRad
rotTM = matrix.clone().init cosAngle, sinAngle, -sinAngle, cosAngle, 0, 0
@translateScaled rotX, rotY
@multiply rotTM
@translateScaled -rotX, -rotY
return @
skew: (xAngle, yAngle, rotX = 0, rotY = 0) ->
xRad = degToRad xAngle
yRad = degToRad yAngle
skewTM = matrix.clone().init().shear tan(xRad), tan(yRad)
@translateScaled rotX, rotY
@multiply skewTM
@translateScaled -rotX, -rotY
return @
shear: (x, y) ->
a = @a
b = @b
@a += y * @c
@b += y * @d
@c += x * a
@d += x * b
return @
isIdentityMatrix: ->
if @a == 1 && @b == 0 && @c == 0 && @d == 1 && @e == 0 && @f == 0
return true
else
return false
isInvertible: ->
det = @getDeterminant()
if det == 0
return false
else
return true
# Returns such baseTM and scaleTM matrixes that: baseTM * scaleTM = @
#
# | ±1 baseC baseE | | sx 0 0 | | @a @c @e |
# | baseB ±1 baseF | * | 0 sy 0 | = | @b @d @f |
# | 0 0 1 | | 0 0 1 | | 0 0 1 |
extractScaleTM: ->
{a, b, c, d, e, f} = @
if a == 0
a = 0.0001
if d == 0
d = 0.0001
baseTM = matrix.clone().init signum(a), b/abs(a), c/abs(d), signum(d), e, f
scaleTM = matrix.clone().init abs(a), 0, 0, abs(d), 0, 0
return {baseTM, scaleTM}
# Returns such baseTM and translateTM matrixes that: baseTM * translateTM = @
#
# | baseA baseC 0 | | 1 0 tx | | @a @c @e |
# | baseB baseD 0 | * | 0 1 ty | = | @b @d @f |
# | 0 0 1 | | 0 0 1 | | 0 0 1 |
extractTranslateTM: ->
baseTM = matrix.clone().init @a, @b, @c, @d, 0, 0
ty = (@f*baseTM.a - @e*baseTM.b) / (-baseTM.c*baseTM.b + baseTM.d*baseTM.a)
tx = (@e - baseTM.c*ty) / baseTM.a
translateTM = matrix.clone().init 1, 0, 0, 1, tx, ty
return {baseTM, translateTM}
# Returns such baseTM and transcaleTM matrixes that: baseTM * transcaleTM = @
#
# | baseA baseC 0 | | sx 0 tx | | @a @c @e |
# | baseB baseD 0 | * | 0 sy ty | = | @b @d @f |
# | 0 0 1 | | 0 0 1 | | 0 0 1 |
extractTranscaleTM: ->
{baseTM, scaleTM} = @extractScaleTM()
{baseTM, translateTM} = baseTM.extractTranslateTM()
# baseTM * translateTM * scaleTM = @
transcaleTM = translateTM.multiply scaleTM
return {baseTM, transcaleTM}
getDeterminant: ->
det = (@a * @d) - (@b * @c)
return det
getRotation: ->
rot = atan2 @b, @a
rot = radToDeg rot
return rot
getScaleX: ->
scaleX = sqrt(pow(@a,2) + pow(@b,2))
return scaleX
getScaleY: ->
scaleY = sqrt(pow(@c,2) + pow(@d,2))
return scaleY
toSVGMatrix: ->
svgMatrix = createSVGMatrix @a, @b, @c, @d, @e, @f
return svgMatrix
toSVGTransform: ->
svgMatrix = @toSVGMatrix()
svgTransform = createSVGTransform svgMatrix
return svgTransform
toString: ->
return "matrix(#{@a}, #{@b}, #{@c}, #{@d}, #{@e}, #{@f})"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment