It would be awfully convenient if the code also returned the total arc length (for px,py pair). That way fractional arc length could be trivially converted to actual pixel units. This length will depend on interpolation method of course. And yes, it is often a one-liner to compute separately hence the comment about sheer convenience.
5
27 Aug 2014
distance2curve
Find the closest point on a (n-dimensional) curve to any given point or set of points
I suppose it would have been nice to add that as a capability, to pass in a spline itself to this code, but it accepts only a list of points. There are several different forms of splines, more than I wanted to worry about. So distance2curve just builds its own spline from scratch.
If you have a spline function of the form
y = f(x)
then it is simple. f(x) is merely a piecewise (often cubic) polynomial. So in each segment to find the closest point to the point (x0,y0), compute the polynomial
(x-x0)^2 + (f(x) - y0)^2
differentiate wrt x, and set to zero, using roots to solve. Then pick the real roots that lie in the interval in question, and choose the point on the curve with the smallest distance. Compare the distance found to the distance to the point at the endpoints of the interval. Then just loop over the intervals.
Other spline forms will be similar. For example, distance2curve builds a spline of the form (x(t),y(t)), where t is a cumulative linear arc length parameter. This allows the curve to be a completely general one that need not be a single valued function, and it works in any number of dimensions. The general idea is the same as above though.
Comment only
27 Aug 2014
distance2curve
Find the closest point on a (n-dimensional) curve to any given point or set of points
To completely resolve the question, perhaps we might look for a symbolic solution.
syms x
D = (x - 4)^2 + (sin(x) - 0)^2;
Differentiating, and setting to zero
dx = diff(D,x)
dx =
2*x + 2*cos(x)*sin(x) - 8
Which we might recognize reduces to:
2*x + sin(2*x) - 8 = 0
I don't see any obvious solution to the mixed trig equation, but it is easy enough to throw the symbolic toolbox at it.
solve('2*x + sin(2*x) - 8 = 0')
ans =
3.6019704355966679057142560063871
See that this agrees with the distance2curve prediction (3.6019704316906) out to about 9 significant digits.
Or, we could use fzero, or for the numerical gear heads like me, write this as a fixed point iteration.
fp = @(x) (8 - sin(2*x))/2;
x = [inf,1];
iter = 0;
while abs(diff(x)) > (10*eps)
iter = iter + 1;
x = [x(2),fp(x(2))];
end
x(2)
ans =
3.60197043559667
iter
iter =
65
Comment only