天天看點

【WP 8.1開發】電子羅盤

羅盤,估計也不用我過多介紹,學過國中實體的都知道,不管是指南針,還是指北針,其本質就是用來辨識方向的。

操作電子羅盤偉感器也不複雜,主要就是兩個角度:

1、目前方向與磁北的夾角;

2、目前方向與地北的夾角。

同時,我們也了解到,地理北極與地磁北極并不是重合的,存在地偏角。在讀取電子羅盤資料時,可以優先考慮讀取與地北極的夾角,如果讀不到地北極的夾角,再讀取磁北極的夾角資料。

CompassReading類(位于Windows.Devices.Sensors命名空間)封裝了從電子羅盤所讀到的資料。

1、HeadingMagneticNorth屬性:擷取目前方向與磁北的夾角度數。

2、HeadingTrueNorth屬性:該屬性擷取的是真北夾角,即地理夾角。我們注意到它的類型為double?,即Nullable<double>,表明這個數值有可能為null,也就是說有可能擷取不到地北夾角的值。在使用時,我們可以先判斷地北角是否為null,如不為null就用這個值;如果為null就用磁北角的值。

3、HeadingAccuracy屬性:表示羅盤讀數的準确性,如果讀數精度較高,其傳回High。我們的應用程式可以在合适的時候檢查這個屬性是否為High,如果不是,可以考慮提示使用者校準羅盤。

提到校準,不得不說一下的是,校準羅盤是不需要系統提示,應用也可以不提示。隻是考慮到使用者體驗的問題,可以提示使用者校準。校準方法很簡單,不管你是使用WP自帶的地圖應用,還是其他第三方應用,或者你自己開發的應用。隻要在使用到羅盤的地方,你拿着手機,在空中做幾次“8”字形來回移動就可以了,不需要等待提示,隻要在用到羅盤的地方就可以随時校準。

電子羅盤的API封裝在Windows.Devices.Sensors.Compass類中,WP API中的所有傳感器調用都很簡單,首先擷取到某個傳感器類的執行個體,一般通過GetDefault方法(靜态方法)就能傳回,然後設定讀取的時間間隔,以毫秒為機關,如果你希望每秒讀一次資料,就把ReportInterval設定為1000,但是,這個時間間隔不能小于MinimumReportInterval屬性指定的值,這個要注意,設定為20毫秒以上的間隔,效果都不錯了,當然這要看你使用的實際情況了。

最後處理ReadingChanged事件,當有新的資料讀到時,會引發該事件,并把新讀到的資料傳遞給該事件,我們就可以從事件參數中擷取最新的讀數。

好了,理論永遠都是抽象的,下面給大家看一下我做的一個簡陋指南針,确實很簡,希望大家莫笑,因為本人較菜,是以連首頁上的羅盤也是用XAML直接畫的。

先上一個效果圖。

【WP 8.1開發】電子羅盤

看吧,簡陋吧,沒辦法,人窮就是這樣,要簡食素衣。指南針背景我是用幾個圈圈畫的,訓示方向的指針是用Path元素畫的。

原理是這樣的:

根據電子羅盤讀到的角度,對紅色的指針對象進行旋轉變換——就是用RotateTransform類來旋轉。但要注意旋轉的角度。比如,我目前方向是20度,即東北偏北方向,那麼,要怎麼設定角度才能保證紅色的指針始終指向南方呢。

我們知道,夾角是以正北為參考的,如果要使指針指向南方,一種方法是将羅盤讀到的角度加上180,因為南北的夾角正好是180度(平角);另一種方法是,讓指針的初始位置向下,即指向正南方,我就是用這個方法的。如圖。

【WP 8.1開發】電子羅盤

不管是指向北方還是南方(上北下南),都可以按相同的角度來旋轉,因為它們的夾角正好是180。

于是,第二個問題産生了——要旋轉多少度才合适?我們上面舉例說目前方向為20度,參照标準是北極,也就是說此時我們的手機已經偏向20度方向,如果把指針旋轉20度,那麼指針相對于螢幕,偏轉的角度就是40度了,本來就偏了20度,你再轉20度,就番倍了,顯然這樣不妥,我們必須把這個角度差抵消掉。

也就是說,如果我目前方向是20度,那麼指針的旋轉變換應為-20度,這樣才能把偏差的角度補平,不然的話,你試試就知道了,如果不抵消的話,指針會越走越偏。

還有一種方法就是用360度作為被減數,如360 - 20 = 340度,-20度和340度雖然計算方向不同,但它們的位置是相同的。是以兩種方法都可以。比如讀數是80度,可以把指針旋轉-80度,也可以旋轉360 - 80度。

async void _compass_ReadingChanged ( Compass sender, CompassReadingChangedEventArgs args )
        {
            var res = args.Reading;
            // 如果地北極的偏角值不可用,則使用磁北極角度
            double val = res.HeadingTrueNorth ?? res.HeadingMagneticNorth;
            await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal,
                () =>
                {
                    // 如果精度較高,則停止校準
                    if (isChecking && res.HeadingAccuracy == MagnetometerAccuracy.High)
                    {
                        fly.Hide();
                        isChecking = false;
                    }

                    // 旋轉的方向是羅盤角度的負值
                    rotatTransform.Angle = -val;
                    Display(val);
                });
        }      

Display方法是我自定義的方法,用來判斷讀數所指的方向,并在頁面上以文本的方式顯示。比如,讀數為0,就是“正北”,讀數為180度,為“正南”等。

/// <summary>
        /// 顯示方位
        /// </summary>
        private void Display ( double v )
        {
            string d = "";
            int ind = Convert.ToInt32(v);
            if (ind == 0 || ind == 360)
            {
                d = "正北";
            }
            else if (ind == 90)
            {
                d = "正東";
            }
            else if (ind == 180)
            {
                d = "正南";
            }
            else if (ind == 270)
            {
                d = "正西";
            }
            else if (ind > 0 && ind < 90)
            {
                d = "東北";
            }
            else if (ind > 90 && ind < 180)
            {
                d = "東南";
            }
            else if (ind > 180 && ind < 270)
            {
                d = "西南";
            }
            else if (ind > 270 && ind < 360)
            {
                d = "西北";
            }
            tbW.Text = string.Format("{0}°({1})", ind, d);
        }      

以上所列是重點的代碼片段,其他代碼大家可以參考我上傳的示例源代碼。

下載下傳位址:https://files.cnblogs.com/tcjiaan/CompassApp.zip