总结Excelhome论坛之揭开Excel平滑曲线的秘密(贝塞尔插值)

引用:资源地址:http://club.excelhome.net/dispbbs.asp?boardID=1&ID=135621&page=1&px=0

   Excel的平滑线散点图,可以根据两组分别代表X-Y坐标的散点数值产生曲线图    但是,却没有提供这个曲线图的公式,所以无法查找曲线上的点坐标    后来我在以下这个网页找到了详细的说明和示例程序 .............................................................................. http://www.xlrotor.com/Smooth_curve_bezier_example_file.zip ..............................................................................    根据其中采用的算法,进一步增添根据X坐标求Y坐标,或根据Y坐标求X坐标,更切合实际需求    这个自定义函数按照Excel的曲线算法 (三次贝塞尔分段插值), 计算平滑曲线上任意一点的点坐标

Excel的平滑曲线的大致算法是:    给出了两组X-Y数值以后,每一对X-Y坐标称为节点,然后在每两个节点之间画出三次贝塞尔曲线(下面简称曲线)    贝塞尔曲线的算法网上有很多资源,这里不介绍了,只作简单说明    每条曲线都由四个节点开始,计算出四个贝塞尔控制点,然后根据控制点画出唯一一条曲线    假设曲线的源数据是节点1 , 节点2, 节点3, 节点4(Dot1, Dot2, Dot3, Dot4)    那么贝塞尔控制点的计算如下                  程序作者: 海底眼(Mr. Dragon Pan)    Dot2是第一个控制点,也是曲点的起点,Dot3是第四个控制点也是曲线的终点

第二个控制点的位置是:        过第一个控制点(Dot2,起点),与Dot1, Dot3的连线平行,且与Dot2距离为 1/6 * 线段Dot1_Dot3的长度        假如是图形的第一段曲线,取节点1,1,2,3进行计算,即 Dot2 = Dot1        且第二个控制点与第一控制点距离取 1/3 * |Dot1_Dot3|,而不是1/6 * |Dot1_Dot3|        假如 1/2 * |Dot2_Dot3| < 1/6 * |Dot1_Dot3|        那么第二个控制点与第一控制点距离取  1/2 * |Dot2_Dot3|,而不是1/6 * |Dot1_Dot3|

第三个控制点的位置是:        过第四个控制点(Dot3,终点),与Dot2, Dot4的连线平行,且与Dot3距离为 1/6 * |Dot2_Dot4|        假如是图形的最后一段曲线,取节点Last-2,Last-1,Last,Last进行计算,即 Dot4 = Dot3        且第三个控制点与第四控制点距离取 1/3 * |Dot2_Dot4|,而不是1/6 * |Dot2_Dot4|        假如 1/2 * |Dot2_Dot3| < 1/6 * |Dot2_Dot4|        那么第二个控制点与第一控制点距离取  1/2 * |Dot2_Dot4|,而不是1/6 * |Dot2_Dot4| ...............................................................................................    这个自定义函数的计算流程是    Step1: 检查输入的X-Y数值是否有错误,如(输入不够三个点,X-Y的数量不一致,起始搜索节点超过范围等等)    Step2: 从参数指定的节点开始,计算出四个贝塞尔控制点,得到贝塞尔插值多项式方程,           然后代入已知的待求数值,看它能不能满足 f(t)=0 有解 (即曲线包含待查数值)    Step3: 如果 f(t)=0 有解,根据解出来的 t 值计算X-Y坐标,退出程序,否则继续检查下一段曲线    Step4: 如果所有分段曲线都不包含待查数值,退出程序 ...............................................................................................

函数:

Function BezierFit(known_x, known_y As Range, known_value, Optional StartKnot As Long = 1, Optional known_value_type As Variant = "x") As Variant Dim j As Long Dim x1Value, y1Value, x2Value, y2Value, x3Value, y3Value As Variant Dim ErrorMsg As Variant

ValueType = LCase(known_value_type)     '待查数值的类型转化为小写,并赋值到全局变量ValueType key_value = known_value                 '待查数值赋值到全局变量key_value

ErrorMsg = ErrorCheck(known_x, known_y, StartKnot)  '检查输入错误 If ErrorMsg <> NoError Then                         '有错误就返回错误信息,退出程序     BezierFit = Array(ErrorMsg, ErrorMsg, ErrorMsg, ErrorMsg, ErrorMsg, ErrorMsg)     Exit Function End If

For j = StartKnot To SizeX - 1              '从指定的节点开始,没有指定节点就从1开始     Call FindFourDots(known_x, known_y, j)  '找出输入X-Y点坐标里面,应该用于计算的四个结点     Call FindFourBezierPoints(Dot1, Dot2, Dot3, Dot4)   '根据四个结点计算四个贝塞尔控制点     Call FindABCD                           '根据待查数值的类型,和贝塞尔控制点,计算贝塞尔插值多项式的系数     Call Find_t                             '检查贝塞尔曲线是否包含待查数值     If Interpol_here = True Then Exit For Next j

If Interpol_here = True Then    '计算点坐标,并返回                                 '以下是由四个贝塞尔控制点决定的,贝塞尔曲线的参数方程     x1Value = (1 - t1) ^ 3 * BezierPt1.x + 3 * t1 * (1 - t1) ^ 2 * BezierPt2.x + 3 * t1 ^ 2 * (1 - t1) * BezierPt3.x + t1 ^ 3 * BezierPt4.x     y1Value = (1 - t1) ^ 3 * BezierPt1.y + 3 * t1 * (1 - t1) ^ 2 * BezierPt2.y + 3 * t1 ^ 2 * (1 - t1) * BezierPt3.y + t1 ^ 3 * BezierPt4.y     x2Value = (1 - t2) ^ 3 * BezierPt1.x + 3 * t2 * (1 - t2) ^ 2 * BezierPt2.x + 3 * t2 ^ 2 * (1 - t2) * BezierPt3.x + t2 ^ 3 * BezierPt4.x     y2Value = (1 - t2) ^ 3 * BezierPt1.y + 3 * t2 * (1 - t2) ^ 2 * BezierPt2.y + 3 * t2 ^ 2 * (1 - t2) * BezierPt3.y + t2 ^ 3 * BezierPt4.y     x3Value = (1 - t3) ^ 3 * BezierPt1.x + 3 * t3 * (1 - t3) ^ 2 * BezierPt2.x + 3 * t3 ^ 2 * (1 - t3) * BezierPt3.x + t3 ^ 3 * BezierPt4.x     y3Value = (1 - t3) ^ 3 * BezierPt1.y + 3 * t3 * (1 - t3) ^ 2 * BezierPt2.y + 3 * t3 ^ 2 * (1 - t3) * BezierPt3.y + t3 ^ 3 * BezierPt4.y     BezierFit = Array(x1Value, y1Value, x2Value, y2Value, x3Value, y3Value) Else     BezierFit = Array(Error10, Error10, Error10, Error10, Error10, Error10) End If

End Function

  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
让用户可以随时查找曲线上任意点的坐标(函数值) 附件的 .mht文件,是一个简单介绍贝塞尔三次插值的文档,可以用IE打开,更多贝塞尔插值算法,可以用搜索引擎找 附件的 .xls文件,打开以后,会看见三个工作表,分别演示了 找一个数值在曲线上的一组对应点 找一个数值在曲线上的所有对应点 和贝塞尔曲线是怎样在通过每两个节点的(每一对输入的X-Y数值代表平面坐标系的一个点,称为节点,Excel平滑曲线通过每一个节点) 要在其他Excel文档使用 BezireInt() 函数,需要按Alt+F11,双击模块一 复制所有文字 然后打开其他Excel文档按Alt+F11,插入---模块,然后粘贴所有文字 自定义函数的使用方法是: 在空白单元格输入 =BezierInt(X坐标的范围,Y坐标的范围,待查的数值) 函数就会返回一个包含六个元素的数组,分别是三个点的X,Y坐标 如: 你根据 a1:a4的数值作为X值,b2:b4的数值作为Y值,画了一个平滑线散点图 想查找c1的数值是不是在这条曲线上 就可以输入 =Index( BezierInt(a1:a4,b1:b4,c1) ,1,1) 得到曲线上第一个 X值=C1数值的点的X坐标 =Index( BezierInt(a1:a4,b1:b4,c1) ,1,2) 得到曲线上第一个 X值=C1数值的点的Y坐标 =Index( BezierInt(a1:a4,b1:b4,c1) ,1,3) 得到第2个 X值=C1数值的点的X坐标 =Index( BezierInt(a1:a4,b1:b4,c1) ,1,4) 得到第2个 X值=C1数值的点的Y坐标 =Index( BezierInt(a1:a4,b1:b4,c1) ,1,5) 得到第3个 X值=C1数值的点的X坐标 =Index( BezierInt(a1:a4,b1:b4,c1) ,1,6) 得到第3个 X值=C1数值的点的Y坐标 如果有多段曲线上的点包含C1的数值,那么可以增加输入参数,指定从哪个节点开始查找 =Index( BezierInt(a1:a4,b1:b4,c1,3),1,1) 得到从第三组X-Y数据开始查找, 返回第一个符合C1数值的点的X坐标 =Index( BezierInt(a1:a4,b1:b4,c1,3),1,2) 得到从第三组X-Y数据开始查找,返回第一个符合C1数值的点的Y坐标 函数默认输入数值是X值,要根据Y值找点的话,还可以增加输入参数, 指定输入的是Y值 =Index( BezierInt(a1:a4,b1:b4,c1,1,"Y"),1,1) 得到返回曲线上第一个 Y值=C1数值的点的X坐标如此类推......

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值