Датчик угла наклона в WinRT

139

Класс датчика угла наклона Inclinometer — один из двух классов, объединяющих показания акселерометра и компаса с некоторым сглаживанием результата. Класс предоставляет информацию в форме углов тангажа (pitch), крена (roll) и отклонения (yaw) — термины позаимствованы в области динамики полета. У летящего самолета отклонение определяет направление, в котором обращен нос. Отклонение изменяется при повороте самолета влево или вправо. Тангаж определяет угол носа самолета относительно горизонтали. Он изменяется при подъеме или опускании носа с целью набора или потери высоты. Крен достигается наклоном корпуса влево или вправо.

Чтобы понять, какое отношение эти углы имеют к компьютеру, представьте, что вы летите на своем планшете, как на ковре-самолете. Вы сидите на экране лицом к верхнему краю (в основной ориентации планшета, конечно). В системе координат, приведенной ранее, отклонение определяет величину поворота по оси Z, тангаж — по оси X, а крен — по оси Y.

Программа YawPitchRoll также помогает наглядно представить эти углы. Файл XAML содержит элементы Rectangle, используемые для рисования линий, элементы Ellipse для рисования шариков, а также текстовые элементы:

<Page ...>

    <Grid Background="#FFFFFFFF">
        <!-- Тангаж -->
        <Rectangle Width="3" Fill="Blue" 
                   HorizontalAlignment="Center"
                   VerticalAlignment="Stretch" />

        <Path Name="pitchPath" 
              Stroke="Blue">
            <Path.Data>
                <EllipseGeometry x:Name="pitchEllipse" RadiusX="20" RadiusY="20" />
            </Path.Data>
        </Path>

        <!-- Крен -->
        <Rectangle Height="3" Fill="Red" 
                   HorizontalAlignment="Stretch"
                   VerticalAlignment="Center" />

        <Path Name="rollPath" Stroke="Red" Fill="Red">
            <Path.Data>
                <EllipseGeometry x:Name="rollEllipse" RadiusX="20" RadiusY="20" />
            </Path.Data>
        </Path>

        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition />
                <RowDefinition />
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition />
                <ColumnDefinition />
            </Grid.ColumnDefinitions>

            <!-- Тангаж -->
            <TextBlock Text="PITCH" Foreground="Blue"
                       HorizontalAlignment="Right" Margin="0 0 24 0" />

            <TextBlock Name="pitchValue" Grid.Column="1"
                       Foreground="Blue"  HorizontalAlignment="Left" Margin="24 0 0 0" />

            <!-- Крен -->
            <TextBlock Text="ROLL" Grid.Row="1"
                       Foreground="Red" HorizontalAlignment="Left"
                       VerticalAlignment="Top" Margin="0 108 0 0">
                <TextBlock.RenderTransform>
                    <RotateTransform Angle="-90" />
                </TextBlock.RenderTransform>
            </TextBlock>

            <TextBlock Name="rollValue"
                       Grid.Row="0"
                       Grid.Column="0"
                       Foreground="Red"
                       HorizontalAlignment="Left"
                       VerticalAlignment="Bottom">
                <TextBlock.RenderTransform>
                    <RotateTransform Angle="-90" />
                </TextBlock.RenderTransform>
            </TextBlock>

            <!-- Отклонение -->
            <Grid Grid.Column="1" HorizontalAlignment="Stretch"
                  RenderTransformOrigin="0 1" VerticalAlignment="Bottom">
                <StackPanel Orientation="Horizontal"
                            HorizontalAlignment="Center">
                    <TextBlock Text="YAW = " Foreground="Green" />
                    <TextBlock Name="yawValue" Foreground="Green" />
                </StackPanel>

                <Rectangle Height="3" Fill="Green"
                           HorizontalAlignment="Stretch"
                           VerticalAlignment="Bottom" />

                <Grid.RenderTransform>
                    <TransformGroup>
                        <RotateTransform Angle="-90" />
                        <RotateTransform x:Name="yawRotate" />
                    </TransformGroup>
                </Grid.RenderTransform>
            </Grid>
        </Grid>
    </Grid>
</Page>

Как мы видим из файла фонового кода, в области создания и использования экземпляров класс Inclinometer мало чем отличается от Accelerometer и Compass:

using System;
using Windows.Devices.Sensors;
using Windows.Foundation;
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
    {
        Inclinometer inclinometer = Inclinometer.GetDefault();

        public MainPage()
        {
            this.InitializeComponent();
            DisplayProperties.AutoRotationPreferences = 
                DisplayProperties.NativeOrientation;
            Loaded += OnMainPageLoaded;
        }

        private async void OnMainPageLoaded(object sender, 
            RoutedEventArgs e)
        {
            if (inclinometer == null)
            {
                await new MessageDialog("Датчик угла наклона не поддерживается").ShowAsync();    
            }
            else
            {
                ShowYawPitchRoll(inclinometer.GetCurrentReading());
                inclinometer.ReportInterval = inclinometer.MinimumReportInterval;
                inclinometer.ReadingChanged += OnInclinometerReadingChanged;
            }
        }

        private async void OnInclinometerReadingChanged(Inclinometer sender, 
            InclinometerReadingChangedEventArgs e)
        {
            await this.Dispatcher.RunAsync(
                CoreDispatcherPriority.Normal, () =>
                {
                    ShowYawPitchRoll(e.Reading);
                });
        }

        private void ShowYawPitchRoll(InclinometerReading inclinometerReading)
        {
            if (inclinometerReading == null)
                return;

            double yaw = inclinometerReading.YawDegrees;
            double pitch = inclinometerReading.PitchDegrees;
            double roll = inclinometerReading.RollDegrees;

            yawValue.Text = yaw.ToString("F0") + "°";
            pitchValue.Text = pitch.ToString("F0") + "°";
            rollValue.Text = roll.ToString("F0") + "°";

            yawRotate.Angle = yaw;

            if (pitch <= 90 && pitch >= -90)
            {
                pitchPath.Fill = pitchPath.Stroke;
                pitchEllipse.Center = new Point(this.ActualWidth / 2,
                                                this.ActualHeight * (pitch + 90) / 180);
            }
            else
            {
                pitchPath.Fill = null;

                if (pitch > 90)
                    pitchEllipse.Center = new Point(this.ActualWidth / 2,
                                                    this.ActualHeight * (270 - pitch) / 180);
                else // pitch < -90
                    pitchEllipse.Center = new Point(this.ActualWidth / 2,
                                                    this.ActualHeight * (-90 - pitch) / 180);
            }
            rollEllipse.Center = new Point(this.ActualWidth * (roll + 90) / 180,
                                           this.ActualHeight / 2);
        }
    }
}

Нет никакого «скрытого компаса», поставляющего информацию датчику угла наклона. Свойство YawDegrees так же ненадежно, как и показания компаса, хотя на самом деле они дополняют друг друга: сумма YawDegrees и показаний Compass всегда равна приблизительно 360. Когда планшет лежит экраном вверх на плоской поверхности, линия отклонения указывает на север (или в его окрестности), а шарики тангажа и крена находятся в центре. Если наклонить верхний край планшета вверх или вниз, PitchDegrees изменяется в диапазоне от 90° (планшет стоит вертикально) до -90° (планшет перевернут «вниз головой»). Значение RollDegrees изменяется в диапазоне от 90° до -90° при наклоне планшета вправо или влево. Вот как выглядит приложение, если приподнять левую и верхнюю стороны планшета:

Пример использования датчика угла наклона

Если устройство лежит экраном вниз, YawDegrees указывает на юг, a PitchDegrees принимает значения в диапазоне от 90° до 180°, и от -90° до -180°. В программе эти значения представлены красным шариком.

Если в вашей программе по экрану летает какой-нибудь объект, этих углов может быть достаточно. Однако может оказаться, что вам нужны более математически-ориентированные данные. Для этих целей и предназначен датчик ориентации в трехмерном пространстве, который мы обсудим в следующей статье.

Пройди тесты
Лучший чат для C# программистов