Find tangent points on a curve from a user-given p

2019-07-22 00:36发布

I am trying to find the tangent lines from a given point outside a closed curve (not on the curve). The curve is defined as 2D x and y coordinates of points,shaped like an irregular ellipse for example.

If given a point by the user: (x0,y0) = (-30,80), how can I know the tangent points (obviously closest point among discrete points from the smooth curve) on curve (i.e. tangent lines from (x0,y0) to curve)?

1条回答
我想做一个坏孩纸
2楼-- · 2019-07-22 01:30

One possibility is to use numerical differentiation to find the tangent line at every point, and decide whether it passes "close enough" to the given point. However, one has to think hard about "close enough" to avoid getting either no matches or too many.

Here is another approach: consider the unit vectors pointing from the given point (x0,y0) to the points on the curve. Find the largest gap between them (the command convhull helps here). The vectors on both sides of the gap determine tangent lines.

In general this will find only two tangent lines, not all of them. But if the curve is convex, there are only two tangent lines anyway.

Here is an example of the tricky situations where the given point is within the convex hull of the curve.

tricky

The code that produced the above picture:

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

Another approach, which works fine if (x0,y0) is not within the convex hull of the curve.

Use convhull to find the convex hull of the union of the curve and of the given points (x0,y0). The two edges of the convex hull that are incident to (x0,y0) are tangent to the curve:

convex hull

The code that produced the above picture:

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
查看更多
登录 后发表回答