Использование компаса в WinRT
82Разработка под Windows 10 --- Использование компаса
Хотя акселерометр отличает верх от низа, он не дает полной информации об ориентации устройства в трехмерном пространстве. Чтобы понять, о чем я говорю, запустите программу AccelerometerAndSimpleOrientation из предыдущей статьи на мобильном устройстве. Встаньте и придайте устройству какое-нибудь необычное положение. Акселерометр сообщит направление к центру Земли. Теперь повернитесь всем телом по кругу. Планшет повернулся на 360° в пространстве, но показания акселерометра практически не изменились, потому что вертикальное направление осталось прежним относительно устройства.
Что изменяется при круговом повороте планшета вокруг вектора ускорения? Один из возможных ответов — направление на север относительно планшета. Именно поэтому так важен встроенный компас: он предоставляет недостающие возможности по определению ориентации планшета. Объединяя показания компаса и акселерометра, вы получаете полную информацию об ориентации планшета в трехмерном пространстве.
Класс Compass имеет практически такую же структуру, как Accelerometer, а класс CompassReading содержит два свойства: HeadingMagneticNorth и HeadingTrueNorth. Оба свойства обозначают угол компьютера относительно направления на север (значения в градусах). Если расположить экран параллельно поверхности Земли и направить верх экрана на север, эти углы должны быть близки к нулю. (Под «верхом» имеется в виду положительное направление оси Y на схемах, приведенных ранее.) При повороте экрана к восточному направлению углы увеличиваются.
Конечно, эти углы почти никогда точно не совпадают. Планшет оснащен магнитометром, который реагирует на магнитный север (положение которого определяется магнитным полем Земли); истинный север определяется положением оси вращения Земли. Интересно, что свойство HeadingMagneticNorth относится к типу double, a HeadingTrueNorth — к типу double с поддержкой null, из чего можно сделать вывод, что значение может быть недоступным.
Посмотрим, как работает компас. Файл XAML проекта SimpleCompass определяет две стрелки, направленные от центра экрана прямо вверх:
<Page ...>
<Grid Background="#FF1D1D1D">
<Canvas HorizontalAlignment="Center" VerticalAlignment="Center">
<Path Data="M -10 0 L 10 0, 10 -300, 0 -350, -10 -300 Z" Fill="Magenta" >
<Path.RenderTransform>
<RotateTransform x:Name="magNorthRotate" />
</Path.RenderTransform>
</Path>
<Path Name="trueNorthPath" Fill="Blue"
Data="M -10 0 L 10 0, 10 -300, 0 -350, -10 -300 Z">
<Path.RenderTransform>
<RotateTransform x:Name="trueNorthRotate" />
</Path.RenderTransform>
</Path>
</Canvas>
</Grid>
</Page>
Магнитному северу соответствует фиолетовый цвет, а истинному — синий. Файл фонового кода скрывает второй объект Path, если значение HeadingTrueNorth равно null:
using System;
using Windows.Devices.Sensors;
using Windows.Graphics.Display;
using Windows.UI.Core;
using Windows.UI.Popups;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
namespace WinRTTestApp
{
public sealed partial class MainPage : Page
{
Compass compass = Compass.GetDefault();
public MainPage()
{
this.InitializeComponent();
DisplayProperties.AutoRotationPreferences =
DisplayProperties.NativeOrientation;
Loaded += OnMainPageLoaded;
}
private async void OnMainPageLoaded(object sender, RoutedEventArgs e)
{
if (compass != null)
{
ShowCompassValues(compass.GetCurrentReading());
compass.ReportInterval = compass.MinimumReportInterval;
compass.ReadingChanged += OnCompassReadingChanged;
}
else
{
await new MessageDialog("Компас не поддерживается").ShowAsync();
}
}
private async void OnCompassReadingChanged(Compass sender,
CompassReadingChangedEventArgs e)
{
await this.Dispatcher.RunAsync(
CoreDispatcherPriority.Normal, () =>
{
ShowCompassValues(e.Reading);
});
}
private void ShowCompassValues(CompassReading compassReading)
{
if (compassReading == null)
return;
magNorthRotate.Angle = -compassReading.HeadingMagneticNorth;
if (compassReading.HeadingTrueNorth.HasValue)
{
trueNorthPath.Visibility = Visibility.Visible;
trueNorthRotate.Angle = -compassReading.HeadingTrueNorth.Value;
}
else
{
trueNorthPath.Visibility = Visibility.Collapsed;
}
}
}
}
Углам поворота двух стрелок задаются свойства HeadingMagneticNorth и HeadingTrueNorth с противоположным знаком. Эти значения обозначают угол поворота компьютера относительно северного направления, поэтому стрелки должны быть повернуты в противоположном направлении, обозначая направление на север относительно компьютера.
На обоих планшетах, использованных мной во время работы (включая Microsoft Surface), результаты не впечатляли. Значение HeadingTrueNorth в обоих случаях было равно null. На Microsoft Surface направление на магнитный север было неточным, а на планшете Samsung значения просто изменялись в диапазоне от 0 до 180°! На планшете моего друга значение HeadingMagneticNorth всегда равно 0.
Теоретически истинный север можно вычислить по магнитному, зная местонахождение компьютера, но включение функциональности Location в файле Package.appxmanifest не помогает.