WM--GPS開發
前幾天,有朋友托我給他寫個GPS程序,就取經緯度坐標,以及將之轉換成高斯直角坐標。花了一些時間,給他做了個小程序。
后來總結時,想起,很多網上朋友都會問及關于GPS開發的一些事。我這里先將我的程序解釋下,然后再總結下,相關經驗及個人看法。
目前在一些移動設備中,都提供GPS功能,設備中都需要一個接收器,用來接收GPS信號。(類似于GPRS工作方式)。GPS一旦啟動后,會自動連接衛星,接收信號,通過算法計算出位置等信息,然后以NMEA data的格式輸出。GPS receiver就是接收衛星信號轉換成NMEA data的設備。
開發GPS有3種選擇:
1、直接使用串口連接GPS接收器
2、GPS Intermediate Driver
3、使用第三方類庫(目前opennetcf提供相應類庫)
目前,WM5.0以上系統,都內置了GPS Intermediate Driver。通過它,我們能夠很方便的取道GPS數據。
關于GPS方面的文章可以參考:
1、30 Days of .NET [Windows Mobile Applications] - Day 03: GPS Compass(GPS指南針)
2、.NET Compact Framework下的GPS NMEA data數據分析
雖然GPS Intermediate Driver提供了我們非常快捷的取得GPS信息,但同時也有一定的弊端。
那下面我講介紹我如何在該項目中使用GPS的。
我使用GPS Intermediate Driver,它能夠快速開發,MS也提供了很強大的例子來方便我們使用。
在微軟的WM SDK安裝目錄下有GPS工程。(Windows Mobile 6 SDK\Samples\PocketPC\CS\GPS)
該Demo中
GPS.cs:封裝了GPS的操作類,比如Open(),Close(),Connect()。可以很快捷的使用。
GpsDeviceState.cs:用于取得目前GPS設備的狀態信息。
GpsPosition.cs:每次GPS數據取得后,都會放入該類。
LocationChangedEventArgs.cs:一旦位置改變,即可將新的GPSPosition取得到。
{
if (!Opened)
{
// create handles for GPS events
newLocationHandle = CreateEvent(IntPtr.Zero, 0, 0, null);
deviceStateChangedHandle = CreateEvent(IntPtr.Zero, 0, 0, null);
stopHandle = CreateEvent(IntPtr.Zero, 0, 0, null);
gpsHandle = GPSOpenDevice(newLocationHandle, deviceStateChangedHan
dle, null, 0);
// if events were hooked up before the device was opened, we'll need
// to create the gps event thread.
if (locationChanged != null || deviceStateChanged != null)
{
CreateGpsEventThread();
}
}
}
通過調用CreateEvent,創建handles,然后調用GPSOpenDevice API,將handle傳入,取到gps設備的handle
得到handle后,再創建一個線程來監聽GPS數據及設備狀態。通過調用CreateGpsEventThread方法。
{
// we only want to create the thread if we don't have one created already
// and we have opened the gps device
if (gpsEventThread == null && gpsHandle != IntPtr.Zero)
{
// Create and start thread to listen for GPS events
gpsEventThread = new System.Threading.Thread(new System.Threading.
ThreadStart(WaitForGpsEvents));
gpsEventThread.Start();
}
}
在WaitForGpsEvents方法中,就while不聽的監聽。
當deviceStateChanged,就調用deviceStateChanged事件,然后取得當前設備狀態。
當locationChanged,就調用locationChanged事件,取得當前坐標。
這樣一個基本的GPS數據取得流程就算完成了。
以下為調用API的函數聲明。

有時候,我們往往不需要簡單的GPS的經緯度,我們或許需要更多的數據。這時候就需要轉換。
比如,在我這個應用中,需要取得對應的高斯直角坐標。
當然我們需要通過一系列的數學運算得到。
我們需要設置一個重要子午線的坐標,然后根據該坐標計算得到。
{
if (enableBLToXY)
{
try
{
//a2 輸入中央子午線,以度.分形式輸入,如115度30分則輸入115.30; 起算數據l0
//f2 以度小數形式輸入經度值, l
//e2 以度小數形式輸入緯度值,b
//s2 計算結果,橫坐標y
//t2 計算結果,縱坐標x
//投影帶號計算 n=[l/6]+1 如:測得經度103.xxxx,故n=[103.x/6]+1=17+1=18
//中央經線經度 l0 = n*6-3 = [l/6]*6+3
double a2, f2, e2, s2, t2;
a2 = centerLine;
f2 = bl1;
e2 = bl2;
e2 = x;
t2 = y;
double b2, h2, i2, j2, k2, l2, m2, n2, o2, p2, q2, r2;
b2 = (int)(a2) + ((int)(a2 * 100) - (int)(a2) * 100) / 60 + (a2 * 10000 -
(int)(a2 * 100) * 100) / 3600;
//把l0化成度(a2)
//g2 = f2 - b2 ' l -l0
//h2 = g2 / 57.2957795130823 '化作弧度
//將經差的單位化為弧度
h2 = (f2 - b2) / 57.2957795130823;
i2 = Math.Tan(e2 / 57.2957795130823);
j2 = Math.Cos(e2 / 57.2957795130823);
k2 = 0.006738525415 * j2 * j2;
l2 = i2 * i2;
m2 = 1 + k2;
n2 = 6399698.9018 / Math.Sqrt(m2);
o2 = h2 * h2 * j2 * j2;
p2 = i2 * j2;
q2 = p2 * p2;
r2 = (32005.78006 + q2 * (133.92133 + q2 * 0.7031));
s2 = ((((l2 - 18) * l2 - (58 * l2 - 14) * k2 + 5) * o2 / 20 + m2 - l2) *
o2 / 6 + 1) * n2 * (h2 * j2);
//在計算的基礎上加上了“帶號”(18)和“東移”(500km)
s2 = s2 + 18500000;
//計算結果,橫坐標y
t2 = 6367558.49686 * e2 / 57.29577951308 - p2 * j2 * r2 + ((((l2 - 58)
* l2 + 61) * o2 / 30 + (4 * k2 + 5) * m2 - l2) * o2 / 12 + 1) * n2 * i2 * o2 / 2;
//計算結果,縱坐標x
x = s2;
y = t2;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
x = 0;
y = 0;
}
}
}
以上就是我的GPS應用程序的主體代碼介紹。希望對大家有用。
可能根據每個項目的實際狀況不一致,我的個人意見如下:
1、項目中GPS部分取得的數據簡單的話,可以直接采用GPS Intermediate Driver
2、最好自己封裝下直接使用串口連接GPS接收器的功能。
3、地圖定位,可以借助Google。
4、注意釋放內存,因為多數都需要調用非托管
5、一定要用線程處理。
最后,附上應用程序CAB包。很多人寫打包程序覺得有時候有困難,其實,一個簡單的打包CAB程序相對很簡單。現在很多WM設備,基本穩妥地還是用基于.net cf2.0為主。所以大家工程發布最好還是以.net cf2.0吧,因為有些設備安裝.net cf3.5不穩定導致。