如何较为方便的在GMap.Net中实现车辆运行轨迹(转载,储备知识点)
2017-11-28 15:50
267 查看
一、简单的思路
要实现车辆运行轨迹,我们可能需要一个定时触发的机制用来更新Marker的位置,除了位置移动,我们可能还需要动态改变车辆的方向,如下图:
![](http://images2017.cnblogs.com/blog/719757/201707/719757-20170726093701107-1614669652.png)
首先,位置移动是最简单的,关键是方向的动态改变如何实现,稍作观察即可看出,汽车的方向总是和路线的切点平行,看来我们得写个方法用来求路线上任意点的切线了。可能对于有些大神来说这也并不棘手,无非是花点时间写个算法而已,但我觉得仅凭我自己的本事可能做不到,所以我打算借助现有的代码库来实现上述的功能。在wpf中,路径动画是很常用的,而它正好和这里的需求相符合,我们是不是能利用它来实现上述的功能呢?
二、路径动画demo
博客园有很多关于wpf路径动画的随笔,如果你还未曾了解过,可以看这里的一篇:http://www.cnblogs.com/zhouyinhui/archive/2007/07/31/837893.html,里面很详细的介绍了路径动画的使用方法,并且附带了demo可供下载,我建议先看完这篇随笔后再往下阅读。为了方便的在动画执行过程中获得运动对象的位置坐标和旋转角度,我选择了这篇随笔中介绍的DoubleAnimationUsingPath的方法,我们需要在此基础上订阅任意一个Transform实例的Changed事件,以便车辆在改变位置时能通知我们:
上面的代码中,我给TranslateTransfor的实例订阅了事件,现在,小车的位置就是new Point(translate.X, translate.Y),小车的旋转角度就是rotate.Angle,好了,该要的东西我们都有了,下面就要在GMap中实现了。
三、自定义Marker
首先,你看到这篇随笔就代表你对GMap还是有一定了解的,那么自然也知道Marker是个啥,不知道的可以利用搜索引擎了解一下,或者参考这篇随笔:http://www.cnblogs.com/luxiaoxun/p/3475355.html,我在这里就不介绍了。在地图上的小车其实就是个我们自定义的Marker,我们姑且称为CarGMapMarker,在CarGMapMarker内部我们需要维护一个Canvas子类(因为继承了Canvas),这个Canvas是Path的容器,然后我们还需要一个Border来当作运动的物体,其实这些过程都是为了模拟http://www.cnblogs.com/zhouyinhui/archive/2007/07/31/837893.html中创建的情形,接着我们还需要一个事件public
event EventHandler<Tuple<double, Point>> PositionChanged,用来通知我们自定义的Marker:喂!我内部维护的那个Border位置和角度改变了,他们分别是xxxxxxxx。而通知的代码就写在二中谈到的Changed事件触发方法中:
然后我们只要在自定义Marker中订阅这个Canvas子类的PositionChanged事件,并从e中获取一个元组,元组的Item1就是角度,Item2就是坐标,我们可以利用角度改变Marker图片的方向,利用坐标改变MarkerPosition的值。
不过在此之前我们Canvas子类中的Path还没有给它的Data属性赋值,生成这个Data其实很简单,就是把小车需要经过的关键点用线连起来就可以了,直接上方法:
这里要注意的是需要把list的第一个坐标赋值给PathFigure的StartPoint属性,剩余的坐标再一一相连接。最后,只要把这个geometry赋值给Canvas子类中Path的Data属性即可,你可以用方法赋值,也可以在Canvas子类中写个属性赋值,随你,我这里使用了后者。
四、图片处理
下面要说的是旋转小车的图片,Marker中的图片用的是Bitmap,旋转Bitmap的方法网上有很多,我们有时候可以奉行拿来主义,搜一个拿来用吧。要注意的是,小车的初始状态车头是要朝上的,因为朝上就是0度,和坐标系吻合。
除此之外还有一个坑需要注意,在GMap中Marker默认都是处于目标点上方的,而不是中心点,可以用以下的图片来理解:
![](http://images2017.cnblogs.com/blog/719757/201707/719757-20170726110806810-938104309.png)
如图,定位点最低点会在路线上,而不是定位点的中心在路线上,如果直接把定位点的图片替换成汽车会如何?会这样子:
![](http://images2017.cnblogs.com/blog/719757/201707/719757-20170726111115091-1741785267.png)
你问为什么车没有旋转?好的,那么我就让她旋转一下,和该点的切线平行好了,Bitmap旋转是围绕中心点旋转的,那么旋转后效果就是这样子的:
![](http://images2017.cnblogs.com/blog/719757/201707/719757-20170726111412998-1017971513.png)
虽然和切线平行了,但是小车完全脱离了路线,怎么办?往下移呗!移多少?高度的一半!光是这样还不够,我们还需要保证小车图片的高度和宽度都要相等,即要是个正方形才可以,至于为什么,博友们可以自己想想。
最后的效果如下:
![](http://images2017.cnblogs.com/blog/719757/201707/719757-20170726113145748-932294858.gif)
最后的最后,细心的博友可能发现了,小车在开始的位置是偏离的,这就涉及到了GMap内部的bitmap绘制机制,经过测试发现,需要使用以下的代码来稍作修正:
要实现车辆运行轨迹,我们可能需要一个定时触发的机制用来更新Marker的位置,除了位置移动,我们可能还需要动态改变车辆的方向,如下图:
![](http://images2017.cnblogs.com/blog/719757/201707/719757-20170726093701107-1614669652.png)
首先,位置移动是最简单的,关键是方向的动态改变如何实现,稍作观察即可看出,汽车的方向总是和路线的切点平行,看来我们得写个方法用来求路线上任意点的切线了。可能对于有些大神来说这也并不棘手,无非是花点时间写个算法而已,但我觉得仅凭我自己的本事可能做不到,所以我打算借助现有的代码库来实现上述的功能。在wpf中,路径动画是很常用的,而它正好和这里的需求相符合,我们是不是能利用它来实现上述的功能呢?
二、路径动画demo
博客园有很多关于wpf路径动画的随笔,如果你还未曾了解过,可以看这里的一篇:http://www.cnblogs.com/zhouyinhui/archive/2007/07/31/837893.html,里面很详细的介绍了路径动画的使用方法,并且附带了demo可供下载,我建议先看完这篇随笔后再往下阅读。为了方便的在动画执行过程中获得运动对象的位置坐标和旋转角度,我选择了这篇随笔中介绍的DoubleAnimationUsingPath的方法,我们需要在此基础上订阅任意一个Transform实例的Changed事件,以便车辆在改变位置时能通知我们:
var translate = new TranslateTransform(); var rotate = new RotateTransform(); var group = new TransformGroup(); translate.Changed += (s, e) => { //在这里获取小车的位置坐标和旋转角度 };
上面的代码中,我给TranslateTransfor的实例订阅了事件,现在,小车的位置就是new Point(translate.X, translate.Y),小车的旋转角度就是rotate.Angle,好了,该要的东西我们都有了,下面就要在GMap中实现了。
三、自定义Marker
首先,你看到这篇随笔就代表你对GMap还是有一定了解的,那么自然也知道Marker是个啥,不知道的可以利用搜索引擎了解一下,或者参考这篇随笔:http://www.cnblogs.com/luxiaoxun/p/3475355.html,我在这里就不介绍了。在地图上的小车其实就是个我们自定义的Marker,我们姑且称为CarGMapMarker,在CarGMapMarker内部我们需要维护一个Canvas子类(因为继承了Canvas),这个Canvas是Path的容器,然后我们还需要一个Border来当作运动的物体,其实这些过程都是为了模拟http://www.cnblogs.com/zhouyinhui/archive/2007/07/31/837893.html中创建的情形,接着我们还需要一个事件public
event EventHandler<Tuple<double, Point>> PositionChanged,用来通知我们自定义的Marker:喂!我内部维护的那个Border位置和角度改变了,他们分别是xxxxxxxx。而通知的代码就写在二中谈到的Changed事件触发方法中:
var translate = new TranslateTransform(); var rotate = new RotateTransform(); var group = new TransformGroup(); translate.Changed += (s, e) => { OnPositionChanged(new Tuple<double, Point>(rotate.Angle, new Point(translate.X, translate.Y))); };
然后我们只要在自定义Marker中订阅这个Canvas子类的PositionChanged事件,并从e中获取一个元组,元组的Item1就是角度,Item2就是坐标,我们可以利用角度改变Marker图片的方向,利用坐标改变MarkerPosition的值。
不过在此之前我们Canvas子类中的Path还没有给它的Data属性赋值,生成这个Data其实很简单,就是把小车需要经过的关键点用线连起来就可以了,直接上方法:
public void SetPoints(List<Point> list) { var geometry = new PathGeometry(); var fi = new PathFigure {StartPoint = list.First() }; foreach (var item in list.Skip(1)) { fi.Segments.Add(new LineSegment(item, false)); } geometry.Figures.Add(fi); }
这里要注意的是需要把list的第一个坐标赋值给PathFigure的StartPoint属性,剩余的坐标再一一相连接。最后,只要把这个geometry赋值给Canvas子类中Path的Data属性即可,你可以用方法赋值,也可以在Canvas子类中写个属性赋值,随你,我这里使用了后者。
四、图片处理
下面要说的是旋转小车的图片,Marker中的图片用的是Bitmap,旋转Bitmap的方法网上有很多,我们有时候可以奉行拿来主义,搜一个拿来用吧。要注意的是,小车的初始状态车头是要朝上的,因为朝上就是0度,和坐标系吻合。
除此之外还有一个坑需要注意,在GMap中Marker默认都是处于目标点上方的,而不是中心点,可以用以下的图片来理解:
![](http://images2017.cnblogs.com/blog/719757/201707/719757-20170726110806810-938104309.png)
如图,定位点最低点会在路线上,而不是定位点的中心在路线上,如果直接把定位点的图片替换成汽车会如何?会这样子:
![](http://images2017.cnblogs.com/blog/719757/201707/719757-20170726111115091-1741785267.png)
你问为什么车没有旋转?好的,那么我就让她旋转一下,和该点的切线平行好了,Bitmap旋转是围绕中心点旋转的,那么旋转后效果就是这样子的:
![](http://images2017.cnblogs.com/blog/719757/201707/719757-20170726111412998-1017971513.png)
虽然和切线平行了,但是小车完全脱离了路线,怎么办?往下移呗!移多少?高度的一半!光是这样还不够,我们还需要保证小车图片的高度和宽度都要相等,即要是个正方形才可以,至于为什么,博友们可以自己想想。
最后的效果如下:
![](http://images2017.cnblogs.com/blog/719757/201707/719757-20170726113145748-932294858.gif)
最后的最后,细心的博友可能发现了,小车在开始的位置是偏离的,这就涉及到了GMap内部的bitmap绘制机制,经过测试发现,需要使用以下的代码来稍作修正:
public override void OnRender(Graphics g) { var bitmap = PictureHelper.RotateImage(_bitmap, _angle); var offsetX = LocalPosition.X-((LocalPosition.X - 30)+bitmap.Width/2); var offsetY = LocalPosition.Y - ((LocalPosition.Y - 60) + bitmap.Height / 2); g.DrawImageUnscaled(bitmap, LocalPosition.X + offsetX, LocalPosition.Y+offsetY); }
相关文章推荐
- 如何较为方便的在GMap.Net中实现车辆运行轨迹
- 如何在 ASP.NET 应用程序中实现模拟用户身份(在ASP.NET中以管理员身份运行网站)
- 【转载】ASP.NET中如何实现 TreeView绑定数据库
- 如何实现多个线程同步 (2013-11-10 12:07:24)转载▼ 标签: it 在编写一个类时,如果该类中的代码可能运行于多线程环境下,那么就要考虑同步的问题,Java实现线程同步的方法很多
- [转载]如何用SQLDMO在ASP.NET页面下实现数据库的备份与恢复
- 如何在ASP.NET大型应用系统的模块化开发实现多版本程序集并存支持[转载]
- [转载]如何用SQLDMO在ASP.NET页面下实现数据库的备份与恢复
- ASP.NET中如何实现FORM认证登录 (转载)
- ASP.NET 开发必备知识点(1):如何让Asp.net网站运行在自定义的Web服务器上
- 如何用SQLDMO在ASP.NET页面下实现数据库的备份与恢复(转载)
- 如何设置ASP.NET页面的运行超时时间 (转载)
- 《Asp.Net Forums2.0深入分析》之 Asp.Net Forums是如何实现代码分离和换
- 【转载】如何把一个lib库文件加入到VC.NET项目中去
- 《Asp.Net Forums2.0深入分析》之 Asp.Net Forums是如何实现代码分离和换
- .net如何实现页面间的参数传递
- 如何快速实现HTML编辑器.NET组件
- VB.NET多线程技术及其实现【转载】
- 在ASP.NET中如何用C#.NET实现基于表单的验证
- ASP.Net一些知识点(关于.net与JS如何交互)
- 如何快速实现HTML编辑器.NET组件