在前一篇谈到多边形拟合后我试着探索了一下多边形拟合的实现,从三角形开始,发现可以分成很多基本问题,比如如何判断一个点在三角形内。
于是自己出了一个练习自己做。点在三角形内可以分成两种情况:一种是在绝对的内部,一种是在某条边上。第二种情况很有趣,因为计算机图形包括一条线都是有宽度的,不能截然分成在边上和不在边上。
判断点在三角形内(边上也适用)的方法是该点与三顶点形成的三个角总和为360度。别的方法也查了,但考虑到简便这次暂且用这个方法。
##由于不擅长画图,文字描述麻烦大家闹补了~~非常抱歉
第二天有了一个脑洞:用像素记录图片的方法导致熵非常大,内部很无序,比如一些不关键的点向左右上下偏移一点都没有问题。能不能有有序的数据结构比如二叉树表示多边形,尤其是三角形?为什么想到二叉树呢,因为三角形的主要特点是有三组以顶点为中心的角「要不也不叫三角形了」,在不考虑第三条边的情况下这个角相当于从一点发出的两条射线,从角的平分线上做垂线你会发现垂线的长度从顶点开始逐渐增大「角度没变但角形成的空间越来越大」,而在保证视觉连续「没有锯齿」的情况下这个宽度线肯定会渐进增长「或逐渐减少——钝角的局部」,这样就适合二叉树——子节点与父节点数量可以在0到2倍间任意匹配。
用二叉树可以做到什么呢?首先可以把三角形内所有点「横纵坐标」放到搜索树里,这样判断一个点在其内与否就直接搜索即可,在图形限于长宽从几百到几千像素(屏幕显示范围)情况下二分搜索很快。其次从三角形的矩形化(最大长宽、最大高低)范围内可以生成一个从一点到另外两点的连续变化,树每一层就是一个像素的变化,最外两点永远是父层最外层两个节点的子节点,然后里面就根据临近原则分配父子节点关系「因为每一层变化都是个位数甚至1、2,每层只需调整少数」。
这样的话三个顶点正好作为二叉树生成或结束的关键点,储存一个三角形只需要储存三个点。唯一不便是二叉树横向搜索的效率很低,水平平行地分割图形不方便,这个初步想法是用二维数组辅助解决。
放下这个脑洞继续写完了判断三角形内点的练习,考虑以像素为基础,所有点的横纵坐标都是整数。
发现了一个问题,就是一开始提到的第二种情况:判断两个向量共线的方法是x1y2-x2y1=0,而多数情况下眼睛看起来共线的时候这个值都不等于0,于是我试探着调整x1y2-x2y1的绝对值的容许范围,发现比较合理的值竟然是200!
于是这个问题被换成:如何或以何种标准近似地判断点在线上?
参考一个Java图形库的做法[1],是先对向量进行标准化(normalisation)变成单位长度的,然后判断x1y2-x2y1在不在Accuracy精度值范围内。[1]的作者把精度定位1e-12,我在屏幕上尝试的结果是:肉眼可辨的范围是1e-3和1e-4之间。见[2]。
引入精度的作法实际上否定了精确表示所有点的想法,因为一个点是否在图形上由人们任意决定,标准可以是屏幕显示效果(如果看起来在那条线上就认为是)也可以是别的。然而用二叉树等有序结构来表示(某个精度基础上的)所有点仍然值得探索,精度影响的范围局限在图形边界上,一两个最多不超过5个像素而已,这恰好是树型结构擅长的,子节点层的两侧微调即可。
搜索之后暂时还没发现有同样做法的尝试,可行性未知。
ps 写完后意识到这个可以类比成源代码和编译的过程,矢量图基于XML[4]是对图形关键信息的描述,而显示出来则要经过渲染。储存三角形的三个点足以还原三角形,于是我设想能否这样:分别储存三个点和所有点的信息,如果储存空间允许但运算能力有限(没时间渲染)就都储存,反之只储存三个点在显示/处理时候通过已知算法还原其中的所有点?
[1] 1
[2] 2
[3]源码
[4] https://www.w3schools.com/graphics/svg_intro.asp