乡镇/街道或商圈的边界坐标获取

时间:2024-05-20 10:49:06

全国按1KM*1KM划分得到的网格数达10598886个,并且所有网格都标注provincecityregion3层级行政区划标签。而成功标注township标签的网格数为9700957个,覆盖率为91.5%(如下图所示)。

乡镇/街道或商圈的边界坐标获取

  从数据库MongoDB提取部分网格后,我们通过通过简单的方格实现数据可视化(如图2所示)。这些网格被打上AB标签,你可以认为Aregion A,也可以认为是township A,这里只是示例。

乡镇/街道或商圈的边界坐标获取

为准确提取区域A的外围边界坐标,我们首先将属于区域A的方格单独提取出来:

乡镇/街道或商圈的边界坐标获取

我们将A实例化,以上海市金山区枫泾镇为例,提取方格的代码如下:

乡镇/街道或商圈的边界坐标获取

执行上述代码,我们可以得到每个方格的4个顶点的经纬度坐标:

乡镇/街道或商圈的边界坐标获取

显然,在技术手段上我们很容易得到区域A包含的所有方格的4顶点坐标。我们用绿色实心点标注处于边界处的顶点,用黑色实心点标注内部的顶点。可以看出,内部的顶点皆为4个方格共同拥有,而边界处的顶点1-3个方格共同拥有(3A)。利用这一几何规律,我们将区域所有方格的所有顶点放至一个list中,然后筛出出现次数小于4的顶点坐标,如图3B所示。

乡镇/街道或商圈的边界坐标获取

然而,仅仅提供边界各顶点坐标信息是不够的,利用这些顶点,我们使用线段连接形成的region结果并不唯一,如下图4所示,该连接方法得到的region A’与实际region A并不相同。

乡镇/街道或商圈的边界坐标获取

因此,我们有必要在添加一个序列维度,用于记录每个顶点坐标的次序(图5A),系统绘制区域边界时,只要按顺序连接各顶点坐标即可显示正确的region边界(图5B)。

乡镇/街道或商圈的边界坐标获取

在此,我们统一使用左下角的顶点作为起始顶点(标记为1),按逆时针方向进行逐个添加序号标签。

技术实现原理:对各方格的左下角顶点坐标(lng1,lng2)进行升序排序,第一条数据即为左下角方格的数据。

乡镇/街道或商圈的边界坐标获取

中起始方格为4750-1412的左下方顶点,为顺利让程序cursor进行绕外圈“滑动”,算法逻辑必须遵循以下规则:

1.每个边界方格至少有两个顶点为边界顶点;

2.各方格严格按照顺时针次序进行取数

3.Cursor到达方格的非首次触及顶点时,需对该顶点的在region出现的次数(简称为polyFreq)进行判定:

    if polyFreq > 1: cursor将切换方格;

    if polyFreq == 1: cursor将按顺时针滑动至该方格的下一个顶点。

4.    Cursor切换方格时,如遇到两个方格时,去除首次触及顶点的索引*比切换前方格索引小1的方格;

5.cursor滑动至起始顶点时,运算结束。

    *注解:顶点索引为1-44个自然数,分别代表左下角,左上角,右上角和右下角位置

比如对某X region由简单的两个方格组成(如下图6),则取数的cursor从左下角方格X1的顶点1开始,取完后按箭头方向滑动至方格X1的顶点2,由于顶点2polyFreq>1cursor将跳跃至方格X2的顶点2中(方格X3的顶点2的索引为1,而前方格X1顶点2的索引为2,因此cursor不会跳跃至方格X3),并滑动至方格X2的顶点3,并进行取数,由于顶点3polyFreq=1cursor将继续滑动至顶点4取数,以此类推,cursor最终将滑动至起始顶点1,程序终止。

乡镇/街道或商圈的边界坐标获取

针对更复杂的region A,我们在启动cursor前需去除region内部的方格,留下cursor会触及的格子。

数学实现原理:

1.计算各方格4顶点的ployFreq总数ployFreqSum

2.去除ployFreqSum>=15的格子

乡镇/街道或商圈的边界坐标获取

以金山区枫泾,程序启动后,cursor滑动72次即回到起始顶点.我们将cursor获取的顶点坐标依次存储在list,并最终转化为dataframe(如图8A).然后用matplotlib按顺序连接各顶点,最终得到图8B示的边界轮廓,与实际枫泾镇网格边界完全一致(8C).

乡镇/街道或商圈的边界坐标获取

然而,有些region的边界可能存在多个闭环(或者称多个多边形),如图9A的朱家角镇。而之前的算法只能描绘出最左侧的多边形(polygon2)。因此,我们在程序中新增判定顶点使用情况的代码,最终可输出npolygon的边界数据(可视化结果如图9B所示)。

乡镇/街道或商圈的边界坐标获取

最终,边界数据以如下格式暂存至mongodb数据库Claudius的集合townBoundary,后续可根据需要进一步转换数据结构。

乡镇/街道或商圈的边界坐标获取

目前使用的是OCM1.6的网格进行描边,由于网格规格为1KM*1KM,颗粒度较粗,如碰到乡镇/街道比较小,描绘得到的边界与实际边界差距可能会比较大。如金山区的石化街道:

乡镇/街道或商圈的边界坐标获取

对于核心城区的街道,部分街道的面积甚至小于1平方公里, 1KM*1KM网格描绘的边界自然更不精准。未来使用正在开发的250M*250M的网格可一定程度上提高描边的准确度。