Usar os sensores de orientação

Saiba como usar os sensores de orientação para determinar a orientação do dispositivo.

Este exemplo cria um aplicativo simples que depende de um sensor de orientação como um dispositivo de entrada. Um sensor de orientação é um dos vários tipos de sensores ambientais que permitem que os aplicativos respondam às alterações na orientação do dispositivo.

Note

Este artigo se concentra no código que demonstra como usar um sensor de orientação. Para obter uma visão geral dos sensores de orientação, consulte Sensores: Sensor de orientação.

Prerequisites

Você deve estar familiarizado com o sensor de orientação e seus usos. Consulte Sensores: Sensor de orientação.

O dispositivo que você está usando deve dar suporte a um sensor de orientação.

Tipos de sensor de orientação

Há dois tipos diferentes de APIs de sensores de orientação incluídas no namespace Windows.Devices.Sensors: OrientationSensor e SimpleOrientation. Embora ambos os sensores sejam sensores de orientação, esse termo é sobrecarregado e eles são usados para fins muito diferentes. No entanto, como ambos são sensores de orientação, ambos são abordados neste artigo.

A API OrientationSensor é usada em aplicativos 3D para obter um quatérnio e uma matriz de rotação. Um quatérnio pode ser facilmente entendido como uma rotação de um ponto [x,y,z] sobre um eixo arbitrário (contrastado com uma matriz de rotação, que representa rotações em torno de três eixos). A matemática por trás de quatérnios é bastante exótica, pois envolve as propriedades geométricas de números complexos e propriedades matemáticas de números imaginários, mas trabalhar com eles é simples, e estruturas como o DirectX os dão suporte. Um aplicativo 3D complexo pode usar o sensor de orientação para ajustar a perspectiva do usuário. Esse sensor combina a entrada do acelerômetro, do giroscópio e da bússola.

A API SimpleOrientationSensor é usada para determinar a orientação física atual do dispositivo em termos de definições como retrato para cima, retrato para baixo, paisagem esquerda e paisagem direita. Ele também pode detectar se um dispositivo está voltado para cima ou para baixo. Em vez de retornar valores como "retrato para cima" ou "paisagem para a esquerda", esse sensor retorna um valor de rotação: "Sem rotação", "Girado 90 graus no sentido anti-horário" e assim por diante. A tabela a seguir mapeia as propriedades de orientação comuns para a leitura do sensor correspondente.

Orientação Leitura do sensor correspondente
Retrato para cima Não rotacionado
Paisagem à Esquerda Girado 90 graus no sentido anti-horário
Retrato para baixo Girado 180 graus no sentido anti-horário
Paisagem à direita Girado 270 graus no sentido anti-horário

Código de exemplo – sensor de orientação

using Microsoft.UI.Dispatching;
using Microsoft.UI.Xaml.Controls;
using Windows.Devices.Sensors;

namespace DevicesDemo.Pages
{
    public sealed partial class OrientationSensorPage : Page
    {
        private OrientationSensor? orientationSensor;

        public OrientationSensorPage()
        {
            InitializeComponent();

            // Get the default orientation sensor object.
            orientationSensor = OrientationSensor.GetDefault();

            if (orientationSensor != null)
            {
                // Establish the report interval.
                uint minReportInterval = orientationSensor.MinimumReportInterval;
                uint reportInterval = minReportInterval > 16 ? minReportInterval : 16;
                orientationSensor.ReportInterval = reportInterval;

                // Assign an event handler for the reading-changed event.
                orientationSensor.ReadingChanged += OrientationSensor_ReadingChanged;
            }
            else
            {
                statusBar.Message = "No orientation sensor was found.";
                statusBar.Severity = InfoBarSeverity.Error;
                statusBar.IsOpen = true;
            }
        }

        // This event handler writes the current orientation
        // reading to the text blocks on the XAML page.
        private void OrientationSensor_ReadingChanged(OrientationSensor sender, OrientationSensorReadingChangedEventArgs args)
        {
            DispatcherQueue?.TryEnqueue(DispatcherQueuePriority.Normal, () =>
            {
                OrientationSensorReading reading = args.Reading;
                // Quaternion values
                txtQuaternionX.Text = String.Format("{0,8:0.00000}", reading.Quaternion.X);
                txtQuaternionY.Text = String.Format("{0,8:0.00000}", reading.Quaternion.Y);
                txtQuaternionZ.Text = String.Format("{0,8:0.00000}", reading.Quaternion.Z);
                txtQuaternionW.Text = String.Format("{0,8:0.00000}", reading.Quaternion.W);

                // Rotation Matrix values
                txtM11.Text = String.Format("{0,8:0.00000}", reading.RotationMatrix.M11);
                txtM12.Text = String.Format("{0,8:0.00000}", reading.RotationMatrix.M12);
                txtM13.Text = String.Format("{0,8:0.00000}", reading.RotationMatrix.M13);
                txtM21.Text = String.Format("{0,8:0.00000}", reading.RotationMatrix.M21);
                txtM22.Text = String.Format("{0,8:0.00000}", reading.RotationMatrix.M22);
                txtM23.Text = String.Format("{0,8:0.00000}", reading.RotationMatrix.M23);
                txtM31.Text = String.Format("{0,8:0.00000}", reading.RotationMatrix.M31);
                txtM32.Text = String.Format("{0,8:0.00000}", reading.RotationMatrix.M32);
                txtM33.Text = String.Format("{0,8:0.00000}", reading.RotationMatrix.M33);
            });
        }
    }
}
<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition/>
        <RowDefinition Height="Auto"/>
    </Grid.RowDefinitions>
    <Grid Margin="24">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition Width="Auto" MinWidth="66"/>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition Width="Auto" MinWidth="66"/>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition Width="Auto" MinWidth="66"/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="44"/>
            <RowDefinition Height="44"/>
            <RowDefinition Height="44"/>
        </Grid.RowDefinitions>
        <TextBlock Text="M11:" Style="{StaticResource LabelTextBlockStyle}"/>
        <TextBlock x:Name="txtM11" Grid.Column="1" Text="---"/>
        <TextBlock Text="M12:" Grid.Row="1" Style="{StaticResource LabelTextBlockStyle}"/>
        <TextBlock x:Name="txtM12" Grid.Column="1" Grid.Row="1" Text="---"/>
        <TextBlock Text="M13:" Grid.Row="2" Style="{StaticResource LabelTextBlockStyle}"/>
        <TextBlock x:Name="txtM13" Grid.Column="1" Grid.Row="2" Text="---"/>

        <TextBlock Text="M21:" Grid.Column="2" Grid.Row="0" Style="{StaticResource LabelTextBlockStyle}"/>
        <TextBlock x:Name="txtM21" Grid.Column="3" Grid.Row="0" Text="---"/>
        <TextBlock Text="M22:" Grid.Column="2" Grid.Row="1" Style="{StaticResource LabelTextBlockStyle}"/>
        <TextBlock x:Name="txtM22" Grid.Column="3" Grid.Row="1" Text="---"/>
        <TextBlock Text="M23:" Grid.Column="2" Grid.Row="2" Style="{StaticResource LabelTextBlockStyle}"/>
        <TextBlock x:Name="txtM23" Grid.Column="3" Grid.Row="2" Text="---"/>

        <TextBlock Text="M31:" Grid.Column="4" Grid.Row="0" Style="{StaticResource LabelTextBlockStyle}"/>
        <TextBlock x:Name="txtM31" Grid.Column="5" Grid.Row="0" Text="---"/>
        <TextBlock Text="M32:" Grid.Column="4" Grid.Row="1" Style="{StaticResource LabelTextBlockStyle}"/>
        <TextBlock x:Name="txtM32" Grid.Column="5" Grid.Row="1" Text="---"/>
        <TextBlock Text="M33:" Grid.Column="4" Grid.Row="2" Style="{StaticResource LabelTextBlockStyle}"/>
        <TextBlock x:Name="txtM33" Grid.Column="5" Grid.Row="2" Text="---"/>

    </Grid>
    <Grid Margin="24" Grid.Row="1">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition Width="Auto"/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="44"/>
            <RowDefinition Height="44"/>
            <RowDefinition Height="44"/>
            <RowDefinition Height="44"/>
        </Grid.RowDefinitions>

        <TextBlock Text="Quaternion X:" Style="{StaticResource LabelTextBlockStyle}"/>
        <TextBlock x:Name="txtQuaternionX" Grid.Column="1" Grid.Row="0" Text="---"/>
        <TextBlock Text="Quaternion Y:" Grid.Row="1" Style="{StaticResource LabelTextBlockStyle}"/>
        <TextBlock x:Name="txtQuaternionY" Grid.Column="1" Grid.Row="1" Text="---"/>
        <TextBlock Text="Quaternion Z:" Grid.Row="2" Style="{StaticResource LabelTextBlockStyle}"/>
        <TextBlock x:Name="txtQuaternionZ" Grid.Column="1" Grid.Row="2" Text="---"/>
        <TextBlock Text="Quaternion W:" Grid.Row="3" Style="{StaticResource LabelTextBlockStyle}"/>
        <TextBlock x:Name="txtQuaternionW" Grid.Column="1" Grid.Row="3" Text="---"/>
    </Grid>

    <InfoBar x:Name="statusBar" Grid.Row="2"/>
</Grid>

Quando o aplicativo é executado, você pode alterar os valores de orientação movendo o dispositivo.

O exemplo anterior demonstra o código essencial que você precisa escrever para integrar a entrada do sensor de orientação ao seu aplicativo.

Conectar-se ao sensor

Chame o método GetDefault para estabelecer uma conexão com o sensor de orientação padrão.

private OrientationSensor? orientationSensor;
// ...
orientationSensor = OrientationSensor.GetDefault();

Você também pode chamar FromIdAsync para criar um objeto OrientationSensor de um valor DeviceInformation.Id. Para obter mais informações, consulte Enumerar dispositivos.

Se nenhum sensor de sensor de orientação for detectado, a mensagem de status será atualizada para informar o usuário.

Definir o intervalo de relatório

O intervalo de relatório é definido dentro do construtor da página. Esse código recupera o intervalo mínimo com suporte do dispositivo e o compara a um intervalo solicitado de 16 milissegundos (que aproxima uma taxa de atualização de 60 Hz). Se o intervalo mínimo com suporte for maior que o intervalo solicitado, o código definirá o valor como o mínimo. Caso contrário, define o valor para o intervalo solicitado.

uint minReportInterval = orientationSensor.MinimumReportInterval;
uint reportInterval = minReportInterval > 16 ? minReportInterval : 16;
orientationSensor.ReportInterval = reportInterval;

Ler dados do sensor

Os novos dados do sensor de orientação são capturados no manipulador de eventos ReadingChanged . Sempre que o driver do sensor recebe novos dados do sensor, ele passa os valores para seu aplicativo usando esse evento. Para este exemplo, esses novos valores são gravados nos blocos de texto encontrados no XAML da página correspondente.

orientationSensor.ReadingChanged += OrientationSensor_ReadingChanged;
// ...

private void OrientationSensor_ReadingChanged(OrientationSensor sender, OrientationSensorReadingChangedEventArgs args)
{
    DispatcherQueue?.TryEnqueue(DispatcherQueuePriority.Normal, () =>
    {
        OrientationSensorReading reading = args.Reading;
        // Quaternion values
        txtQuaternionX.Text = String.Format("{0,8:0.00000}", reading.Quaternion.X);
        txtQuaternionY.Text = String.Format("{0,8:0.00000}", reading.Quaternion.Y);
        txtQuaternionZ.Text = String.Format("{0,8:0.00000}", reading.Quaternion.Z);
        txtQuaternionW.Text = String.Format("{0,8:0.00000}", reading.Quaternion.W);

        // Rotation Matrix values
        txtM11.Text = String.Format("{0,8:0.00000}", reading.RotationMatrix.M11);
        txtM12.Text = String.Format("{0,8:0.00000}", reading.RotationMatrix.M12);
        txtM13.Text = String.Format("{0,8:0.00000}", reading.RotationMatrix.M13);
        txtM21.Text = String.Format("{0,8:0.00000}", reading.RotationMatrix.M21);
        txtM22.Text = String.Format("{0,8:0.00000}", reading.RotationMatrix.M22);
        txtM23.Text = String.Format("{0,8:0.00000}", reading.RotationMatrix.M23);
        txtM31.Text = String.Format("{0,8:0.00000}", reading.RotationMatrix.M31);
        txtM32.Text = String.Format("{0,8:0.00000}", reading.RotationMatrix.M32);
        txtM33.Text = String.Format("{0,8:0.00000}", reading.RotationMatrix.M33);
    });
}

Código de exemplo – sensor de orientação simples

using Microsoft.UI.Dispatching;
using Microsoft.UI.Xaml.Controls;
using Windows.Devices.Sensors;

namespace DevicesDemo.Pages
{
    public sealed partial class SimpleOrientationPage : Page
    {
        private SimpleOrientationSensor? simpleOrientationSensor;

        public SimpleOrientationPage()
        {
            InitializeComponent();

            // Get the default simple orientation sensor object.
            simpleOrientationSensor = SimpleOrientationSensor.GetDefault();

            // Assign an event handler.
            if (simpleOrientationSensor != null)
            {
                // Assign an event handler for the reading-changed event.
                simpleOrientationSensor.OrientationChanged 
                    += SimpleOrientationSensor_OrientationChanged;
            }
            else
            {
                statusBar.Message = "No simple orientation sensor was found.";
                statusBar.Severity = InfoBarSeverity.Error;
                statusBar.IsOpen = true;
            }
        }

        // This event handler writes the current simple orientation
        // reading to the text block on the XAML page.
        private void SimpleOrientationSensor_OrientationChanged(SimpleOrientationSensor sender, 
            SimpleOrientationSensorOrientationChangedEventArgs args)
        {
            DispatcherQueue.TryEnqueue(DispatcherQueuePriority.Normal, () =>
            {
                switch (args.Orientation)
                {
                    case SimpleOrientation.NotRotated:
                        txtOrientation.Text = "Not Rotated";
                        break;
                    case SimpleOrientation.Rotated90DegreesCounterclockwise:
                        txtOrientation.Text = "Rotated 90 Degrees Counterclockwise";
                        break;
                    case SimpleOrientation.Rotated180DegreesCounterclockwise:
                        txtOrientation.Text = "Rotated 180 Degrees Counterclockwise";
                        break;
                    case SimpleOrientation.Rotated270DegreesCounterclockwise:
                        txtOrientation.Text = "Rotated 270 Degrees Counterclockwise";
                        break;
                    case SimpleOrientation.Faceup:
                        txtOrientation.Text = "Faceup";
                        break;
                    case SimpleOrientation.Facedown:
                        txtOrientation.Text = "Facedown";
                        break;
                    default:
                        txtOrientation.Text = "Unknown orientation";
                        break;
                }
            });
        }
    }
}
<Grid>
    <Grid.RowDefinitions>
        <RowDefinition />
        <RowDefinition Height="Auto"/>
    </Grid.RowDefinitions>
    <Grid Margin="24">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="44"/>
        </Grid.RowDefinitions>
        <TextBlock Text="Orientation:" Style="{StaticResource LabelTextBlockStyle}"/>
        <TextBlock x:Name="txtOrientation" Grid.Column="1" Text="---"/>
    </Grid>

    <InfoBar x:Name="statusBar" Grid.Row="1"/>
</Grid>

Quando o aplicativo é executado, você pode alterar os valores de orientação movendo o dispositivo.

O exemplo anterior demonstra o código essencial que você precisa escrever para integrar a entrada do sensor de orientação simples ao seu aplicativo.

Conecte-se ao sensor de orientação básico

Chame o método GetDefault para estabelecer uma conexão com o sensor de orientação padrão.

private SimpleOrientationSensor? simpleOrientationSensor;
// ...
simpleOrientationSensor = SimpleOrientationSensor.GetDefault();

Você também pode chamar FromIdAsync para criar um objeto SimpleOrientationSensor a partir de um valor DeviceInformation.Id. Para obter mais informações, consulte Enumerar dispositivos.

Se nenhum sensor de sensor de orientação simples for detectado, a mensagem de status será atualizada para informar o usuário.

Ler os dados simples do sensor de orientação

Os novos dados do sensor de orientação simples são capturados no manipulador de eventos OrientationChanged . Sempre que o driver do sensor recebe novos dados do sensor, ele passa os valores para seu aplicativo usando esse evento. Para este exemplo, esses novos valores são gravados no bloco de texto encontrado no XAML da página correspondente.

simpleOrientationSensor.OrientationChanged 
    += SimpleOrientationSensor_OrientationChanged;
// ...

private void SimpleOrientationSensor_OrientationChanged(SimpleOrientationSensor sender,
    SimpleOrientationSensorOrientationChangedEventArgs args)
{
    DispatcherQueue.TryEnqueue(DispatcherQueuePriority.Normal, () =>
    {
        switch (args.Orientation)
        {
            case SimpleOrientation.NotRotated:
                txtOrientation.Text = "Not Rotated";
                break;
            case SimpleOrientation.Rotated90DegreesCounterclockwise:
                txtOrientation.Text = "Rotated 90 Degrees Counterclockwise";
                break;
            case SimpleOrientation.Rotated180DegreesCounterclockwise:
                txtOrientation.Text = "Rotated 180 Degrees Counterclockwise";
                break;
            case SimpleOrientation.Rotated270DegreesCounterclockwise:
                txtOrientation.Text = "Rotated 270 Degrees Counterclockwise";
                break;
            case SimpleOrientation.Faceup:
                txtOrientation.Text = "Faceup";
                break;
            case SimpleOrientation.Facedown:
                txtOrientation.Text = "Facedown";
                break;
            default:
                txtOrientation.Text = "Unknown orientation";
                break;
        }
    });
}

Como alternativa ao OrientationChanged evento, você pode fazer uma leitura única da orientação atual chamando o método GetCurrentOrientation .