Given a line with first end point P(x1,y1) another end point is unknown, intersect with a circle that located at origin with radius R at only one point(tangent) T(x2,y2). Anyone know how to get the point T? Thanks in advance!
Given a line with first end point P(x1,y1) another end point is unknown, intersect with a circle that located at origin with radius R at only one point(tangent) T(x2,y2). Anyone know how to get the point T?
Some of the other solutions seem a little like overkill. I think the simplest way is just to notice that this is a right triangle, with vertices P, T, and O (the origin). The angle PTO is the right angle, because a tangent line is always at a right angle to a radius.
You know the length of TO
because it's of length r
and has a vertex at the origin; you know OP
because you know where O
and P
is. Given two sides of a right triangle, it's easy to find the length and direction of the third side. This is homework, so I'll leave the rest as an exercise to the reader.
__...------__ T(x2, y2)
_.-'' -(+)
,-' |----
,' | ----
,' | ' ----
/ | ` ----
/ | `. ----
/ | \ ----
| | | ----
| | | ----
| | | ----
| (+)---------------------------------------------(+) P (x1,y1)
| .'
| O |
| .'
\ /
\ ,'
` /
'. ,'
'-. _,'
'-._ _,(+) T'(x3, y3)
'`--......---'
There are two possible directions for TO
, since the point T' is also a valid tangent point, so you will have two congruent triangles.
OP
is the diameter of the circumcircle for OPT
. –
Gorham All you need is in dmckee's answer, but if you care for some code check this implementation using Javascript and HTML canvas.
Full example: http://jsfiddle.net/zxqCw/1/
// find tangents
dx = cx - px;
dy = cy - py;
dd = Math.sqrt(dx * dx + dy * dy);
a = Math.asin(radius / dd);
b = Math.atan2(dy, dx);
t = b - a
ta = { x:radius * Math.sin(t), y:radius * -Math.cos(t) };
t = b + a
tb = { x:radius * -Math.sin(t), y:radius * Math.cos(t) };
Take R
as the radius of the circle and D
the distance from the external point to the center of the circle such that D > R
.
The tanget line makes and angle of \alpha
with the line connecting the external point and the center, where
\alpha = arcsin(R/D)
The line connecting the external point (P
) and the center (C
) makes an angle with the horizontal of
\beta = arctan((C_y - P_y)/(C_x - P_x))
That gives you the angle of the tangent line with the horizontal as
\theta = \beta +/- \alpha
Note the ambiguity.
The length of the tangent segment is
L = sqrt(D^2 - R^2)
which is all you need.
arcsin
. You would use arccos
for the angle between the connecting line (CP) and the radius (CT). –
Graphology imbrizi's answer assumes that the circle's center is (0,0).
This is the correct answer in Objective C:
- (NSArray *)pointsTangentToCircleWithCenter:(CGPoint)centerPoint
radius:(CGFloat)radius
outerPoint:(CGPoint)outerPoint {
float dx = centerPoint.x - outerPoint.x;
float dy = centerPoint.y - outerPoint.y;
float dd = sqrt(dx*dx + dy*dy);
float a = asinf(radius / dd);
float b = atan2f(dy, dx);
float t1 = b - a;
CGPoint tangentPoint1 = CGPointMake(centerPoint.x + radius*sinf(t1),
centerPoint.y + radius*-cosf(t1));
float t2 = b + a;
CGPoint tangentPoint2 = CGPointMake(centerPoint.x + radius*-sinf(t2),
centerPoint.y + radius*cosf(t2));
NSArray *points = @[
[NSValue valueWithCGPoint:tangentPoint1],
[NSValue valueWithCGPoint:tangentPoint2]
];
return points;
}
You can find direction of vector DX if you rotate vector DO by angle alpha (angle alpha is found as asin(len(OX) / len(DO)), which is simply arcsinus of radius over hypotenuse)
You can find the length of vector DX trivially as following: sqrt(len(DO)*len(DO) - len(OX)*len(OX))
Given the direction and length of vector DX, you can find the value of point X. One approach would be to normalize DX and multiply it by the length of it.
auto dist = D.Distance(O); auto side = sqrt(dist*dist - rad*rad) auto line = Vector2D(D, O); line.Rotate(asin(rad / dist)); //get the direction line.Normalize(); //set length to 1 line*=side; //we have the direction, now get length Point2D X = D + line;
P.S. Note that there is also a second tangent, which is found by rotating DO by minus alpha
It is not obvious to me that this is homework, but I do like the intuition that a right triangle is defined. Even so, there will be some algebra with that solution.
Another approach that seems viable is to simply define the problem as the solution of two equations in two unknowns. That is, the equation of a circle, centered at (0,0), with radius R is
x^2 + y^2 = R^2
The equation of a line that passes through the point (xt,yt), with (unknown) slope S is
(y - yt) = S*(x - xt)
Solve the system of two equations for the intersection point. Depending upon the value of S, there will be zero, one or two solutions to this pair of equations. It will also turn out that there are two values of S such that the solution is unique. Solve for those two values of S that make the solution unique, then recover the intersection point (xt,yt). I won't go through the actual solution in depth in case this is homework, but that part is trivial algebra.
My point is that this algebraic approach is another way to view the solution of the computational geometry problem. It highlights an interesting point in that there are two lines which intersect the circle at a tangent point, and that when a line intersects at a tangent point, there is a single point of intersection.
A flaw of this approach is that is fails due to a singularity for SOME problems. I.e., when the line with slope S is vertical, then S is undefined. Other approaches that rely on simple distances and the Pythagorean theorem are robust to that event.
Here is a C# solution (it can be easily adapted to other languages) that doesn't use trigonometric functions, only geometric construction.
You can see a living representation here (P, C and radius can be moved): https://www.desmos.com/calculator/ifzt2nzyl9
public static double[] GetTangentPoints(
double px,
double py,
double cx,
double cy,
double radius)
{
var points = new double[4];
var dx = cx - px;
var dy = cy - py;
if (dx == 0 && dy == 0)
return null; // no solution
// PC is distance between P and C, pc2 is PC^2
var pc2 = dx * dx + dy * dy;
var pc = Math.Sqrt(pc2);
if (pc < radius)
return null; // no solution
// R is radius of circle centered in P, r2 is R^2
var r2 = pc2 - radius * radius;
// d is the P => X0 distance (demonstration is here https://mathworld.wolfram.com/Circle-CircleIntersection.html where PC is named 'd' in there)
var d = r2 / pc;
// h is the X0 => X1 (and X0 => X2) distance
var h = Math.Sqrt(r2 - d * d);
// first tangent point
points[0] = px + (dx * d - dy * h) / pc;
points[1] = py + (dy * d + dx * h) / pc;
// second tangent point
points[2] = px + (dx * d + dy * h) / pc;
points[3] = py + (dy * d - dx * h) / pc;
return points;
}
Use the x,y coordinates of the intersecting equations (the one of the circle and the one of the line). That's the point.
If you have only one end point from which to draw the line you'll get two different points, as there will be two different tangent lines, one up and one down.
I usually use Maple software to solve such problems. It can even generate C code from those equations.
Here's the output:
t1 = v_x * v_x;
t2 = t1 * t1;
t3 = v_y * v_y;
t6 = sqrt(t1 * t3 - t1 + t2);
t7 = v_y + t6;
t9 = 0.1e1 / (t1 + t3);
t13 = 0.1e1 / v_x;
x1 = -(t7 * t9 * v_y - 0.1e1) * t13;
y1 = t7 * t9;
t16 = (-v_y + t6) * t9;
x2 = -(-t16 * v_y - 0.1e1) * t13;
y2 = -t16;
Obviously, you need to add float or double to the variables, also check for negative value before taking the square root.
Another solution; less elegant than dmindreader`s, but maybe simpler to understand:
You know that the point T
is on the circle and that the line OT
is perpendicular to the line PT
that gives you
abs(O - T) = R
dotProduct(O - T, P - T) = 0
Here is my C# answer. Just 7 lines of code. You have to watch "Youtube A Miraculous Proof (Ptolemy's Theorem) - Numberphile" to figure out how it works. The code is tested and produces the correct answers. Sorry about the inserted line feeds. I just copied from Visual Studio to here.
static void FindTangentPoints(float r, PointF p, out PointF tangent1, out PointF tangent2)
{
float incidentLength = MathF.Sqrt(p.X * p.X + p.Y * p.Y); //the distance from the origin to the point outside the circle
float reflectedLength = (r * r) / incidentLength; //see Youtube A Miraculous Proof (Ptolemy's Theorem) - Numberphile
//take particular note when Prof Stankova writes OA1 * OA = R*R
PointF p2 = new PointF(p.X * reflectedLength / incidentLength, p.Y * reflectedLength / incidentLength); //the inversion in the plane of pointOutsideTheCircle
float pRadians = MathF.Atan2(p.Y, p.X); //the same as the angle to point p2
float angleP2OT = MathF.Acos(MathF.Sqrt(p2.X * p2.X + p2.Y * p2.Y) / r); //the angle between the tangent point and p
tangent1 = new PointF(r * MathF.Cos(pRadians + angleP2OT), r * MathF.Sin(pRadians + angleP2OT));
tangent2 = new PointF(r * MathF.Cos(pRadians - angleP2OT), r * MathF.Sin(pRadians - angleP2OT));
}
© 2022 - 2024 — McMap. All rights reserved.