В очередном выпуске «Как создать андроид-приложение» мы рассмотрим приложение с эффектом дополненной реальности, как игра PokemonGo. Да, да, мы тоже будем с вами ловить покемонов, привязанных к определенным координатам на местности, используя датчики android устройства.

Итак, что такое «Дополненная реальность»? Этот термин стал довольно популярным в последние несколько лет благодаря Google glass, но идея старше, чем первый телефон Android. Вы помните фильм Терминатор? Наш герой имел зрение, которое отображало расстояние до ближайших объектов и дополнительную информацию о них.
Существует несколько определений дополненной реальности: исследователь Рональд Азума (англ. Ronald Azuma) в 1997 году определил её как систему, которая:

  1. совмещает виртуальное и реальное;
  2. взаимодействует в реальном времени;
  3. работает в 3D.

Не путайте дополненную реальность с виртуальной реальностью — это разные технологии. Отличие заключается в том, что дополненная реальность — это наложение оцифрованной информации на реальный мир. Давайте рассмотрим простое приложение, которое отображает привязанную к координатам картинку на CameraView. Картинка отображается поверх изображения с камеры, если устройство находится поблизости и повернуто в сторону координат расположения картинки. С координатами местоположения понятно, но каким образом устройство будет определять направление расположения устройства относительно точки привязки картинки? В этом нам поможет теория геодезии и такое понятие, как азимут.

Немного теории

Кто не знает, азимут — это угол, образуемый заданным направлением движения и направлением на север.

Azimut_ru.svg

Источник: https://ru.wikipedia.org/wiki/Азимут

Приложение будет определять точку назначения, сравнивая азимут, вычисленный из основных свойств прямоугольного треугольника и реальный азимут, который указывает устройство. Вот примерный алгоритм для достижения этой цели:

  • получить местоположение устройства
  • получить местоположение точки назначения
  • вычислить расстояние до точки назначения
  • рассчитать теоретический азимут
  • получить реальный азимут устройства
  • сравнить оба азимута
  • вызвать событие при совпадении значений азимута и расстояния в пределах допустимой погрешности

Теперь вопрос заключается в том, как вычислить азимут и расстояние. Это довольно просто, потому что мы будем игнорировать кривизну Земли и рассматривать ее как плоскую поверхность:

Источник: https://www.netguru.co/blog/augmented-reality-mobile-android

Источник: https://www.netguru.co/blog/augmented-reality-mobile-android

Как вы можете видеть, у нас есть прямоугольный треугольник, и мы можем вычислить угол ᵠ между точками  с помощью простого уравнения:

2016-08-17_22-23-34

В приведенной таблице представлены отношения между уголом в градах и азимутом A(AB):

 

2016-08-18_11-53-31

Источник: https://www.netguru.co/blog/augmented-reality-mobile-android

А чтобы определить расстояние до точки назначения, воспользуемся этой формулой:

2016-08-17_22-29-33

Рассмотрим реализацию нашего приложения

Ниже код проекта в Андроид Студио, который мы сейчас подробно разберем.

Для начала посмотрим ресурсы. Нам понадобится изображение покемона.

Вот ссылка на ресурсы: https://yadi.sk/d/Y06QyQ6juJibC

В нашем приложении 2 активити, поэтому нам нужны 2 макета компоновки для них. В одном будет отображаться превью камеры с наложением текста и картинки, а также кнопка для перехода на карту.

В другом макете будет отображаться карта Google Maps.

Я не буду подробно останавливаться на том, как встроить карту Google Maps в приложение,  урок об этом смотрите на нашем сайте: ссылка

Теперь перейдем к коду. Нам понадобятся два интерфейса. Первый —  это слушатель изменения местоположения.

Второй — слушатель изменения азимута.

В классе MyCurrentLocation будем определять местоположение устройства. Этот класс реализует такие интерфейсы: GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, LocationListener.

Это местоположение мы будем получать через конструктор этого класса в главном классе приложения, который будет реализовать интерфейс nLocationChangedListener.

А теперь смотрим класс для определения азимута по методу, о котором я говорил в начале урока. Класс MyCurrentAzimuth имплементирует интерфейс SensorEventListener.

Как видите, здесь используется виртуальный датчик, TYPE_ROTATION_VECTOR, который берет информацию сразу с нескольких сенсоров — акселерометра, гироскопа и датчика магнитного поля. И если акселерометр есть в каждом устройстве, то датчик магнитного поля в старых бюджетных телефонах зачастую отсутствует.  Следовательно, на таком смартфоне азимут определяться не будет, так как датчик TYPE_ROTATION_VECTOR будет всегда возвращать 0. Но позже я покажу, как мы обойдем это ограничение, чтобы наше приложение работало.

А как получить список сенсоров в вашем устройстве — смотрите по ссылке на экране и в описании видео. На нашем сайте есть небольшая инструкция об этом с перечнем и назначением основных сенсоров: ссылка

А мы рассмотрим следующий класс — MapActivity. Его задача — отображение карты с меткой в месте привязки покемона.

Здесь мы просто создаем карту Google Map и добавляем маркер в точку с заранее определенными координатами, для простоты здесь мы их берем из переменных в классе главного активити. В методе добавления маркера также устанавливаем позицию камеры и масштаб карты. Для работы с Google Maps нужно получить apikey в консоли разработчика Google и прописать его в манифесте приложения.  Подробнее о получении ключа и работе с картами Google смотрите тут и тут.

Еще нам понадобится класс Pikachu — здесь просто набор переменных: имя и координаты, а также геттеры для них.

После того как вы подготовили данные от датчиков, пришло время для реализации главного класса CameraViewActivity. Первая и наиболее важная вещь заключается в реализации инетрфейса SurfaceHolder.Callback который позволяет отправить изображение с камеры в наш макет и обработать связанные с этим различные события. Интерфейс реализует три метода, ответственных за это: surfaceChanged() surfaceCreated() surfaceDestroyed(). Позже мы рассмотрим реализыцию этих методов более подробно.

Класс CameraViewActivity имплементирует также интерфейсы OnLocationChangedListener, OnAzimuthChangedListener, с их методами onLocationChanged и onAzimuthChanged, а также интерфейс View.OnClickListener — слушатель нажатия кнопки с методом onClick.

В методе onCreate вызываем методы setupListeners(); setupLayout(); setAugmentedRealityPoint();
Теперь посмотрим манифест приложения:
Нам нужен доступ к камере, доступ к интернету и сетевым подключениям.
Для определения местоположения прописаны такие строчки:
  • android.permission.ACCESS_FINE_LOCATION – позволяет максимально точно определять местоположение, используя все доступные способы: GPS, Wi-Fi и сеть сотовой связи
  • ACCESS_COARSE_LOCATION — позволяет приложению получить доступ к приблизительному  местоположению.
  • com.google.android.providers.gsf.permission.READ_GSERVICES позволяет работать с гулокартами
Далее описаны 2 активити, причем для MapActivity указан атрибут android :name=»android.support.PARENT_ACTIVITY», определяющий его как дочернее по отношению к главному активити. Этот подход упрощает навигацию, размещая в экшнбаре MapActivity стрелку, ведущую назад к главному активити.
Также здесь видим секцию meta-data, где прописаны версия google_play_services и API_KEY для работы Google карт.
Как я уже говорил, для работы с Google Maps нужно получить apikey в консоли разработчика Google и прописать его здесь, в манифесте приложения. Ссылки на инструкции выше по тексту.
Итак наше приложение готово к запуску. Тестировать его нужно на реальном устройстве. Запускаем приложение и видим на экране превью камеры, а на нем — обновляющуюся информацию о местоположении и растоянии до цели, а также азимуты. Азимуты отображаются в градусах, а дистанция в условных единицах, примерно равных 0.9 м. В своем приложении я указал для покемона местоположение, которое совпадает с моим, поэтому на экране дистанция равна 0, что соответствует диапазону, указанному в условиии. А при совпадении азимутов в пределах константы в поле зрения камеры на экране появляется изображение покемона.
Чтобы посмотреть местоположение покемона на карте, нажмите кнопку Map. Открывается карта с меткой, указывающей местоположение покемона. А при нажатии метки появляется кнопка приложения GoogleMaps (если оно установлено на устройстве) с возможнстью открыть метку в приложении Google карты или расчитать маршрут до цели. Очень удобно, если вы разместили покемона далеко от вас.
device-2016-08-18-135749
Это я тестирую приложение на устройстве Nexus-5 которое имеет большой набор датчиков и без проблем расчитывает азимут. А если запустить приложение на Lenovo-820, например, то выяснится, что реальный азимут равен 0. Он не расчитывается, так на устройстве как нет необходимого сенсора. Расчитывается только дистанция до цели. Поэтому сейчас изображение покемона показывается на экране постоянно, независимо от того, куда я поворачиваю устройство. Но если я отойду от этой точки на дистанцию более 5 единиц, покемон исчезнет с экрана.
Ну вот , если вы до сих пор не бегали за покемонами по округе — у вас появился повод это сделать. вы можете тестировать приложение, меняя параметры, такие как целевое местоположение и константы допустимых значений. Экспериментируйте при получении и расчете данных сенсоров. добавляйте новые условия, расширяйте функционал приложения. например, в качестве простого домашнего задания добавьте возможность отображения на карте вашего местоположения. Ссылку на урок об этом найдете выше по тексту, где инструкция на работу с картами.
Делаем приложение с дополненной реальностью как PokemonGo обновлено: Август 18, 2016 автором: admin

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

*
*
Website