两点生成曲线

本文介绍了一种在游戏场景中根据起点和终点生成曲线轨迹的方法。通过计算两点距离和圆心角,确定一个参考点,然后使用拉格朗日插值法生成曲线。在实现过程中,作者意识到最初的抛物线模型存在问题,并计划研究更适合的曲线模型,如贝塞尔曲线。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

引言:

看了标题的人可能会有这样的反应:两点不是能确定无限条曲线吗,这不是扯淡吗。。其实现在的需求是这样的:在一个游戏里,我们需要根据起点和落点生成一条看上去合理的曲线运动轨迹。在我的想象中,它至少应该是往近处抛弧度小,往远处抛弧度大的这样一个表现。于是我设计了如下曲线生成方案,给游戏客户端那边去用。


算法如下:

1.通过起点终点,算出两点距离。用这个距离根据配置换算出一个圆心角a
2.用起点,终点,圆心角a确定一个圆o,取o与通过中点((起点+终点)/2)的竖线的上方的交点,作为参考点
3.用起点,终点,参考点生成曲线(矩阵,拉格朗日插值,高斯消元都行)
4.算法示意图
算法示意图


算法解析:

首先两点是无法确定曲线的,这时候需要引入第三个点,这个第三个点的表现直接影响到曲线的轨迹表现,所以我在设计的时候将输入的起点终点放到一个圆上,然后第三个点在两点构成的弧上取,这样我可以通过控制圆的大小来间接控制曲线的弧度。
然后圆的大小怎么控制呢,两点距离固定了,我们可以控制两点和圆心连线构成的圆心角大小来控制。所以我设计的转换方式是:

max_distance = 100.0
angle = [30, 160]
def getAngle(distance):
    return (1 - distance / max_distance) * (angle[1] - angle[0]) + angle[0]

给定配置一个最远距离和圆心角范围,距离越远,圆心角越小,这样出来的参考点就离起点终点连线的线段越远。最终表现出来曲线更陡峭,而且这个程度也能通过最远距离和圆心角范围手动调参。
接下来,为什么我要取过中点的直线和圆的交点作为参考点呢。这是因为为了防止出现曲线往一定倾斜角度歪(事后想想是多余的,因为后面我用拉格朗日插值求抛物线方程,既然能求出来,那肯定不会出现歪的,毕竟这是函数的定义,一个x对应一个y)
接下来,我们有三个点了,我们就能选择拟合的函数模型了,我最初其实是选择了抛物线的,考虑问题都以抛物线来考虑。但是在写blog的时候才发现一些逻辑上的BUG,这个放后面总结。最简洁的姿势肯定是用矩阵求y=a*x^2+b*x+c里的abc,其次是用拉格朗日插值求(写起来相对复杂,运算量也相对大一点点,但是不需要矩阵运算支持,只需要基础的四则运算,移植性强),再者就是直接推出a,b,c关于三个点的式子。综合考虑下来,我选择的是拉格朗日插值法。

具体代码:

为了快速验证我的想法,我用py一边查API一边把我的想法实现了出来,代码如下:

# coding=utf-8#
import matplotlib as mpl
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
import matplotlib.pyplot as plt
from scipy.interpolate import lagrange

### MATLAB通过两点绘制曲线的方法 在MATLAB中,可以通过插值方法生成经过给定两点的平滑曲线。具体来说,可以使用`polyfit`函数拟合一条直线或者更高阶的多项式来表示这两点之间的关系[^1]。 以下是实现这一功能的具体代码: #### 方法一:使用 `polyfit` 和 `polyval` 对于两个已知点 `(x1, y1)` 和 `(x2, y2)`,可以通过以下方式生成并绘制它们之间的一条直线: ```matlab % 已知两点坐标 x = [x1, x2]; y = [y1, y2]; % 使用 polyfit 进行线性拟合 p = polyfit(x, y, 1); % 在更密集的范围内计算拟合值 xx = linspace(min(x), max(x), 100); yy = polyval(p, xx); % 绘制结果 figure; plot(xx, yy, 'r-', 'LineWidth', 2); % 绘制拟合后的曲线 hold on; scatter(x, y, 'b', 'filled'); % 标记原始数据点 xlabel('X'); ylabel('Y'); title('Curve Passing Through Two Points'); grid on; legend('Fitted Line', 'Data Points'); ``` 此代码会生成一条穿过这两个点的直线,并将其可视化显示出来[^1]。 --- #### 方法二:使用三次样条插值 (`spline`) 如果希望得到更加灵活和平滑的结果,则可以选择三次样条插值法。这种方法适用于需要更多灵活性的情况,尽管只有两个点时效果可能有限。 ```matlab % 已知两点坐标 x = [x1, x2]; y = [y1, y2]; % 插值范围 xx = linspace(min(x), max(x), 100); % 计算三次样条插值 yy = spline(x, y, xx); % 绘制结果 figure; plot(xx, yy, 'g--', 'LineWidth', 2); % 绘制插值后的曲线 hold on; scatter(x, y, 'k', 'filled'); % 标记原始数据点 xlabel('X'); ylabel('Y'); title('Spline Interpolation Between Two Points'); grid on; legend('Interpolated Spline', 'Data Points'); ``` 这段代码展示了如何利用三次样条插值创建一条更为复杂的曲线[^2]。 --- #### 方法三:自定义参数化曲线 当仅需简单连接两定点而不考虑其他约束条件时,还可以采用参数化的形式构建路径。例如下面的例子展示了一种基于圆弧轨迹的方式: ```matlab function drawArcThroughTwoPoints(x1, y1, x2, y2) r = sqrt((x2-x1)^2 + (y2-y1)^2)/2; % 半径 c_x = (x1+x2)/2; % 圆心横坐标 c_y = (y1+y2)/2; % 圆心纵坐标 theta_start = atan2(y1-c_y,x1-c_x); % 起始角度 theta_end = atan2(y2-c_y,x2-c_x); % 结束角度 t = linspace(theta_start,theta_end,100)'; xc = c_x+r*cos(t); yc = c_y+r*sin(t); figure(); plot(xc,yc,'b-','LineWidth',2); % 绘制圆弧 scatter([x1,x2],[y1,y2],'ro','filled'); % 高亮原有点位 axis equal; end ``` 调用该函数即可获得一段优雅过渡于指定端点间的圆周片段[^3]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值