agt 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (103) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.md +7 -0
  3. data/README.md +5 -0
  4. data/app/assets/javascripts/agt/config.coffee +9 -0
  5. data/app/assets/javascripts/agt/dom.coffee +12 -0
  6. data/app/assets/javascripts/agt/function.coffee +317 -0
  7. data/app/assets/javascripts/agt/geom/circle.coffee +338 -0
  8. data/app/assets/javascripts/agt/geom/cubic_bezier.coffee +37 -0
  9. data/app/assets/javascripts/agt/geom/diamond.coffee +241 -0
  10. data/app/assets/javascripts/agt/geom/ellipsis.coffee +141 -0
  11. data/app/assets/javascripts/agt/geom/linear_spline.coffee +56 -0
  12. data/app/assets/javascripts/agt/geom/matrix.coffee +240 -0
  13. data/app/assets/javascripts/agt/geom/mixins/geometry.coffee +171 -0
  14. data/app/assets/javascripts/agt/geom/mixins/intersections.coffee +150 -0
  15. data/app/assets/javascripts/agt/geom/mixins/path.coffee +145 -0
  16. data/app/assets/javascripts/agt/geom/mixins/proxyable.coffee +9 -0
  17. data/app/assets/javascripts/agt/geom/mixins/spline.coffee +329 -0
  18. data/app/assets/javascripts/agt/geom/mixins/surface.coffee +55 -0
  19. data/app/assets/javascripts/agt/geom/mixins/triangulable.coffee +112 -0
  20. data/app/assets/javascripts/agt/geom/point.coffee +454 -0
  21. data/app/assets/javascripts/agt/geom/polygon.coffee +119 -0
  22. data/app/assets/javascripts/agt/geom/quad_bezier.coffee +43 -0
  23. data/app/assets/javascripts/agt/geom/quint_bezier.coffee +42 -0
  24. data/app/assets/javascripts/agt/geom/rectangle.coffee +599 -0
  25. data/app/assets/javascripts/agt/geom/spiral.coffee +90 -0
  26. data/app/assets/javascripts/agt/geom/transformation_proxy.coffee +43 -0
  27. data/app/assets/javascripts/agt/geom/triangle.coffee +442 -0
  28. data/app/assets/javascripts/agt/impulse.coffee +105 -0
  29. data/app/assets/javascripts/agt/index.coffee +56 -0
  30. data/app/assets/javascripts/agt/inflector/inflection.coffee +21 -0
  31. data/app/assets/javascripts/agt/inflector/inflections.coffee +75 -0
  32. data/app/assets/javascripts/agt/inflector/inflector.coffee +235 -0
  33. data/app/assets/javascripts/agt/inheritance.coffee +132 -0
  34. data/app/assets/javascripts/agt/math.coffee +45 -0
  35. data/app/assets/javascripts/agt/mixins/activable.coffee +31 -0
  36. data/app/assets/javascripts/agt/mixins/aliasable.coffee +25 -0
  37. data/app/assets/javascripts/agt/mixins/alternate_case.coffee +72 -0
  38. data/app/assets/javascripts/agt/mixins/cloneable.coffee +71 -0
  39. data/app/assets/javascripts/agt/mixins/delegation.coffee +90 -0
  40. data/app/assets/javascripts/agt/mixins/disposable.coffee +7 -0
  41. data/app/assets/javascripts/agt/mixins/equatable.coffee +37 -0
  42. data/app/assets/javascripts/agt/mixins/formattable.coffee +52 -0
  43. data/app/assets/javascripts/agt/mixins/globalizable.coffee +175 -0
  44. data/app/assets/javascripts/agt/mixins/has_ancestors.coffee +47 -0
  45. data/app/assets/javascripts/agt/mixins/has_collection.coffee +107 -0
  46. data/app/assets/javascripts/agt/mixins/has_nested_collection.coffee +51 -0
  47. data/app/assets/javascripts/agt/mixins/memoizable.coffee +64 -0
  48. data/app/assets/javascripts/agt/mixins/parameterizable.coffee +101 -0
  49. data/app/assets/javascripts/agt/mixins/poolable.coffee +62 -0
  50. data/app/assets/javascripts/agt/mixins/sourcable.coffee +45 -0
  51. data/app/assets/javascripts/agt/mixins/state_machine.coffee +47 -0
  52. data/app/assets/javascripts/agt/net/router.coffee +165 -0
  53. data/app/assets/javascripts/agt/object.coffee +9 -0
  54. data/app/assets/javascripts/agt/particles/actions/base_action.coffee +7 -0
  55. data/app/assets/javascripts/agt/particles/actions/die_on_surface.coffee +14 -0
  56. data/app/assets/javascripts/agt/particles/actions/force.coffee +11 -0
  57. data/app/assets/javascripts/agt/particles/actions/friction.coffee +14 -0
  58. data/app/assets/javascripts/agt/particles/actions/live.coffee +9 -0
  59. data/app/assets/javascripts/agt/particles/actions/macro_action.coffee +13 -0
  60. data/app/assets/javascripts/agt/particles/actions/move.coffee +11 -0
  61. data/app/assets/javascripts/agt/particles/actions/null_action.coffee +9 -0
  62. data/app/assets/javascripts/agt/particles/counters/by_rate.coffee +17 -0
  63. data/app/assets/javascripts/agt/particles/counters/fixed.coffee +9 -0
  64. data/app/assets/javascripts/agt/particles/counters/null_counter.coffee +9 -0
  65. data/app/assets/javascripts/agt/particles/emission.coffee +35 -0
  66. data/app/assets/javascripts/agt/particles/emitters/null_emitter.coffee +7 -0
  67. data/app/assets/javascripts/agt/particles/emitters/path.coffee +10 -0
  68. data/app/assets/javascripts/agt/particles/emitters/ponctual.coffee +9 -0
  69. data/app/assets/javascripts/agt/particles/emitters/surface.coffee +10 -0
  70. data/app/assets/javascripts/agt/particles/initializers/explosion.coffee +19 -0
  71. data/app/assets/javascripts/agt/particles/initializers/life.coffee +16 -0
  72. data/app/assets/javascripts/agt/particles/initializers/macro_initializer.coffee +10 -0
  73. data/app/assets/javascripts/agt/particles/initializers/null_initializer.coffee +7 -0
  74. data/app/assets/javascripts/agt/particles/initializers/particle_sub_system.coffee +12 -0
  75. data/app/assets/javascripts/agt/particles/initializers/stream.coffee +20 -0
  76. data/app/assets/javascripts/agt/particles/mixins/randomizable.coffee +10 -0
  77. data/app/assets/javascripts/agt/particles/particle.coffee +32 -0
  78. data/app/assets/javascripts/agt/particles/sub_system.coffee +11 -0
  79. data/app/assets/javascripts/agt/particles/system.coffee +103 -0
  80. data/app/assets/javascripts/agt/particles/timers/instant.coffee +11 -0
  81. data/app/assets/javascripts/agt/particles/timers/limited.coffee +19 -0
  82. data/app/assets/javascripts/agt/particles/timers/null_timer.coffee +11 -0
  83. data/app/assets/javascripts/agt/particles/timers/unlimited.coffee +9 -0
  84. data/app/assets/javascripts/agt/particles/timers/until_death.coffee +11 -0
  85. data/app/assets/javascripts/agt/promise.coffee +214 -0
  86. data/app/assets/javascripts/agt/random/random.coffee +100 -0
  87. data/app/assets/javascripts/agt/random/seeds/lagged_fibonnacci.coffee +53 -0
  88. data/app/assets/javascripts/agt/random/seeds/linear.coffee +16 -0
  89. data/app/assets/javascripts/agt/random/seeds/linear_congruential.coffee +23 -0
  90. data/app/assets/javascripts/agt/random/seeds/math_random.coffee +9 -0
  91. data/app/assets/javascripts/agt/random/seeds/mersenne_twister.coffee +42 -0
  92. data/app/assets/javascripts/agt/random/seeds/no_random.coffee +12 -0
  93. data/app/assets/javascripts/agt/random/seeds/paul_houle.coffee +19 -0
  94. data/app/assets/javascripts/agt/signal.coffee +272 -0
  95. data/app/assets/javascripts/agt/sprites/animation.coffee +13 -0
  96. data/app/assets/javascripts/agt/sprites/sprite.coffee +30 -0
  97. data/app/assets/javascripts/agt/widgets/hash.coffee +36 -0
  98. data/app/assets/javascripts/agt/widgets/widgets.coffee +194 -0
  99. data/app/assets/javascripts/agt/widgets/widgets/checked_input.coffee +7 -0
  100. data/app/assets/javascripts/agt/widgets/widgets/focus_bubbling.coffee +15 -0
  101. data/lib/agt.rb +8 -0
  102. data/lib/agt/version.rb +5 -0
  103. metadata +173 -0
@@ -0,0 +1,119 @@
1
+ namespace('agt.geom')
2
+
3
+ # Public:
4
+ class agt.geom.Polygon
5
+ @extend agt.mixins.Aliasable
6
+
7
+ @include agt.mixins.Formattable('Polygon', 'vertices')
8
+ @include agt.mixins.Sourcable('agt.geom.Polygon', 'vertices')
9
+ @include agt.mixins.Cloneable()
10
+ @include agt.geom.Geometry
11
+ @include agt.geom.Intersections
12
+ @include agt.geom.Triangulable
13
+ @include agt.geom.Surface
14
+ @include agt.geom.Path
15
+
16
+ ### Public ###
17
+
18
+ @polygonFrom: (vertices) ->
19
+ if vertices? and typeof vertices is 'object'
20
+ isArray = Object::toString.call(vertices).indexOf('Array') isnt -1
21
+ return vertices unless isArray
22
+ {vertices}
23
+ else
24
+ vertices: null
25
+
26
+ constructor: (vertices) ->
27
+ {vertices} = @polygonFrom vertices
28
+
29
+ @noVertices() unless vertices?
30
+ @notEnougthVertices vertices if vertices.length < 3
31
+ @vertices = vertices
32
+
33
+ center: ->
34
+ x = y = 0
35
+
36
+ for vertex in @vertices
37
+ x += vertex.x
38
+ y += vertex.y
39
+
40
+ x = x / @vertices.length
41
+ y = y / @vertices.length
42
+
43
+ new agt.geom.Point x, y
44
+
45
+ translate: (x,y) ->
46
+ {x,y} = agt.geom.Point.pointFrom x,y
47
+ for vertex in @vertices
48
+ vertex.x += x
49
+ vertex.y += y
50
+ this
51
+
52
+ rotate: (rotation) ->
53
+ center = @center()
54
+ for vertex,i in @vertices
55
+ @vertices[i] = vertex.rotateAround center, rotation
56
+ this
57
+
58
+ @alias 'rotate', 'rotateAroundCenter'
59
+
60
+ scale: (scale) ->
61
+ center = @center()
62
+ for vertex,i in @vertices
63
+ @vertices[i] = center.add vertex.subtract(center).scale(scale)
64
+ this
65
+
66
+
67
+ @alias 'scale', 'scaleAroundCenter'
68
+
69
+ points: ->
70
+ (vertex.clone() for vertex in @vertices).concat(@vertices[0].clone())
71
+
72
+ closedGeometry: -> true
73
+
74
+ pointAtAngle: (angle) ->
75
+ center = @center()
76
+ distance = (a,b) -> a.distance(center) - b.distance(center)
77
+ vec = center.add Math.cos(angle)*10000,
78
+ Math.sin(angle)*10000
79
+ @intersections(points: -> [center, vec])?.sort(distance)[0]
80
+
81
+ acreage: ->
82
+ acreage = 0
83
+ acreage += tri.acreage() for tri in @triangles()
84
+ acreage
85
+
86
+ contains: (x,y) ->
87
+ return true for tri in @triangles() when tri.contains x,y
88
+ false
89
+
90
+ randomPointInSurface: (random) ->
91
+ unless random?
92
+ random = new agt.random.Random new agt.random.MathRandom
93
+
94
+ acreage = @acreage()
95
+ triangles = @triangles()
96
+ ratios = triangles.map (t, i) -> t.acreage() / acreage
97
+ ratios[i] += ratios[i-1] for n,i in ratios when i > 0
98
+
99
+ random.inArray(triangles, ratios, true).randomPointInSurface random
100
+
101
+ length: ->
102
+ length = 0
103
+ points = @points()
104
+ for i in [1..points.length-1]
105
+ length += points[i-1].distance(points[i])
106
+ length
107
+
108
+ memoizationKey: -> @vertices.map((pt) -> "#{pt.x},#{pt.y}").join ";"
109
+
110
+ ### Internal ###
111
+
112
+ polygonFrom: Polygon.polygonFrom
113
+
114
+ noVertices: ->
115
+ throw new Error 'No vertices provided to Polygon'
116
+
117
+ notEnougthVertices: (vertices) ->
118
+ length = vertices.length
119
+ throw new Error "Polygon must have at least 3 vertices, was #{length}"
@@ -0,0 +1,43 @@
1
+ namespace('agt.geom')
2
+
3
+ # Public:
4
+ #
5
+ # ### Included Mixins
6
+ #
7
+ # - {agt.geom.Geometry}
8
+ # - {agt.geom.Intersections}
9
+ # - {agt.geom.Path}
10
+ # - [agt.mixins.Spline](../../../files/geom/mixins/spline.coffee.html)
11
+ # - [agt.mixins.Formattable](../../../files/mixins/formattable.coffee.html)
12
+ # - [agt.mixins.Memoizable](../../../files/mixins/memoizable.coffee.html)
13
+ # - [agt.mixins.Sourcable](../../../files/mixins/sourcable.coffee.html)
14
+ class agt.geom.QuadBezier
15
+ @include agt.mixins.Formattable('QuadBezier')
16
+ @include agt.mixins.Sourcable('agt.geom.QuadBezier', 'vertices', 'bias')
17
+ @include agt.geom.Geometry
18
+ @include agt.geom.Path
19
+ @include agt.geom.Intersections
20
+ @include agt.geom.Spline(2)
21
+
22
+ ### Public ###
23
+
24
+ constructor: (vertices, bias=20) ->
25
+ @initSpline vertices, bias
26
+
27
+ pointInSegment: (t, seg) ->
28
+ pt = new agt.geom.Point()
29
+ pt.x = (seg[0].x * @b1 (t)) +
30
+ (seg[1].x * @b2 (t)) +
31
+ (seg[2].x * @b3 (t))
32
+ pt.y = (seg[0].y * @b1 (t)) +
33
+ (seg[1].y * @b2 (t)) +
34
+ (seg[2].y * @b3 (t))
35
+ pt
36
+
37
+ ### Internal ###
38
+
39
+ b1: (t) -> ((1 - t) * (1 - t) )
40
+
41
+ b2: (t) -> (2 * t * (1 - t))
42
+
43
+ b3: (t) -> (t * t)
@@ -0,0 +1,42 @@
1
+
2
+ namespace('agt.geom')
3
+
4
+ # Public:
5
+ class agt.geom.QuintBezier
6
+ @include agt.mixins.Formattable('QuintBezier')
7
+ @include agt.mixins.Sourcable('agt.geom.QuintBezier', 'vertices', 'bias')
8
+ @include agt.geom.Geometry
9
+ @include agt.geom.Path
10
+ @include agt.geom.Intersections
11
+ @include agt.geom.Spline(4)
12
+
13
+ ### Public ###
14
+
15
+ constructor: (vertices, bias=20) ->
16
+ @initSpline vertices, bias
17
+
18
+ pointInSegment: (t, seg) ->
19
+ pt = new agt.geom.Point()
20
+ pt.x = (seg[0].x * @b1 (t)) +
21
+ (seg[1].x * @b2 (t)) +
22
+ (seg[2].x * @b3 (t)) +
23
+ (seg[3].x * @b4 (t)) +
24
+ (seg[4].x * @b5 (t))
25
+ pt.y = (seg[0].y * @b1 (t)) +
26
+ (seg[1].y * @b2 (t)) +
27
+ (seg[2].y * @b3 (t)) +
28
+ (seg[3].y * @b4 (t)) +
29
+ (seg[4].y * @b5 (t))
30
+ pt
31
+
32
+ ### Internal ###
33
+
34
+ b1: (t) -> ((1 - t) * (1 - t) * (1 - t) * (1 - t))
35
+
36
+ b2: (t) -> (4 * t * (1 - t) * (1 - t) * (1 - t))
37
+
38
+ b3: (t) -> (6 * t * t * (1 - t) * (1 - t))
39
+
40
+ b4: (t) -> (4 * t * t * t * (1 - t))
41
+
42
+ b5: (t) -> (t * t * t * t)
@@ -0,0 +1,599 @@
1
+
2
+ namespace('agt.geom')
3
+
4
+ # Public: A `Rectangle` geometry is defined with a position, a size
5
+ # and a rotation.
6
+ #
7
+ # ```coffeescript
8
+ # rectangle = new Rectangle 20, 20, 80, 40, Math.PI * 0.1
9
+ # rectangle = new Rectangle x: 20, y: 20, width: 80, height: 40, rotation: Math.PI * 0.1
10
+ # ```
11
+ #
12
+ # <script>window.exampleKey = 'rectangle'</script>
13
+ # <script>drawGeometry(exampleKey, {highlight: true})</script>
14
+ #
15
+ # ### Included Mixins
16
+ #
17
+ # - {agt.geom.Geometry}
18
+ # - {agt.geom.Intersections}
19
+ # - {agt.geom.Path}
20
+ # - {agt.geom.Surface}
21
+ # - {agt.mixins.Aliasable}
22
+ # - [agt.mixins.Cloneable](../../../files/mixins/cloneable.coffee.html)
23
+ # - [agt.mixins.Equatable](../../../files/mixins/equatable.coffee.html)
24
+ # - [agt.mixins.Formattable](../../../files/mixins/formattable.coffee.html)
25
+ # - [agt.mixins.Memoizable](../../../files/mixins/memoizable.coffee.html)
26
+ # - [agt.mixins.Parameterizable](../../../files/mixins/parameterizable.coffee.html)
27
+ # - [agt.mixins.Sourcable](../../../files/mixins/sourcable.coffee.html)
28
+ class agt.geom.Rectangle
29
+ properties = ['x','y','width','height','rotation']
30
+
31
+ @extend agt.mixins.Aliasable
32
+
33
+ @include agt.mixins.Cloneable()
34
+ @include agt.mixins.Equatable.apply(null, properties)
35
+ @include agt.mixins.Formattable.apply(null, ['Rectangle'].concat properties)
36
+ @include agt.mixins.Sourcable.apply(null, ['agt.geom.Rectangle'].concat properties)
37
+ @include agt.mixins.Parameterizable('rectangleFrom', {
38
+ x: NaN
39
+ y: NaN
40
+ width: NaN
41
+ height: NaN
42
+ rotation: NaN
43
+ })
44
+ @include agt.geom.Geometry
45
+ @include agt.geom.Surface
46
+ @include agt.geom.Path
47
+ @include agt.geom.Triangulable
48
+ @include agt.geom.Proxyable
49
+ @include agt.geom.Intersections
50
+
51
+ ### Public ###
52
+
53
+ # A specific intersection algorithm when confronting two rectangles.
54
+ #
55
+ # <script>drawShapeIntersections(exampleKey, exampleKey)</script>
56
+ #
57
+ # geom1 - The first rectangle.
58
+ # geom2 - The second rectangle.
59
+ # block - The callback {Function} to call for each intersection.
60
+ # data - A {Boolean} of whether to include extra data per intersection.
61
+ @eachRectangleRectangleIntersections: (geom1, geom2, block, data=false) ->
62
+ if geom1.equals geom2
63
+ for p in geom1.points()
64
+ return if block.call this, p
65
+ else
66
+ @eachIntersections geom1, geom2, block, data
67
+
68
+ # Registers the fast intersections iterators for the Rectangle class
69
+ iterators = agt.geom.Intersections.iterators
70
+ k = 'RectangleRectangle'
71
+ iterators[k] = Rectangle.eachRectangleRectangleIntersections
72
+
73
+ # Creates a new `Rectangle` instance.
74
+ #
75
+ # x - The x coordinate {Number} of the rectangle or a rectangle-like {Object}.
76
+ # y - The y coordinate {Number} of the rectangle.
77
+ # width - The width {Number} of the rectangle.
78
+ # height - The height {Number} of the rectangle.
79
+ # rotation - The rotation {Number} of the rectangle.
80
+ constructor: (x, y, width, height, rotation) ->
81
+ args = @defaultToZero @rectangleFrom.apply this, arguments
82
+ {@x,@y,@width,@height,@rotation} = args
83
+
84
+ # Returns the coordinates of the rectangle's corners in an {Array}.
85
+ #
86
+ # <script>drawGeometryPoints(exampleKey, 'corners')</script>
87
+ #
88
+ # Returns an {Array}.
89
+ corners: -> [@topLeft(), @topRight(), @bottomRight(), @bottomLeft()]
90
+
91
+ # Returns the coordinates of the top left corner of the rectangle.
92
+ #
93
+ # <script>drawGeometryPoints(exampleKey, 'topLeft')</script>
94
+ #
95
+ # Returns a [Point]{agt.geom.Point}.
96
+ topLeft: -> new agt.geom.Point(@x, @y)
97
+
98
+ # Returns the coordinates of the top right corner of the rectangle.
99
+ #
100
+ # <script>drawGeometryPoints(exampleKey, 'topRight')</script>
101
+ #
102
+ # Returns a [Point]{agt.geom.Point}.
103
+ topRight: -> @topLeft().add(@topEdge())
104
+
105
+ # Returns the coordinates of the bottom left corner of the rectangle.
106
+ #
107
+ # <script>drawGeometryPoints(exampleKey, 'bottomLeft')</script>
108
+ #
109
+ # Returns a [Point]{agt.geom.Point}.
110
+ bottomLeft: -> @topLeft().add(@leftEdge())
111
+
112
+ # Returns the coordinates of the bottom right corner of the rectangle.
113
+ #
114
+ # <script>drawGeometryPoints(exampleKey, 'bottomRight')</script>
115
+ #
116
+ # Returns a [Point]{agt.geom.Point}.
117
+ bottomRight: -> @topLeft().add(@topEdge()).add(@leftEdge())
118
+
119
+ # Returns the coordinates of the center of the rectangle.
120
+ #
121
+ # <script>drawGeometry(exampleKey, {center: true})</script>
122
+ #
123
+ # Returns a [Point]{agt.geom.Point}
124
+ center: -> @topLeft().add(@diagonal().scale(0.5))
125
+
126
+ # Returns the coordinates of the center of the upper edge of the rectangle.
127
+ #
128
+ # <script>drawGeometryPoints(exampleKey, 'topEdgeCenter')</script>
129
+ #
130
+ # Returns a [Point]{agt.geom.Point}.
131
+ topEdgeCenter: -> @topLeft().add(@topEdge().scale(0.5))
132
+
133
+ # Returns the coordinates of the center of the bottom edge of the rectangle.
134
+ #
135
+ # <script>drawGeometryPoints(exampleKey, 'bottomEdgeCenter')</script>
136
+ #
137
+ # Returns a [Point]{agt.geom.Point}.
138
+ bottomEdgeCenter: -> @bottomLeft().add(@topEdge().scale(0.5))
139
+
140
+ # Returns the coordinates of the center of the left edge of the rectangle.
141
+ #
142
+ # <script>drawGeometryPoints(exampleKey, 'leftEdgeCenter')</script>
143
+ #
144
+ # Returns a [Point]{agt.geom.Point}.
145
+ leftEdgeCenter: -> @topLeft().add(@leftEdge().scale(0.5))
146
+
147
+ # Returns the coordinates of the center of the right edge of the rectangle.
148
+ #
149
+ # <script>drawGeometryPoints(exampleKey, 'rightEdgeCenter')</script>
150
+ #
151
+ # Returns a [Point]{agt.geom.Point}.
152
+ rightEdgeCenter: -> @topRight().add(@leftEdge().scale(0.5))
153
+
154
+ # Returns an array containing all the rectangle's edges vectors.
155
+ #
156
+ # Returns an {Array}.
157
+ edges: -> [@topEdge(), @topRight(), @bottomRight(), @bottomLeft()]
158
+
159
+ # Returns the rectangle's top edge vector.
160
+ #
161
+ # <script>drawGeometryEdge(exampleKey, 'topLeft', 'topEdge')</script>
162
+ #
163
+ # Returns a [Point]{agt.geom.Point}.
164
+ topEdge: -> new agt.geom.Point @width * Math.cos(@rotation),
165
+ @width * Math.sin(@rotation)
166
+
167
+ # Returns the rectangle's left edge vector.
168
+ #
169
+ # <script>drawGeometryEdge(exampleKey, 'topLeft', 'leftEdge')</script>
170
+ #
171
+ # Returns a [Point]{agt.geom.Point}.
172
+ leftEdge: ->
173
+ new agt.geom.Point @height * Math.cos(@rotation + Math.PI / 2),
174
+ @height * Math.sin(@rotation + Math.PI / 2)
175
+
176
+ # Returns the rectangle's bottom edge vector.
177
+ #
178
+ # <script>drawGeometryEdge(exampleKey, 'bottomLeft', 'bottomEdge')</script>
179
+ #
180
+ # Returns a [Point]{agt.geom.Point}.
181
+ bottomEdge: -> @topEdge()
182
+
183
+ # Returns the rectangle's right edge vector.
184
+ #
185
+ # <script>drawGeometryEdge(exampleKey, 'topRight', 'rightEdge')</script>
186
+ #
187
+ # Returns a [Point]{agt.geom.Point}.
188
+ rightEdge: -> @leftEdge()
189
+
190
+ # Returns the rectangle's diagonal vector.
191
+ #
192
+ # <script>drawGeometryEdge(exampleKey, 'topLeft', 'diagonal')</script>
193
+ #
194
+ # Returns a [Point]{agt.geom.Point}.
195
+ diagonal: -> @leftEdge().add(@topEdge())
196
+
197
+ # Returns the top-most coordinate of the rectangle shape.
198
+ #
199
+ # <script>drawGeometryBound(exampleKey, 'top')</script>
200
+ #
201
+ # Returns a {Number}.
202
+ top: -> Math.min @y, @topRight().y, @bottomRight().y, @bottomLeft().y
203
+
204
+ # Returns the bottom-most coordinate of the rectangle shape.
205
+ #
206
+ # <script>drawGeometryBound(exampleKey, 'bottom')</script>
207
+ #
208
+ # Returns a {Number}.
209
+ bottom: -> Math.max @y, @topRight().y, @bottomRight().y, @bottomLeft().y
210
+
211
+ # Returns the left-most coordinate of the rectangle shape.
212
+ #
213
+ # <script>drawGeometryBound(exampleKey, 'left')</script>
214
+ #
215
+ # Returns a {Number}.
216
+ left: -> Math.min @x, @topRight().x, @bottomRight().x, @bottomLeft().x
217
+
218
+ # Returns the right-most coordinate of the rectangle shape.
219
+ #
220
+ # <script>drawGeometryBound(exampleKey, 'right')</script>
221
+ #
222
+ # Returns a {Number}.
223
+ right: -> Math.max @x, @topRight().x, @bottomRight().x, @bottomLeft().x
224
+
225
+ # Sets the position of the rectangle using its center as reference.
226
+ #
227
+ # <script>drawTransform(exampleKey, {type: 'setCenter', args: [100, 50], width: 150})</script>
228
+ #
229
+ # x - A {Number} for the x coordinate or a point-like {Object}.
230
+ # y - A {Number} for the y coordinate if the first argument
231
+ # was also a number.
232
+ #
233
+ # Returns this [Rectangle]{agt.geom.Rectangle}.
234
+ setCenter: (x, y) ->
235
+ pt = agt.geom.Point.pointFrom(x, y).subtract(@center())
236
+
237
+ @x += pt.x
238
+ @y += pt.y
239
+ this
240
+
241
+ # Adds the passed-in [Point]{agt.geom.Point} to the position
242
+ # of this rectangle.
243
+ #
244
+ # <script>drawTransform(exampleKey, {type: 'translate', args: [50, 0], width: 150})</script>
245
+ #
246
+ # x - A {Number} for the x coordinate or a point-like {Object}.
247
+ # y - A {Number} for the y coordinate if the first argument
248
+ # was also a number.
249
+ #
250
+ # Returns this {Rectangle}.
251
+ translate: (x, y) ->
252
+ pt = agt.geom.Point.pointFrom(x, y)
253
+
254
+ @x += pt.x
255
+ @y += pt.y
256
+ this
257
+
258
+ # Adds the passed-in rotation to the current rectangle rotation.
259
+ #
260
+ # <script>drawTransform(exampleKey, {type: 'rotate', args: [-Math.PI/ 4]})</script>
261
+ #
262
+ # **Note:** This method is also aliased as `rotateAroundCenter`.
263
+ #
264
+ # rotation - The rotation {Number}.
265
+ #
266
+ # Returns this {Rectangle}.
267
+ rotate: (rotation) ->
268
+ {@x,@y} = @topLeft().rotateAround(@center(), rotation)
269
+ @rotation += rotation
270
+ this
271
+
272
+ @alias 'rotate', 'rotateAroundCenter'
273
+
274
+ # Scales the rectangle by multiplying its width and height by the passed-in
275
+ # scale factor. The scaling is performed from the center of the rectangle,
276
+ # which imply changing the rectangle position.
277
+ # You can use the `width` and `height` property to change the size of the
278
+ # rectangle without affecting the position.
279
+ #
280
+ # <script>drawTransform(exampleKey, {type: 'scale', args: [0.6]})</script>
281
+ #
282
+ # scale - The scale {Number} to apply to the rectangle.
283
+ #
284
+ # Returns this {Rectangle}.
285
+ scale: (scale) ->
286
+ center = @center()
287
+ @width *= scale
288
+ @height *= scale
289
+ @setCenter center
290
+ this
291
+
292
+ @alias 'scale', 'scaleAroundCenter'
293
+
294
+ # Inflates the rectangle around its center by the amount of the arguments.
295
+ #
296
+ # <script>drawTransform(exampleKey, {type: 'inflateAroundCenter', args: [10, 10]})</script>
297
+ #
298
+ # x - A {Number} for the width or a point-like {Object}.
299
+ # y - A {Number} for the height if the first argument
300
+ # was also a number.
301
+ #
302
+ # Returns this [Rectangle]{agt.geom.Rectangle}.
303
+ inflateAroundCenter: (x, y) ->
304
+ center = @center()
305
+ @inflate x, y
306
+ @setCenter center
307
+ this
308
+
309
+ # Inflates the rectangle from its origin by the amount of the arguments.
310
+ #
311
+ # <script>drawTransform(exampleKey, {type: 'inflate', args: [10, 10]})</script>
312
+ #
313
+ # x - A {Number} for the width or a point-like {Object}.
314
+ # y - A {Number} for the height if the first argument
315
+ # was also a number.
316
+ #
317
+ # Returns this [Rectangle]{agt.geom.Rectangle}.
318
+ inflate: (x, y) ->
319
+ pt = agt.geom.Point.pointFrom x, y
320
+ @width += pt.x
321
+ @height += pt.y
322
+ this
323
+
324
+ # Inflates the rectangle width to the left by the passed-in value.
325
+ #
326
+ # <script>drawTransform(exampleKey, {type: 'inflateLeft', args: [10]})</script>
327
+ #
328
+ # inflate - a {Number} for the width inflation.
329
+ #
330
+ # Returns this [Rectangle]{agt.geom.Rectangle}.
331
+ inflateLeft: (inflate) ->
332
+ @width += inflate
333
+ offset = @topEdge().normalize(-inflate)
334
+ {@x,@y} = @topLeft().add(offset)
335
+ this
336
+
337
+ # Inflates the rectangle width to the right by the passed-in value.
338
+ #
339
+ # <script>drawTransform(exampleKey, {type: 'inflateRight', args: [10]})</script>
340
+ #
341
+ # inflate - A {Number} for width inflation.
342
+ #
343
+ # Returns this [Rectangle]{agt.geom.Rectangle}.
344
+ inflateRight: (inflate) ->
345
+ @width += inflate
346
+ this
347
+
348
+ # Inflates the rectangle height to the top by the passed-in value.
349
+ #
350
+ # <script>drawTransform(exampleKey, {type: 'inflateTop', args: [10]})</script>
351
+ #
352
+ # x - A {Number} for the height inflation.
353
+ #
354
+ # Returns this [Rectangle]{agt.geom.Rectangle}.
355
+ inflateTop: (inflate) ->
356
+ @height += inflate
357
+ offset = @leftEdge().normalize(-inflate)
358
+ {@x,@y} = @topLeft().add(offset)
359
+ this
360
+
361
+ # Inflates the rectangle height to the bottom by the passed-in value.
362
+ #
363
+ # <script>drawTransform(exampleKey, {type: 'inflateBottom', args: [10]})</script>
364
+ #
365
+ # x - A {Number} for the height inflation.
366
+ #
367
+ # Returns this [Rectangle]{agt.geom.Rectangle}.
368
+ inflateBottom: (inflate) ->
369
+ @height += inflate
370
+ this
371
+
372
+ # Inflates the rectangle to the top left by the amount of the arguments.
373
+ #
374
+ # <script>drawTransform(exampleKey, {type: 'inflateTopLeft', args: [10, 10]})</script>
375
+ #
376
+ # x - A {Number} for the width or a point-like {Object}.
377
+ # y - A {Number} for the height if the first argument
378
+ # was also a number.
379
+ #
380
+ # Returns this [Rectangle]{agt.geom.Rectangle}.
381
+ inflateTopLeft: (x, y) ->
382
+ pt = agt.geom.Point.pointFrom x, y
383
+ @inflateLeft pt.x
384
+ @inflateTop pt.y
385
+ this
386
+
387
+ # Inflates the rectangle to the top right by the amount of the arguments.
388
+ #
389
+ # <script>drawTransform(exampleKey, {type: 'inflateTopRight', args: [10, 10]})</script>
390
+ #
391
+ # x - A {Number} for the width or a point-like {Object}.
392
+ # y - A {Number} for the height if the first argument
393
+ # was also a number.
394
+ #
395
+ # Returns this [Rectangle]{agt.geom.Rectangle}.
396
+ inflateTopRight: (x, y) ->
397
+ pt = agt.geom.Point.pointFrom x, y
398
+ @inflateRight pt.x
399
+ @inflateTop pt.y
400
+ this
401
+
402
+ # Inflates the rectangle to the bottom left by the amount of the arguments.
403
+ #
404
+ # <script>drawTransform(exampleKey, {type: 'inflateBottomLeft', args: [10, 10]})</script>
405
+ #
406
+ # x - A {Number} for the width or a point-like {Object}.
407
+ # y - A {Number} for the height if the first argument
408
+ # was also a number.
409
+ #
410
+ # Returns this [Rectangle]{agt.geom.Rectangle}.
411
+ inflateBottomLeft: (x, y) ->
412
+ pt = agt.geom.Point.pointFrom x, y
413
+ @inflateLeft pt.x
414
+ @inflateBottom pt.y
415
+ this
416
+
417
+ # Inflates the rectangle to the bottom right by the amount of the arguments.
418
+ #
419
+ # <script>drawTransform(exampleKey, {type: 'inflateBottomRight', args: [10, 10]})</script>
420
+ #
421
+ # x - A {Number} for the width or a point-like {Object}.
422
+ # y - A {Number} for the height if the first argument
423
+ # was also a number.
424
+ #
425
+ # Returns this [Rectangle]{agt.geom.Rectangle}.
426
+ inflateBottomRight: (x, y) -> @inflate x, y
427
+
428
+ # Always returns `true`.
429
+ #
430
+ # Returns a {Boolean}.
431
+ closedGeometry: -> true
432
+
433
+ # Returns the rectangle points.
434
+ #
435
+ # <script>drawGeometryPoints(exampleKey, 'points')</script>
436
+ #
437
+ # Returns an {Array}.
438
+ points: ->
439
+ [@topLeft(), @topRight(), @bottomRight(), @bottomLeft(), @topLeft()]
440
+
441
+ # Returns the [Point]{agt.geom.Point} on the perimeter of the rectangle
442
+ # at the given `angle`.
443
+ #
444
+ # angle - The angle {Number}.
445
+ #
446
+ # <script>drawGeometry(exampleKey, {angle: true})</script>
447
+ #
448
+ # Returns a [Point]{agt.geom.Point}.
449
+ pointAtAngle: (angle) ->
450
+ center = @center()
451
+ vec = center.add Math.cos(angle)*10000,
452
+ Math.sin(angle)*10000
453
+ @intersections(points: -> [center, vec])?[0]
454
+
455
+ # Returns the surface {Number} of this rectangle.
456
+ #
457
+ # Returns a {Number}.
458
+ acreage: -> @width * @height
459
+
460
+ # Returns `true` when the given point is contained in the rectangle.
461
+ #
462
+ # In the example below all the green points on the screen represents
463
+ # coordinates that are contained in the rectangle.
464
+ #
465
+ # <script>drawGeometry(exampleKey, {contains: true})</script>
466
+ #
467
+ # x - A {Number} for the x coordinate or a point-like {Object}.
468
+ # y - A {Number} for the y coordinate if the first argument
469
+ # was also a number.
470
+ #
471
+ # Returns a {Boolean}.
472
+ contains: (x, y) ->
473
+ {x,y} = new agt.geom.Point(x, y).rotateAround(@topLeft(), -@rotation)
474
+ (@x <= x <= @x + @width) and (@y <= y <= @y + @height)
475
+
476
+ # Returns a randomly generated point within the rectangle perimeter.
477
+ #
478
+ # <script>drawGeometry(exampleKey, {surface: true})</script>
479
+ #
480
+ # random - An optional [Random]{agt.random.Random} instance to use instead
481
+ # of the default `Math` random method.
482
+ #
483
+ # Returns a [Point]{agt.geom.Point}.
484
+ randomPointInSurface: (random) ->
485
+ unless random?
486
+ random = new agt.random.Random new agt.random.MathRandom
487
+ @topLeft()
488
+ .add(@topEdge().scale random.get())
489
+ .add(@leftEdge().scale random.get())
490
+
491
+ # Returns the length {Number} of the rectangle perimeter.
492
+ #
493
+ # Returns a {Number}.
494
+ length: -> @width * 2 + @height * 2
495
+
496
+ # Returns a [Point]{agt.geom.Point} on the rectangle perimeter using
497
+ # a {Number} between `0` and `1`.
498
+ #
499
+ # <script>drawGeometry(exampleKey, {paths: [0, 1/3, 2/3]})</script>
500
+ #
501
+ # n - A {Number} between `0` and `1`a {Number} between `0` and `1`.
502
+ # pathBasedOnLength - A {Boolean} of whether the position on the path
503
+ # consider the length of the path segments or not.
504
+ # When true, each segment will only weight as much
505
+ # as their own length.
506
+ # When false, every segment have the same weight,
507
+ # resulting in a difference in speed when animating
508
+ # an object along a path.
509
+ #
510
+ # Returns a [Point]{agt.geom.Point}.
511
+ pathPointAt: (n, pathBasedOnLength=true) ->
512
+ [p1,p2,p3] = @pathSteps pathBasedOnLength
513
+
514
+ if n < p1
515
+ @topLeft().add @topEdge().scale Math.map n, 0, p1, 0, 1
516
+ else if n < p2
517
+ @topRight().add @rightEdge().scale Math.map n, p1, p2, 0, 1
518
+ else if n < p3
519
+ @bottomRight().add @bottomEdge().scale Math.map(n, p2, p3, 0, 1) * -1
520
+ else
521
+ @bottomLeft().add @leftEdge().scale Math.map(n, p3, 1, 0, 1) * -1
522
+
523
+ # Returns the angle of the rectangle perimeter at the path position {Number}.
524
+ #
525
+ # <script>drawGeometry(exampleKey, {paths: [0, 1/3, 2/3]})</script>
526
+ #
527
+ # n - A {Number} between `0` and `1`a {Number} between `0` and `1`.
528
+ # pathBasedOnLength - A {Boolean} of whether the position on the path
529
+ # consider the length of the path segments or not.
530
+ # When true, each segment will only weight as much
531
+ # as their own length.
532
+ # When false, every segment have the same weight,
533
+ # resulting in a difference in speed when animating
534
+ # an object along a path.
535
+ #
536
+ # Returns a {Number}.
537
+ pathOrientationAt: (n, pathBasedOnLength=true) ->
538
+ [p1,p2,p3] = @pathSteps pathBasedOnLength
539
+
540
+ if n < p1
541
+ p = @topEdge()
542
+ else if n < p2
543
+ p = @rightEdge()
544
+ else if n < p3
545
+ p = @bottomEdge().scale -1
546
+ else
547
+ p = @leftEdge().scale -1
548
+
549
+ p.angle()
550
+
551
+ # Internal: Calculates the proportions of each step of the rectangle path.
552
+ #
553
+ # Returns an {Array}.
554
+ pathSteps: (pathBasedOnLength=true) ->
555
+ if pathBasedOnLength
556
+ l = @length()
557
+ p1 = @width / l
558
+ p2 = (@width + @height) / l
559
+ p3 = p1 + p2
560
+ else
561
+ p1 = 1 / 4
562
+ p2 = 1 / 2
563
+ p3 = 3 / 4
564
+
565
+ [p1, p2, p3]
566
+
567
+ # {Delegates to: agt.geom.Geometry.drawPath}
568
+ drawPath: (context) ->
569
+ context.beginPath()
570
+ context.moveTo(@x, @y)
571
+ context.lineTo(@topRight().x, @topRight().y)
572
+ context.lineTo(@bottomRight().x, @bottomRight().y)
573
+ context.lineTo(@bottomLeft().x, @bottomLeft().y)
574
+ context.lineTo(@x, @y)
575
+ context.closePath()
576
+
577
+ # Pastes the values of the passed-in rectangle into this one.
578
+ #
579
+ # x - The x coordinate {Number} of the rectangle or a rectangle-like {Object}.
580
+ # y - The y coordinate {Number} of the rectangle.
581
+ # width - The width {Number} of the rectangle.
582
+ # height - The height {Number} of the rectangle.
583
+ # rotation - The rotation {Number} of the rectangle.
584
+ paste: (x, y, width, height, rotation) ->
585
+ values = @rectangleFrom x, y, width, height, rotation
586
+ @[k] = parseFloat v for k,v of values when Math.isFloat v
587
+
588
+ # Internal: Resets all invalid number in the passed-in array to `0`.
589
+ #
590
+ # values - An {Array} containing numeric values.
591
+ #
592
+ # Returns an {Array}.
593
+ defaultToZero: (values) ->
594
+ values[k] = 0 for k,v of values when not Math.isFloat v
595
+ values
596
+
597
+ @proxy 'pathOrientationAt', as: 'Angle'
598
+ @proxy 'points', 'corners', 'edges', as: 'PointList'
599
+ @proxy 'topLeft', 'topRight', 'bottomLeft', 'bottomRight', 'center', 'topEdgeCenter', 'bottomEdgeCenter', 'leftEdgeCenter', 'rightEdgeCenter', 'topEdge', 'leftEdge', 'rightEdge', 'bottomEdge', 'diagonal', 'pathPointAt', as: 'Point'