Работа с датчиками, определение местоположения
Цель работы: освоить методы работы со встроенными датчиками
Встроенные датчики
При разработке для Windows Phone можно использовать показания встроенных датчиков устройства, сведения о них можно найти в обзорном материале по пространству имен Windows.Devices.Sensors (http://msdn.microsoft.com/en-us/library/windowsphone/develop/br206408.aspx). Один из доступных датчиков – акселерометр, он позволяет организовывать управление программами путем перемещения телефона в пространстве.
При работе с акселерометром данные, которые можно от него получить, представляют сведения об ускорении устройства в гравитационных единицах. Например, (1,0,0). Если сопоставить эти данные с телефоном, то, если расположить телефон кнопками, расположенными под экраном, вниз, лицевой стороной к наблюдателю, окажется, что ось Y проходит вдоль длинной стороны экрана (положительное направление оси – вверх), X – вдоль короткой (положительное направление оси – вправо), ось Z располагается перпендикулярно экрану (положительное направление – в сторону наблюдателя). Это остаётся справедливым и при поворотах телефона.
Когда телефон неподвижен, акселерометр, регистрирует силу земного притяжения, что отражается в его показаниях (они, по соответствующей оси, близки к 1), перемещения телефона в пространстве приводят к изменению показаний.
Таким образом, оказывается, например, если телефон лежит на горизонтальной поверхности неподвижно, экраном вверх, показания акселерометра выглядят как (0, 0, -1). Если расположить телефон вертикально, кнопками вниз, мы имеем в показаниях (0, -1, 0), перевернув телефон "вверх ногами" – (0, 1, 0). Если повернуть телефон на 90° против часовой стрелки – мы получим (-1,0,0). Акселерометр очень чувствителен, даже при неподвижном устройстве показания не бывают в точности равными идеальным, к тому же, они колеблются в небольших пределах.
В демонстрационном проекте P16_1, на странице AccPage.xaml показана работа с акселерометром. В этом примере мы, кроме того, рассматриваем использование карты и работу с сервисом определения местоположения (этот пример основан на примере Simple Map control sample, скачать пример в исходном виде можно здесь: http://code.msdn.microsoft.com/wpapps/Simple-Map-control-sample-fc94908f). На рис. 47.1. показан состав проекта и страница настройки возможностей в редакторе манифеста приложения. Обратите внимание на то, что включены возможности ID_CAP_LOCATION и ID_CAP_MAP – в противном случае приложение работать не будет.
увеличить изображение
Рис. 47.1. Проект, демонстрирующий работу акселерометра и службы определения местоположения
На странице находятся три текстовых блока, мы перемещаем их в плоскости страницы в соответствии с данными об ускорении по осям X и Y, при этом выводим в соответствующих полях сведения об ускорении. В одном из полей мы выводим данные по оси Z, при этом мы не используем для управления объектами эти данные. В Листинге 24.1 вы можете видеть код файла AccPage.xaml.cs. Обратите внимание на то, что код здесь максимально упрощён, в реальном приложении, использующем акселерометр, нужно позаботиться о дополнительных механизмах, в частности, об обработке ошибок.
using System;
using Microsoft.Phone.Controls;
using Microsoft.Devices.Sensors;
using System.Windows.Media;
namespace P16_1
{
public partial class AccPage : PhoneApplicationPage
{
//Для акселерометра
private Accelerometer accelerometer;
//Для трансформации
private TranslateTransform moveTranslation;
public AccPage()
{
InitializeComponent();
//Новый экземпляр объекта Accelerometer
accelerometer = new Accelerometer();
//Время между обновлениями показаний акселерометра
accelerometer.TimeBetweenUpdates = TimeSpan.FromMilliseconds(20);
//Подключаем обработчик события, возникающего при получении новых данных
accelerometer.CurrentValueChanged += new System.EventHandler<SensorReadingEventArgs<AccelerometerReading>>
(accelerometer_CurrentValueChanged);
//Запуск акселерометра
accelerometer.Start();
//Новая трансформация
moveTranslation = new TranslateTransform();
//Назначаем трансформацию текстовым блокам
txtX.RenderTransform = this.moveTranslation;
txtY.RenderTransform = this.moveTranslation;
txtZ.RenderTransform = this.moveTranslation;
}
//Обработчик
void accelerometer_CurrentValueChanged(object sender,
SensorReadingEventArgs<AccelerometerReading> e)
{
//Вызов метода, который работает с объектами в потоке пользовательского интерфейса
Dispatcher.BeginInvoke(() => MoveObject(e.SensorReading));
}
//Метод для перемещения объекта
void MoveObject(AccelerometerReading accData)
{
//Задаем текст для вывода в текстовые блоки
txtX.Text = "X=" + accData.Acceleration.X.ToString();
txtY.Text = "Y=" + accData.Acceleration.Y.ToString();
txtZ.Text = "Z=" + accData.Acceleration.Z.ToString();
//Перемещаем блоки на плоскости
moveTranslation.X += accData.Acceleration.X * 2;
moveTranslation.Y -= accData.Acceleration.Y * 2;
//Задаём границы области, которые не могут пересечь перемещаемые объекты
if (moveTranslation.X <= 0)
{
moveTranslation.X = 0;
}
if (moveTranslation.Y <= 0)
{
moveTranslation.Y = 0;
}
if (moveTranslation.X >= 300)
{
moveTranslation.X = 300;
}
if (moveTranslation.Y >= 550)
{
moveTranslation.Y = 550;
}
}
}
}
Листинг
47.1.
Код файла AccPage.xaml.cs
Обратите внимание на обработчик accelerometer_CurrentValueChanged. Этот обработчик выполняется в собственном потоке, а пользовательский интерфейс – в собственном. В итоге, для того, чтобы обратиться к элементу пользовательского интерфейса, нам понадобится воспользоваться диспетчером (Dispatcher), с помощью которого можно направить задание из одного потока в другой. В данном случае мы используем лямбда-выражение.
