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,37 @@
1
+ namespace('agt.geom')
2
+
3
+ # Public:
4
+ class agt.geom.CubicBezier
5
+ @include agt.mixins.Formattable('CubicBezier')
6
+ @include agt.mixins.Sourcable('agt.geom.CubicBezier', 'vertices', 'bias')
7
+ @include agt.geom.Geometry
8
+ @include agt.geom.Path
9
+ @include agt.geom.Intersections
10
+ @include agt.geom.Spline(3)
11
+
12
+ ### Public ###
13
+
14
+ constructor: (vertices, bias=20) ->
15
+ @initSpline vertices, bias
16
+
17
+ pointInSegment: (t, seg) ->
18
+ pt = new agt.geom.Point()
19
+ pt.x = (seg[0].x * @b1 (t)) +
20
+ (seg[1].x * @b2 (t)) +
21
+ (seg[2].x * @b3 (t)) +
22
+ (seg[3].x * @b4 (t))
23
+ pt.y = (seg[0].y * @b1 (t)) +
24
+ (seg[1].y * @b2 (t)) +
25
+ (seg[2].y * @b3 (t)) +
26
+ (seg[3].y * @b4 (t))
27
+ pt
28
+
29
+ ### Internal ###
30
+
31
+ b1: (t) -> ((1 - t) * (1 - t) * (1 - t))
32
+
33
+ b2: (t) -> (3 * t * (1 - t) * (1 - t))
34
+
35
+ b3: (t) -> (3 * t * t * (1 - t))
36
+
37
+ b4: (t) -> (t * t * t)
@@ -0,0 +1,241 @@
1
+ namespace('agt.geom')
2
+
3
+ # Public:
4
+ class agt.geom.Diamond
5
+ properties = ['topLength', 'rightLength', 'bottomLength', 'leftLength', 'x', 'y', 'rotation']
6
+
7
+ @include agt.mixins.Formattable(['Diamond'].concat(properties)...)
8
+ @include agt.mixins.Parameterizable('diamondFrom', {
9
+ topLength: 1
10
+ rightLength: 1
11
+ bottomLength: 1
12
+ leftLength: 1
13
+ x: 0
14
+ y: 0
15
+ rotation: 0
16
+ })
17
+ @include agt.mixins.Sourcable(['agt.geom.Diamond'].concat properties)
18
+ @include agt.mixins.Equatable(properties...)
19
+ @include agt.mixins.Cloneable()
20
+ @include agt.mixins.Memoizable
21
+ @include agt.geom.Geometry
22
+ @include agt.geom.Surface
23
+ @include agt.geom.Path
24
+ @include agt.geom.Intersections
25
+
26
+ ### Public ###
27
+
28
+ constructor: (topLength, rightLength, bottomLength, leftLength, x, y, rotation) ->
29
+ args = @diamondFrom topLength, rightLength, bottomLength, leftLength, x, y, rotation
30
+ {@topLength, @rightLength, @bottomLength, @leftLength, @x, @y, @rotation} = args
31
+
32
+ center: -> new agt.geom.Point(@x, @y)
33
+
34
+ topAxis: -> new agt.geom.Point(0,-@topLength).rotate(@rotation)
35
+
36
+ bottomAxis: -> new agt.geom.Point(0,@bottomLength).rotate(@rotation)
37
+
38
+ leftAxis: -> new agt.geom.Point(-@leftLength,0).rotate(@rotation)
39
+
40
+ rightAxis: -> new agt.geom.Point(@rightLength,0).rotate(@rotation)
41
+
42
+ corners: ->
43
+ [
44
+ @topCorner()
45
+ @rightCorner()
46
+ @bottomCorner()
47
+ @leftCorner()
48
+ ]
49
+
50
+ topCorner: -> @center().add(@topAxis())
51
+
52
+ bottomCorner: -> @center().add(@bottomAxis())
53
+
54
+ leftCorner: -> @center().add(@leftAxis())
55
+
56
+ rightCorner: -> @center().add(@rightAxis())
57
+
58
+ edges: ->
59
+ [
60
+ @topLeftEdge()
61
+ @topRightEdge()
62
+ @bottomRightEdge()
63
+ @bottomLeftEdge()
64
+ ]
65
+
66
+ topLeftEdge: -> @topCorner().subtract(@leftCorner())
67
+
68
+ topRightEdge: -> @rightCorner().subtract(@topCorner())
69
+
70
+ bottomLeftEdge: -> @leftCorner().subtract(@bottomCorner())
71
+
72
+ bottomRightEdge: -> @bottomCorner().subtract(@rightCorner())
73
+
74
+ quadrants: ->
75
+ [
76
+ @topLeftQuadrant()
77
+ @topRightQuadrant()
78
+ @bottomRightQuadrant()
79
+ @bottomLeftQuadrant()
80
+ ]
81
+
82
+ topLeftQuadrant: ->
83
+ k = 'topLeftQuadrant'
84
+ return @memoFor k if @memoized k
85
+ @memoize k, new agt.geom.Triangle(@center(), @topCorner(), @leftCorner())
86
+
87
+ topRightQuadrant: ->
88
+ k = 'topRightQuadrant'
89
+ return @memoFor k if @memoized k
90
+ @memoize k, new agt.geom.Triangle(@center(), @topCorner(), @rightCorner())
91
+
92
+ bottomLeftQuadrant: ->
93
+ k = 'bottomLeftQuadrant'
94
+ return @memoFor k if @memoized k
95
+ @memoize k, new agt.geom.Triangle(@center(), @bottomCorner(), @leftCorner())
96
+
97
+ bottomRightQuadrant: ->
98
+ k = 'bottomRightQuadrant'
99
+ return @memoFor k if @memoized k
100
+ @memoize k, new agt.geom.Triangle(@center(), @bottomCorner(), @rightCorner())
101
+
102
+ top: -> Math.min @topCorner().y,
103
+ @bottomCorner().y,
104
+ @leftCorner().y,
105
+ @rightCorner().y,
106
+
107
+ bottom: -> Math.max @topCorner().y,
108
+ @bottomCorner().y,
109
+ @leftCorner().y,
110
+ @rightCorner().y,
111
+
112
+ left: -> Math.min @topCorner().x,
113
+ @bottomCorner().x,
114
+ @leftCorner().x,
115
+ @rightCorner().x,
116
+
117
+ right: -> Math.max @topCorner().x,
118
+ @bottomCorner().x,
119
+ @leftCorner().x,
120
+ @rightCorner().x,
121
+
122
+ translate: (xOrPt, y) ->
123
+ {x,y} = agt.geom.Point.pointFrom xOrPt, y
124
+
125
+ @x += x
126
+ @y += y
127
+ this
128
+
129
+ rotate: (rotation) ->
130
+ @rotation += rotation
131
+ this
132
+
133
+ scale: (scale) ->
134
+ @topLength *= scale
135
+ @bottomLength *= scale
136
+ @rightLength *= scale
137
+ @leftLength *= scale
138
+ this
139
+
140
+ points: ->
141
+ [t = @topCorner(), @rightCorner(), @bottomCorner(), @leftCorner(), t]
142
+
143
+ triangles: -> @quadrants()
144
+
145
+ closedGeometry: -> true
146
+
147
+ pointAtAngle: (angle) ->
148
+ center = @center()
149
+ vec = center.add Math.cos(angle)*10000,
150
+ Math.sin(angle)*10000
151
+ @intersections(points: -> [center, vec])?[0]
152
+
153
+ acreage: ->
154
+ @topLeftQuadrant().acreage() +
155
+ @topRightQuadrant().acreage() +
156
+ @bottomLeftQuadrant().acreage() +
157
+ @bottomRightQuadrant().acreage()
158
+
159
+ contains: (x,y) ->
160
+ @center().equals(x,y) or
161
+ @topLeftQuadrant().contains(x,y) or
162
+ @topRightQuadrant().contains(x,y) or
163
+ @bottomLeftQuadrant().contains(x,y) or
164
+ @bottomRightQuadrant().contains(x,y)
165
+
166
+ randomPointInSurface: (random) ->
167
+ l = @acreage()
168
+ q1 = @topLeftQuadrant()
169
+ q2 = @topRightQuadrant()
170
+ q3 = @bottomRightQuadrant()
171
+ q4 = @bottomLeftQuadrant()
172
+
173
+ a1 = q1.acreage()
174
+ a2 = q2.acreage()
175
+ a3 = q3.acreage()
176
+ a4 = q4.acreage()
177
+ a = a1 + a2 + a3 + a4
178
+
179
+ l1 = a1 / a
180
+ l2 = a2 / a
181
+ l3 = a3 / a
182
+ l4 = a4 / a
183
+
184
+ n = random.get()
185
+
186
+ if n < l1
187
+ q1.randomPointInSurface random
188
+ else if n < l1 + l2
189
+ q2.randomPointInSurface random
190
+ else if n < l1 + l2 + l3
191
+ q3.randomPointInSurface random
192
+ else
193
+ q4.randomPointInSurface random
194
+
195
+ length: ->
196
+ @topRightEdge().length() +
197
+ @topLeftEdge().length() +
198
+ @bottomRightEdge().length() +
199
+ @bottomLeftEdge().length()
200
+
201
+ pathPointAt: (n, pathBasedOnLength=true) ->
202
+ [p1,p2,p3] = @pathSteps pathBasedOnLength
203
+
204
+ if n < p1
205
+ @topCorner().add @topRightEdge().scale Math.map n, 0, p1, 0, 1
206
+ else if n < p2
207
+ @rightCorner().add @bottomRightEdge().scale Math.map n, p1, p2, 0, 1
208
+ else if n < p3
209
+ @bottomCorner().add @bottomLeftEdge().scale Math.map n, p2, p3, 0, 1
210
+ else
211
+ @leftCorner().add @topLeftEdge().scale Math.map n, p3, 1, 0, 1
212
+
213
+ pathOrientationAt: (n, pathBasedOnLength=true) ->
214
+ [p1,p2,p3] = @pathSteps pathBasedOnLength
215
+
216
+ if n < p1
217
+ p = @topRightEdge()
218
+ else if n < p2
219
+ p = @bottomRightEdge()
220
+ else if n < p3
221
+ p = @bottomLeftEdge().scale -1
222
+ else
223
+ p = @topLeftEdge().scale -1
224
+
225
+ p.angle()
226
+
227
+ pathSteps: (pathBasedOnLength=true) ->
228
+ if pathBasedOnLength
229
+ l = @length()
230
+ p1 = @topRightEdge().length() / l
231
+ p2 = p1 + @bottomRightEdge().length() / l
232
+ p3 = p2 + @bottomLeftEdge().length() / l
233
+ else
234
+ p1 = 1 / 4
235
+ p2 = 1 / 2
236
+ p3 = 3 / 4
237
+
238
+ [p1, p2, p3]
239
+
240
+ memoizationKey: ->
241
+ "#{@x};#{@y};#{@rotation};#{@topLength};#{@bottomLength};#{@leftLength};#{@rightLength};"
@@ -0,0 +1,141 @@
1
+ namespace('agt.geom')
2
+
3
+ # Public:
4
+ class agt.geom.Ellipsis
5
+ properties = ['radius1', 'radius2', 'x', 'y', 'rotation', 'segments']
6
+
7
+ @include agt.mixins.Equatable(properties...)
8
+ @include agt.mixins.Formattable(['Ellipsis'].concat(properties)...)
9
+ @include agt.mixins.Parameterizable('ellipsisFrom', {
10
+ radius1: 1
11
+ radius2: 1
12
+ x: 0
13
+ y: 0
14
+ rotation: 0
15
+ segments: 36
16
+ })
17
+ @include agt.mixins.Sourcable(['agt.geom.Ellipsis'].concat(properties)...)
18
+ @include agt.mixins.Cloneable()
19
+ @include agt.mixins.Memoizable
20
+ @include agt.geom.Geometry
21
+ @include agt.geom.Surface
22
+ @include agt.geom.Path
23
+ @include agt.geom.Intersections
24
+
25
+ ### Public ###
26
+
27
+ constructor: (r1, r2, x, y, rot, segments) ->
28
+ {@radius1,@radius2,@x,@y,@rotation,@segments} = @ellipsisFrom r1, r2,
29
+ x, y, rot,
30
+ segments
31
+
32
+ center: -> new agt.geom.Point @x, @y
33
+
34
+ left: -> Math.min.apply Math, @xBounds()
35
+
36
+ right: -> Math.max.apply Math, @xBounds()
37
+
38
+ bottom: -> Math.max.apply Math, @yBounds()
39
+
40
+ top: -> Math.min.apply Math, @yBounds()
41
+
42
+ # Internal:
43
+ xBounds: ->
44
+ phi = @rotation
45
+ t = Math.atan(-@radius2 * Math.tan(phi) / @radius1)
46
+ [t, t+Math.PI].map (t) =>
47
+ @x + @radius1*Math.cos(t)*Math.cos(phi) -
48
+ @radius2*Math.sin(t)*Math.sin(phi)
49
+
50
+ # Internal:
51
+ yBounds: ->
52
+ phi = @rotation
53
+ t = Math.atan(@radius2 * (Math.cos(phi) / Math.sin(phi)) / @radius1)
54
+ [t, t+Math.PI].map (t) =>
55
+ @y + @radius1*Math.cos(t)*Math.sin(phi) +
56
+ @radius2*Math.sin(t)*Math.cos(phi)
57
+
58
+ translate: (xOrPt, y) ->
59
+ {x,y} = agt.geom.Point.pointFrom xOrPt, y
60
+
61
+ @x += x
62
+ @y += y
63
+ this
64
+
65
+ rotate: (rotation) ->
66
+ @rotation += rotation
67
+ this
68
+
69
+ scale: (scale) ->
70
+ @radius1 *= scale
71
+ @radius2 *= scale
72
+ this
73
+
74
+ points: ->
75
+ @memoFor('points').concat() if @memoized 'points'
76
+ @memoize 'points', (@pathPointAt n / @segments for n in [0..@segments])
77
+
78
+ triangles: ->
79
+ return @memoFor 'triangles' if @memoized 'triangles'
80
+
81
+ triangles = []
82
+ points = @points()
83
+ center = @center()
84
+ for i in [1..points.length-1]
85
+ triangles.push new agt.geom.Triangle center, points[i-1], points[i]
86
+
87
+ @memoize 'triangles', triangles
88
+
89
+ closedGeometry: -> true
90
+
91
+ pointAtAngle: (angle) ->
92
+ a = angle - @rotation
93
+ ratio = @radius1 / @radius2
94
+ vec = new agt.geom.Point Math.cos(a) * @radius1, Math.sin(a) * @radius1
95
+ vec.x = vec.x / ratio if @radius1 < @radius2
96
+ vec.y = vec.y * ratio if @radius1 > @radius2
97
+ a = vec.angle()
98
+ p = new agt.geom.Point Math.cos(a) * @radius1, Math.sin(a) * @radius2
99
+
100
+ @center().add p.rotate(@rotation)
101
+
102
+ acreage: -> Math.PI * @radius1 * @radius2
103
+
104
+ randomPointInSurface: (random) ->
105
+ unless random?
106
+ random = new agt.random.Random new agt.random.MathRandom
107
+
108
+ pt = @pathPointAt random.get()
109
+ center = @center()
110
+ dif = pt.subtract center
111
+ center.add dif.scale Math.sqrt random.random()
112
+
113
+ contains: (xOrPt, y) ->
114
+ p = new agt.geom.Point xOrPt, y
115
+ c = @center()
116
+ d = p.subtract c
117
+ a = d.angle()
118
+ p2 = @pointAtAngle a
119
+ c.distance(p2) >= c.distance(p)
120
+
121
+ length: -> Math.PI * (3*(@radius1 + @radius2) -
122
+ Math.sqrt((3* @radius1 + @radius2) * (@radius1 + @radius2 *3)))
123
+
124
+ pathPointAt: (n) ->
125
+ a = n * Math.PI * 2
126
+ p = new agt.geom.Point Math.cos(a) * @radius1, Math.sin(a) * @radius2
127
+
128
+ @center().add p.rotate(@rotation)
129
+
130
+ drawPath: (context) ->
131
+ context.save()
132
+ context.translate(@x, @y)
133
+ context.rotate(@rotation)
134
+ context.scale(@radius1, @radius2)
135
+ context.beginPath()
136
+ context.arc(0,0,1,0, Math.PI*2)
137
+ context.closePath()
138
+ context.restore()
139
+
140
+ memoizationKey: ->
141
+ "#{@radius1};#{@radius2};#{@x};#{@y};#{@rotation};#{@segments}"
@@ -0,0 +1,56 @@
1
+ namespace('agt.geom')
2
+
3
+ # Public: The `LinearSpline` is the simplest spline you can find.
4
+ #
5
+ # <script>window.exampleKey = 'linear_spline'</script>
6
+ # <script>drawGeometry(exampleKey, {highlight: true})</script>
7
+ #
8
+ # ### Included Mixins
9
+ #
10
+ # - {agt.geom.Geometry}
11
+ # - {agt.geom.Intersections}
12
+ # - {agt.geom.Path}
13
+ # - [agt.mixins.Spline](../../../files/geom/mixins/spline.coffee.html)
14
+ # - [agt.mixins.Formattable](../../../files/mixins/formattable.coffee.html)
15
+ # - [agt.mixins.Memoizable](../../../files/mixins/memoizable.coffee.html)
16
+ # - [agt.mixins.Sourcable](../../../files/mixins/sourcable.coffee.html)
17
+ class agt.geom.LinearSpline
18
+ @include agt.mixins.Formattable('LinearSpline')
19
+ @include agt.mixins.Sourcable('agt.geom.LinearSpline', 'vertices', 'bias')
20
+ @include agt.geom.Geometry
21
+ @include agt.geom.Path
22
+ @include agt.geom.Intersections
23
+ @include agt.geom.Spline(1)
24
+
25
+ ### Public ###
26
+
27
+ # Creates a new [LinearSpline]{agt.geom.LinearSpline}
28
+ #
29
+ # vertices - An {Array} of [Points]{agt.geom.Point} that forms the spline.
30
+ constructor: (vertices) ->
31
+ @initSpline vertices
32
+
33
+ # The points of a linear spline are the same as its array of vertices.
34
+ #
35
+ # <script>drawGeometryPoints(exampleKey, 'points')</script>
36
+ #
37
+ # Returns an {Array} of [Points]{agt.geom.Point}.
38
+ points: -> vertex.clone() for vertex in @vertices
39
+
40
+ # Returns the number of segments in the spline.
41
+ #
42
+ # Returns a {Number}
43
+ segments: -> @vertices.length - 1
44
+
45
+ # **Unsupported** - As the final points of a linear spine are its vertices
46
+ # there's no need to render the connections between them.
47
+ drawVerticesConnections: ->
48
+
49
+ ### Internal ###
50
+
51
+ # Validates the size of the vertices array.
52
+ #
53
+ # vertices - The {Array} of vertices to validate.
54
+ #
55
+ # Returns a {Boolean}.
56
+ validateVertices: (vertices) -> vertices.length >= 2