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!
问题:
回答1:
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.
回答2:
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) };
回答3:
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.
回答4:
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;
}
回答5:
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
回答6:
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.
回答7:
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.
回答8:
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.
回答9:
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