# simianarmy/Canvas-Physics

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

`…llisions`
• Loading branch information...
1 parent 58d6d45 commit a421701df80ee34f5f75a9fbbb71cbe79a6cab68 committed Feb 5, 2012
 @@ -1,3 +1,6 @@ +# @module bitmapDemo + +#= require ./mylibs/Math #= require ./mylibs/Polygon #= require ./mylibs/collisions @@ -75,7 +78,7 @@ bitmapDemo = (bitmap) -> lastRot += 45 context.save() context.translate(imgX, imgY) - context.rotate degreesToRadians(lastRot) + context.rotate Math.degreesToRadians(lastRot) context.drawImage(img, 0, 0) context.restore() @@ -85,7 +88,7 @@ bitmapDemo = (bitmap) -> context.save() context.translate(imgX, imgY) context.scale 0.5, 0.5 - context.rotate degreesToRadians(lastRot) + context.rotate Math.degreesToRadians(lastRot) context.drawImage(img, 0, 0) context.restore()
 @@ -17,14 +17,18 @@ Canvas = (() -> @width = canvasEl.width @height = canvasEl.height + context = () -> @ctxt + # Set the origin of the canvas # @param {String} id (topleft | bottomleft) setOrigin = (id) -> if id == 'topleft' # translate world for origin at bottom left @ctxt.scale(1, -1) @ctxt.translate(0, -@height) - + else + # bottom left is default + # Draw a circle on the canvas # @param {Circle} c a Circle object drawCircle = (c) -> @@ -96,6 +100,7 @@ Canvas = (() -> drawLine: drawLine drawEllipse: drawEllipse inContext: inContext + context: context rotate: rotate translate: translate clear: clear
 @@ -0,0 +1,28 @@ +# @module Math +# +# Extensions to the built-in Math module + +#= require ./vec + +# angularVelocity +# +# Angular velocity of a particle in 2 dimensions +# @param {Vector} v velocity vector of the particle +# @param {Vector} r position vector of the particle (from origin or rotation) +# @param {Float} theta angle of rotation (in radians) +# @return {Float} the angular velocity +Math.angularVelocity = (v, r, theta) -> + (v.mag() * Math.sin(theta)) / r.mag() + +# Returns a random float between min and max +# Using Math.round() will give you a non-uniform distribution! +Math.getRandom = (min, max) -> + (Math.random() * (max - min + 1)) + min + +# Returns a random integer between min and max +# Using Math.round() will give you a non-uniform distribution! +Math.getRandomInt = (min, max) -> + Math.floor(Math.random() * (max - min + 1)) + min + +Math.degreesToRadians = (degrees) -> + degrees * Math.PI / 180
 @@ -1,5 +1,6 @@ -# PoolTable.coffee +# @module PoolTable +#= require ./Math #= require ./vec #= require ./collisions #= require ./Line @@ -319,7 +320,7 @@ PoolTable = (ctxt, opts) -> context.save() context.translate balls[0].pos.e(1), balls[0].pos.e(2) - context.rotate degreesToRadians(cueRotDegrees) + context.rotate Math.degreesToRadians(cueRotDegrees) context.translate ogCuePos.e(1), ogCuePos.e(2) context.drawImage(cueImg, 0, 0, cueImg.width, cueImg.height) context.restore()
 @@ -9,9 +9,14 @@ class Shape @mass = @efficiency = 1.0 @collisionNormal = null # vector @[x] = val for x, val of opts + # initial speed, angular speed, etc @velocity ?= Vector.Zero(3) @displacement ?= Vector.Zero(3) @direction ?= Vector.Zero(3) + @speed ?= 0 + @rotation ?= 0 + @angSpeed ?= 0 + @rotDirection ?= 1 move: (vec) -> @pos = @pos.add(vec) @@ -20,6 +25,20 @@ class Shape y: -> @pos.e(2) z: -> @pos.e(3) + angularDirection: -> @rotDirection + + # calculate shape's angular velocity + # @return {Number} pseudovector omega with sign dependent + # on direction of rotation around axis (clockwiseNormal) + angularVelocity: -> + @angularDirection() * @angSpeed + + # set the shape's angular velocity + # @param {Number} v degrees/second + setAngularVelocity: (v) -> + @rotDirection = if v > 0 then 1 else -1 + @angSpeed = Math.abs(v) # * 180 / Math.PI + # prototype properties toString: -> kvs = for key, val of @ when val? and typeof(val) != 'function'
 @@ -1,8 +1,9 @@ # @module scene # Module for moving circles in a box -#= require 'libs/raphael-min' +#= require libs/raphael-min #= require ./vec +#= require ./Math #= require ./collisions #= require ./Line #= require ./Circle @@ -63,15 +64,15 @@ scene = (opts) -> # Return a random circle color randomCircleColor = -> - CIRCLE_COLORS[getRandomInt(1, CIRCLE_COLORS.length)-1] + CIRCLE_COLORS[Math.getRandomInt(1, CIRCLE_COLORS.length)-1] # Return a y-value for a circle circleY = -> - if freeY then getRandom(-MAX_VELOCITY_Y, MAX_VELOCITY_Y) else 0 + if freeY then Math.getRandom(-MAX_VELOCITY_Y, MAX_VELOCITY_Y) else 0 # Create and return a new (free) circle createFreeCircle = (x, y, i) -> - velx = getRandom(-MAX_VELOCITY_X, MAX_VELOCITY_X) + velx = Math.getRandom(-MAX_VELOCITY_X, MAX_VELOCITY_X) new Circle(x, y, 0, { radius: CIRCLE_RADIUS velocity: Vector.create([velx, circleY(), 0]) @@ -91,7 +92,7 @@ scene = (opts) -> if diff > 0 # Add balls for i in [1..diff] - circles.push createFreeCircle(getRandom(0, bw), bh/2, i) + circles.push createFreeCircle(Math.getRandom(0, bw), bh/2, i) else # remove balls circles.pop() for i in [1..(circles.length-nballs)]
 @@ -2,7 +2,8 @@ #= require ../libs/sylvester -collisions = -> +collisions = {} +collisions = (-> # constants collisions.NONE = -1 collisions.EMBEDDED = -2 @@ -106,6 +107,39 @@ collisions = -> t = intersectionTime(c.pos.add(r), c.displacement, wall.pos, wall.vec) [t, collisionNormal] + # Check for collision between rotating line and circle + # Anglular values should be in radians + # @param {Number} theta0 angle of starting position of line from the vertical + # @param {Number} omega angular velocity of rotating line + # @param {Number} l line length + # @param {Number} r ball radius + # @param {Number} d distance of line origin to ball center + # @param {Number} alpha angle of vertical and line to ball center + angularCollisionLineCircle = (theta0, omega, l, r, d, alpha) -> + return collisison.NONE if d > l + r + return collisions.EMBEDDED if d < r + k = 1 + # move into a calculation within the range of [0,2pi] + alpha -= theta0 + if omega < 0 + omega = -omega + alpha = -alpha + k = -1 + + pi2 = Math.PI * 2 + while alpha < 0 + alpha += pi2 + while alpha > pi2 + alpha -= pi2 + + # check if there is a possible collision + # return collisions.NONE if alpha > omega + # now perform the appropriate collision check + if d*d <= (l*l + r*r) + (alpha - k * Math.asin(r / d)) / omega + else + (alpha - k * Math.acos((l*l + d*d - r*r) / (2*l*d))) / omega + isImpendingCollision = (ts) -> 0 < ts <= 1 @@ -321,8 +355,10 @@ collisions = -> isImpendingCollision, resolveCollision, resolveInelasticCollisionFixed, + angularCollisionLineCircle, pointInTriangle, pointInPolygon} - +)() + root = exports ? window -root.collisions = collisions() +root.collisions = collisions
 @@ -9,7 +9,7 @@ # isClockwise # -# Determines if object at p with velocity v is moving clockwise about the origin +# Determines if object starts at p with velocity v is moving clockwise about the origin # @returns {Boolean} Vector.isClockwise = (v, p) -> n = p.clockwiseNormal() @@ -93,4 +93,3 @@ Vector::clockwiseNormal = -> Vector::moment = (p) -> @clockwiseNormal().dot(p) -
 @@ -31,21 +31,3 @@ window.requestAnimFrame = (function() { window.setTimeout(callback, 1000/60); }; })(); - -// Returns a random float between min and max -// Using Math.round() will give you a non-uniform distribution! -function getRandom(min, max) -{ - return (Math.random() * (max - min + 1)) + min; -} - -// Returns a random integer between min and max -// Using Math.round() will give you a non-uniform distribution! -function getRandomInt(min, max) -{ - return Math.floor(Math.random() * (max - min + 1)) + min; -} - -function degreesToRadians(degrees) { - return degrees * Math.PI / 180 -}

#### 0 comments on commit `a421701`

Please sign in to comment.