Python求解定点到曲线最短距离时获取曲线上最近点的方法
问题解答
fmin_cobyla本身就会返回最优解对应的优化变量值,你当前代码中定义的优化变量X就是曲线上点的横纵坐标[x,y],约束条件c1强制要求点落在拟合曲线上,所以优化返回的X就是你要的最近点坐标,直接读取X[0]、X[1]就可以拿到横纵坐标,不需要额外配置参数。
你现在的代码只用到了objective(X)计算距离,没有打印/调用X本身的数值,所以没发现这个返回值。
代码优化建议
- 补全缺失的依赖导入:原代码没有导入
numpy,直接运行会报错,需要在开头加import numpy as np。 - 简化目标函数:最小化欧氏距离和最小化欧氏距离的平方完全等价,去掉开平方操作可以减少计算量、降低浮点误差,修改后的目标函数如下,最后输出实际距离时再做开方即可:
def objective(X): x, y = X return (x - P[0])**2 + (y - P[1])**2
- 降维优化提升稳定性:你当前是2维带约束优化,实际上因为曲线上的点满足
y = f(x),完全可以把优化变量从2个降到1个(只优化x坐标,y由曲线函数直接算出),改成无约束优化,收敛速度和稳定性都会更好:
from scipy.optimize import minimize_scalar # 定义仅关于x的距离平方函数 def dist_sq(x): y = f(x) return (x - P[0])**2 + (y - P[1])**2 # 在x的取值范围内做有界1维优化 opt_res = minimize_scalar(dist_sq, bounds=(x.min(), x.max()), method="bounded") best_x = opt_res.x best_y = f(best_x) min_dist = np.sqrt(opt_res.fun)
- 绘图优化:你绘制的距离圆如果要视觉上为正圆形,需要给坐标轴设置等比例,否则会显示为椭圆,添加一行代码即可:
ax.axis("equal")
其他求解方案
如果不想用优化方法,也可以选下面两种更简单的实现:
- 离散采样法:直接用你已经生成的曲线采样点数组,批量计算所有点到P的距离,取最小值对应的点即可,实现零门槛、不会出现优化不收敛的问题,精度由x的采样密度决定:
y_curve = logifunc(x, *popt) all_dist = np.sqrt((x - P[0])**2 + (y_curve - P[1])**2) min_idx = np.argmin(all_dist) best_x = x[min_idx] best_y = y_curve[min_idx] min_dist = all_dist[min_idx]
如果需要更高精度,可以在粗找到的最优点附近细分x的步长,二次搜索即可。
- 解析求根法:根据几何性质,点到曲线的最短距离对应的点,满足「P到该点的连线与曲线在该点的切线垂直」的条件,可以对这个条件列方程,用
scipy.optimize.root_scalar求根得到精确解,但缺点是需要手动推导曲线的导函数,换曲线就要重新推导,通用性差。

内容的提问来源于stack exchange,提问作者Aaron
相关产品推荐
相关产品推荐

