应用微积分平滑连接Flash中两条二次贝赛尔曲线

大学里有一门很重要的课程,叫高等数学。这门课是既让人喜又让人忧的课,我觉得还是忧占多数吧,书上讲的很抽象,而且很少提到这些东西在实际中的运用,所以很难提起大学的兴趣,最终会被大多数人归为‘天书’,我当年就觉得没兴趣。
但最近要实现的功能里必须用到微积分的知识,终于体会到了它带来的乐趣。。。
这次是要做一个网络拓扑的flash,包含拓扑图的编辑和展现功能,遇到一个难点是两台主机之间如多有个连接时,连接需要用孤线。在flash中孤线有二次贝赛尔曲线的绘图函数,只要提供三个点就OK了。但是,我的需求里,每个连接是要表示连接的两个方向流量信息,所以实际上,我们是要两段线组成一段线。直线就最简单,知道两个点取中点,分别画两条线就OK了,但要两根二次贝赛尔曲线组合成一根圆滑的曲线,就成了难点了。
现在就是,我们有一个起始点和一个结束点的数据,还有中点的数据是自己规定的,现在需要用两根二次贝赛尔曲线来组合成这一根曲线,以达到“把一条曲线分成两部分”的效果。下图就是最终实现后的效果。我这儿故意多连了几根线,但设了不同的带宽来表示同一条线的流量,所以颜色是不一样的。根据带宽和当前流量值设置各段线的颜色不是难点,呵呵。

最终实现的曲线连接效果,flash+PHP+XML组合,曲线为两段连接

我的设计就是这样的:节点就是一个Node对象,连线Link对象有维护两个文字节点和两个线段(由三个点维护),其它属性这儿不关心。上图其实就是2个node对象之间有4个 Link对象,每个Link对象有两个文字节点对象和各自的三个点数据。这三个点是已知数据,在节点移动后我们也能很简单地取到,而直线分成两段很简单,难点就是要用三个点来把要画的曲线分成两段。
现在要圆滑地连接两根曲线成另一根,我们已知的数据是起点终点和中间点,分成两段后,相当于我们知道了两条线段各自的起点和终点,需要算两个曲线的控制点,这样才能带入到flash的画二次贝塞尔曲线的函数(Graphics.curveTo)中去。


如上图,Pc是我们自己取的点,即是我们希望作为中点的点。这个点是Ps和Pe所在直线的中垂线上的点。我的设计是根据线条的个数取的:就是后面的连接Pc肯定取得比先连接的线Pc取得更远。
现在要求Pc-Ps,Pc-Pe两段二次贝塞尔曲线的控制点。他们各自的控制点一定要满足两条曲线在Pc点的斜率等于Ps和Pe连线的斜率,这样线条就一定能圆滑。
数学分析,先看二次贝塞尔曲线公式:(图片截自维基百科)

先对曲线公式进行微分:
dB/dt=2(t-1)P0+(2-4t)P1+2tP2
又知他们在Pc点(t=0)的斜率k(通过Ps,Pe两点求斜率很简单的,对吧?),代入t=0到上式,得到
k=-2P0+2P1
控制点
P1=k/2+P0
对于Ps-Pc曲线,控制点就是Ps-Pc点的斜率除以2加上Ps点坐标
另一条线同理。
知道了控制点了,代入Graphics.moveTo和Graphics.CurveTo就可以各自画曲线了,最后发现,两段生成的曲线能连接得很圆滑!
什么时候把我的这个网络拓扑flash 发上来吧,效果还是很不错的。
最终的心得就是让我觉得以前讨厌的东西真的是越来越有趣了。。。

Join the Conversation

8 Comments

Leave a Reply to Anonymous

Your email address will not be published. Required fields are marked *

  1. 上面说得挺清楚了吧.计算起来肯定还是有点麻烦的,三次贝塞尔曲线的表达式可以到百科上去查的.

  2. 我看了上面的留言,然后根据那个留言去计算,发现我算不出来。。。您能告诉我具体的算法么 ??

  3. 你可以设三次曲线控制点为p5,p6,求导三次曲线公式,t=0时的求导后公式值等于直线p5-p0的斜率,t=1时的值等于p6-p3的斜率。回代p1,p2到三次公式中,可以计算出p5,p6的计算公式。

  4. 你好,看了你做的二次贝塞尔曲线的例子,挺好的。我想问下,如果画一条三次贝塞尔曲线,有四个点,p0,p1,p2,p3,其中p0和p3是起点和终点,并且曲线经过p1,p2,那么那条曲线的控制点应该如何求呢,苦苦求了好多天,找网上的资料也没有说明白,对这个问题,你有什么方法吗?^^