1 概述
通過ArcGIS Runtime for WindowsPhone SDK開發手機地圖應用,能夠定位所在位置,並將多個定位位置資訊匯出為GPX檔案,供其他軟體,如ArcMap、Google Earth等調用。本文將介紹如何?地圖定位,以及匯出GPX檔案的功能。
2 GeoCoordinateWatcher
Windows Phone SDK提供了GeoCoordinateWatcher類實現定位相關功能,需要引入System.Device.dll庫,添加System.Device.Location命名空間。
2.1 參數設定
使用GeoCoordinateWatcher,需要建立一個執行個體,並設定定位精度、移動間距等基本屬性,另外監聽狀態變化、結果變化等事件。如下代碼所示:
if (_watcher == null){ _watcher = new GeoCoordinateWatcher(GeoPositionAccuracy.High); // 使用高定位精度 _watcher.MovementThreshold = 50; // 最小移動間距,單位米,大於該間距的點才會觸發PositionChanged事件 _watcher.StatusChanged += new EventHandler<GeoPositionStatusChangedEventArgs>(watcher_StatusChanged); _watcher.PositionChanged += new EventHandler<GeoPositionChangedEventArgs<GeoCoordinate>>(watcher_PositionChanged);}
2.2 啟動定位
啟動定位功能,即調用GeoCoordinateWatcher的Start方法,如下:
_watcher.Start();
2.3 定位狀態
監聽定位狀態變化事件,如果出錯可提示使用者,如下:
void watcher_StatusChanged(object sender, GeoPositionStatusChangedEventArgs e){ switch (e.Status) { case GeoPositionStatus.Disabled: if (_watcher.Permission == GeoPositionPermission.Denied) { txtStatus.Text = "應用程式無權訪問定位服務"; } else { txtStatus.Text = "裝置不支援定位服務"; } break; case GeoPositionStatus.Initializing: break; case GeoPositionStatus.NoData: txtStatus.Text = "擷取定位元據失敗"; break; case GeoPositionStatus.Ready: txtStatus.Text = "GPS已經就緒"; break; }}
2.4 定位結果
對定位結果的處理,需要在定位位置變化事件中進行,如下所示:
void watcher_PositionChanged(object sender, GeoPositionChangedEventArgs<GeoCoordinate> e){ try { txtStatus.Text = ""; MapPoint point = new MapPoint(e.Position.Location.Longitude, e.Position.Location.Latitude); ESRI.ArcGIS.Client.Projection.WebMercator mercator = new ESRI.ArcGIS.Client.Projection.WebMercator(); MapPoint ptCurrent = mercator.FromGeographic(point) as MapPoint; //更新GPS錨點位置 _gLocation.Geometry = ptCurrent; //更新軌跡線 if (_gpsPoints == null) { _gpsPoints = new PointCollection(); _gpsPoints.Add(ptCurrent); } else { _gpsPoints.Add(ptCurrent); Polyline line = new Polyline(); line.Paths.Add(_gpsPoints); _gTrackLine.Geometry = line; } #region 記錄GPS定位資訊 GpsInfo gpsInfo = new GpsInfo(); gpsInfo.Altitude = e.Position.Location.Altitude; gpsInfo.Course = e.Position.Location.Course; gpsInfo.HorizontalAccuracy = e.Position.Location.HorizontalAccuracy; gpsInfo.Latitude = e.Position.Location.Latitude; gpsInfo.Longitude = e.Position.Location.Longitude; gpsInfo.Speed = e.Position.Location.Speed; gpsInfo.VerticalAccuracy = e.Position.Location.VerticalAccuracy; gpsInfo.Time = e.Position.Timestamp.DateTime; _gpxWriter.AddGpsInfo(gpsInfo); #endregion _gpsLayer.Refresh(); map.ZoomToResolution(2.38865713397468, ptCurrent);//定位到16級比例尺 } catch (Exception ex) { MessageBox.Show("顯示定位資訊錯誤"); }}
其中ESRI.ArcGIS.Client.Projection.WebMercator是用於將GPS獲得的WGS 84經緯度座標轉換為Web Mercator投影座標,這需要根據座標系的具體情況來選擇,如果地圖座標系本身就是WGS84,則無需轉換,如果地圖是Web Mercator,則需要進行轉換,如果地圖是其他座標系,如Xian1980,或CGCS2000等,則需要調用ArcGIS
Server的Geometry Service進行線上轉換。
2.5 停止定位
當需要停止定位的時候,直接調用Stop方法即可,如下:
if (_watcher != null){ _watcher.Stop(); txtStatus.Text = ""; _gpsLayer.Graphics.Clear();}
3 匯出GPX檔案
在上文定位結果處理中,已經將每次位置記錄儲存為GpsInfo對象,便於進行統一的匯出處理。
3.1 GpsInfo
GpsInfo對象只是簡單的屬性欄位集合,用於記錄GPS裝置擷取的資料資訊。其屬性如下:
public class GpsInfo { private double _longitude = 0; public double Longitude { get { return _longitude; } set { _longitude = value; } } private double _latitude = 0; public double Latitude { get { return _latitude; } set { _latitude = value; } } private double _altitude = 0; public double Altitude { get { return _altitude; } set { _altitude = value; } } private double _speed = 0; public double Speed { get { return _speed; } set { _speed = value; } } private double _course = 0; public double Course { get { return _course; } set { _course = value; } } private double _horizontalAccuracy = 0; public double HorizontalAccuracy { get { return _horizontalAccuracy; } set { _horizontalAccuracy = value; } } private double _verticalAccuracy = 0; public double VerticalAccuracy { get { return _verticalAccuracy; } set { _verticalAccuracy = value; } } private DateTime _time = new DateTime(); public DateTime Time { get { return _time; } set { _time = value; } } }
3.2 GpxWriter
GpxWriter則提供了將GpsInfo寫入GPX檔案的功能,代碼如下:
public class GpxWriter { private string _gpxFile = ""; private IList<GpsInfo> _lstGpsInfo = null; private XmlWriterSettings _settings = null; public GpxWriter(string gpxFile) { _settings = new XmlWriterSettings(); _settings.Indent = true; _settings.Encoding = new UTF8Encoding(false); _settings.NewLineChars = Environment.NewLine; _lstGpsInfo = new List<GpsInfo>(); _gpxFile = gpxFile; } public void AddGpsInfo(GpsInfo gpsInfo) { _lstGpsInfo.Add(gpsInfo); } public void WriteToGpx() { try { if (_lstGpsInfo == null || _lstGpsInfo.Count == 0) return; IsolatedStorageFile myIsolatedStorage = IsolatedStorageFile.GetUserStoreForApplication(); if (myIsolatedStorage.FileExists(_gpxFile) == true) { myIsolatedStorage.DeleteFile(_gpxFile); } using (IsolatedStorageFileStream stream = myIsolatedStorage.OpenFile(_gpxFile, FileMode.CreateNew)) { using (XmlWriter xmlWriter = XmlWriter.Create(stream, _settings)) { //寫xml檔案開始<?xml version="1.0" encoding="utf-8" ?> xmlWriter.WriteStartDocument(); //寫根節點 xmlWriter.WriteStartElement("gpx", "http://www.topografix.com/GPX/1/0"); //給節點添加屬性 xmlWriter.WriteAttributeString("xmlns", "xsi", null, "http://www.w3.org/2001/XMLSchema-instance"); xmlWriter.WriteAttributeString("xmlns", "mbx", null, "http://www.motionbased.net/mbx"); xmlWriter.WriteAttributeString("xsi", "schemaLocation", null, "http://www.topografix.com/GPX/1/0 http://www.topografix.com/GPX/1/0/gpx.xsd http://www.motionbased.net/mbx http://www.motionbased.net/site/schemas/mbx/0.0.1/mbx.xsd"); xmlWriter.WriteAttributeString("creator", "YELLOW EAST http://weibo.com/yelloweast"); xmlWriter.WriteAttributeString("version", "1.0"); //寫內容根節點 xmlWriter.WriteStartElement("trk"); //寫內容根節點 xmlWriter.WriteStartElement("trkseg"); //寫GPS資訊節點 foreach (GpsInfo gpsInfo in _lstGpsInfo) { xmlWriter.WriteStartElement("trkpt"); //給節點添加屬性 xmlWriter.WriteAttributeString("lat", gpsInfo.Latitude.ToString()); xmlWriter.WriteAttributeString("lon", gpsInfo.Longitude.ToString()); //添加子節點 xmlWriter.WriteElementString("ele", gpsInfo.Altitude.ToString()); xmlWriter.WriteElementString("time", gpsInfo.Time.ToShortDateString() + " " + gpsInfo.Time.ToLongTimeString()); xmlWriter.WriteElementString("course", gpsInfo.Course.ToString()); xmlWriter.WriteElementString("speed", gpsInfo.Speed.ToString()); xmlWriter.WriteEndElement();//trkpt } xmlWriter.WriteEndElement();//trkseg xmlWriter.WriteEndElement();//trk xmlWriter.WriteEndElement();//gpx xmlWriter.WriteEndDocument(); } } _lstGpsInfo.Clear();//清空記錄 } catch (Exception ex) { System.Windows.MessageBox.Show("寫GPX檔案錯誤:" + ex.Message); } } }
在調用的時候,只需要指定gpx檔案名稱,然後調用相關的方法,例如變數定義:
private GpxWriter _gpxWriter = null;
初始化:
DateTime now = DateTime.Now; string gpxName = String.Format("{0}-{1}-{2}_{3}-{4}-{5}.gpx", now.Year, now.Month, now.Day, now.Hour, now.Minute, now.Second); _gpxWriter = new GpxWriter(gpxName);
匯出GPX檔案:
_gpxWriter.WriteToGpx();