|
| 1 | + |
| 2 | +# |
| 3 | +# Chris Coyne, 2012. You can do what you like this with this file. Sell, burn, mutate, copy. |
| 4 | +# |
| 5 | +# Class for 2D affine transformations. |
| 6 | +# A 2D affine transformation of a point P is |
| 7 | +# defined by a 2*2 matrix (M) and a 2D translating vector (V) and is used to transform points like this:: |
| 8 | +# |
| 9 | +# P' = M*P + V |
| 10 | +# |
| 11 | +# which executes like this: |
| 12 | +# |
| 13 | +# [ px' ] [ M00 M01 ] [ px ] [ v0 ] |
| 14 | +# [ ] = [ ] * [ ] + [ ] |
| 15 | +# [ py' ] [ M10 M11 ] [ py ] [ v1 ] |
| 16 | +# |
| 17 | +# Commonly we represent the transformation as one matrix, like this: |
| 18 | +# |
| 19 | +# [ m00 m01 v0 ] |
| 20 | +# [ m10 m11 v1 ] |
| 21 | +# |
| 22 | +# So we'll have 6 nums: |
| 23 | +# |
| 24 | +# m00,m01,m10,m11,v0,v1 |
| 25 | +# |
| 26 | +# |
| 27 | + |
| 28 | +exports.compose = (a1,a2) -> |
| 29 | + res = a2.copy() |
| 30 | + res.rightComposeWith a1 |
| 31 | + res |
| 32 | + |
| 33 | +class affine2d |
| 34 | + # Multiple ways to construct; check it below |
| 35 | + constructor: (args...) -> |
| 36 | + # if passed nothing, trivial affine |
| 37 | + if args.length == 0 |
| 38 | + @m00 = 1 |
| 39 | + @m01 = 0 |
| 40 | + @m10 = 0 |
| 41 | + @m11 = 1 |
| 42 | + @v0 = 0 |
| 43 | + @v1 = 0 |
| 44 | + # if passed another affine, copy it |
| 45 | + else if args.length == 1 |
| 46 | + @m00 = args[0].m00 |
| 47 | + @m01 = args[0].m01 |
| 48 | + @m10 = args[0].m10 |
| 49 | + @m11 = args[0].m11 |
| 50 | + @v0 = args[0].v0 |
| 51 | + @v1 = args[0].v1 |
| 52 | + # else expecting 6 components |
| 53 | + else |
| 54 | + @m00 = args[0] |
| 55 | + @m01 = args[1] |
| 56 | + @m10 = args[2] |
| 57 | + @m11 = args[3] |
| 58 | + @v0 = args[4] |
| 59 | + @v1 = args[5] |
| 60 | + |
| 61 | + copy: -> new affine2d @ |
| 62 | + |
| 63 | + transform: (v0, v1) -> |
| 64 | + # returns a pair array |
| 65 | + t0 = @m00 * v0 + @m01 * v1 + @v0 |
| 66 | + t1 = @m10 * v0 + @m11 * v1 + @v1 |
| 67 | + [t0, t1] |
| 68 | + |
| 69 | + leftComposeWith: (a) -> |
| 70 | + ### |
| 71 | + destructively edits @, and produces composition of @(a) |
| 72 | + ### |
| 73 | + t_m10 = @m00 * a.m10 + @m10 * a.m11 |
| 74 | + t_m11 = @m01 * a.m10 + @m11 * a.m11 |
| 75 | + t_v1 = @v0 * a.m10 + @v1 * a.m11 + a.v1 |
| 76 | + t_m00 = @m00 * a.m00 + @m10 * a.m01 |
| 77 | + t_m01 = @m01 * a.m00 + @m11 * a.m01 |
| 78 | + t_v0 = @v0 * a.m00 + @v1 * a.m01 + a.v0 |
| 79 | + @m00 = t_m00 |
| 80 | + @m01 = t_m01 |
| 81 | + @m10 = t_m10 |
| 82 | + @m11 = t_m11 |
| 83 | + @v0 = t_v0 |
| 84 | + @v1 = t_v1 |
| 85 | + |
| 86 | + rightComposeWith: (a) -> |
| 87 | + ### |
| 88 | + destructively edits @, and produces composition a(@) |
| 89 | + ### |
| 90 | + t_m10 = a.m00 * @m10 + a.m10 * @m11 |
| 91 | + t_m11 = a.m01 * @m10 + a.m11 * @m11 |
| 92 | + t_v1 = a.v0 * @m10 + a.v1 * @m11 + @v1 |
| 93 | + t_m00 = a.m00 * @m00 + a.m10 * @m01 |
| 94 | + t_m01 = a.m01 * @m00 + a.m11 * @m01 |
| 95 | + t_v0 = a.v0 * @m00 + a.v1 * @m01 + @v0 |
| 96 | + @m00 = t_m00 |
| 97 | + @m01 = t_m01 |
| 98 | + @m10 = t_m10 |
| 99 | + @m11 = t_m11 |
| 100 | + @v0 = t_v0 |
| 101 | + @v1 = t_v1 |
| 102 | + |
| 103 | + getXScale: -> Math.sqrt @m00 * @m00 + @m10 * @m10 |
| 104 | + getYScale: -> Math.sqrt @m01 * @m01 + @m11 * @m11 |
| 105 | + getXCenter: -> @v0 |
| 106 | + getYCenter: -> @v1 |
| 107 | + |
| 108 | +class rotation extends affine2d |
| 109 | + constructor: (r) -> |
| 110 | + console.log r |
| 111 | + console.log Math.cos(r) |
| 112 | + super Math.cos(r), -Math.sin(r), Math.sin(r), Math.cos(r), 0, 0 |
| 113 | + |
| 114 | +class scaling extends affine2d |
| 115 | + constructor: (sx, sy) -> super sx, 0, 0, sy, 0, 0 |
| 116 | + |
| 117 | +class translation extends affine2d |
| 118 | + constructor: (x, y) -> super 1, 0, 0, 1, x, y |
| 119 | + |
| 120 | +class reflectionUnit extends affine2d |
| 121 | + # math for reflection borrowed from John H. |
| 122 | + # couldn't get the damn thing right, myself. |
| 123 | + constructor: (ux, uy) -> |
| 124 | + super 2.0 * ux * ux - 1.0, \ |
| 125 | + 2.0 * ux * uy, \ |
| 126 | + 2.0 * ux * uy, \ |
| 127 | + 2.0 * uy * uy - 1.0, \ |
| 128 | + 0.0, \ |
| 129 | + 0.0 |
| 130 | + |
| 131 | +class reflection extends reflectionUnit |
| 132 | + constructor: (r) -> |
| 133 | + super Math.cos r, Math.sin r |
| 134 | + |
| 135 | +class flipX extends affine2d |
| 136 | + constructor: -> super -1, 0, 0, 1, 0, 0 |
| 137 | + |
| 138 | +class flipY extends affine2d |
| 139 | + constructor: -> super 1, 0, 0, -1, 0, 0 |
| 140 | + |
| 141 | +exports.affine2d = affine2d |
| 142 | +exports.rotation = rotation |
| 143 | +exports.scaling = scaling |
| 144 | +exports.translation = translation |
| 145 | +exports.reflectionUnit = reflectionUnit |
| 146 | +exports.reflection = reflection |
| 147 | +exports.flipX = flipX |
| 148 | +exports.flipY = flipY |
| 149 | + |
0 commit comments