首先,谈谈这个编写任务介绍。此次是在win下开发,后续项目会在linux下结合hadoop或spark开发。这次要实现以下几点:
1. 能够将GPS数据在地图上呈现出来
2. 编写dbscan算法
3. 根据dbscan算法将GPS数据点分簇。并且在地图上用不同颜色标记各个簇。
4. 绘制地图围栏,也就是绘制每个簇形成的多边形
5. 给出一系列GPS数据,求出其经过密集区的顺序
在开发之前,我们需要明确用哪种地图,如果是用C#写,直接基于ArcGis Enginer二次开发倒是个不错的方法。不过,我决定用python来写,地图就用百度地图就行了。
本次开发涉及知识: 百度Map API调用 + PyQt4开发+ dbscan算法设计。所以这一篇,主要是讲讲百度地图API的相关使用和PyQt4的基本运用。百度地图我们选用js版本的API。我没学过js,所以就写写简单版本。 使用百度地图APi之前,需要去申请一个开发者ke。然后我们直接参考官网API来写。(点我)。。基本代码如下:
基于DBSCAN的热点区域分析
放大后:
接下来是第二个需要解决的问题,就是如何绘制地图围栏。这里我们通过查看api可以看到:
看完之后容易了吧,我们要绘制围栏的时候,只要调用这个api就好了。不过,真正写起来可没那么好。我采用的方法是 先用js写围栏函数,参数是points 如下:
var fencingAreas = new Array();
function getFencing(points) { // 参数是Array类型的 元素是Point
// 实现: 通过一些列的点 生成多边形覆盖物(聚合区)
// 把每次获取到的多边形 变量存放到fencingAreas变量当中
var polygon = new BMap.Polygon(points);
polygon.setStrokeColor("red");// 设置红色的边缘线
polygon.disableMassClear(); // 禁止调用removeOvlays方法移除
fencingAreas.push(polygon);
map.addOverlay(polygon);
}
def addFencing(self, points):
"""
@brief: 生成地图围栏 其实就是绘制一个多边形
:param points: 这个是list对象存放的数据 元素是DataObject类型的 表示点集合
:return: None
"""
js_order = "var tmp = new Array();var pointTmp =0;"
for p in points:
js_order += "pointTmp = new BMap.Point("+str(p.getLongitude())\
+","+str(p.getLatitude())+");tmp.push(pointTmp);"
js_order += "getFencing(tmp);"
self.__js(js_order)
self.isFencing = True
def __js(self, arg):#为减少重复代码量 封装成js私有函数
self.webView.page().mainFrame().evaluateJavaScript(arg)
参数points是list类型的,我定义了GPS数据类,用来存放地图数据。
效果图如下:
在上图中,我是测试一个人的数据,黄色点事噪音点。另外两个围栏属于不同的簇。 效果满意吧? 接下来是如何判断一个点在这个地图围栏里面。说实话,百度API真的有点坑,找起来真麻烦。这里我提供地址:http://api.map.baidu.com/library/GeoUtils/1.2/docs/symbols/BMapLib.GeoUtils.html
{Boolean} BMapLib.GeoUtils.isPointInPolygon(point, polygon)
判断点是否多边形内
参数:
{Point} point
点对象
{Polyline} polygon
多边形对象
返回值:
{Boolean} 点在多边形内返回true,否则返回false
function isInTheFencing(lng, lat){
var point = new BMap.Point(lng, lat);
for(var i=0;i
接下来谈谈PyQt4的几个重点。因为我之前学过Qt开发,在PyQt里面,函数名,通信思想是一样的。不过涉及到信号和槽时,我还是折腾了会。这里简单说说PyQt4里面如何自定义信号和槽。
1) 如何编写槽函数:
@QtCore.pyqtSignature("int")
def fun(self, index):
......
如上,定义槽函数时,先用装饰器来声明我这个是Qt的槽函数,并且它有个形参,参数是int类型的。。不要参数的话就留空“”。。顺带一提,那我要定义一个字符串类型的形参呢?? 这里需要留意下,是这样声明
@QtCore.pyqtSignature("QString")这个QString是Qt里面封装的字符串类。。
那么如何定义一个信号呢??
_signal_clearMarkers = QtCore.pyqtSignal(int) 这里,把信号弄成了一个变量。 注意,字符串参数填写str
最后一个问题:如何绑定信号和槽?
1)非自定义信号的绑定:
self.connect(self.action_file_save_pic, QtCore.SIGNAL('triggered()'), \ QtCore.SLOT('menuActionTriggered()'))
说明下,如果带参数,是填写类型而不是变量名。。。。
2)自定义信号的绑定:
self._signal_testOver.connect(self.slotTestOver)
好了,ui部分就写到这里。下一篇,说说dbscan算法的代码实现。