c# 基于GMap.NET实现电子围栏功能(WPF版)
前言
GMap.NET是一个强大、免费、跨平台、开源的.NET控件。分为WPF和winform版。GMap.NET的基本知识不做过多介绍,本文主要介绍如何使用该控件实现电子围栏功能。
电子围栏主要有两个功能模块:界面展示围栏区域,判断人员出入围栏的逻辑。GMap.NET的WPF版本功能并不强大,实现一些复杂的功能就只能发掘WPF的潜力了。GMap.NET给我们提供了一个基本的平台,必须熟练掌握WPF才能开发出复杂gis产品。
围栏区域界面显示
1认识GMapMarker
GMapControl是地图的主容器;地图就是多个图片拼接而来,这个图片组成GMapControl的底图。底图之上点缀用户自定义的控件。用户自定义控件必须通过GMapMarker间接添加进来,看下面代码:
GMapMarkermaker=newGMapMarker(ptLatLng); //UserControlFence用户自定控件 _ctrlCurrentFence=newUserControlFence(){Marker=maker,MapCtrl=MainMap}; _ctrlCurrentFence.FenceInfo=CreateFenceInfoModel(); maker.Shape=_ctrlCurrentFence; this.MainMap.Markers.Add(maker);
GMapMarker的定义也不复杂:
publicclassGMapMarker:INotifyPropertyChanged { publicobjectTag; publicGMapMarker(PointLatLngpos); publicUIElementShape{get;set;} publicPointLatLngPosition{get;set;} publicGMapControlMap{get;} publicPointOffset{get;set;} publicintLocalPositionX{get;} publicintLocalPositionY{get;} publicintZIndex{get;set;} publiceventPropertyChangedEventHandlerPropertyChanged; publicvirtualvoidClear(); protectedvoidOnPropertyChanged(stringname); protectedvoidOnPropertyChanged(PropertyChangedEventArgsname); }
一个GMapMarker关联一个gps坐标,同时可以显示一个控件(Shape );为什么在Shape外面包含一个marker?maker主要功能就是将控件钉到GMapControl的一个点。当地图移动时,maker会做相应的移动,maker移动会带动shape移动。所以,我们只管把shape内部处理好就行了,不用管地图移动。maker的作用不大,并不能帮我们实现复杂的功能;Shape才是我们施展拳脚的地方。
2用户控件实现画图
在控件中UserControlFence实现电子围栏的绘制,该控件会关联到maker的shape。UserControlFence控件以Grid(name为gridRoot)布局;WPF的Path可以实现任意图像的绘画,首先要将Path加入到Grid。我们的输入是多个gps点坐标,怎么能转换成Path上各个点坐标?这需要经过多次转换;
PointToCtrlPoint(PointLatLnggpsPoint) { //转换成GMap.NET控件坐标 GPointptOfMapCtrl=MapCtrl.FromLatLngToLocal(gpsPoint); //GMap.NET控件坐标要转换成控件相对于直接父面板的坐标 PointptToMapCtrl2=newPoint(ptOfMapCtrl.X,ptOfMapCtrl.Y); //转成屏幕坐标 PointptOfScreen=MapCtrl.PointToScreen(ptToMapCtrl2); //转换成相对于gridRoot的坐标 PointptOfParentPanel=gridRoot.PointFromScreen(ptOfScreen); returnptOfParentPanel; }
转换过程就是:相对于Map控件坐标-->屏幕坐标-->相对于Grid的坐标。因为Path是Grid的Child,最后的坐标也是相对于Grid的坐标。用该坐标绘制Path,就是电子围栏的区域;
Path的Data是Geometry,生成Geometry函数如下:
privatePathGeometryCreatPath() { if(_listPoints.Count<=1) { PathRouteLine.Data=null; returnnull; } ListlistPt=ListWndPoint; PathFigurepathFigure=newPathFigure(); pathFigure.StartPoint=listPt[0];//起始点 pathFigure.IsClosed=true; for(inti=1;i 这样就完成电子围栏的区域绘制。还有一点要注意:当地图缩放时,必须重新绘制。地图缩放比例不同,绘制区域大小也会改变(形状不会变)。只需要监视地图控件的事件 publiceventMapZoomChangedOnMapZoomChanged;就行。
出入电子围栏区域判断
该判断逻辑有多种实现方法,下面逐一介绍;
1利用WPF的辅助函数VisualTreeHelper.HitTest
通过判断gps点坐标是否在控件内来判断。gps坐标先要转成控件点坐标(转换函数见前文)。函数实现比较简单;
privateboolIsInFence(PointLatLnggpsPoint) { if(_listPoints.Count<=2) returnfalse; PointptWnd=ToCtrlPoint(gpsPoint); HitTestResultresult=VisualTreeHelper.HitTest(gridRoot,ptWnd); if(result==null||result.VisualHit==null) returnfalse; boolhit=result.VisualHit==PathRouteLineInner; returnhit; }2通过GraphicsPath、Region实现
这是System.Drawing下的一组类,属于微软早期的类库;该类的点坐标还是float型,精度不高。对于gps坐标我先做了放大处理,如果不做处理误差会很大。
privateboolIsInFence2(PointLatLnggpsPoint) { doublerate=100000;//由于float精度问题。对坐标放大处理,否则误差会很大。 System.Drawing.Drawing2D.GraphicsPathpointPath=newSystem.Drawing.Drawing2D.GraphicsPath(); System.Drawing.PointF[]points=_listPoints.Select(o=>newSystem.Drawing.PointF((float)(o.Lng*rate),(float)(o.Lat*rate))).ToArray(); pointPath.AddLines(points); pointPath.CloseFigure(); System.Drawing.Regionregion=newSystem.Drawing.Region(pointPath); System.Drawing.PointFptHit=newSystem.Drawing.PointF((float)(gpsPoint.Lng*rate),(float)(gpsPoint.Lat*rate)); boolvisible=region.IsVisible(ptHit); returnvisible; }3直接根据点坐标计算
理论上这种方式效率是最高的,并且不依赖界面控件。但是这种方法不是微软提供的,准确性还需要验证。下面的函数是从网上找的,我对此计算结果做了验证,与前两种计算方法的结果一致的。
privateboolIsInFence3(PointLatLnggpsPoint) { intcount=_listPoints.Count; if(count<3) { returnfalse; } boolresult=false; for(inti=0,j=count-1;i=gpsPoint.Lat||p2.Lat =gpsPoint.Lat) { if(p1.Lng+(gpsPoint.Lat-p1.Lat)/(p2.Lat-p1.Lat)*(p2.Lng-p1.Lng) 后记
电子围栏区域绘制方法与轨迹回放、测距等处理有类似之处;GMap.Net为我们做的工作并不多,关键是要掌握处理这一类问题的精髓,做到举一反三,许多问题就会迎刃而解。
以上就是c#基于GMap.NET实现电子围栏功能(WPF版)的详细内容,更多关于c#GMap.NET实现电子围栏的资料请关注毛票票其它相关文章!
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。