Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

figured out angular velocity and rotating line + stationary circle co…

…llisions
  • Loading branch information...
commit a421701df80ee34f5f75a9fbbb71cbe79a6cab68 1 parent 58d6d45
Marc Mauger authored
7 source/js/bitmap.js.coffee
... ... @@ -1,3 +1,6 @@
  1 +# @module bitmapDemo
  2 +
  3 +#= require ./mylibs/Math
1 4 #= require ./mylibs/Polygon
2 5 #= require ./mylibs/collisions
3 6
@@ -75,7 +78,7 @@ bitmapDemo = (bitmap) ->
75 78 lastRot += 45
76 79 context.save()
77 80 context.translate(imgX, imgY)
78   - context.rotate degreesToRadians(lastRot)
  81 + context.rotate Math.degreesToRadians(lastRot)
79 82 context.drawImage(img, 0, 0)
80 83 context.restore()
81 84
@@ -85,7 +88,7 @@ bitmapDemo = (bitmap) ->
85 88 context.save()
86 89 context.translate(imgX, imgY)
87 90 context.scale 0.5, 0.5
88   - context.rotate degreesToRadians(lastRot)
  91 + context.rotate Math.degreesToRadians(lastRot)
89 92 context.drawImage(img, 0, 0)
90 93 context.restore()
91 94
7 source/js/mylibs/Canvas.js.coffee
@@ -17,6 +17,8 @@ Canvas = (() ->
17 17 @width = canvasEl.width
18 18 @height = canvasEl.height
19 19
  20 + context = () -> @ctxt
  21 +
20 22 # Set the origin of the canvas
21 23 # @param {String} id (topleft | bottomleft)
22 24 setOrigin = (id) ->
@@ -24,7 +26,9 @@ Canvas = (() ->
24 26 # translate world for origin at bottom left
25 27 @ctxt.scale(1, -1)
26 28 @ctxt.translate(0, -@height)
27   -
  29 + else
  30 + # bottom left is default
  31 +
28 32 # Draw a circle on the canvas
29 33 # @param {Circle} c a Circle object
30 34 drawCircle = (c) ->
@@ -96,6 +100,7 @@ Canvas = (() ->
96 100 drawLine: drawLine
97 101 drawEllipse: drawEllipse
98 102 inContext: inContext
  103 + context: context
99 104 rotate: rotate
100 105 translate: translate
101 106 clear: clear
28 source/js/mylibs/Math.js.coffee
... ... @@ -0,0 +1,28 @@
  1 +# @module Math
  2 +#
  3 +# Extensions to the built-in Math module
  4 +
  5 +#= require ./vec
  6 +
  7 +# angularVelocity
  8 +#
  9 +# Angular velocity of a particle in 2 dimensions
  10 +# @param {Vector} v velocity vector of the particle
  11 +# @param {Vector} r position vector of the particle (from origin or rotation)
  12 +# @param {Float} theta angle of rotation (in radians)
  13 +# @return {Float} the angular velocity
  14 +Math.angularVelocity = (v, r, theta) ->
  15 + (v.mag() * Math.sin(theta)) / r.mag()
  16 +
  17 +# Returns a random float between min and max
  18 +# Using Math.round() will give you a non-uniform distribution!
  19 +Math.getRandom = (min, max) ->
  20 + (Math.random() * (max - min + 1)) + min
  21 +
  22 +# Returns a random integer between min and max
  23 +# Using Math.round() will give you a non-uniform distribution!
  24 +Math.getRandomInt = (min, max) ->
  25 + Math.floor(Math.random() * (max - min + 1)) + min
  26 +
  27 +Math.degreesToRadians = (degrees) ->
  28 + degrees * Math.PI / 180
5 source/js/mylibs/PoolTable.coffee
... ... @@ -1,5 +1,6 @@
1   -# PoolTable.coffee
  1 +# @module PoolTable
2 2
  3 +#= require ./Math
3 4 #= require ./vec
4 5 #= require ./collisions
5 6 #= require ./Line
@@ -319,7 +320,7 @@ PoolTable = (ctxt, opts) ->
319 320
320 321 context.save()
321 322 context.translate balls[0].pos.e(1), balls[0].pos.e(2)
322   - context.rotate degreesToRadians(cueRotDegrees)
  323 + context.rotate Math.degreesToRadians(cueRotDegrees)
323 324 context.translate ogCuePos.e(1), ogCuePos.e(2)
324 325 context.drawImage(cueImg, 0, 0, cueImg.width, cueImg.height)
325 326 context.restore()
19 source/js/mylibs/Shape.js.coffee
@@ -9,9 +9,14 @@ class Shape
9 9 @mass = @efficiency = 1.0
10 10 @collisionNormal = null # vector
11 11 @[x] = val for x, val of opts
  12 + # initial speed, angular speed, etc
12 13 @velocity ?= Vector.Zero(3)
13 14 @displacement ?= Vector.Zero(3)
14 15 @direction ?= Vector.Zero(3)
  16 + @speed ?= 0
  17 + @rotation ?= 0
  18 + @angSpeed ?= 0
  19 + @rotDirection ?= 1
15 20
16 21 move: (vec) ->
17 22 @pos = @pos.add(vec)
@@ -20,6 +25,20 @@ class Shape
20 25 y: -> @pos.e(2)
21 26 z: -> @pos.e(3)
22 27
  28 + angularDirection: -> @rotDirection
  29 +
  30 + # calculate shape's angular velocity
  31 + # @return {Number} pseudovector omega with sign dependent
  32 + # on direction of rotation around axis (clockwiseNormal)
  33 + angularVelocity: ->
  34 + @angularDirection() * @angSpeed
  35 +
  36 + # set the shape's angular velocity
  37 + # @param {Number} v degrees/second
  38 + setAngularVelocity: (v) ->
  39 + @rotDirection = if v > 0 then 1 else -1
  40 + @angSpeed = Math.abs(v) # * 180 / Math.PI
  41 +
23 42 # prototype properties
24 43 toString: ->
25 44 kvs = for key, val of @ when val? and typeof(val) != 'function'
11 source/js/mylibs/circles_scene.js.coffee
... ... @@ -1,8 +1,9 @@
1 1 # @module scene
2 2 # Module for moving circles in a box
3 3
4   -#= require 'libs/raphael-min'
  4 +#= require libs/raphael-min
5 5 #= require ./vec
  6 +#= require ./Math
6 7 #= require ./collisions
7 8 #= require ./Line
8 9 #= require ./Circle
@@ -63,15 +64,15 @@ scene = (opts) ->
63 64
64 65 # Return a random circle color
65 66 randomCircleColor = ->
66   - CIRCLE_COLORS[getRandomInt(1, CIRCLE_COLORS.length)-1]
  67 + CIRCLE_COLORS[Math.getRandomInt(1, CIRCLE_COLORS.length)-1]
67 68
68 69 # Return a y-value for a circle
69 70 circleY = ->
70   - if freeY then getRandom(-MAX_VELOCITY_Y, MAX_VELOCITY_Y) else 0
  71 + if freeY then Math.getRandom(-MAX_VELOCITY_Y, MAX_VELOCITY_Y) else 0
71 72
72 73 # Create and return a new (free) circle
73 74 createFreeCircle = (x, y, i) ->
74   - velx = getRandom(-MAX_VELOCITY_X, MAX_VELOCITY_X)
  75 + velx = Math.getRandom(-MAX_VELOCITY_X, MAX_VELOCITY_X)
75 76 new Circle(x, y, 0, {
76 77 radius: CIRCLE_RADIUS
77 78 velocity: Vector.create([velx, circleY(), 0])
@@ -91,7 +92,7 @@ scene = (opts) ->
91 92 if diff > 0
92 93 # Add balls
93 94 for i in [1..diff]
94   - circles.push createFreeCircle(getRandom(0, bw), bh/2, i)
  95 + circles.push createFreeCircle(Math.getRandom(0, bw), bh/2, i)
95 96 else
96 97 # remove balls
97 98 circles.pop() for i in [1..(circles.length-nballs)]
42 source/js/mylibs/collisions.js.coffee
@@ -2,7 +2,8 @@
2 2
3 3 #= require ../libs/sylvester
4 4
5   -collisions = ->
  5 +collisions = {}
  6 +collisions = (->
6 7 # constants
7 8 collisions.NONE = -1
8 9 collisions.EMBEDDED = -2
@@ -106,6 +107,39 @@ collisions = ->
106 107 t = intersectionTime(c.pos.add(r), c.displacement, wall.pos, wall.vec)
107 108 [t, collisionNormal]
108 109
  110 + # Check for collision between rotating line and circle
  111 + # Anglular values should be in radians
  112 + # @param {Number} theta0 angle of starting position of line from the vertical
  113 + # @param {Number} omega angular velocity of rotating line
  114 + # @param {Number} l line length
  115 + # @param {Number} r ball radius
  116 + # @param {Number} d distance of line origin to ball center
  117 + # @param {Number} alpha angle of vertical and line to ball center
  118 + angularCollisionLineCircle = (theta0, omega, l, r, d, alpha) ->
  119 + return collisison.NONE if d > l + r
  120 + return collisions.EMBEDDED if d < r
  121 + k = 1
  122 + # move into a calculation within the range of [0,2pi]
  123 + alpha -= theta0
  124 + if omega < 0
  125 + omega = -omega
  126 + alpha = -alpha
  127 + k = -1
  128 +
  129 + pi2 = Math.PI * 2
  130 + while alpha < 0
  131 + alpha += pi2
  132 + while alpha > pi2
  133 + alpha -= pi2
  134 +
  135 + # check if there is a possible collision
  136 + # return collisions.NONE if alpha > omega
  137 + # now perform the appropriate collision check
  138 + if d*d <= (l*l + r*r)
  139 + (alpha - k * Math.asin(r / d)) / omega
  140 + else
  141 + (alpha - k * Math.acos((l*l + d*d - r*r) / (2*l*d))) / omega
  142 +
109 143 isImpendingCollision = (ts) ->
110 144 0 < ts <= 1
111 145
@@ -321,8 +355,10 @@ collisions = ->
321 355 isImpendingCollision,
322 356 resolveCollision,
323 357 resolveInelasticCollisionFixed,
  358 + angularCollisionLineCircle,
324 359 pointInTriangle,
325 360 pointInPolygon}
326   -
  361 +)()
  362 +
327 363 root = exports ? window
328   -root.collisions = collisions()
  364 +root.collisions = collisions
3  source/js/mylibs/vec.js.coffee
@@ -9,7 +9,7 @@
9 9
10 10 # isClockwise
11 11 #
12   -# Determines if object at p with velocity v is moving clockwise about the origin
  12 +# Determines if object starts at p with velocity v is moving clockwise about the origin
13 13 # @returns {Boolean}
14 14 Vector.isClockwise = (v, p) ->
15 15 n = p.clockwiseNormal()
@@ -93,4 +93,3 @@ Vector::clockwiseNormal = ->
93 93 Vector::moment = (p) ->
94 94 @clockwiseNormal().dot(p)
95 95
96   -
18 source/js/plugins.js
@@ -31,21 +31,3 @@ window.requestAnimFrame = (function() {
31 31 window.setTimeout(callback, 1000/60);
32 32 };
33 33 })();
34   -
35   -// Returns a random float between min and max
36   -// Using Math.round() will give you a non-uniform distribution!
37   -function getRandom(min, max)
38   -{
39   - return (Math.random() * (max - min + 1)) + min;
40   -}
41   -
42   -// Returns a random integer between min and max
43   -// Using Math.round() will give you a non-uniform distribution!
44   -function getRandomInt(min, max)
45   -{
46   - return Math.floor(Math.random() * (max - min + 1)) + min;
47   -}
48   -
49   -function degreesToRadians(degrees) {
50   - return degrees * Math.PI / 180
51   -}
80 source/js/rot_collisions.js.coffee
@@ -4,31 +4,54 @@
4 4
5 5 #= require ./plugins
6 6 #= require mylibs/vec
  7 +#= require mylibs/Math
7 8 #= require mylibs/Line
8 9 #= require mylibs/Circle
9 10 #= require mylibs/Canvas
  11 +#= require mylibs/collisions
10 12
11 13 $(document).ready ->
12 14 canvas = new Canvas($("#maincanvas").get(0))
13   - canvas.setOrigin('topleft')
14   - elapsed = lastTime = 0
  15 + #canvas.setOrigin('topleft')
  16 + elapsed = lastTime = lastAngle = 0
  17 + startingAngle = 20
  18 + startingTheta = 90 - startingAngle
15 19 angle = 0
16   - angleInc = .3
  20 + angularVel = 15 # degrees / second
17 21 lineLength = 200
18 22 line = null
19 23 ball = null
20 24 objects = []
21 25 paused = true
22   -
23   - drawScene = (objects, dt) ->
  26 + angVel = tanVel = ballDistance = ballAngle = collisionIn = 0
  27 +
  28 + drawInfo = (text) ->
  29 + $('#info').append(text + '<br/>')
  30 +
  31 + drawText = (text) ->
  32 + canvas.inContext ->
  33 + ctxt = canvas.context()
  34 + ctxt.fillStyle = 'black'
  35 + ctxt.font = '12px Arial sans-serif'
  36 + ctxt.textBaseline = 'top'
  37 + ctxt.fillText(text, canvas.width/2, 10)
  38 +
  39 + drawScene = () ->
24 40 canvas.clear()
25 41
  42 + if collisionIn >= 0
  43 + drawText "Collision in #{collisionIn}"
  44 + else if collisionIn == collisions.EMBEDDED
  45 + drawText "EMBEDDED"
  46 + else
  47 + drawText "No collision"
  48 +
26 49 for obj in objects
27 50 switch obj.name
28 51 when 'Line'
29 52 canvas.inContext ->
30 53 canvas.translate obj.pos.e(1), obj.pos.e(2)
31   - canvas.rotate(degreesToRadians(angle))
  54 + canvas.rotate(Math.degreesToRadians(-obj.rotation))
32 55 canvas.translate(-obj.pos.e(1), -obj.pos.e(2))
33 56 canvas.drawLine(obj)
34 57
@@ -38,26 +61,51 @@ $(document).ready ->
38 61
39 62 setupScene = ->
40 63 # draw rotating line
41   - angle = 90
  64 + angle = lastAngle = startingAngle
42 65 line = new Line(canvas.width/2, canvas.height/2, lineLength, 0, {
43   - color: 'black'
  66 + color: 'black',
  67 + rotation: startingAngle
44 68 })
45 69 # draw stationary circle
46   - ball = new Circle(canvas.width/2+lineLength/2, canvas.height/2+40, 0, {
47   - radius: lineLength/8
  70 + ball = new Circle(canvas.width/2+lineLength/1.2, canvas.height/2, 0, {
  71 + radius: lineLength/8,
48 72 color: 'blue'
49 73 })
  74 + # these two variable can be computed dynamically if the ball is moving
  75 + ballDistance = ball.pos.subtract(line.pos).mag()
  76 + ballAngle = Math.degreesToRadians 90
  77 + line.setAngularVelocity(angularVel)
  78 + angVel = Math.degreesToRadians(line.angularVelocity())
50 79 objects = [line, ball]
51 80
  81 + drawInfo("Theta0: #{startingTheta}")
  82 + drawInfo("Line length: #{lineLength}")
  83 + drawInfo("rotation axis: #{line.pos.inspect()}")
  84 + drawInfo("ball pos: #{ball.pos.inspect()}")
  85 + drawInfo("ball radius: #{ball.radius}")
  86 + drawInfo("ball angle: #{ballAngle}")
  87 + drawInfo("axis-ball distance: #{ballDistance}")
  88 + drawInfo("ang vel: #{angVel}")
  89 +
  90 + updateObjects = (t) ->
  91 + # update the line's rotation
  92 + rot = line.rotation - line.angularVelocity() * (t / 1000)
  93 + if Math.abs(rot) >= 360
  94 + rot = 0
  95 + line.rotation = rot
  96 +
  97 + checkCollisions = (t) ->
  98 + collisionIn = collisions.angularCollisionLineCircle(Math.degreesToRadians(90-line.rotation),
  99 + angVel, lineLength, ball.radius, ballDistance, ballAngle)
  100 +
52 101 # animate all objects
53 102 update = ->
54 103 # Pass latest timestep to the collision detection function
55 104 timeNow = new Date().getTime()
56 105 if lastTime != 0
57 106 elapsed = timeNow - lastTime
58   - angle -= angleInc
59   - if Math.abs(angle) >= 360
60   - angle = 0
  107 + updateObjects(elapsed)
  108 + checkCollisions()
61 109
62 110 lastTime = timeNow
63 111
@@ -66,12 +114,16 @@ $(document).ready ->
66 114 requestAnimFrame(tick)
67 115 unless paused
68 116 update()
69   - drawScene(objects, elapsed)
  117 +
  118 + drawScene(objects, elapsed)
70 119
71 120 # event handlers
72 121 $('canvas').click ->
  122 + checkCollisions elapsed
73 123 paused = !paused
74 124
75 125 setupScene()
  126 + checkCollisions()
  127 + drawScene(objects, 0)
76 128 tick()
77 129
4 source/rotation_cols.html.erb
@@ -12,8 +12,8 @@
12 12 </ul>
13 13 Click on canvas to play or pause
14 14 <canvas id="maincanvas" width="800" height="600"></canvas>
15   - <p>
16   - </p>
  15 + <div id="info">
  16 + </div>
17 17 </div>
18 18 <footer>
19 19 Source:

0 comments on commit a421701

Please sign in to comment.
Something went wrong with that request. Please try again.