1. 程式人生 > >如何較為方便的在GMap.Net中實現車輛運行軌跡

如何較為方便的在GMap.Net中實現車輛運行軌跡

中介 rotate str path 簡單的 clas 為什麽 handler sin

一、簡單的思路

  要實現車輛運行軌跡,我們可能需要一個定時觸發的機制用來更新Marker的位置,除了位置移動,我們可能還需要動態改變車輛的方向,如下圖:

技術分享

  首先,位置移動是最簡單的,關鍵是方向的動態改變如何實現,稍作觀察即可看出,汽車的方向總是和路線的切點平行,看來我們得寫個方法用來求路線上任意點的切線了。可能對於有些大神來說這也並不棘手,無非是花點時間寫個算法而已,但我覺得僅憑我自己的本事可能做不到,所以我打算借助現有的代碼庫來實現上述的功能。在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默認都是處於目標點上方的,而不是中心點,可以用以下的圖片來理解:

  技術分享

  如圖,定位點最低點會在路線上,而不是定位點的中心在路線上,如果直接把定位點的圖片替換成汽車會如何?會這樣子:

  技術分享

  你問為什麽車沒有旋轉?好的,那麽我就讓她旋轉一下,和該點的切線平行好了,Bitmap旋轉是圍繞中心點旋轉的,那麽旋轉後效果就是這樣子的:

  技術分享

  雖然和切線平行了,但是小車完全脫離了路線,怎麽辦?往下移唄!移多少?高度的一半!光是這樣還不夠,我們還需要保證小車圖片的高度和寬度都要相等,即要是個正方形才可以,至於為什麽,博友們可以自己想想。

  最後的效果如下:

  技術分享

如何較為方便的在GMap.Net中實現車輛運行軌跡