从曲线外的用户给定点查找曲线上的切点

Find tangent points on a curve from a user-given point outside the curve

我正在尝试从闭合曲线外(不在曲线上)的给定点找到切线。曲线定义为点的二维x和y坐标,例如形状像一个不规则的椭圆。

如果用户给定一个点:(x0,y0) = (-30,80),我怎么知道曲线上的切点(从平滑曲线离散点中明显最近的点)(即切线从 (x0,y0) 到曲线的直线)?

一种可能是用数值微分求出每一点的切线,并判断它是否通过"close enough"到给定的点。但是,必须仔细考虑 "close enough" 以避免没有匹配项或匹配项太多。

这是另一种方法:考虑从给定点 (x0,y0) 指向曲线上的点的单位向量。找到它们之间的最大差距(命令 convhull 在这里有帮助)。间隙两侧的矢量确定切线。

一般来说,这只会找到两条切线,而不是全部。但是如果曲线是凸的,反正只有两条切线。

这是一个棘手情况的示例,其中给定点位于曲线的凸包内。

生成上图的代码:

t = linspace(0,2*pi,100);
x = 10*cos(t) + sin(7*t);
y = 6*sin(t) + cos(13*t);                 % x,y  describe the curve; 

x0 = 4; y0 = 5;                           % given point 

xn = (x-x0)./sqrt((x-x0).^2+(y-y0).^2);   % unit vectors 
yn = (y-y0)./sqrt((x-x0).^2+(y-y0).^2);   % from x0,y0 to points on the curve
cvx = convhull(xn,yn);                    % convex hull of unit vectors  

[~,i] = max(diff(xn(cvx)).^2+diff(yn(cvx)).^2);    % largest gap in the hull
x1 = xn(cvx(i)); y1=yn(cvx(i));            % vectors on both sides
x2 = xn(cvx(i+1)); y2=yn(cvx(i+1));        % of the gap     

plot(x,y)
hold on
s = linspace(0,10);
plot(x0+s*x1, y0+s*y1, 'r')                % output
plot(x0+s*x2, y0+s*y2, 'r') 
hold off

另一种方法,如果 (x0,y0) 不在曲线的凸包内,则效果很好。

使用convhull求出曲线与给定点(x0,y0)并集的凸包。入射到 (x0,y0) 的凸包的两条边与曲线相切:

生成上图的代码:

t = linspace(0,2*pi,100);
x = 10*cos(t) + sin(7*t);
y = 6*sin(t) + cos(13*t);                 % x,y  describe the curve; 

x0 = 4; y0 = 8;                           % given point 

xe = [x0, x]; ye = [y0, y];               % put all points together 
cvx = convhull(xe,ye);                    % find convex hull 

x1 = xe(cvx(2)); y1=ye(cvx(2));           % one neighbor of (x0,y0)
x2 = xe(cvx(end-1)); y2=ye(cvx(end-1));   % another neighbor

plot(x,y)
hold on
s = linspace(0,2);
plot(x0+s*(x1-x0), y0+s*(y1-y0), 'r')     % plot the lines 
plot(x0+s*(x2-x0), y0+s*(y2-y0), 'r') 
hold off