本人目前正在连载微积分系列教程
《让微积分穿梭于工作与学习之间》系列总目录_iloveas2014的专栏-CSDN博客
然后我打算开始讲一下自己目前打交道最多的一种曲线——圆弧直线,但这种线它似乎远不如贝塞尔曲线来得出名。这种线到底指的是啥,其设计初衷是什么,有何优缺点,都应用在什么地方,感觉看到我文章的朋友大概还一脸懵逼。所以我感觉我有必要先给大家介绍一下相关的一些知识。
为了给大家一个更直观的认识,我在我的项目里简单地录了个屏来演示一下自己目前的工作内容。
说白了这里面的功能无非是图形编辑的常用操作,诸如绘图,点线面的变换等。其中用到的算法基本上跟计算几何有关,包括但不限于曲线求交,封闭图形搜索,布尔运算等等的数学知识。
然后本文的重点是介绍直线和曲线的基本构成。首先来讲讲直线。
在图形软件中,可编辑的直线一般都不会无限延伸,也就是说它会是一条线段,加上两点确定一条直线,所以一条线段用两个端点来存储即可满足要求。然后哪怕用到了直线,也会用两个端点来描述,相比起用其它的方式(诸如斜率方程),两点式显得更加统一。
所以直线(线段)的基本构成,已经有一个全世界都没什么争议的标准了,哪怕是我的技术上级,理解起来都非常容易。
但曲线就不一样了,不同种类的曲线,表达的方式千差万别。即使是同样的曲线,也有不同的方法来描述。但软件要针对其自身特点选出最适合它自己的存储方式。
下面我们列出几种常用曲线的描述方式。
圆弧:圆心,半径,起点角度,终点角度
贝塞尔曲线:起点,控制点,终点
样条曲线:起点,控制点,拟合点,终点
椭圆弧:圆心,半径,起点角度,终点角度,长轴向量
我们发现,它们的存储方式确实有比较大的差异,然后我们不妨看一下在诸如Photoshop或者Flash这样的软件里面,它们都是如何被用户操作的。
下图是用钢笔工具绘制出来的贝塞尔曲线,可见它的UI操作方式跟数学的描述基本一致,都是通过编辑端点和控制点进行变形。
然后画一个圆,我们再尝试去编辑它,却发现它的操作方式跟贝塞尔曲线没有太大区别,并且一个圆被拆成了4段。
画椭圆得到的结果也是一样。
也就是说,类似于贝塞尔曲线这样的编辑方式更能得到图形软件的青睐,哪怕是圆弧和椭圆弧,在图形软件中也被转换为了贝塞尔曲线。
纵观上述几种常见曲线的存储方式,我们可以简单地分成两类。第一类是贝塞尔曲线和样条曲线,它们的特点是包含了起点和终点的信息,而第二类,圆弧和椭圆弧则不包含。如果把直线也算进来的话,那它将属于第一类存储方式。
显然图形软件优先选择了第一类。换而言之,它们非常注重起点和终点的信息,并且希望直接存储到文件的数据当中。再看一下我下面的一段录屏,在拖动点的过程中,所有用到这个点的图形都被跟着一起变化了。
因此,如果使用第二类方式进行存储的话,点就无法被共用(就算不看引用只看值,也会因为浮点误差等问题而无法让多段线条之间的共点达成一致),这对于图形编辑来说将非常不友好。
除此以外,一根线也可以被最多两个图形共用,所以在这类软件中,线也会以引用的方式存储到数据中。
至于面,虽然不需要共用,但是其中的线也需要共用。
所以这类软件的数据结构中,除了点是直接以数值的方式存储以外,线的端点和面的线条都以索引的形式表示。
以下图的图形为例。
先存好点的数组,(0,0),(100,0),(200,0),(200,100),(100,100),(0,100)。
然后线包括AB,BC,CD,DE,EF,FA,BE。这里我们并不会把值代入到线段的数据中,而以索引代之,从而确保共点是一个引用:AB=[0,1],BC=[1,2],CD=[2,3],DE=[3,4],EF=[4,5],FA=[5,0],BE=[1,4]。
然后面有ABEF和BCDE,它会取线的索引进行存储。
ABEF=[0,5,3,4],BCDE=[1,2,3,5]。
这样点线面就融为一体,浑然天成了。
然而我上级非常反对这种存储的方式。因为在他眼里,线不是一个必要的存在,如果软件上要显示或者操作,那它应该是独立于数据而属于显示层。至于点他更是觉得不用这么管,还搞索引不是给自己添麻烦么。
实际上在我上级眼里,需要存储的只是面,并且各自存放属于自己的点数据就完事了。
ABEF=(0,0),(100,0),(100,100),(0,100),BCDE=(100,0),(200,0),(200,100),(100,100),多么简洁明了。又不用担心两个面之间有什么冲突。然后吧,这个事情拿去问别的同事,80%都赞同我上级的观点,而我可是百口莫辩啊。直到我说那做弧线了怎么办,他就冷冷地丢了句“哦你要做弧线那没得说了”。实际上我这个存储方式它的意义远不止弧线,我也很清楚他还是不明白的,只是只有弧线这个词才能止住他的反驳。为此全场陷入了非常尴尬的境地。
我也不争了,就自己安安静静地把这功能给做出来,然而我上级不但不肯定我的成果,而且还批评我写的东西很多bug(事实上那些bug50%以上是我的功能把他们的老漏洞给挖了出来,30%是我的做法跟他们旧的东西冲突了,15%是对他们老的东西不理解给改坏的,只有5%左右是我本身算法的问题)。
然后我也不多说了,上面只看结果,我的绩效远没我上级好,所以,如果你们的数学水平跟我上级一样菜的话,那一定要投简历来三维家哦,因为你能取得很好的绩效。然后如果你们数学水平了得,那就更要来三维家了,不然真的没谁可以拯救我。
言归正传,我们的软件会直接跟生产对接,而目前很多的生产工具都未支持贝塞尔曲线的制作,大多只支持直线和圆弧。这样的话,我们就希望有一套这样的方案,它既能描述一段圆弧,又包含了起点和终点的信息。
我们知道不在同一直线上的三点确定一个圆,然后如果拿其中的两个点作为端点,另一个则用来充当类似于控制点的功能,那么事情是不是就可以得到有效解决了呢?然后如果第三个点刚好在另外两点所确定的直线上,那它就又能描述直线了。前面提到的“圆弧直线”就是这样来的。
事实上,AutoCAD早就通过类似的方式存储直线和圆弧了,但由于我前面发牢骚,所以这篇有点长了,那我就放到下一篇去,敬请期待!