How can I get a fast estimate for the distance between a point and a bicubic spline surface in Python? Is there an existing solution that I could leverage in SciPy, NumPy, or some other package?
I've got surface defined by a bicubic interpolation as this:
import numpy as np
import scipy.interpolate
# Define regular grid surface
xmin,xmax,ymin,ymax = 25, 125, -50, 50
x = np.linspace(xmin,xmax, 201)
y = np.linspace(ymin,ymax, 201)
xx, yy = np.meshgrid(x, y)
z_ideal = ( xx**2 + yy**2 ) / 400
z_ideal += z_ideal + np.random.uniform(-0.5, 0.5, z_ideal.shape)
s_ideal = scipy.interpolate.interp2d(x, y, z_ideal, kind='cubic')
and I've got some measured points of that surface:
# Fake some measured points on the surface
z_measured = z_ideal + np.random.uniform(-0.1, 0.1, z_ideal.shape)
s_measured = scipy.interpolate.interp2d(x, y, z_measured, kind='cubic')
p_x = np.random.uniform(xmin,xmax,10000)
p_y = np.random.uniform(ymin,ymax,10000)
p_z = s_measured( p_x, p_y )
I want to find the closest point on the surface s_ideal
to each point in p
. A general case could have multiple solutions for wildly varying splines, so I'm limiting the problem to surfaces that are known to have only one solution in the vicinity of the point's projection along z.
This isn't a tiny number of measurement or surface definition points, so I'd like to optimize the speed even at the expense of accuracy to maybe 1E-5
.
The method that comes to mind is to use a gradient descent approach and do something like for each measurement point p
:
- Use
pt = [p_x, p_y, p_z]
as the initial test point, wherep_z = s_ideal(pt)
- Calculate the slope (tangent) vector
m = [ m_x, m_y ]
atpt
- Calculate the vector
r
frompt
top
:r = p - pt
- If the angle
theta
betweenr
andm
is within some threshold of 90 deg, thenpt
is the final point. - Otherwise, update
pt
as:
r_len = numpy.linalg.norm(r)
dx = r_len * m_x
dy = r_len * m_y
if theta > 90:
pt = [ p_x + dx, p_y + dy ]
else:
pt = [ p_x - dx, p_y - dy ]
I found this suggesting a method could produce fast results to a very high accuracy for the 1D case, but it's for a single dimension and might be too hard for me to convert to two.
p_z
is not the ideal solution, it is the projection of the point on the surface in Z. The closest pointPs
on the surface to a given pointP
will be the one whose surface normal vector passes throughP
. Each test point should result in a corresponding closest surface point, so clustering seems to not serve that purpose. – Jerrylee