var resolution:Number = .03;
var pointNum:int = Math.ceil(1 / resolution);
var bezA:Array = new Array();
populateArray(bezA);
var a:Sprite = dot(100, 200);
var b:Sprite = dot(200, 100);
var c:Sprite = dot(300, 200);
var bezB:Array = new Array();
populateArray(bezB);
var d:Sprite = dot(300, 100, 0xCCCC00);
var e:Sprite = dot(120, 130, 0xCCCC00);
var f:Sprite = dot(200, 300, 0xCCCC00);
addEventListener(Event.ENTER_FRAME, onLoop);
function onLoop(evt:Event):void {
with(graphics){
clear();
lineStyle(0, 0x000000);
// calc and draw bezier points
drawBezier(bezA, a, b, c);
drawBezier(bezB, d, e, f);
// calc collisions
var intersections:Array = calculateIntersection(bezA, bezB);
// draw collisions
beginFill(0xFF0000);
if (intersections.length > 0){
for (var i:int = 0; i< intersections.length; i++){
drawCircle(intersections[i].x, intersections[i].y, 3);
}
}
endFill();
}
}
function populateArray(a:Array):void {
for (var i:int = 0; i<pointNum; i++){
a.push(new Point());
}
}
function drawBezier(bez:Array, a:Sprite, b:Sprite, c:Sprite):void{
with(graphics){
bezier(bez, a.x, a.y, b.x, b.y, c.x, c.y);
var leng:Number = bez.length;
moveTo(bez[0].x, bez[0].y);
for (var i:int = 1; i<leng; i++){
lineTo(bez[i].x, bez[i].y);
}
}
}
function bezier(bez:Array, x1:Number, y1:Number, x2:Number, y2:Number, x3:Number, y3:Number):void {
var b:Number, a2:Number, ab2:Number, b2:Number;
var pnt:Point;
var inc:int = 0;
for (var a:Number = 0; a <=1; a+=resolution) {
b= 1 - a;
a2 = a * a;
ab2 = a * b * 2;
b2 = b * b;
pnt = bez[inc];
pnt.x = a2 * x1 + ab2 * x2 + b2 * x3;
pnt.y = a2 * y1 + ab2 * y2 + b2 * y3;
inc++;
}
}
function calculateIntersection(bezA:Array, bezB:Array):Array {
var intersections:Array = new Array();
var ip:Point;
var aLength:int = bezA.length;
var bLength:int = bezB.length;
var p1:Point, p2:Point, p3:Point, p4:Point;
// compare all line segments and check for
// intersections
for (var i:int = 1; i<aLength; i++){
p1 = bezA[i - 1];
p2 = bezA[i];
for (var j:int = 1; j<bLength; j++){
p3 = bezB[j - 1];
p4 = bezB[j];
ip = intersection(p1, p2, p3, p4);
if (ip){
intersections.push(ip.clone());
}
}
}
return intersections;
}
var ip:Point = new Point();
function intersection(p1:Point, p2:Point, p3:Point, p4:Point):Point {
var nx:Number, ny:Number, dn:Number;
var x4_x3:Number = p4.x - p3.x;
var pre2:Number = p4.y - p3.y;
var pre3:Number = p2.x - p1.x;
var pre4:Number = p2.y - p1.y;
var pre5:Number = p1.y - p3.y;
var pre6:Number = p1.x - p3.x;
nx = x4_x3 * pre5 - pre2 * pre6;
ny = pre3 * pre5 - pre4 * pre6;
dn = pre2 * pre3 - x4_x3 * pre4;
if (dn == 0){
return null
}
nx /= dn;
ny /= dn;
// has intersection
if(nx >= 0 && nx <= 1 && ny >= 0 && ny <= 1){
ny = p1.y + nx * pre4;
nx = p1.x + nx * pre3;
ip.x = nx;
ip.y = ny;
}else{
return null;
}
return ip
}
// draggable dot
function dot(xp:Number, yp:Number, col:uint = 0x507399, noDrag:Boolean = false):Sprite {
var s:Sprite = Sprite(addChild(new Sprite));
s.x = xp;
s.y = yp;
with(s.graphics) beginFill(col), drawCircle(0,0,5);
if (!noDrag){
s.buttonMode = true;
s.addEventListener(MouseEvent.MOUSE_DOWN, onDrag);
}
return s;
}
function onDrag(evt:MouseEvent):void {
evt.currentTarget.startDrag()
}
stage.addEventListener(MouseEvent.MOUSE_UP, onUp);
function onUp(evt:MouseEvent):void{
stopDrag();
}
This is not a snippet, but it uses some functions that could be considered snippets on their own. Take a look at the swf here:
This demo show a brute force method for getting the coordinates of all intersections between two given quadtratic bezier curves. The approach is pretty simple, each bezier is actually made up of a series of line segments. The resolution variable determines how many line segments make up one bezier curve. By default I use a resolution of 0.03 (~34 lines)… the higher the resolution decimal value, the fewer the number of line segments. I then use a slight variation on yesterdays line segment intersection function to test all existing line segments for intersections.
This is a brute for approach with lots of room for improvement. But in the scenario that you only need to check a few bezier curves for intersection this approach works quite nicely. I don’t recommend this approach if your trying to create a complex vector drawing tool with boolean vector operations etc…
It’s easy to get an idea of the different approaches to this problem with a little googling. One example I found is from Graphics Gems:
http://tog.acm.org/GraphicsGems/gemsiv/curve_isect/
it’s been awhile, but I believe this website also contains information related to this topic: