technohippy-Pongo 0.1.0

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.
@@ -0,0 +1,7 @@
1
+ module Pongo
2
+ class IForce
3
+ def get_value(inv_mass)
4
+ raise NotImplementedError
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,21 @@
1
+ module Pongo
2
+ module Logger
3
+ class Logger
4
+ def print(message)
5
+ puts(message)
6
+ end
7
+
8
+ def error(message)
9
+ print("Error: #{message}")
10
+ end
11
+
12
+ def warn(message)
13
+ print("Warn: #{message}")
14
+ end
15
+
16
+ def info(message)
17
+ print("Info: #{message}")
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,15 @@
1
+ require 'pongo/logger/logger'
2
+
3
+ module Pongo
4
+ module Logger
5
+ class ShoesLogger < Logger
6
+ def initialize(shoes)
7
+ @shoes = shoes
8
+ end
9
+
10
+ def print(message)
11
+ @shoes.info(message)
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,11 @@
1
+ require 'pongo/logger/logger'
2
+
3
+ module Pongo
4
+ module Logger
5
+ class StandardLogger < Logger
6
+ def print(message)
7
+ puts message
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,79 @@
1
+ require 'pongo/abstract_particle'
2
+ require 'pongo/util/math_util'
3
+
4
+ module Pongo
5
+ class RectangleParticle < AbstractParticle
6
+ attr_accessor :extents, :axes, :radian
7
+
8
+ def initialize(x, y, width, height, options={})
9
+ options = {:rotation => 0.0, :fixed => false, :mass => 1.0, :elasticity => 0.3, :friction => 0.0}.update(options)
10
+ super(x, y, options[:fixed], options[:mass], options[:elasticity], options[:friction])
11
+ @extents = [width/2.0, height/2.0]
12
+ @axes = [Vector.new, Vector.new]
13
+ self.radian = options[:rotation]
14
+ end
15
+
16
+ # The rotation of the RectangleParticle in radians. For drawing methods you may
17
+ # want to use the <code>angle</code> property which gives the rotation in
18
+ # degrees from 0 to 360.
19
+ #
20
+ # Note that while the RectangleParticle can be rotated, it does not have angular
21
+ # velocity. In otherwords, during collisions, the rotation is not altered,
22
+ # and the energy of the rotation is not applied to other colliding particles.
23
+ def radian=(rad)
24
+ @radian = rad
25
+ set_axes(rad)
26
+ end
27
+
28
+ # The rotation of the RectangleParticle in degrees.
29
+ def angle
30
+ self.radian * MathUtil::ONE_EIGHTY_OVER_PI
31
+ end
32
+ alias degree angle
33
+
34
+ def angle=(deg)
35
+ self.radian = deg * MathUtil::PI_OVER_ONE_EIGHTY
36
+ end
37
+ alias degree= angle=
38
+
39
+ def width=(w)
40
+ @extents[0] = w / 2.0
41
+ end
42
+
43
+ def width
44
+ @extents[0] * 2.0
45
+ end
46
+
47
+ def height=(h)
48
+ @extents[1] = h / 2.0
49
+ end
50
+
51
+ def height
52
+ @extents[1] * 2.0
53
+ end
54
+
55
+ def projection(axis)
56
+ radius =
57
+ self.extents[0] * axis.dot(axes[0]).abs +
58
+ self.extents[1] * axis.dot(axes[1]).abs
59
+
60
+ c = @samp.dot(axis)
61
+
62
+ @interval.min = c - radius
63
+ @interval.max = c + radius
64
+ @interval
65
+ end
66
+ alias get_projection projection
67
+
68
+ def set_axes(rad)
69
+ s = Math.sin(rad)
70
+ c = Math.cos(rad)
71
+
72
+ self.axes[0].x = c
73
+ self.axes[0].y = s
74
+ self.axes[1].x = -s
75
+ self.axes[1].y = c
76
+ end
77
+ #alias axes= set_axes
78
+ end
79
+ end
@@ -0,0 +1,61 @@
1
+ module Pongo
2
+ module Renderer
3
+ class Renderer
4
+ def cleanup(item)
5
+ case item
6
+ when CircleParticle
7
+ cleanup_circle(item)
8
+ when RectangleParticle
9
+ cleanup_rectangle(item)
10
+ when WheelParticle
11
+ cleanup_wheel(item)
12
+ when SpringConstraint
13
+ cleanup_spring(item)
14
+ else
15
+ raise UnknownItemError.new(item.class.name)
16
+ end
17
+ end
18
+ def cleanup_circle(item); end
19
+ def cleanup_rectangle(item); end
20
+ def cleanup_wheel(item); end
21
+ def cleanup_spring(item); end
22
+
23
+ def draw(item)
24
+ return unless item.visible?
25
+ case item
26
+ when CircleParticle
27
+ draw_circle(item)
28
+ when RectangleParticle
29
+ draw_rectangle(item)
30
+ when WheelParticle
31
+ draw_wheel(item)
32
+ when SpringConstraint
33
+ draw_spring(item)
34
+ when AbstractCollection
35
+ item.particles.each {|p| p.draw if p.always_redraw? or not p.fixed?}
36
+ item.constraints.each {|c| c.draw if c.always_redraw? or not c.fixed?}
37
+ else
38
+ raise UnknownItemError.new(item.class.name)
39
+ end
40
+ end
41
+ def draw_circle(item); end
42
+ def draw_rectangle(item); end
43
+ def draw_wheel(item); end
44
+ def draw_spring(item); end
45
+
46
+ def with(options, &block)
47
+ @shoes.nostroke if options[:nostroke]
48
+ @shoes.stroke(options[:stroke]) if options[:stroke]
49
+ @shoes.fill(options[:fill]) if options[:fill]
50
+ @shoes.transform(options[:transform]) if options[:transform]
51
+ @shoes.rotate(options[:rotate]) if options[:rotate]
52
+ block.call(@shoes)
53
+ @shoes.rotate(-options[:rotate]) if options[:rotate]
54
+ @shoes.transform(:corner) if options[:transform]
55
+ @shoes.fill(@shoes.black) if options[:fill]
56
+ @shoes.stroke(@shoes.black) if options[:stroke]
57
+ @shoes.stroke(@shoes.black) if options[:nostroke]
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,51 @@
1
+ require 'pongo/renderer/renderer'
2
+
3
+ module Pongo
4
+ module Renderer
5
+ class ShoesRenderer < Renderer
6
+ attr_reader :shoes
7
+
8
+ def initialize(shoes)
9
+ @shoes = shoes
10
+ end
11
+
12
+ def draw_circle(item)
13
+ if item.user_data[:shape]
14
+ item.user_data[:shape].style(
15
+ :left => item.px - item.radius,
16
+ :top => item.py - item.radius
17
+ )
18
+ else
19
+ item.user_data[:shape] = @shoes.oval(
20
+ item.px - item.radius,
21
+ item.py - item.radius,
22
+ item.radius * 2
23
+ )
24
+ end
25
+ end
26
+ alias draw_wheel draw_circle
27
+
28
+ def draw_rectangle(item)
29
+ item.user_data[:shape].remove if item.user_data[:shape]
30
+ with(:transform => :center, :rotate => -item.angle) do
31
+ item.user_data[:shape] =
32
+ @shoes.rect(
33
+ :left => (item.px - item.width/2),
34
+ :top => (item.py - item.height/2),
35
+ :width => item.width,
36
+ :height => item.height
37
+ )
38
+ end
39
+ end
40
+
41
+ def draw_spring(item)
42
+ if item.collidable?
43
+ draw_rectangle(item.scp)
44
+ else
45
+ item.user_data[:shape].remove if item.user_data[:shape]
46
+ item.user_data[:shape] = @shoes.line(item.p1.px, item.p1.py, item.p2.px, item.p2.py)
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,73 @@
1
+ require 'pongo/renderer/renderer'
2
+
3
+ module Pongo
4
+ module Renderer
5
+ class TkRenderer < Renderer
6
+ def initialize(canvas)
7
+ @canvas = canvas
8
+ end
9
+
10
+ def draw_circle(item)
11
+ if item.user_data[:shape]
12
+ item.user_data[:shape].coords(
13
+ item.px - item.radius,
14
+ item.py - item.radius,
15
+ item.px + item.radius,
16
+ item.py + item.radius
17
+ )
18
+ else
19
+ item.user_data[:shape] =TkcOval.new(@canvas,
20
+ item.px - item.radius,
21
+ item.py - item.radius,
22
+ item.px + item.radius,
23
+ item.py + item.radius,
24
+ :fill => 'black'
25
+ )
26
+ end
27
+ end
28
+ alias draw_wheel draw_circle
29
+
30
+ def draw_rectangle(item)
31
+ c = Vector.new(item.px, item.py)
32
+ x1 = -item.width/2
33
+ y1 = -item.height/2
34
+ x2 = item.width/2
35
+ y2 = item.height/2
36
+ p1 = Vector.new(x1, y1).rotate!(item.radian) + c
37
+ p2 = Vector.new(x1, y2).rotate!(item.radian) + c
38
+ p3 = Vector.new(x2, y2).rotate!(item.radian) + c
39
+ p4 = Vector.new(x2, y1).rotate!(item.radian) + c
40
+ if item.user_data[:shape]
41
+ item.user_data[:shape].coords(
42
+ p1.x, p1.y,
43
+ p2.x, p2.y,
44
+ p3.x, p3.y,
45
+ p4.x, p4.y
46
+ )
47
+ else
48
+ item.user_data[:shape] = TkcPolygon.new(@canvas,
49
+ p1.x, p1.y,
50
+ p2.x, p2.y,
51
+ p3.x, p3.y,
52
+ p4.x, p4.y,
53
+ :fill => 'black'
54
+ )
55
+ end
56
+ end
57
+
58
+ def draw_spring(item)
59
+ if item.collidable?
60
+ draw_rectangle(item.scp)
61
+ else
62
+ if item.user_data[:shape]
63
+ item.user_data[:shape].coords(item.p1.px,
64
+ item.p1.py, item.p2.px, item.p2.py)
65
+ else
66
+ item.user_data[:shape] =TkcLine.new(@canvas, item.p1.px,
67
+ item.p1.py, item.p2.px, item.p2.py)
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,53 @@
1
+ require 'pongo/util/math_util'
2
+
3
+ module Pongo
4
+ class RimParticle
5
+ attr_accessor :curr, :prev, :wr, :angular_velocity, :speed, :max_torque
6
+
7
+ # The RimParticle is really just a second component of the wheel model.
8
+ # The rim particle is simulated in a coordsystem relative to the wheel's
9
+ # center, not in worldspace.
10
+ #
11
+ # Origins of this code are from Raigan Burns, Metanet Software
12
+ def initialize(r, mt)
13
+ @curr = Vector.new(r, 0)
14
+ @prev = Vector.new(0, 0)
15
+ @speed = 0
16
+ @angular_velocity = 0
17
+ @max_torque = mt
18
+ @wr = r
19
+ end
20
+
21
+ def update(dt)
22
+ @speed = MathUtil.max(-@max_torque, MathUtil.min(@max_torque, @speed + @angular_velocity))
23
+
24
+ # apply torque
25
+ # this is the tangent vector at the rim particle
26
+ dx = -@curr.y
27
+ dy = @curr.x
28
+
29
+ # normalize so we can scale by the rotational speed
30
+ len = Math.sqrt(dx * dx + dy * dy)
31
+ dx /= len
32
+ dy /= len
33
+
34
+ @curr.x += @speed * dx
35
+ @curr.y += @speed * dy
36
+
37
+ ox = @prev.x
38
+ oy = @prev.y
39
+ px = @prev.x = @curr.x
40
+ py = @prev.y = @curr.y
41
+
42
+ @curr.x += APEngine.damping * (px - ox)
43
+ @curr.y += APEngine.damping * (py - oy)
44
+
45
+ # hold the rim particle in place
46
+ clen = @curr.magnitude
47
+ diff = (clen - wr) / clen
48
+
49
+ @curr.x -= @curr.x * diff
50
+ @curr.y -= @curr.y * diff
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,128 @@
1
+ require 'pongo/abstract_constraint'
2
+ require 'pongo/spring_constraint_particle'
3
+ require 'pongo/util/math_util'
4
+
5
+ module Pongo
6
+ class SpringConstraint < AbstractConstraint
7
+ attr_accessor :p1, :p2, :rest_length, :collidable, :scp
8
+
9
+ def initialize(p1, p2, options={})
10
+ options = {:stiffness => 0.5, :collidable => false, :rect_height => 1, :rect_scale => 1, :scale_to_length => false}.update(options)
11
+ super(options[:stiffness])
12
+ @p1 = p1
13
+ @p2 = p2
14
+ check_particles_location
15
+ @rest_length = curr_length
16
+ set_collidable(options[:collidable], options[:rect_height], options[:rect_scale], options[:scale_to_length])
17
+ end
18
+
19
+ def radian
20
+ d = delta
21
+ Math.atan2(d.y, d.x)
22
+ end
23
+
24
+ def angle
25
+ radian * MathUtil::ONE_EIGHTY_OVER_PI
26
+ end
27
+
28
+ def center
29
+ (@p1.curr + @p2.curr) / 2
30
+ end
31
+
32
+ def rect_scale=(s)
33
+ if @scp
34
+ @scp.rect_scale = s
35
+ end
36
+ end
37
+
38
+ def rect_scale
39
+ @scp.rect_scale
40
+ end
41
+
42
+ def curr_length
43
+ @p1.curr.distance(@p2.curr)
44
+ end
45
+
46
+ def rect_height
47
+ @scp.rect_height
48
+ end
49
+
50
+ def rect_height=(h)
51
+ if @scp
52
+ @scp.rect_height = h
53
+ end
54
+ end
55
+
56
+ def rest_length=(r)
57
+ raise ArgumentError.new('restLength must be greater than 0') if r <= 0
58
+ @rest_length = r
59
+ end
60
+
61
+ def collidable?
62
+ @collidable
63
+ end
64
+
65
+ def fixed_end_limit
66
+ @scp.fixed_end_limit
67
+ end
68
+
69
+ def fixed_end_limit=(f)
70
+ if @scp
71
+ @scp.fixed_end_limit = f
72
+ end
73
+ end
74
+
75
+ def set_collidable(b, rect_height, rect_scale, scale_to_length)
76
+ if @collidable = b
77
+ @scp = SpringConstraintParticle.new(@p1, @p2, self, rect_height, rect_scale, scale_to_length)
78
+ else
79
+ @scp = nil
80
+ end
81
+ end
82
+
83
+ def is_connected_to?(p)
84
+ [@p1, @p2].include? p
85
+ end
86
+
87
+ def fixed
88
+ @p1.fixed? and @p2.fixed?
89
+ end
90
+ alias fixed? fixed
91
+
92
+ def init
93
+ cleanup
94
+ if collidable?
95
+ @scp.init
96
+ else
97
+ init_display
98
+ end
99
+ draw
100
+ end
101
+
102
+ def resolve
103
+ return if fixed?
104
+
105
+ delta_length = curr_length
106
+ diff = (delta_length - rest_length) /
107
+ (delta_length * (@p1.inv_mass + @p2.inv_mass))
108
+ dmds = delta * (diff * stiffness)
109
+
110
+ @p1.curr.minus!(dmds * @p1.inv_mass)
111
+ @p2.curr.plus!( dmds * @p2.inv_mass)
112
+ end
113
+
114
+ def init_display
115
+ #raise NotImplementedError
116
+ end
117
+
118
+ def delta
119
+ @p1.curr - @p2.curr
120
+ end
121
+
122
+ def check_particles_location
123
+ if @p1.curr.x == @p2.curr.x and @p1.curr.y == @p2.curr.y
124
+ @p2.curr.x += 0.0001
125
+ end
126
+ end
127
+ end
128
+ end