Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Draw a line from a point to opposite tangents on a circle? Cone/wedge shape in AS3

This should be a bit of simple geometry: How do I calculate the points to draw the lines in the code below so that it makes a 2D cone or wedge shape?

import flash.geom.Point;

//draw circle
var mc=new Sprite()
mc.graphics.lineStyle(0,0)
mc.graphics.drawCircle(0,0,30)
mc.x=mc.y=Math.random()*300+100
addChild(mc)

//draw lines:
graphics.lineStyle(0,0)
var p=new Point(Math.random()*500,Math.random()*400)
graphics.moveTo(p.x, p.y)
graphics.lineTo(mc.x,mc.y) // << should be point on edge of circle
graphics.moveTo(p.x, p.y)
graphics.lineTo(mc.x,mc.y) // << should be point on opposite edge of circle

UPDATE:
Thanks guys, I should have mentioned my aim is not to draw a wedge shape, but to draw a line from a random point to the edge of an existing circle.

If you're more comfortable with algebra than actionscript, maybe you could have a look at this graphic and post a formula for me? tangents

like image 516
cronoklee Avatar asked Apr 15 '11 23:04

cronoklee


2 Answers

Your question is about Thales theorem (see http://en.wikipedia.org/wiki/Thales%27_theorem).

The following is the theorem modified slightly to work with AS3.

import flash.geom.Point;

// The radius of the circle
var r1:Number = 30;
// The center point of the circle
var cp:Number = Math.random() * 300+100;
var c:Point = new Point(cp, cp);

// draw circle
var mc=new Sprite();
mc.graphics.lineStyle(0,0);
mc.graphics.drawCircle(0,0,r1);
mc.x = mc.y = cp;
addChild(mc);

// The point
var p = new Point(Math.random() * 500, Math.random() * 400);

// Calculate points for intesecting circle
var c2:Point = Point.interpolate(c, p, 0.5);
var r2:Number = Point.distance(c2, c);
var d:Number = Point.distance(c, c2);

// Remove comment below to see intersecting circle
//graphics.beginFill(0xFF0000, 0.25);
//graphics.drawCircle(c2.x, c2.y, r2);

var a:Number = (r1*r1 - r2*r2 + d*d) / (2*d);
var p2x:Number = c.x + a * ( c2.x - c.x ) / d;
var p2y:Number = c.y + a * ( c2.y - c.y ) / d;
var h:Number = Math.sqrt(r1*r1 - a*a);

var d1x:Number = p2x + h * ( c2.y - c.y ) / d;
var d1y:Number = p2y - h * ( c2.x - c.x ) / d;
var d2x:Number = p2x - h * ( c2.y - c.y ) / d;
var d2y:Number = p2y + h * ( c2.x - c.x ) / d;

// Draw lines
graphics.lineStyle(1, 0xFF00FF, 0.5);
graphics.moveTo(p.x, p.y);
graphics.lineTo(d1x, d1y);
graphics.moveTo(p.x, p.y);
graphics.lineTo(d2x, d2y);

The final product:

enter image description here

With the second circle drawn (you don't actually need to draw in the second circle, you just need its center point and radius)

enter image description here

Checkout the following SWF to see in action (refresh to see different random circles):

http://megaswf.com/serve/1097652

like image 196
Chris Avatar answered Sep 20 '22 09:09

Chris


Let (xP, yP) be the intersection of the tangents, (xC,yY) be the center of the circle, where you are looking for the coordinates (xT,yT) of the tangent points. Further more let T be the vector of the tangent and R be the vector of the radius. Since they are perpendicular, you have R . T = 0.

This gives us

(xT-xC,yT-yC) . (xT-xP, yT-yP) = 0

Let r be the radius of the circle and let x:=xT-xC, y:=yT-yC, xp:=xP-xC, yp:=yP-yC (basically, we move the circle into (0,0)). The tangent point is on the circle, so you have x²+y²=r² and thus also y=sqrt(r²-x²).

The variable substitution applied to the above equation gives us:

(x,y) . (x-xp, y-yp) = 0
x²-xp*x + y²-yp*y = 0

Using the circle information we have:

r² -xp*x - yp*sqrt(r²-x²) = 0
r² -xp*x = yp*sqrt(r²-x²)
r^4 - 2*r²*xp*x + xp²*x² = yp²*(r²-x²)
(yp²+xp²)*x² - 2*r²*xp*x + r^4-yp²*r² = 0

now let a:=yp²+xp², b:=2*r²*xp, c:= (r²-yp²)*r²
=> ax² + bx + c = 0

This is a quadratic equation with 0, 1 or 2 solutions. 0, if P is in the circle, 1, if P is on the circle and 2, if P is outside the circle.

I won't put the explicit solution here, since it's a hell of a formula and it's a lot easier to write, if you map the variables introduced here to variables in your code as:

var sq:Function = function (f:Number) { return f*f; }, sqrt:Function = Math.sqrt;
var xp:Number = xP-xC, yp:Number = yP-yC,
    a:Number = sq(xp)+sq(yp), b:Number = 2*sq(r)*xp, c:Number = sq(r)*(sq(r)-sq(yp));
var x1:Number = (-b+sqrt(sq(b)-4*a*c)) / (2 * a),
    x2:Number = (-b+sqrt(sq(b)-4*a*c)) / (2 * a);
if (isNan(x1)) return [];
var p1:Point = new Point(x1+cX, sqrt(sq(r)-sq(x1))+cY),//calculate y and undo shift
    p2:Point = new Point(x2+cX, sqrt(sq(r)-sq(x2))+cY);
return p1.equals(p2) ? [p1] : [p1, p2];

Best of luck with this, because I am very bad with calculus, plus it's 04:00 here, so you can bet, there's a mistake somewhere, but it should get you in the right direction ;)

like image 38
back2dos Avatar answered Sep 21 '22 09:09

back2dos