本来今天想写一篇关于Cut操作的文章,但是。。。
虽然cut这个东西感觉非常简单,不就是用一个切割者cutter(一条线),把被切割者cuttee(线或体)切成几段嘛。。。但是实际上真的至少有好几千行代码才能支持起这个功能。。。
为当年Esri的程序员默哀一分钟。。。
这么复杂一个东西我们也不能一口吃成个胖子,那就先谈谈它的一个前置:使用Cluster的的图形简化
话说Cluster不是什么丛?簇?团?聚类的意思吗?!!里面的意思是把这整个簇通过聚类的思想化简成一个点吧。
一、为什么要化简图形?
用过地图的同学都知道啊,一条河流在大分辨率时候是曲线,小一点是复杂曲线,更小就会出现岸线出现更复杂的地貌
这个功能就是矢量的简化,一是因为不需要那么细数据量太大,二是因为计算机也不能给你分的那么细。
如果太细的话,一个或者几个线段上的点就都被压缩到一个最小单元上面了,显示的时候难道要用一个像素表示里面有一堆属性吗(甲方爸爸:我要五彩斑斓的黑色)?矢量图形处理的时候难道不会把这个点当做自相交报错的吗?
所以为了保证图形的正确,我们在修改空间分辨率的时候要使小于分辨率的要素简化合并成一个,这里就是使用了Cluster实现了这个操作。
Cluster定义:Implementation for the vertex clustering.Used by the TopoGraph and Simplify.:用于图形简化的顶点聚类。
二、怎么实现这个功能?
通过上面的描述,我们能很清楚Cluster构造
输入:1.图形数据 shape; 2.空间分辨率(精度) tolerance。
功能:控制图形的顶点间的距离大于精度。
输出:控制之后的图形数据。
现在我们来由内及外来推理它的实现过程:
其核心功能函数肯定是:
CLUSTER-VERTEX(vertex1,vertex2,tolerance) //vertex:顶点;merge:合并;tolerance:精度
if distance(vertex1,vertex2) <= tolerance
vertexNew = MERGE(vertex1,vertex2)
return vertexNew
扩展一下:如果这个几个顶点权重不同呢:
MERGE(vertex1,vertex2,weight1,weight2) //vertex:顶点;weight:权重
vertexNew.x = (vertex1.x*weight1 + vertex2.x*weight2 )/ (weight1+weight2)
vertexNew.y = (vertex1.y*weight1 + vertex2.y*weight2 )/ (weight1+weight2)
weightNew = weight1+weight2
return vertexNew,weightNew
OK核心准备好了,现在开始准备外围:
首先顶点1和顶点2是怎么选取的呢?
A.所有点遍历一遍!n² 我开心!
B.建立空间索引找到相近的点!
毫无疑问选B,那怎么建立空间索引呢?
这里我们引入精度,做一个类似栅格化的操作(其实也就是将矢量更粗糙)
double dx = m_pt.x - m_origin.x;
int xi = (int) (dx * m_inv_cell_size + 0.5);
double dy = m_pt.y - m_origin.y;
int yi = (int) (dy * m_inv_cell_size + 0.5);
现在这里面的每个点从坐标xy,转换成了编码xi,yi 。
这样每一个格子的间距就都是大于精度了!精度控制完成!完美!
再将每一个点的xi,yi计算一个通过散列函数转换变成一串关键字存到列表去(就理解成HSAHMAP)
这时候我们的空间索引也做好了,怎么使用它呢?
现在每个点有三种情况:
A.一个格子里面有n个点肯定距离小于精度
B.一个格子跟紧贴着的几个格子之间可能距离小于精度
C.跨了一个以上格子的不可能距离小于精度
ok我们直接按顺序遍历点,把该点所在格子和邻接格子内的其他点都拿出来(这一步使用了空间索引!),放到备合并组(candidate)里面,开始CLUSTER!
起始点:第一个点FristPoint
过程: 遍历candidate找到与FristPoint距离最近的值(欧式距离计算) 【是的这里就是聚类算法了】
合并他们 CLUSTER-VERTEX(vertex1,vertex2,tolerance)
删掉旧值(点+hash),写入新值NewPoint
遍历candidate找到与NewPoint距离最近的值
......循环ing
如果candidate里面没有点了-停止;如果下一个最近的值距离大于精度了(CLUSTER-VERTEX失败)-停止;
......循环ing
循环:顺序遍历图形的下一个点
停止:图形遍历结束
最终我们就得到了大于精度的图形。
三、我们收获了什么?
1.控制精度的思路 - 引入精度建立空间索引的一种简单方法
2.简化时使用聚类方法的手段
3.操作图形要考虑的地方:
结构是:形状 - 形里面包含的线 - 线里面包含了点
干啥事千万别忘了精度
编好编号后,加一步:用散列表的手段保存和使用编号
注意权重
注意空值检查
嗯,如果我有写错的写的不好的地方欢迎指出,如果看了我的东西或者看了代码另有所悟欢迎交流~
代码在这里,有兴趣的自己扒一下啦~