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,需要創建一個實例,並設置定位精度、移動間距等基本屬性,另外監聽狀態變化、結果變化等事件。如下代碼所示:
[csharp]
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方法,如下:
[csharp]
_watcher.Start();
2.3 定位狀態
監聽定位狀態變化事件,如果出錯可提示用戶,如下:
[csharp]
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 定位結果
對定位結果的處理,需要在定位位置變化事件中進行,如下所示:
[csharp]
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方法即可,如下:
[csharp]
if (_watcher != null)
{
_watcher.Stop();
txtStatus.Text = "";
_gpsLayer.Graphics.Clear();
}
3 導出GPX文件
在上文定位結果處理中,已經將每次位置記錄存儲為GpsInfo對象,便於進行統一的導出處理。
3.1 GpsInfo
GpsInfo對象只是簡單的屬性字段集合,用於記錄GPS設備獲取的數據信息。其屬性如下:
[csharp]
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文件的功能,代碼如下:
[csharp]
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文件名,然後調用相關的方法,例如變量定義:
[csharp]
private GpxWriter _gpxWriter = null;
初始化:
[csharp]
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文件:
[csharp]
_gpxWriter.WriteToGpx();