Circle & Line collision calculation
Its all about the details, a circle & line collision for a physics engine ...
/**
* Copyright leichtgewicht ( http://wonderfl.net/user/leichtgewicht )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/lgDJ
*/
/**
* User: Martin Heidegger
*/
package {
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.events.Event;
import flash.events.MouseEvent;
public class Test extends Sprite {
private var l:Gate;
private var l2:Gate;
private var c:Circle;
private var s: int = 0;
public function Test() {
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.align = StageAlign.TOP_LEFT;
scaleX = scaleY = 1.76;
x = 50;
y = 50;
l = new Gate(60, 60, 180, 195);
l2 = new Gate(180, 195, 200, 60);
c = new Circle(10, new Velocity( -40, 80));
change();
addEventListener(Event.ENTER_FRAME, update);
stage.addEventListener(MouseEvent.CLICK, change);
}
private function change(e: Event = null): void {
if (s == 0) {
c.velocity.update( 10, 80 );
} else if( s == 1 ) {
c.velocity.update( -80, -40 );
} else if ( s == 2 ) {
c.velocity.update( 80, -10 );
s = 0;
return;
}
s++;
}
private function update(event:Event):void {
c.x = mouseX;
c.y = mouseY;
graphics.clear();
c.draw(graphics);
l.draw(graphics, l.intersectCircle(c, graphics));
l2.draw(graphics, l2.intersectCircle(c, graphics));
}
}
}
import flash.display.Graphics;
import spark.filters.ColorMatrixFilter;
class Velocity {
public var x: Number = 0;
public var y: Number = 0;
public var d: Number = 0;
public var yn:Number;
public var xn:Number;
public function Velocity(x: Number, y: Number) {
update(x, y);
}
public function update(x: Number, y: Number ): void {
this.x = x;
this.y = y;
this.d = Math.sqrt(x*x+y*y);
xn = x/d;
yn = y/d;
}
}
class Circle {
public var velocity: Velocity;
public var x: Number;
public var y: Number;
public var r: Number;
public function Circle(r: Number, velocity: Velocity ) {
this.x = 0;
this.y = 0;
this.r = r;
this.velocity = velocity;
}
public function draw( g: Graphics ): void {
var xEnd: Number = r * velocity.yn;
var yEnd: Number = -r * velocity.xn;
g.lineStyle( 1, 0xBCBCBC);
g.moveTo(x+xEnd, y+yEnd);
g.lineTo(x+velocity.x+xEnd, y+velocity.y+yEnd );
g.moveTo(x-xEnd, y-yEnd);
g.lineTo(x+velocity.x-xEnd, y+velocity.y-yEnd );
g.lineStyle( 1, 0x000000);
g.drawCircle( x, y, r );
g.lineStyle( 1, 0x999999);
g.drawCircle( x+velocity.x, y+velocity.y, r );
g.lineStyle( 1, 0xAAAAAA);
g.moveTo(x, y);
g.lineTo(x+velocity.x, y+velocity.y );
}
}
class Gate {
private var startX: Number;
private var startY: Number;
private var endX: Number;
private var endY: Number;
private var a: Number;
private var sin: Number;
private var cos: Number;
private var length: Number;
private var distanceX: Number;
private var distanceY: Number;
private var slopeYNormalized: Number;
private var slopeXNormalized: Number;
public function Gate(startX: Number, startY: Number, endX: Number, endY: Number) {
update(startX, startY, endX, endY);
}
private function update(startX: Number, startY: Number, endX: Number, endY: Number): void {
this.startX = startX;
this.startY = startY;
this.endX = endX;
this.endY = endY;
distanceX = endX - startX;
distanceY = endY - startY;
length = Math.sqrt( distanceX * distanceX + distanceY * distanceY );
slopeXNormalized = distanceX / length;
slopeYNormalized = distanceY / length;
a = Math.atan2(distanceX, distanceY);
sin = Math.sin(a);
cos = Math.cos(a);
}
public function intersectCircle( circle: Circle, g: Graphics ): Number {
const distanceVectorX: Number = circle.velocity.x;
const distanceVectorY: Number = circle.velocity.y;
const newSlopeX: Number = circle.velocity.xn*cos - circle.velocity.yn*sin;
const newSlopeY: Number = circle.velocity.yn*cos + circle.velocity.xn*sin;
const xRel: Number = circle.x - startX;
const yRel: Number = circle.y - startY;
const newX: Number = xRel*cos - yRel*sin;
const newY: Number = yRel*cos + xRel*sin;
const cutY: Number = newY - newSlopeY / newSlopeX * newX;
const newEndX: Number = newX + newSlopeX * circle.velocity.d;
const newEndY: Number = newY + newSlopeY * circle.velocity.d;
if ( newX < -circle.r || newEndX > circle.r ) {
return NaN;
}
var cutStartX: Number = 0;
var cutStartY: Number = cutY;
var cutEndX: Number = 0;
var cutEndY: Number = 0;
const alpha1: Number = Math.PI / 2 - Math.atan2(newSlopeX, newSlopeY);
const limit: Number = circle.r * Math.sin(alpha1) / Math.cos(alpha1);
var beta: Number;
var alpha: Number;
var alpha2: Number;
var a2: Number;
var a: Number;
var b: Number;
var x: Number;
if ( cutY < -limit ) {
cutPart = cutY;
a = cutPart;
b = circle.r;
if( alpha1 < Math.PI ) {
beta = Math.PI / 2 + alpha1;
alpha = Math.asin((Math.sin(beta) * a / b));
if(!isNaN(alpha)) {
alpha2 = alpha - alpha1;
a2 = b * Math.sin(alpha2);
x = Math.sqrt(b * b - a2 * a2);
if( cutPart < -circle.r ) {
x *= -1;
}
cutStartX = 0;
cutStartY = 0;
cutEndX = x;
cutEndY = a2;
} else {
return NaN;
}
} else {
return NaN;
}
} else {
if( cutY > -limit ) {
var cutPart: Number = cutY - length;
if ( cutPart < -limit) {
alpha = Math.atan2(newSlopeX, newSlopeY);
cutStartY = cutY + circle.r / Math.sin(alpha) * Math.sin(Math.PI/2-alpha);
cutStartX = 0;
cutEndX = circle.r;
cutEndY = cutStartY;
} else {
if( alpha1 > 0 ) {
a = cutPart;
b = circle.r;
beta = Math.PI / 2 - alpha1;
alpha = Math.asin((Math.sin(beta) * a / b));
if(!isNaN(alpha)) {
alpha2 = alpha - alpha1;
a2 = b * Math.sin(alpha2);
x = Math.sqrt(b * b - a2 * a2);
if( cutPart >= circle.r ) {
x *= -1;
}
cutStartX = 0;
cutStartY = length;
cutEndX = x;
cutEndY = length + a2;
} else {
return NaN;
}
} else {
return NaN;
}
}
} else {
return NaN;
}
}
var dt: Number = 1 / (newX - newEndX) * (newX - cutEndX);
if ( dt < 0 ) {
return NaN;
}
g.lineStyle(1, 0);
g.moveTo(0, 0);
g.lineTo(0, length);
g.lineStyle(1, 0x00FFFF);
g.moveTo(newX,newY);
g.lineTo(newX+newSlopeX*circle.velocity.d, newY+newSlopeY*circle.velocity.d);
g.drawCircle(newEndX, newEndY, circle.r);
g.drawCircle(newX,newY,circle.r);
g.lineStyle(1, 0xFF0000);
g.drawCircle(0,cutY,2);
g.moveTo(cutStartX,cutStartY);
g.lineTo(cutEndX, cutEndY);
g.drawCircle(cutEndX, cutEndY, circle.r);
return dt;
}
public function draw( g: Graphics, i: Number ): void {
g.lineStyle( 1, !isNaN(i) ? 0xFF0000 : 0x00FF00 );
g.moveTo( startX, startY );
g.lineTo( endX, endY );
}
}