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.
- checksums.yaml +7 -0
- data/LICENSE.md +7 -0
- data/README.md +5 -0
- data/app/assets/javascripts/agt/config.coffee +9 -0
- data/app/assets/javascripts/agt/dom.coffee +12 -0
- data/app/assets/javascripts/agt/function.coffee +317 -0
- data/app/assets/javascripts/agt/geom/circle.coffee +338 -0
- data/app/assets/javascripts/agt/geom/cubic_bezier.coffee +37 -0
- data/app/assets/javascripts/agt/geom/diamond.coffee +241 -0
- data/app/assets/javascripts/agt/geom/ellipsis.coffee +141 -0
- data/app/assets/javascripts/agt/geom/linear_spline.coffee +56 -0
- data/app/assets/javascripts/agt/geom/matrix.coffee +240 -0
- data/app/assets/javascripts/agt/geom/mixins/geometry.coffee +171 -0
- data/app/assets/javascripts/agt/geom/mixins/intersections.coffee +150 -0
- data/app/assets/javascripts/agt/geom/mixins/path.coffee +145 -0
- data/app/assets/javascripts/agt/geom/mixins/proxyable.coffee +9 -0
- data/app/assets/javascripts/agt/geom/mixins/spline.coffee +329 -0
- data/app/assets/javascripts/agt/geom/mixins/surface.coffee +55 -0
- data/app/assets/javascripts/agt/geom/mixins/triangulable.coffee +112 -0
- data/app/assets/javascripts/agt/geom/point.coffee +454 -0
- data/app/assets/javascripts/agt/geom/polygon.coffee +119 -0
- data/app/assets/javascripts/agt/geom/quad_bezier.coffee +43 -0
- data/app/assets/javascripts/agt/geom/quint_bezier.coffee +42 -0
- data/app/assets/javascripts/agt/geom/rectangle.coffee +599 -0
- data/app/assets/javascripts/agt/geom/spiral.coffee +90 -0
- data/app/assets/javascripts/agt/geom/transformation_proxy.coffee +43 -0
- data/app/assets/javascripts/agt/geom/triangle.coffee +442 -0
- data/app/assets/javascripts/agt/impulse.coffee +105 -0
- data/app/assets/javascripts/agt/index.coffee +56 -0
- data/app/assets/javascripts/agt/inflector/inflection.coffee +21 -0
- data/app/assets/javascripts/agt/inflector/inflections.coffee +75 -0
- data/app/assets/javascripts/agt/inflector/inflector.coffee +235 -0
- data/app/assets/javascripts/agt/inheritance.coffee +132 -0
- data/app/assets/javascripts/agt/math.coffee +45 -0
- data/app/assets/javascripts/agt/mixins/activable.coffee +31 -0
- data/app/assets/javascripts/agt/mixins/aliasable.coffee +25 -0
- data/app/assets/javascripts/agt/mixins/alternate_case.coffee +72 -0
- data/app/assets/javascripts/agt/mixins/cloneable.coffee +71 -0
- data/app/assets/javascripts/agt/mixins/delegation.coffee +90 -0
- data/app/assets/javascripts/agt/mixins/disposable.coffee +7 -0
- data/app/assets/javascripts/agt/mixins/equatable.coffee +37 -0
- data/app/assets/javascripts/agt/mixins/formattable.coffee +52 -0
- data/app/assets/javascripts/agt/mixins/globalizable.coffee +175 -0
- data/app/assets/javascripts/agt/mixins/has_ancestors.coffee +47 -0
- data/app/assets/javascripts/agt/mixins/has_collection.coffee +107 -0
- data/app/assets/javascripts/agt/mixins/has_nested_collection.coffee +51 -0
- data/app/assets/javascripts/agt/mixins/memoizable.coffee +64 -0
- data/app/assets/javascripts/agt/mixins/parameterizable.coffee +101 -0
- data/app/assets/javascripts/agt/mixins/poolable.coffee +62 -0
- data/app/assets/javascripts/agt/mixins/sourcable.coffee +45 -0
- data/app/assets/javascripts/agt/mixins/state_machine.coffee +47 -0
- data/app/assets/javascripts/agt/net/router.coffee +165 -0
- data/app/assets/javascripts/agt/object.coffee +9 -0
- data/app/assets/javascripts/agt/particles/actions/base_action.coffee +7 -0
- data/app/assets/javascripts/agt/particles/actions/die_on_surface.coffee +14 -0
- data/app/assets/javascripts/agt/particles/actions/force.coffee +11 -0
- data/app/assets/javascripts/agt/particles/actions/friction.coffee +14 -0
- data/app/assets/javascripts/agt/particles/actions/live.coffee +9 -0
- data/app/assets/javascripts/agt/particles/actions/macro_action.coffee +13 -0
- data/app/assets/javascripts/agt/particles/actions/move.coffee +11 -0
- data/app/assets/javascripts/agt/particles/actions/null_action.coffee +9 -0
- data/app/assets/javascripts/agt/particles/counters/by_rate.coffee +17 -0
- data/app/assets/javascripts/agt/particles/counters/fixed.coffee +9 -0
- data/app/assets/javascripts/agt/particles/counters/null_counter.coffee +9 -0
- data/app/assets/javascripts/agt/particles/emission.coffee +35 -0
- data/app/assets/javascripts/agt/particles/emitters/null_emitter.coffee +7 -0
- data/app/assets/javascripts/agt/particles/emitters/path.coffee +10 -0
- data/app/assets/javascripts/agt/particles/emitters/ponctual.coffee +9 -0
- data/app/assets/javascripts/agt/particles/emitters/surface.coffee +10 -0
- data/app/assets/javascripts/agt/particles/initializers/explosion.coffee +19 -0
- data/app/assets/javascripts/agt/particles/initializers/life.coffee +16 -0
- data/app/assets/javascripts/agt/particles/initializers/macro_initializer.coffee +10 -0
- data/app/assets/javascripts/agt/particles/initializers/null_initializer.coffee +7 -0
- data/app/assets/javascripts/agt/particles/initializers/particle_sub_system.coffee +12 -0
- data/app/assets/javascripts/agt/particles/initializers/stream.coffee +20 -0
- data/app/assets/javascripts/agt/particles/mixins/randomizable.coffee +10 -0
- data/app/assets/javascripts/agt/particles/particle.coffee +32 -0
- data/app/assets/javascripts/agt/particles/sub_system.coffee +11 -0
- data/app/assets/javascripts/agt/particles/system.coffee +103 -0
- data/app/assets/javascripts/agt/particles/timers/instant.coffee +11 -0
- data/app/assets/javascripts/agt/particles/timers/limited.coffee +19 -0
- data/app/assets/javascripts/agt/particles/timers/null_timer.coffee +11 -0
- data/app/assets/javascripts/agt/particles/timers/unlimited.coffee +9 -0
- data/app/assets/javascripts/agt/particles/timers/until_death.coffee +11 -0
- data/app/assets/javascripts/agt/promise.coffee +214 -0
- data/app/assets/javascripts/agt/random/random.coffee +100 -0
- data/app/assets/javascripts/agt/random/seeds/lagged_fibonnacci.coffee +53 -0
- data/app/assets/javascripts/agt/random/seeds/linear.coffee +16 -0
- data/app/assets/javascripts/agt/random/seeds/linear_congruential.coffee +23 -0
- data/app/assets/javascripts/agt/random/seeds/math_random.coffee +9 -0
- data/app/assets/javascripts/agt/random/seeds/mersenne_twister.coffee +42 -0
- data/app/assets/javascripts/agt/random/seeds/no_random.coffee +12 -0
- data/app/assets/javascripts/agt/random/seeds/paul_houle.coffee +19 -0
- data/app/assets/javascripts/agt/signal.coffee +272 -0
- data/app/assets/javascripts/agt/sprites/animation.coffee +13 -0
- data/app/assets/javascripts/agt/sprites/sprite.coffee +30 -0
- data/app/assets/javascripts/agt/widgets/hash.coffee +36 -0
- data/app/assets/javascripts/agt/widgets/widgets.coffee +194 -0
- data/app/assets/javascripts/agt/widgets/widgets/checked_input.coffee +7 -0
- data/app/assets/javascripts/agt/widgets/widgets/focus_bubbling.coffee +15 -0
- data/lib/agt.rb +8 -0
- data/lib/agt/version.rb +5 -0
- metadata +173 -0
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
|
|
2
|
+
namespace('agt.geom')
|
|
3
|
+
|
|
4
|
+
# Public:
|
|
5
|
+
class agt.geom.Spiral
|
|
6
|
+
properties = ['radius1', 'radius2', 'twirl', 'x', 'y', 'rotation','segments']
|
|
7
|
+
|
|
8
|
+
@include agt.mixins.Equatable.apply(null, properties)
|
|
9
|
+
@include agt.mixins.Formattable.apply(null, ['Spiral'].concat properties)
|
|
10
|
+
@include agt.mixins.Parameterizable('spiralFrom', {
|
|
11
|
+
radius1: 1
|
|
12
|
+
radius2: 1
|
|
13
|
+
twirl: 1
|
|
14
|
+
x: 0
|
|
15
|
+
y: 0
|
|
16
|
+
rotation: 0
|
|
17
|
+
segments: 36
|
|
18
|
+
})
|
|
19
|
+
@include agt.mixins.Sourcable.apply(null, ['agt.geom.Spiral'].concat properties)
|
|
20
|
+
@include agt.mixins.Cloneable()
|
|
21
|
+
@include agt.mixins.Memoizable
|
|
22
|
+
@include agt.geom.Geometry
|
|
23
|
+
@include agt.geom.Path
|
|
24
|
+
@include agt.geom.Intersections
|
|
25
|
+
|
|
26
|
+
### Public ###
|
|
27
|
+
|
|
28
|
+
constructor: (r1, r2, twirl, x, y, rot, segments) ->
|
|
29
|
+
{
|
|
30
|
+
@radius1
|
|
31
|
+
@radius2
|
|
32
|
+
@twirl
|
|
33
|
+
@x
|
|
34
|
+
@y
|
|
35
|
+
@rotation
|
|
36
|
+
@segments
|
|
37
|
+
} = @spiralFrom r1, r2, twirl, x, y, rot, segments
|
|
38
|
+
|
|
39
|
+
center: -> new agt.geom.Point @x, @y
|
|
40
|
+
|
|
41
|
+
ellipsis: ->
|
|
42
|
+
return @memoFor 'ellipsis' if @memoized 'ellipsis'
|
|
43
|
+
@memoize 'ellipsis', new agt.geom.Ellipsis this
|
|
44
|
+
|
|
45
|
+
translate: (x,y) ->
|
|
46
|
+
{x,y} = agt.geom.Point.pointFrom x, y
|
|
47
|
+
@x += x
|
|
48
|
+
@y += y
|
|
49
|
+
this
|
|
50
|
+
|
|
51
|
+
rotate: (rotation) ->
|
|
52
|
+
@rotation += rotation
|
|
53
|
+
this
|
|
54
|
+
|
|
55
|
+
scale: (scale) ->
|
|
56
|
+
@radius1 *= scale
|
|
57
|
+
@radius2 *= scale
|
|
58
|
+
this
|
|
59
|
+
|
|
60
|
+
points: ->
|
|
61
|
+
return @memoFor('points').concat() if @memoized 'points'
|
|
62
|
+
points = []
|
|
63
|
+
center = @center()
|
|
64
|
+
ellipsis = @ellipsis()
|
|
65
|
+
|
|
66
|
+
for i in [0..@segments]
|
|
67
|
+
p = i / @segments
|
|
68
|
+
points.push @pathPointAt p
|
|
69
|
+
|
|
70
|
+
@memoize 'points', points
|
|
71
|
+
|
|
72
|
+
pathPointAt: (pos, posBasedOnLength=true) ->
|
|
73
|
+
center = @center()
|
|
74
|
+
ellipsis = @ellipsis()
|
|
75
|
+
PI2 = Math.PI * 2
|
|
76
|
+
angle = @rotation + pos * PI2 * @twirl % PI2
|
|
77
|
+
pt = ellipsis.pointAtAngle(angle)?.subtract(center).scale(pos)
|
|
78
|
+
center.add pt
|
|
79
|
+
|
|
80
|
+
fill: ->
|
|
81
|
+
|
|
82
|
+
drawPath: (context) ->
|
|
83
|
+
points = @points()
|
|
84
|
+
start = points.shift()
|
|
85
|
+
context.beginPath()
|
|
86
|
+
context.moveTo(start.x,start.y)
|
|
87
|
+
context.lineTo(p.x,p.y) for p in points
|
|
88
|
+
|
|
89
|
+
memoizationKey = ->
|
|
90
|
+
"#{@radius1};#{@radius2};#{@twirl};#{@x};#{@y};#{@rotation};#{@segments}"
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
|
|
2
|
+
namespace('agt.geom')
|
|
3
|
+
|
|
4
|
+
# Public:
|
|
5
|
+
class agt.geom.TransformationProxy
|
|
6
|
+
### Public ###
|
|
7
|
+
|
|
8
|
+
@defineProxy: (key, type) ->
|
|
9
|
+
switch type
|
|
10
|
+
when 'PointList'
|
|
11
|
+
@::[key] = ->
|
|
12
|
+
points = @geometry[key].apply(@geometry, arguments)
|
|
13
|
+
if @matrix?
|
|
14
|
+
points.map (pt) => @matrix.transformPoint pt
|
|
15
|
+
else points
|
|
16
|
+
|
|
17
|
+
when 'Point'
|
|
18
|
+
@::[key] = ->
|
|
19
|
+
point = @geometry[key].apply(@geometry, arguments)
|
|
20
|
+
if @matrix? then @matrix.transformPoint point else point
|
|
21
|
+
|
|
22
|
+
when 'Angle'
|
|
23
|
+
@::[key] = ->
|
|
24
|
+
angle = @geometry[key].apply(@geometry, arguments)
|
|
25
|
+
if @matrix?
|
|
26
|
+
vec = new agt.geom.Point Math.cos(angle),
|
|
27
|
+
Math.sin(angle)
|
|
28
|
+
@matrix.transformPoint(vec).angle()
|
|
29
|
+
else angle
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
constructor: (@geometry, @matrix) ->
|
|
33
|
+
@proxiedMethods = @detectProxyableMethods @geometry
|
|
34
|
+
|
|
35
|
+
proxied: -> k for k,v of @proxiedMethods
|
|
36
|
+
|
|
37
|
+
detectProxyableMethods: (geometry) ->
|
|
38
|
+
proxiedMethods = {}
|
|
39
|
+
for k,v of geometry.constructor.prototype
|
|
40
|
+
if v.proxyable
|
|
41
|
+
proxiedMethods[k] = v.proxyable
|
|
42
|
+
TransformationProxy.defineProxy k, v.proxyable
|
|
43
|
+
proxiedMethods
|
|
@@ -0,0 +1,442 @@
|
|
|
1
|
+
|
|
2
|
+
namespace('agt.geom')
|
|
3
|
+
|
|
4
|
+
# Public: A `Triangle` is only defined using three [Points]{agt.geom.Point}.
|
|
5
|
+
# It is the simplest geometry you can find in the `geom` package, every other
|
|
6
|
+
# surface geometries can be reduced to a set of triangles.
|
|
7
|
+
#
|
|
8
|
+
# <script>window.exampleKey = 'triangle'</script>
|
|
9
|
+
# <script>drawGeometry(exampleKey, {highlight: true})</script>
|
|
10
|
+
#
|
|
11
|
+
# ### Included Mixins
|
|
12
|
+
#
|
|
13
|
+
# - {agt.geom.Geometry}
|
|
14
|
+
# - {agt.geom.Intersections}
|
|
15
|
+
# - {agt.geom.Path}
|
|
16
|
+
# - {agt.geom.Surface}
|
|
17
|
+
# - [agt.mixins.Aliasable](../../../classes/agt/mixins/aliasable.coffee.html)
|
|
18
|
+
# - [agt.mixins.Cloneable](../../../files/mixins/cloneable.coffee.html)
|
|
19
|
+
# - [agt.mixins.Equatable](../../../files/mixins/equatable.coffee.html)
|
|
20
|
+
# - [agt.mixins.Formattable](../../../files/mixins/formattable.coffee.html)
|
|
21
|
+
# - [agt.mixins.Memoizable](../../../files/mixins/memoizable.coffee.html)
|
|
22
|
+
# - [agt.mixins.Sourcable](../../../files/mixins/sourcable.coffee.html)
|
|
23
|
+
class agt.geom.Triangle
|
|
24
|
+
@extend agt.mixins.Aliasable
|
|
25
|
+
|
|
26
|
+
@include agt.mixins.Equatable('a','b','c')
|
|
27
|
+
@include agt.mixins.Formattable('Triangle','a','b','c')
|
|
28
|
+
@include agt.mixins.Sourcable('agt.geom.Triangle','a','b','c')
|
|
29
|
+
@include agt.mixins.Cloneable()
|
|
30
|
+
@include agt.mixins.Memoizable
|
|
31
|
+
@include agt.geom.Geometry
|
|
32
|
+
@include agt.geom.Surface
|
|
33
|
+
@include agt.geom.Path
|
|
34
|
+
@include agt.geom.Intersections
|
|
35
|
+
|
|
36
|
+
### Public ###
|
|
37
|
+
|
|
38
|
+
# Returns a triangle-like {Object} using the given arguments.
|
|
39
|
+
#
|
|
40
|
+
# a - Either a [Point]{agt.geom.Point} or a triangle-like {Object}.
|
|
41
|
+
# b - A [Point]{agt.geom.Point} when the first parameter is also a point.
|
|
42
|
+
# c - A [Point]{agt.geom.Point} when the first parameter is also a point.
|
|
43
|
+
#
|
|
44
|
+
# Returns an {Object} with the following properties:
|
|
45
|
+
# :a - A [Point]{agt.geom.Point} for the first vertex of the triangle.
|
|
46
|
+
# :b - A [Point]{agt.geom.Point} for the second vertex of the triangle.
|
|
47
|
+
# :c - A [Point]{agt.geom.Point} for the mast vertex of the triangle.
|
|
48
|
+
@triangleFrom: (a, b, c) ->
|
|
49
|
+
{a,b,c} = a if a? and typeof a is 'object' and not agt.geom.Point.isPoint a
|
|
50
|
+
|
|
51
|
+
@invalidPoint 'a', a unless agt.geom.Point.isPoint a
|
|
52
|
+
@invalidPoint 'b', b unless agt.geom.Point.isPoint b
|
|
53
|
+
@invalidPoint 'c', c unless agt.geom.Point.isPoint c
|
|
54
|
+
|
|
55
|
+
{
|
|
56
|
+
a: new agt.geom.Point(a)
|
|
57
|
+
b: new agt.geom.Point(b)
|
|
58
|
+
c: new agt.geom.Point(c)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
# Creates a new `Triangle` instance.
|
|
62
|
+
#
|
|
63
|
+
# a - Either a [Point]{agt.geom.Point} or a triangle-like {Object}.
|
|
64
|
+
# b - A [Point]{agt.geom.Point} when the first parameter is also a point.
|
|
65
|
+
# c - A [Point]{agt.geom.Point} when the first parameter is also a point.
|
|
66
|
+
constructor: (a, b, c) ->
|
|
67
|
+
{@a,@b,@c} = @triangleFrom a, b, c
|
|
68
|
+
|
|
69
|
+
# Returns the center of the triangle.
|
|
70
|
+
#
|
|
71
|
+
# <script>drawGeometry(exampleKey, {center: true})</script>
|
|
72
|
+
#
|
|
73
|
+
# Returns a [Point]{agt.geom.Point}.
|
|
74
|
+
center: -> new agt.geom.Point (@a.x + @b.x + @c.x) / 3,
|
|
75
|
+
(@a.y + @b.y + @c.y) / 3
|
|
76
|
+
|
|
77
|
+
# Returns the center of the `ab` edge of the triangle.
|
|
78
|
+
#
|
|
79
|
+
# <script>drawGeometryPoints(exampleKey, 'abCenter')</script>
|
|
80
|
+
#
|
|
81
|
+
# Returns a [Point]{agt.geom.Point}.
|
|
82
|
+
abCenter: -> @a.add @ab().scale(0.5)
|
|
83
|
+
|
|
84
|
+
# Returns the center of the `ac` edge of the triangle.
|
|
85
|
+
#
|
|
86
|
+
# <script>drawGeometryPoints(exampleKey, 'acCenter')</script>
|
|
87
|
+
#
|
|
88
|
+
# Returns a [Point]{agt.geom.Point}.
|
|
89
|
+
acCenter: -> @a.add @ac().scale(0.5)
|
|
90
|
+
|
|
91
|
+
# Returns the center of the `bc` edge of the triangle.
|
|
92
|
+
#
|
|
93
|
+
# <script>drawGeometryPoints(exampleKey, 'bcCenter')</script>
|
|
94
|
+
#
|
|
95
|
+
# Returns a [Point]{agt.geom.Point}.
|
|
96
|
+
bcCenter: -> @b.add @bc().scale(0.5)
|
|
97
|
+
|
|
98
|
+
# Returns an {Array} with the triangle's edges vectors.
|
|
99
|
+
#
|
|
100
|
+
# Returns an {Array}.
|
|
101
|
+
edges: -> [@ab(), @bc(), @ca()]
|
|
102
|
+
|
|
103
|
+
# Returns the triangle's `ab` edge vector.
|
|
104
|
+
#
|
|
105
|
+
# <script>drawGeometryEdge(exampleKey, 'a', 'ab')</script>
|
|
106
|
+
#
|
|
107
|
+
# Returns a [Point]{agt.geom.Point}.
|
|
108
|
+
ab: -> @b.subtract @a
|
|
109
|
+
|
|
110
|
+
# Returns the triangle's `ab` edge vector.
|
|
111
|
+
#
|
|
112
|
+
# <script>drawGeometryEdge(exampleKey, 'a', 'ac')</script>
|
|
113
|
+
#
|
|
114
|
+
# Returns a [Point]{agt.geom.Point}.
|
|
115
|
+
ac: -> @c.subtract @a
|
|
116
|
+
|
|
117
|
+
# Returns the triangle's `ba` edge vector.
|
|
118
|
+
#
|
|
119
|
+
# <script>drawGeometryEdge(exampleKey, 'b', 'ba')</script>
|
|
120
|
+
#
|
|
121
|
+
# Returns a [Point]{agt.geom.Point}.
|
|
122
|
+
ba: -> @a.subtract @b
|
|
123
|
+
|
|
124
|
+
# Returns the triangle's `bc` edge vector.
|
|
125
|
+
#
|
|
126
|
+
# <script>drawGeometryEdge(exampleKey, 'b', 'bc')</script>
|
|
127
|
+
#
|
|
128
|
+
# Returns a [Point]{agt.geom.Point}.
|
|
129
|
+
bc: -> @c.subtract @b
|
|
130
|
+
|
|
131
|
+
# Returns the triangle's `ca` edge vector.
|
|
132
|
+
#
|
|
133
|
+
# <script>drawGeometryEdge(exampleKey, 'c', 'ca')</script>
|
|
134
|
+
#
|
|
135
|
+
# Returns a [Point]{agt.geom.Point}.
|
|
136
|
+
ca: -> @a.subtract @c
|
|
137
|
+
|
|
138
|
+
# Returns the triangle's `cb` edge vector.
|
|
139
|
+
#
|
|
140
|
+
# <script>drawGeometryEdge(exampleKey, 'c', 'cb')</script>
|
|
141
|
+
#
|
|
142
|
+
# Returns a [Point]{agt.geom.Point}.
|
|
143
|
+
cb: -> @b.subtract @c
|
|
144
|
+
|
|
145
|
+
# Returns the angle formed by the {::ba} and {::bc} vectors.
|
|
146
|
+
#
|
|
147
|
+
# Returns a {Number}.
|
|
148
|
+
abc: -> @ba().angleWith @bc()
|
|
149
|
+
|
|
150
|
+
# Returns the angle formed by the {::ab} and {::ac} vectors.
|
|
151
|
+
#
|
|
152
|
+
# Returns a {Number}.
|
|
153
|
+
bac: -> @ab().angleWith @ac()
|
|
154
|
+
|
|
155
|
+
# Returns the angle formed by the {::ca} and {::cb} vectors.
|
|
156
|
+
#
|
|
157
|
+
# Returns a {Number}.
|
|
158
|
+
acb: -> @ca().angleWith @cb()
|
|
159
|
+
|
|
160
|
+
# Returns the top-most coordinate of the triangle shape.
|
|
161
|
+
#
|
|
162
|
+
# <script>drawGeometryBound(exampleKey, 'top')</script>
|
|
163
|
+
#
|
|
164
|
+
# Returns a {Number}.
|
|
165
|
+
top: -> Math.min @a.y, @b.y, @c.y
|
|
166
|
+
|
|
167
|
+
# Returns the bottom-most coordinate of the triangle shape.
|
|
168
|
+
#
|
|
169
|
+
# <script>drawGeometryBound(exampleKey, 'bottom')</script>
|
|
170
|
+
#
|
|
171
|
+
# Returns a {Number}.
|
|
172
|
+
bottom: -> Math.max @a.y, @b.y, @c.y
|
|
173
|
+
|
|
174
|
+
# Returns the left-most coordinate of the triangle shape.
|
|
175
|
+
#
|
|
176
|
+
# <script>drawGeometryBound(exampleKey, 'left')</script>
|
|
177
|
+
#
|
|
178
|
+
# Returns a {Number}.
|
|
179
|
+
left: -> Math.min @a.x, @b.x, @c.x
|
|
180
|
+
|
|
181
|
+
# Returns the right-most coordinate of the triangle shape.
|
|
182
|
+
#
|
|
183
|
+
# <script>drawGeometryBound(exampleKey, 'right')</script>
|
|
184
|
+
#
|
|
185
|
+
# Returns a {Number}.
|
|
186
|
+
right: -> Math.max @a.x, @b.x, @c.x
|
|
187
|
+
|
|
188
|
+
# Returns `true` if the triangle's edge have the same length.
|
|
189
|
+
#
|
|
190
|
+
# Returns a {Boolean}.
|
|
191
|
+
equilateral: ->
|
|
192
|
+
Math.deltaBelowRatio(@ab().length(), @bc().length()) and
|
|
193
|
+
Math.deltaBelowRatio(@ab().length(), @ac().length())
|
|
194
|
+
|
|
195
|
+
# Returns `true` if two edges of the triangle have the same length.
|
|
196
|
+
#
|
|
197
|
+
# Returns a {Boolean}.
|
|
198
|
+
isosceles: ->
|
|
199
|
+
Math.deltaBelowRatio(@ab().length(), @bc().length()) or
|
|
200
|
+
Math.deltaBelowRatio(@ab().length(), @ac().length()) or
|
|
201
|
+
Math.deltaBelowRatio(@bc().length(), @ac().length())
|
|
202
|
+
|
|
203
|
+
# Returns `true` if one angle of the triangle has a value of `Math.PI / 2`
|
|
204
|
+
# radians (90 degrees).
|
|
205
|
+
#
|
|
206
|
+
# Returns a {Boolean}.
|
|
207
|
+
rectangle: ->
|
|
208
|
+
sqr = Math.PI / 2
|
|
209
|
+
Math.deltaBelowRatio(Math.abs(@abc()), sqr) or
|
|
210
|
+
Math.deltaBelowRatio(Math.abs(@bac()), sqr) or
|
|
211
|
+
Math.deltaBelowRatio(Math.abs(@acb()), sqr)
|
|
212
|
+
|
|
213
|
+
# Adds the passed-in [Point]{agt.geom.Point} to the position
|
|
214
|
+
# of this triangle.
|
|
215
|
+
#
|
|
216
|
+
# <script>drawTransform(exampleKey, {type: 'translate', args: [50, 0], width: 150})</script>
|
|
217
|
+
#
|
|
218
|
+
# x - A {Number} for the x coordinate or a point-like {Object}.
|
|
219
|
+
# y - A {Number} for the y coordinate if the first argument
|
|
220
|
+
# was also a number.
|
|
221
|
+
#
|
|
222
|
+
# Returns this [Triangle]{agt.geom.Triangle}.
|
|
223
|
+
translate: (x,y) ->
|
|
224
|
+
pt = agt.geom.Point.pointFrom x,y
|
|
225
|
+
@a.x += pt.x; @a.y += pt.y
|
|
226
|
+
@b.x += pt.x; @b.y += pt.y
|
|
227
|
+
@c.x += pt.x; @c.y += pt.y
|
|
228
|
+
this
|
|
229
|
+
|
|
230
|
+
# Adds the passed-in rotation to the current triangle rotation.
|
|
231
|
+
#
|
|
232
|
+
# <script>drawTransform(exampleKey, {type: 'rotate', args: [Math.PI/ 3]})</script>
|
|
233
|
+
#
|
|
234
|
+
# rotation - The rotation {Number}.
|
|
235
|
+
#
|
|
236
|
+
# Returns this [Triangle]{agt.geom.Triangle}.
|
|
237
|
+
rotate: (rotation) ->
|
|
238
|
+
center = @center()
|
|
239
|
+
@a = @a.rotateAround center, rotation
|
|
240
|
+
@b = @b.rotateAround center, rotation
|
|
241
|
+
@c = @c.rotateAround center, rotation
|
|
242
|
+
this
|
|
243
|
+
|
|
244
|
+
@alias 'rotate', 'rotateAroundCenter'
|
|
245
|
+
|
|
246
|
+
# Scales the triangle around its center.
|
|
247
|
+
#
|
|
248
|
+
# <script>drawTransform(exampleKey, {type: 'scale', args: [0.6]})</script>
|
|
249
|
+
#
|
|
250
|
+
# scale - The scale {Number} to apply to the triangle.
|
|
251
|
+
#
|
|
252
|
+
# Returns this [Triangle]{agt.geom.Triangle}.
|
|
253
|
+
scale: (scale) ->
|
|
254
|
+
center = @center()
|
|
255
|
+
@a = center.add @a.subtract(center).scale(scale)
|
|
256
|
+
@b = center.add @b.subtract(center).scale(scale)
|
|
257
|
+
@c = center.add @c.subtract(center).scale(scale)
|
|
258
|
+
this
|
|
259
|
+
|
|
260
|
+
@alias 'scale', 'scaleAroundCenter'
|
|
261
|
+
|
|
262
|
+
# Always returns `true`.
|
|
263
|
+
#
|
|
264
|
+
# Returns a {Boolean}.
|
|
265
|
+
closedGeometry: -> true
|
|
266
|
+
|
|
267
|
+
# Returns the triangle points.
|
|
268
|
+
#
|
|
269
|
+
# <script>drawGeometryPoints(exampleKey, 'points')</script>
|
|
270
|
+
#
|
|
271
|
+
# Returns an {Array}.
|
|
272
|
+
points: -> [@a.clone(), @b.clone(), @c.clone(), @a.clone()]
|
|
273
|
+
|
|
274
|
+
# Returns the [Point]{agt.geom.Point} on the perimeter of the triangle
|
|
275
|
+
# at the given `angle`.
|
|
276
|
+
#
|
|
277
|
+
# angle - The angle {Number}.
|
|
278
|
+
#
|
|
279
|
+
# <script>drawGeometry(exampleKey, {angle: true})</script>
|
|
280
|
+
#
|
|
281
|
+
# Returns a [Point]{agt.geom.Point}.
|
|
282
|
+
pointAtAngle: (angle) ->
|
|
283
|
+
center = @center()
|
|
284
|
+
vec = center.add Math.cos(angle)*10000,
|
|
285
|
+
Math.sin(angle)*10000
|
|
286
|
+
@intersections(points: -> [center, vec])?[0]
|
|
287
|
+
|
|
288
|
+
# Returns the surface {Number} of this triangle.
|
|
289
|
+
#
|
|
290
|
+
# Returns a {Number}.
|
|
291
|
+
acreage: ->
|
|
292
|
+
return @memoFor 'acreage' if @memoized 'acreage'
|
|
293
|
+
@memoize 'acreage', @ab().length() *
|
|
294
|
+
@bc().length() *
|
|
295
|
+
Math.abs(Math.sin(@abc())) / 2
|
|
296
|
+
|
|
297
|
+
# Returns `true` when the given point is contained in the triangle.
|
|
298
|
+
#
|
|
299
|
+
# In the example below all the green points on the screen represents
|
|
300
|
+
# coordinates that are contained in the triangle.
|
|
301
|
+
#
|
|
302
|
+
# <script>drawGeometry(exampleKey, {contains: true})</script>
|
|
303
|
+
#
|
|
304
|
+
# x - A {Number} for the x coordinate or a point-like {Object}.
|
|
305
|
+
# y - A {Number} for the y coordinate if the first argument
|
|
306
|
+
# was also a number.
|
|
307
|
+
#
|
|
308
|
+
# Returns a {Boolean}.
|
|
309
|
+
contains: (x, y) ->
|
|
310
|
+
p = new agt.geom.Point x, y
|
|
311
|
+
|
|
312
|
+
v0 = @ac()
|
|
313
|
+
v1 = @ab()
|
|
314
|
+
v2 = p.subtract(@a)
|
|
315
|
+
|
|
316
|
+
dot00 = v0.dot v0
|
|
317
|
+
dot01 = v0.dot v1
|
|
318
|
+
dot02 = v0.dot v2
|
|
319
|
+
dot11 = v1.dot v1
|
|
320
|
+
dot12 = v1.dot v2
|
|
321
|
+
|
|
322
|
+
invDenom = 1 / (dot00 * dot11 - dot01 * dot01)
|
|
323
|
+
u = (dot11 * dot02 - dot01 * dot12) * invDenom
|
|
324
|
+
v = (dot00 * dot12 - dot01 * dot02) * invDenom
|
|
325
|
+
|
|
326
|
+
u > 0 and v > 0 and u + v < 1
|
|
327
|
+
|
|
328
|
+
# Returns a randomly generated point within the triangle perimeter.
|
|
329
|
+
#
|
|
330
|
+
# <script>drawGeometry(exampleKey, {surface: true})</script>
|
|
331
|
+
#
|
|
332
|
+
# random - An optional [Random]{agt.random.Random} instance to use instead
|
|
333
|
+
# of the default `Math` random method.
|
|
334
|
+
#
|
|
335
|
+
# Returns a [Point]{agt.geom.Point}.
|
|
336
|
+
randomPointInSurface: (random) ->
|
|
337
|
+
unless random?
|
|
338
|
+
random = new agt.random.Random new agt.random.MathRandom
|
|
339
|
+
|
|
340
|
+
a1 = random.get()
|
|
341
|
+
a2 = random.get()
|
|
342
|
+
p = @a.add(@ab().scale(a1))
|
|
343
|
+
.add(@ca().scale(a2 * -1))
|
|
344
|
+
|
|
345
|
+
if @contains p
|
|
346
|
+
p
|
|
347
|
+
else
|
|
348
|
+
p.add @bcCenter().subtract(p).scale(2)
|
|
349
|
+
|
|
350
|
+
# Returns the length {Number} of the triangle perimeter.
|
|
351
|
+
#
|
|
352
|
+
# Returns a {Number}.
|
|
353
|
+
length: -> @ab().length() + @bc().length() + @ca().length()
|
|
354
|
+
|
|
355
|
+
# Returns a [Point]{agt.geom.Point} on the triangle perimeter using
|
|
356
|
+
# a {Number} between `0` and `1`.
|
|
357
|
+
#
|
|
358
|
+
# <script>drawGeometry(exampleKey, {paths: [0, 1/3, 2/3]})</script>
|
|
359
|
+
#
|
|
360
|
+
# n - A {Number} between `0` and `1`a {Number} between `0` and `1`.
|
|
361
|
+
# pathBasedOnLength - A {Boolean} of whether the position on the path
|
|
362
|
+
# consider the length of the path segments or not.
|
|
363
|
+
# When true, each segment will only weight as much
|
|
364
|
+
# as their own length.
|
|
365
|
+
# When false, every segment have the same weight,
|
|
366
|
+
# resulting in a difference in speed when animating
|
|
367
|
+
# an object along a path.
|
|
368
|
+
#
|
|
369
|
+
# Returns a [Point]{agt.geom.Point}.
|
|
370
|
+
pathPointAt: (n, pathBasedOnLength=true) ->
|
|
371
|
+
[l1, l2] = @pathSteps pathBasedOnLength
|
|
372
|
+
|
|
373
|
+
if n < l1
|
|
374
|
+
@a.add @ab().scale Math.map n, 0, l1, 0, 1
|
|
375
|
+
else if n < l2
|
|
376
|
+
@b.add @bc().scale Math.map n, l1, l2, 0, 1
|
|
377
|
+
else
|
|
378
|
+
@c.add @ca().scale Math.map n, l2, 1, 0, 1
|
|
379
|
+
|
|
380
|
+
# Returns the orientation of the path at the given position.
|
|
381
|
+
#
|
|
382
|
+
# <script>drawGeometry(exampleKey, {paths: [0, 1/3, 2/3]})</script>
|
|
383
|
+
#
|
|
384
|
+
# n - A {Number} between `0` and `1`a {Number} between `0` and `1`.
|
|
385
|
+
# pathBasedOnLength - A {Boolean} of whether the position on the path
|
|
386
|
+
# consider the length of the path segments or not.
|
|
387
|
+
# When true, each segment will only weight as much
|
|
388
|
+
# as their own length.
|
|
389
|
+
# When false, every segment have the same weight,
|
|
390
|
+
# resulting in a difference in speed when animating
|
|
391
|
+
# an object along a path.
|
|
392
|
+
#
|
|
393
|
+
# Returns a [Point]{agt.geom.Point}.
|
|
394
|
+
pathOrientationAt: (n, pathBasedOnLength=true) ->
|
|
395
|
+
[l1, l2] = @pathSteps pathBasedOnLength
|
|
396
|
+
|
|
397
|
+
if n < l1
|
|
398
|
+
@ab().angle()
|
|
399
|
+
else if n < l2
|
|
400
|
+
@bc().angle()
|
|
401
|
+
else
|
|
402
|
+
@ca().angle()
|
|
403
|
+
|
|
404
|
+
# Internal: Calculates the proportions of each step of the triangle path.
|
|
405
|
+
#
|
|
406
|
+
# Returns an {Array}.
|
|
407
|
+
pathSteps: (pathBasedOnLength) ->
|
|
408
|
+
if pathBasedOnLength
|
|
409
|
+
l = @length()
|
|
410
|
+
l1 = @ab().length() / l
|
|
411
|
+
l2 = l1 + @bc().length() / l
|
|
412
|
+
else
|
|
413
|
+
l1 = 1 / 3
|
|
414
|
+
l2 = 2 / 3
|
|
415
|
+
|
|
416
|
+
[l1,l2]
|
|
417
|
+
|
|
418
|
+
# {Delegates to: agt.geom.Geometry.drawPath}
|
|
419
|
+
drawPath: (context) ->
|
|
420
|
+
context.beginPath()
|
|
421
|
+
context.moveTo @a.x, @a.y
|
|
422
|
+
context.lineTo @b.x, @b.y
|
|
423
|
+
context.lineTo @c.x, @c.y
|
|
424
|
+
context.lineTo @a.x, @a.y
|
|
425
|
+
context.closePath()
|
|
426
|
+
|
|
427
|
+
# Generates the memoization key for this instance's state.
|
|
428
|
+
#
|
|
429
|
+
# For a circle, a memoized value will be invalidated whenever one of the
|
|
430
|
+
# following properties changes:
|
|
431
|
+
# - a
|
|
432
|
+
# - b
|
|
433
|
+
# - c
|
|
434
|
+
#
|
|
435
|
+
# Returns a {String}.
|
|
436
|
+
memoizationKey: -> "#{@a.x};#{@a.y};#{@b.x};#{@b.y};#{@c.x};#{@c.y}"
|
|
437
|
+
|
|
438
|
+
triangleFrom: Triangle.triangleFrom
|
|
439
|
+
|
|
440
|
+
### Internal ###
|
|
441
|
+
|
|
442
|
+
invalidPoint: (k,v) -> throw new Error "Invalid point #{v} for vertex #{k}"
|