Given a point outside of an arc, how can one find the point on the arc which extends to that point?
For example, the radius of the circle (R) is 10cm, it's center point is [0,0].
The origin (o) of the line (8) is at [-3, 10]
How can we find the point (p) (p8) were the tangent at that point continues to the origin of the line?
A brute force solution would not be acceptable.
Let point coordinates are px, py
, and circle center is at (0,0)
(if not - subtract center cx, cy
from all coordinates to simplify equations, add them back at the end).
You can write two equations for unknown x,y
. Circle equation and perpendicularity one - tangent is perpendicular to radius-vector, their dot product is zero.
(x - px) * x + (y - py) * y = 0
x^2 + y^2 = r^2
x^2 - px * x + y^2 - py * y = 0
r^2 - px * x = py * y
y = (r^2 - px * x) / py
y^2 = r^4 / py ^2 - x * 2 * r^2 * px / py^2 + x^2 * px^2 / py^2
x^2 * (1 + px^2 / py^2) - x * 2 * r^2 * px / py^2 + (r^4 / py^2 - r^2) = 0
x^2 * (py^2 + px^2) - x * 2 * r^2 * px + (r^4 - r^2 * py^2) = 0
Solve the last quadratic equation for x
, then calculate y
.
Delphi function for reference (note: py=0 case is treated separately)
function GetTangentPts(px, py, r: Double): TArray<Double>;
var
px2, py2, pxpy, r2, Dis, x, y: Double;
begin
px2 := px * px;
py2 := py * py;
r2 := r * r;
pxpy := px2 + py2;
Dis := pxpy - r2;
if Dis < 0 then //point is inside
Exit(nil)
else if Dis = 0 then begin //point is at circumference
SetLength(Result, 2);
if py = 0 then begin
x := px;
y := 0;
end else begin
x := px * r2 / pxpy;
y := (r2 - px * x) / py;
end;
Result[0] := x;
Result[1] := y;
end else begin //general case, two tangents
SetLength(Result, 4);
if py = 0 then begin
y := - r * Sqrt(Dis) / px;
x := px / Abs(px) * r * Sqrt(1 - Dis/px2);
Result[0] := x;
Result[1] := y;
y := r * Sqrt(Dis) / px;
Result[2] := x;
Result[3] := y;
end else begin
x := (px * r2 - r * Sqrt(py2 * Dis)) / pxpy;
y := (r2 - px * x) / py;
Result[0] := x;
Result[1] := y;
x := (px * r2 + r * Sqrt(py2 * Dis)) / pxpy;
y := (r2 - px * x) / py;
Result[2] := x;
Result[3] := y;
end;
end;
end;
some results:
10.00 10.00 10.00 //two perpendicular tangents
0.00
10.00
10.00
0.00
-10.00 10.00 10.00
-10.00
0.00
0.00
10.00
1.00 1.00 10.00
//inside
0.00 10.00 10.00 //horizontal tangent
0.00
10.00
10.00 0.00 10.00 //vertical tangent
10.00
0.00
-14.14 0.00 10.00 //two tangents from OX-axis
-7.07
7.07
-7.07
-7.07