Цель лекции: научиться работать с координатами,
Устройство Windows Phone 7 должно иметь ряд аппаратных возможностей – иногда называемых датчиками – и предоставлять некоторые программные сервисы, возможно, с аппаратной поддержкой. Рассмотрим те из них, которые наиболее интересны разработчикам:
Устройства Windows Phone имеют
Моделирование уровня нивелира является основным применением
Выходные данные
Тогда как три координаты $$(x, y, z)$$ точно определяют точку в пространстве, вектор $$(x, y, z)$$ обозначает направление и величину. Очевидно, что точка и вектор взаимосвязаны. Направление вектора $$(x, y, z)$$ – это луч из точки $$(0, 0, 0)$$ в точку $$(x, y, z)$$. Но вектор $$(x, y, z)$$ это совсем не отрезок, соединяющий $$(0, 0, 0)$$ и $$(x, y, z)$$. Это направление этого отрезка.
Для вычисления модуля вектора $$(x, y, z)$$ используется трехмерная форма теоремы Пифагора:
Модуль = $$\sqrt{x^2+y^2+z^2}$$
Для работы с
(рис 8.1) Трехмерная система координат
Это традиционная трехмерная система координат, такая же используется при создании 3D-графики на XNA. Ее называют правой системой координат. Расположите указательный палец правой руки вдоль положительного направления $$Х$$, средний палец – вдоль положительного направления $$Y$$, и большой палец будет указывать на положительное направление $$Z$$.
Эта координатная система фиксирована относительно телефона независимо от его положения в пространстве и независимо от ориентации изображения выполняемых приложений. Кстати, как можно догадаться,
Когда телефон неподвижен, вектор
Поверните телефон на $$90°$$ против часовой стрелки (так называемое левостороннее альбомное расположение), и вектор ускорения станет равным $$(–1, 0, 0)$$; переверните телефон "вверх ногами" – вектор равен $$(0, 1, 0)$$; еще один поворот на $$90°$$ против часовой стрелки обеспечивает правостороннее альбомное расположение и вектор ускорения равный $$(1, 0, 0)$$. Положите телефон на стол экраном вверх, и вектор ускорения будет $$(0, 0, –1)$$. (Эмулятор Windows Phone 7 всегда возвращает это значение.)
Конечно, вектор ускорения редко будет принимать такие точные значения, даже его модуль не будет точно равен 1. Для неподвижного телефона значения модуля могут колебаться в пределах нескольких процентов для разных ориентаций. На Луне величина вектора ускорения Windows Phone 7 будет в районе 0,17, но мобильная связь неустойчивая.
Мы рассмотрели значения вектора ускорения для неподвижного устройства. Вектор ускорения может менять направление (и модуль может быть больше или меньше), когда телефон перемещается с разной скоростью. Например, если тряхнуть телефон влево, вектор ускорения будет указывать вправо, но только пока устройство набирает скорость. Как только скорость стабилизируется, вектор ускорения опять будет отражать только
Когда телефон, движущийся влево, начнет замедляться, вектор ускорения ненадолго направится влево до остановки устройства.
При свободном падении модуль вектора ускорения, теоретически, должен стремиться к нулю.
Для работы с
<Capability Name="ID_CAP_SENSORS"/>
Это задается по умолчанию.
В приложении создается экземпляр класса
Рассмотрим проект SilverlightAccelerometer.project, который просто обеспечивает выведение на экран текущих показаний. Центрированный TextBlock описывается в файле XAML:
Проект Silverlight: SilverlightAccelerometer Файл: MainPage.xaml (фрагмент)
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<TextBlock Name="txtblk" HorizontalAlignment="Center" VerticalAlignment="Center" />
</Grid>
Чтобы добавить библиотеку
(рис 8.2) Добавление библиотеки Microsoft.Devices.SensorsMicrosoft.Devices.Sensors ; в MainPage.xaml.csЭто приложение будет обеспечивать вывод на экран вектора
Проект Silverlight: SilverlightAccelerometer Файл: MainPage.xaml.cs (фрагмент)
public MainPage()
{
InitializeComponent();
Accelerometer acc = new Accelerometer();
acc.ReadingChanged += OnAccelerometerReadingChanged;
try
{
acc.Start();
}
catch (Exception exc)
{
txtblk.Text = exc.Message;
}
}
Документация предупреждает, что вызов Start может привести к формированию исключения, поэтому приложение защищает себя от этого. Класс также поддерживает методы Stop (Остановить) и Dispose (Удалить), но в данной программе они не используются. Для обеспечения сведения о доступности State.
Событие ReadingChanged обеспечивается классом аргументов события AccelerometerReadingEventArgs. Этот объект имеет свойства $$X$$, $$Y$$ и $$Z$$ типа double и свойство TimeStamp типа DateTimeOffset (Смещение даты-времени). В приложении SilverlightAccelerometer задача обработчика события – форматировать эти данные в строку и задать ее как значение свойства Text объекта TextBlock.
Загвоздка здесь в том, что обработчик события (в данном случае, OnAccelerometerReadingChanged (При изменении показаний
Немного теории. Создание и доступ ко всем элементам и объектам пользовательского интерфейса в приложении на Silverlight выполняется в основном потоке выполнения, который часто называют потоком пользовательского интерфейса или UI-потоком. Эти объекты пользовательского интерфейса не являются потокобезопасными; для них не предусмотрен одновременный доступ из множества потоков. Поэтому Silverlight не допустит доступа к объекту пользовательского интерфейса из потока, не являющегося UI-потоком.
Это означает, что метод OnAccelerometerReadingChanged не может напрямую обратиться к элементу TextBlock, чтобы задать новое значение его свойству Text.
К счастью в пространстве имен System.Windows.Threading описан класс Dispatcher (Диспетчер), который обеспечивает решение этой проблемы. Через класс Dispatcher можно направлять задания из потока, не являющегося UI-потоком, в очередь, которая позднее будет обработана UI-потоком. Все это звучит довольно запутанно, но с точки зрения разработчика все довольно просто, потому что эти задания принимают форму простых вызовов методов.
Экземпляр Dispatcher уже доступен. Класс DependencyObject (Зависимость) описывает свойство Dispatcher типа Dispatcher, и от DependencyObject наследуется множество классов Silverlight. С экземплярами всех этих классов можно работать из потоков, не являющихся UI-потоками, потому что все они имеют свойства Dispatcher. Из любого производного от DependencyObject класса, созданного в UI-потоке, может использоваться любой объект Dispatcher. Они все одинаковые.
Класс Dispatcher определяет метод CheckAccess (Проверить возможность доступа), который возвращает true, если текущий поток имеет доступ к конкретному объекту пользовательского интерфейса. (Метод CheckAccess также дублируется самим DependencyObject.) Для случаев, когда доступ к объекту из текущего потока невозможен, Dispatcher предоставляет две версии метода Invoke (Вызвать), с помощью которых выполняется отправка заданий для UI-потока.
В проекте SilverlightAccelerometer реализована версия кода, доскональная с точки зрения синтаксиса.
В развернутой версии требуется делегат и метод, соответствующий этому делегату. Делегат (и метод) не должен иметь возвращаемого значения, но у него должно быть такое количество аргументов, которого будет достаточно для выполнения задания. В данном случае это задание состоит в присвоении строки в качестве значения свойства Text объекта TextBlock:
Проект: SilverlightAccelerometer Файл: MainPage.xaml.cs (фрагмент)
delegate void SetTextBlockTextDelegate(TextBlock txtblk, string text);
void SetTextBlockText(TextBlock txtblk, string text)
{
txtblk.Text = text;
}
OnAccelerometerReadingChanged отвечает за вызов SetTextBlockText (Задать текст блока текста). Он впервые использует CheckAccess, чтобы определить возможность вызова метода SetTextBlockText напрямую. Если это невозможно, обработчик вызывает метод BeginInvoke (Начать вызов). Его первым аргументом является SetTextBlockText. За ним следуют все необходимые SetTextBlockText аргументы:
Проект: SilverlightAccelerometer Файл: MainPage.xaml.cs (фрагмент)
void OnAccelerometerReadingChanged(object sender, AccelerometerReadingEventArgs args)
{
string str = String.Format("X = {0:F2}\n" + "Y = {1:F2}\n" + "
Z = {2:F2}\n\n" + "Magnitude = {3:F2}\n\n" + "{4}",
args.X, args.Y, args.Z, Math.Sqrt(args.X * args.X + args.Y * args.Y + args.Z * args.Z), args.Timestamp);
if (txtblk.CheckAccess()) { SetTextBlockText(txtblk, str);
}
else
{
txtblk.Dispatcher.BeginInvoke(new SetTextBlockTextDelegate(SetTextBlockText), txtblk, str);
}
}
Это не самый плохой вариант, но необходимость перепрыгивать из потока в поток повлекла за собой применение дополнительного метода и делегата.
В эмуляторе Windows Phone 7 нет
(рис 8.3) Результат программы
С согласия пользователя приложение для Windows Phone 7 может принимать географические координаты телефона по методу Assisted-
Наиболее точный метод определения местоположения – по сигналам спутников
Основным классом для определения местоположения является GeoCoordinateWatcher (Система отслеживания географических координат). Нам понадобится ссылка на сборку System.Device и директива using для пространства имен System.Device.Location. В файле WMAppManifest.xml должен присутствовать такой тег:
<Capability Name="ID_CAP_LOCATION"/>
Конструктор GeoCoordinateWatcher принимает один из элементов перечисления GeoPositionAccuracy (Точность географических координат):
После создания объекта GeoCoordinateWatcher необходимо задать обработчик события PositionChanged (Местоположение изменилось) и вызвать метод Start. Событие PositionChanged возвращает объект (Географические координаты), имеющий восемь свойств:
Если приложение не имеет разрешения на определение местоположения, свойства и будут иметь значение Double.NaN, и IsUnknown будет true.
Кроме того, в есть метод GetDistanceTo (Определить расстояние до), вычисляющий расстояние между двумя объектами .
Мы рассмотрим первые два свойства. Их называют географическими координатами. Они определяют точку на поверхности Земли. Широта – это угловое расстояние от экватора. Как правило, широта обозначается как угол от 0 до 90 градусов с указанием С или Ю (сервер или юг). Например, широта Нью-Йорка примерно 40°С. В объекте
Географические местоположения с одинаковой широтой образуют линию широты или параллель. Для заданной широты долгота – это угловое расстояние от нулевого меридиана, который проходит через Гринвичскую астрономическую обсерваторию, Англия. Долготу определяют как западную или восточную. Нью-Йорк располагается на 74° западной долготы, потому что он находится на запад от нулевого меридиана. В объекте
Пространство имен System.Device.Location включает классы, которые используют географические координаты для определения адресов (улиц и городов), но эта возможность не реализована в первой выпущенной версии Windows Phone 7.
Проект XnaLocation просто обеспечивает вывод на экран числовых значений.
Не забудьте добавить соответствующий шрифт.
Добавьте библиотеку System.Device тем же способом, как мы добавляли
Проект XNA: XnaLocation Файл: Game1.cs (фрагмент, демонстрирующий поля)
…
using System.Device.Location;
…
public class Game1 : Microsoft.Xna.Framework.Game
{ GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
SpriteFont segoe14;
string text = "Obtaining location...";
Viewport viewport;
Vector2 textPosition;
…
Как и в случае с
Проект XNA: XnaLocation Файл: Game1.cs (фрагмент)
protected override void Initialize()
{
GeoCoordinateWatcher geoWatcher = new GeoCoordinateWatcher();
geoWatcher.PositionChanged += OnGeoWatcherPositionChanged;
geoWatcher.Start();
base.Initialize();
}
void OnGeoWatcherPositionChanged(object sender, GeoPositionChangedEventArgs<GeoCoordinate> args)
{
text = String.Format("Latitude: {0:F3}\r\n" + "Longitude: {1:F3}\r\n" +
"Altitude: {2}\r\n\r\n" + "{3}", args.Position.Location.Latitude,
args.Position.Location.Longitude, args.Position.Location.Altitude, args.Position.Timestamp);
}
Метод LoadContent просто получает шрифт и сохраняет Viewport для позиционирования текста впоследствии:
Проект XNA: XnaLocation Файл: Game1.cs (фрагмент)
protected override void LoadContent()
{
spriteBatch = new SpriteBatch(GraphicsDevice);
segoe14 = this.Content.Load<SpriteFont>("Segoe14");
viewport = this.GraphicsDevice.Viewport;
}
Размер отображаемой строки может меняться в зависимости от значений, поэтому ее местоположение вычисляется на основании ее размера и значений Viewport в методе Update:
Проект XNA: XnaLocation Файл: Game1.cs (фрагмент)
protected override void Update(GameTime gameTime)
{
// Обеспечиваем возможность выхода из игры
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed) this.Exit();
Vector2 textSize = segoe14.MeasureString(text);
textPosition = new Vector2((viewport.Width - textSize.X) / 2,(viewport.Height - textSize.Y) / 2);
base.Update(gameTime);
}
Метод Draw обычный:
Проект XNA: XnaLocation Файл: Game1.cs (фрагмент)
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.Navy);
spriteBatch.Begin();
spriteBatch.DrawString(segoe14, text, textPosition, Color.White);
spriteBatch.End(); base.Draw(gameTime);
}
GeoCoordinateWatcher выполняется в течение всего выполнения приложения, поэтому он должен обновлять данные о местоположении в случае перемещения телефона.
В данной лекции мы:
Если вы пользовались эмулятором, постарайтесь найти мобильное устройство на базе WP7 и протестировать на нём написанные программы. Это позволит более наглядно продемонстрировать работу
Для получения официальных документов о завершении программы дополнительного профессионального образования (удостоверения о повышении квалификации, дипломов о профессиональной переподготовке и MBA) необходимо предоставить:
Внимание! Вы можете не заказывать доставку бумажной версии официального документы, а скачать его в электронном виде и распечатать самостоятельно. Информация о выданном документе в течение 1 месяца загружается в Федеральную информационную систему «Федеральный реестр сведений о документах об образовании и (или) о квалификации, документах об обучении» - ФИС ФРДО.
Доступ на новый сайт осуществляется с использованием адреса электронной почты, который был указан вами при регистрации на "старом". Мы постарались перенести все ваши данные с прежнего ресурса, однако не исключена вероятность потери части информации.
При возникновении проблемы со входом, воспользуйтесь функцией сброса пароля
Если вы обнаружите несоответствия, пожалуйста, сообщите нам.