Как определить азимут на яндекс карте
Перейти к содержимому

Как определить азимут на яндекс карте

  • автор:

Как определить азимут по карте

Это таинственное слово азимут. Далеко не сразу понял, как им пользоваться. По правде говоря, не понимал по причине ненадобности, лишь появление детей все изменило. После штудирования учебника по навигации и небольшой практики начал осознавать, как много современные люди теряют в этом суетливом, вечно бегущем, технологическом мире. Так давайте вспомним озорное детство, вперёд за сокровищами!

Что такое азимут

Представьте себе, что от вас отходит две линии. Одна — на север. Вторая — в то место, к которому идете. Угол между этими линиями — и есть азимут.
На картинке более наглядно изображено.

Азимуты бывают разные, например:

  • астрономический;
  • географический;
  • магнитный;
  • прямой;
  • обратный.

Я перечислил только основные, есть и более специфические. К счастью, они нужны только в конкретных специальностях, а обычным людям можно глубоко не влазить в дебри.

Определение азимута по карте

Это самый легкий способ.
Чтобы определить азимут, необходимо знать своё текущее положение и положение цели.

Если вы знаете нужные координаты, то вычисление производится очень просто.
Ниже написал пошаговые действия для поиска азимута по карте:

  1. Отметить свое положение на карте.
  2. Отметить положение цели.
  3. Под линейку провести прямую через цель и текущее положение до пересечения с ближайшим меридианом с левой стороны.
  4. Замерить угол по часовой стрелке между проведенной прямой и меридианом.

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

Как использовать полученный азимут

Но беда в том, что для путешествия истинный азимут малопригоден. Ведь магнитное поле неоднородно, и не везде стрелка компаса показывает на север.
Для устранения этой погрешности существует магнитное склонение, для каждой местности оно свое и указывается на картах.
Для перехода к магнитному азимуту, по которому будете путешествовать, есть формула №1: Ам=А-(±δ), (1),
где Ам — магнитный азимут (он и нужен); А — истинный азимут; δ — магнитное склонение.

Надеюсь, мой ответ был полезен. Удачи вам.

как определить азимут от одного населенного пункта до другого. Определить по картам Яндекс или ГУГЛ.

Азимут- это угол между направление на север и направлением на местный предмет. Север на карте находится вверху.

Остальные ответы

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

Похожие вопросы
Ваш браузер устарел

Мы постоянно добавляем новый функционал в основной интерфейс проекта. К сожалению, старые браузеры не в состоянии качественно работать с современными программными продуктами. Для корректной работы используйте последние версии браузеров Chrome, Mozilla Firefox, Opera, Microsoft Edge или установите браузер Atom.

6. Азимут

1024px-Azimut_ru.svg.png

Единица измерения угла — градус , который записывается так: \(1°\). Градусом называют \(1/360\) долю окружности. Окружность циферблата компаса тоже поделена на \(360°\).

азимуты.png

Для определения азимута с помощью компаса его сначала ориентируют. Затем на компас кладут тонкую палочку по направлению от центра компаса к предмету.

compass.png

Азимут отсчитывают от севера по часовой стрелке в направлении на предмет. Так, направление на север имеет азимут \(0°\) или \(360°\), на восток — \(90°\), на юг — \(180°\), на запад — \(270°\).

компас и азимут 2.png

По рисунку мы видим, что азимут составляет:

  • на дом — \(40°\) ;
  • на колодец — \(140°\) ;
  • на мельницу — \(220°\) ;
  • на дерево — \(320°\) .

Yandex MapKit для новичков: разрабатываем карты в Android-приложении

Yandex MapKit — это кроссплатформенная библиотека, позволяющая использовать картографические данные и технологии Яндекса в мобильных приложениях. Список доступных возможностей действительно впечатляет, но разработчику, впервые столкнувшемуся с необходимостью работать с Яндекс-картами, многое может показаться непонятным и неочевидным в использовании.

Поэтому, чтобы научиться применять полезные особенности MapKit’a, мы с вами напишем небольшое приложение, в которое внедрим и настроим данную библиотеку: откроем определённую область на карте; выставим метку в нужном месте; установим на неё желаемые растровые и векторные изображения; поиграемся с зумом; обработаем нажатие на пин; а также будем при клике визуально выделять объекты на карте и получать от них интересующую нас информацию.

1) Введение: внедрение и настройка Yandex MapKit в проекте

Чтобы создать и запустить приложение с Яндекс-картами, первым делом необходимо:

  • Получить ключ;
  • Установить библиотеку MapKit;
  • Настроить библиотеку;
  • Собрать и запустить приложение.

Эти пункты весьма понятно и доступно описаны в документации. Дабы не копировать информацию, читателям предлагается самим ознакомиться, повторить данные шаги и затем запустить приложение с Яндекс-картой. Отметим, что в нашем приложении мы будем использовать полную full-версию библиотеки (на момент написания статьи — версия 4.3.1-full), а писать код на языке Kotlin, используя View Binding.

Отметим несколько важных моментов:

  • Какими знаниями вы должны обладать: Kotlin базовый уровень; умение собрать проект, запустить приложение на эмуляторе или телефоне, загрузить необходимые библиотеки; View Binding.
  • Ознакомьтесь с условиями использования MapKit. Так, например, нельзя скрывать логотип Яндекса на карте за другими объектами. Также, в вашем приложении в разделе «о программе» должна быть ссылка на условия использования Яндекс-карт.
  • API-ключ должен быть задан единожды перед инициализацией MapKitFactory. Хорошим тоном будет задать ключ при запуске приложения в методе Application.onCreate() , а инициализировать уже в других необходимых активити и фрагментах. Если же при каких-то условиях будет повторно вызван MapKitFactory.setApiKey(«Ваш API-ключ»), вы получите краш приложения и ошибку в логах: «java.lang.AssertionError: You need to set the API key before using MapKit!». Примером появления подобной ошибки может быть следующий сценарий: переход с одного экрана во фрагмент с Яндекс-картами, где мы задаём API-ключ (карта при этом откроется и будет адекватно работать) -> возвращаемся на предыдущий экран -> вновь открываем фрагмент с картами -> происходит краш приложения.
  • Допущения в данном проекте: в случае, если по каким-то причинам (как, например, в нашем приложении), логика работы карт и API-ключ находятся в одном активити/фрагменте, раздувать макет необходимо только после того, как установлен API-ключ. Иначе, проявится ошибка, указанная в предыдущем пункте. Также необходимо учесть момент пересоздания активити/фрагмента, например, для случая изменения ориентации экрана, вследствие чего вновь будет вызван метод MapKitFactory.setApiKey(«Ваш API-ключ»). Воспользуемся проверкой: установили ли мы ранее API-ключ для Яндекс-карт. Для этого сохраним данную информацию:
override fun onSaveInstanceState(outState: Bundle)

А при создании активности, в методе onCreate будем проверять, был ли уже установлен API-ключ ранее при помощи функции setApiKey:

private fun setApiKey(savedInstanceState: Bundle?) < val haveApiKey = savedInstanceState?.getBoolean("haveApiKey") ?: false // При первом запуске приложения всегда false if (!haveApiKey) < MapKitFactory.setApiKey(MAPKIT_API_KEY)>> // API-ключ должен быть задан единожды перед инициализацией MapKitFactory 

Что же, надеюсь, у вас получилось собрать проект со своей первой Яндекс-картой и перед вами на экране отобразились материки, моря да океаны:

Земля в иллюминаторе, Земля в иллюминаторе, Земля в иллюминаторе видна.

А код выглядит примерно следующим образом:

class MainActivity : AppCompatActivity() < private lateinit var binding: ActivityMainBinding override fun onCreate(savedInstanceState: Bundle?) < super.onCreate(savedInstanceState) setApiKey(savedInstanceState) // Проверяем: был ли уже ранее установлен API-ключ в приложении. Если нет - устанавливаем его. MapKitFactory.initialize(this) // Инициализация библиотеки для загрузки необходимых нативных библиотек. binding = ActivityMainBinding.inflate(layoutInflater) // Раздуваем макет только после того, как установили API-ключ setContentView(binding.root) // Размещаем пользовательский интерфейс в экране активности >private fun setApiKey(savedInstanceState: Bundle?) < val haveApiKey = savedInstanceState?.getBoolean("haveApiKey") ?: false // При первом запуске приложения всегда false if (!haveApiKey) < MapKitFactory.setApiKey(MAPKIT_API_KEY) // API-ключ должен быть задан единожды перед инициализацией MapKitFactory >> // Если Activity уничтожается (например, при нехватке памяти или при повороте экрана) - сохраняем информацию, что API-ключ уже был получен ранее override fun onSaveInstanceState(outState: Bundle) < super.onSaveInstanceState(outState) outState.putBoolean("haveApiKey", true) >// Отображаем карты перед моментом, когда активити с картой станет видимой пользователю: override fun onStart() < super.onStart() MapKitFactory.getInstance().onStart() binding.mapview.onStart() >// Останавливаем обработку карты, когда активити с картой становится невидимым для пользователя: override fun onStop() < binding.mapview.onStop() MapKitFactory.getInstance().onStop() super.onStop() >companion object < const val MAPKIT_API_KEY = "Ваш API-ключ" >>

Соответствующая разметка .xml:

Теперь, когда все готово, перейдём к ещё более интересным и полезным моментам – интерактивам с картой. Пример полного кода будет приведён в конце статьи, а также его можно найти в GitHub.

2) Открываем определённую область на карте

Первым делом сделаем так, чтобы при открытии карты нам сразу показывалась определённая область. Здесь и далее, при необходимости импорта, выбираем библиотеку Яндекса. Добавим новые переменные: startLocation – точку, содержащую координаты (широту и долготу), в которую должна переместиться камера и zoomValue – величину приближения к данной точке:

private val startLocation = Point(59.9402, 30.315) private var zoomValue: Float = 16.5f

Создадим функцию moveToStartLocation() , в которой у нашей mapview для карты вызовем метод, перемещающий камеру к необходимой позиции:

private fun moveToStartLocation()

Конструктор класса CameraPosition принимает, соответственно: точку с координатами, величину необходимого приближения, азимут и наклон (наклон камеры в градусах, добавляет визуально ощущение 3d). Максимальное возможное значение зума – 21.0f, минимальное – 0.0f. Также можем вызвать перегруженный метод move, чтобы перемещение в нужную область происходило красиво со стартовой анимацией:

binding.mapview.map.move( CameraPosition(startLocation, zoomValue, 0.0f, 0.0f), Animation(SMOOTH, 5f), null)

Здесь, помимо CameraPosition, дополнительно необходимо указать параметры анимации (которая зависит от типа animationType и длительности duration) и функцию CameraCallback , которая принимает логический аргумент, обозначающий завершение действия камеры. Если движение камеры по каким-то причинам прерывается, то в качестве аргумента передаётся «false»; если движение камеры завершилось успешно – «true». CameraCallback имеет необязательный тип, т.е. может быть не инициализирован – укажем здесь null.

Не забываем вызвать moveToStartLocation() в методе onCreate – и можем проверять работу перемещения камеры на стартовую локацию:

У моря над вольной Невой раскинулся каменный град - дворцов и соборов парад!

3) Устанавливаем метку на карте

Отметим нашу стартовую точку пином. Для начала загрузим в проект иконку с расширением png – скачайте файл ic_pin_png и перетащите его в папку drawable проекта.

Заранее создадим две переменные, которые проинициализируем и о которых более подробно расскажем далее:

private lateinit var mapObjectCollection: MapObjectCollection private lateinit var placemarkMapObject: PlacemarkMapObject

Реализуем функцию setMarkerInStartLocation() , отвечающую за установку метки на карте. В ней первым делом создаём ссылку на нашу картинку — marker. Затем инициализируем коллекцию различных возможных объектов на карте mapObjectCollection, которая может содержать любой набор элементов MapObject. MapObject – это пользовательский объект, отображаемый на карте, например, метка с иконкой или геометрическая фигура. Создадим такой геопозиционированный объект PlacemarkMapObject , являющийся наследником MapObject – метку с иконкой — который будет располагаться по координате, используемой ранее.

Для этого к mapObjectCollection применим метод addPlacemark , в котором укажем необходимую точку с координатами и, с помощью класса ImageProvider , ссылку на иконку. Таким образом мы создадим новую метку с нашим изображением и добавим её в текущую коллекцию. Если указать только точку с координатами, тогда получится пин со значком и стилем по умолчанию (будет выглядеть, как обычная точка на карте).

Дополнительно, к placemarkMapObject мы можем применить различные свойства, например, установить прозрачность метки и текст сверху в придачу при помощи команд setOpacity и setText соответственно. В итоге, произведя все вышеперечисленные действия, мы имеем следующую функцию:

private fun setMarkerInStartLocation() < val marker = R.drawable.ic_pin_black_png // Добавляем ссылку на картинку mapObjectCollection = binding.mapview.map.mapObjects // Инициализируем коллекцию различных объектов на карте placemarkMapObject = mapObjectCollection.addPlacemark(startLocation, ImageProvider.fromResource(this, marker)) // Добавляем метку со значком placemarkMapObject.opacity = 0.5f // Устанавливаем прозрачность метке placemarkMapObject.setText("Обязательно к посещению!") // Устанавливаем текст сверху метки >

Вызываем setMarkerFirstOpen() в onCreate, запускаем приложение и наблюдаем метку над Эрмитажем.

Вот он - один из крупнейших в мире художественных и культурно-исторических музеев.

4) Использование векторных изображений

Обычно мы используем не png файлы, а векторные изображения. Тут имеется одна неприятная особенность: векторные изображения в качестве маркеров в MapKit не поддерживаются – они просто не будут отображаться. Но данный момент можно обойти. ImageProvider умеет работать с bitmap. Таким образом, нам стоит просто перевести векторное изображение в bitmap и использовать по назначению. Для этого создадим соответствующую функцию:

private fun createBitmapFromVector(art: Int): Bitmap?

Используем её: загрузите приложенные векторные изображения ic_pin_black_svg, ic_pin_blue_svg и ic_pin_red_svg. Затем добавьте их в свой проект: правой кнопкой по папке drawable -> Vector Asset -> Local file -> установите размер 64dp X 64dp -> Finish.

После этого в функции setMarkerInStartLocation() исправим marker и placemarkMapObject на:

val marker = createBitmapFromVector(R.drawable.ic_pin_black_svg) placemarkMapObject = mapObjectCollection.addPlacemark(startLocation, ImageProvider.fromBitmap(marker))

Таким образом мы можем использовать в качестве иконок для меток и векторные и растровые изображения.

5) Работа с зумом: меняем иконку маркера при отдалении и приближении камеры

Теперь обработаем моменты увеличения и уменьшения масштаба карты пользователем: пусть при пересечении некоторой границы величины зума маркер становится красным при отдалении камеры и синим при приближении. Данную величину границы зума сразу вынесем в константу в companion object:

const val ZOOM_BOUNDARY = 16.4f

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

class MainActivity : AppCompatActivity(), CameraListener 

и переопределяем метод onCameraPositionChanged , который срабатывает при изменении положения камеры:

override fun onCameraPositionChanged( map: Map, cameraPosition: CameraPosition, cameraUpdateReason: CameraUpdateReason, finished: Boolean ) <>

Здесь параметрами являются:

  • map - новая область карты (будьте внимательны при импорте – это не коллекция Map);
  • cameraPosition - текущее положение камеры;
  • cameraUpdateReason - причина обновления камеры. Это enum-класс, включающий в себя две константы: APPLICATION – т.е. причиной обновления камеры является вызов приложением метода move; GESTURES – причиной являются действия пользователя, такие как масштабирование, поворот и прочее;
  • finished – завершилось ли движение камеры окончательно. Будет «true», если камера закончила движение, «false» - в противном случае.

Обсудим логику работы изменения иконки метки при регулировании масштаба отображения карты. После того как пользователь успешно приблизил или отдалил карту, т.е. finished==true, проверим величину нового зума. Если величина зума cameraPosition.zoom будет меньше фиксированного значения ZOOM_BOUNDARY - мы поменяем изображение метки на красную иконку. Иначе, будет установлен пин синего цвета. Так же, чтобы каждый раз не производить излишнюю замену иконки при изменении масштаба пользователем, когда порог ZOOM_BOUNDARY не был преодолён, добавим дополнительную проверку: стала ли новая величина зума больше или меньше фиксированного значения? Для этого будем перезаписывать значение zoomValue после каждого изменения масштаба карты пользователем. В итоге имеем:

override fun onCameraPositionChanged( map: Map, cameraPosition: CameraPosition, cameraUpdateReason: CameraUpdateReason, finished: Boolean ) < if (finished) < // Если камера закончила движение when < cameraPosition.zoom >= ZOOM_BOUNDARY && zoomValue  < placemarkMapObject.setIcon(ImageProvider.fromBitmap(createBitmapFromVector(R.drawable.ic_pin_blue_svg))) >cameraPosition.zoom = ZOOM_BOUNDARY -> < placemarkMapObject.setIcon(ImageProvider.fromBitmap(createBitmapFromVector(R.drawable.ic_pin_red_svg))) >> zoomValue = cameraPosition.zoom // После изменения позиции камеры сохраняем величину зума > >

И последний штрих: необходимо инициализировать метод слушателя камеры, чтобы логика, прописанная в onCameraPositionChanged , срабатывала. В onCreate добавляем следующую команду и после проверяем в приложении изменение иконки метки при регулировании масштаба:

binding.mapview.map.addCameraListener(this)

Далековато будет! А так уже и рассмотреть все можно в мельчайших деталях

6) Обработка события нажатия на метку

Перейдем к обработке события нажатия на пин – выведем всплывающее окно Toast с надписью.

Для этого нам понадобится интерфейс MapObjectTapListener, как раз отвечающий за тапы по различным объектам на карте. Создадим экземпляр класса MapObjectTapListener и переопределим onMapObjectTap, который возвращает «true», если событие было обработано, иначе – «false». При этом, мы можем использовать информацию о mapObject’е и точке с координатами, по которой произошёл тап. Мы же просто воспользуемся Toast’ом с фиксированным текстом:

private val mapObjectTapListener = object : MapObjectTapListener < override fun onMapObjectTap(mapObject: MapObject, point: Point): Boolean< Toast.makeText(applicationContext, "Эрмитаж — музей изобразительных искусств", Toast.LENGTH_SHORT).show() return true >>

Интерфейс MapObjectTapListener может быть присоединён к любому MapObject’у. Подключим этот слушатель в функции setMarkerFirstOpen() к нашей метке placemarkMapObject :

placemarkMapObject.addTapListener(mapObjectTapListener)

Готово! Теперь, при тапе на метку, будет появляться всплывающее окно с необходимой информацией.

Осведомлён - значит вооружён!

Отдельно отметим, почему мы создаем отдельную переменную mapObjectTapListener , а не сразу пишем в функции setMarkerFirstOpen подобным образом:

placemarkMapObject.addTapListener(object : MapObjectTapListener < override fun onMapObjectTap(mapObject: MapObject, point: Point): Boolean< Toast.makeText(applicationContext, "Эрмитаж — музей изобразительных искусств", Toast.LENGTH_SHORT).show() return true>>)

Дело в том, что MapKit хранит слабые ссылки на передаваемые ему Listener-объекты, поэтому их необходимо сохранять на стороне приложения. Иначе, первое время клики будут работать адекватно, а затем перестанут реагировать на тапы. Это связано с тем, что сборщик мусора, который не учитывает связь ссылки и объекта в куче при выявлении объектов, подлежащих удалению, в какой-то момент удалит наш слушатель. После этого при тапе на пин в логах возникнет неприятное сообщение: «yandex.maps.runtime: Java object is already finalized. Nothing to do» и клики перестанут обрабатываться должным образом. Поэтому, необходимо использовать строгую ссылку на объект MapObjectTapListener, что мы и делаем выше.

Бонусные разделы

Весьма полезной и интересной темой в Mapkit является получения информации об объекте, используя поиск и метаданные. Поскольку наш туториал рассчитан на новичков, сейчас мы не будем подробно разбираться в том, как именно устроен поиск и как работать с метаданными в mapkit. Но, в качестве дополнительной полезной информации, без особой конкретики и не раскрывая темы в полном объёме, приведём примеры кода с использованием этих моментов в пунктах 7*) и 8*). Более подробно прочитать о данных возможностях Mapkit можно в статье «Поиск в MapKit: Tips & Tricks».

7) Выделение объекта на карте

Продолжим знакомство со слушателями объектов на карте. Теперь будем работать с GeoObject – объектом в слоях карты, примером которого может выступать здание или памятник. Слушателем будет выступать экземпляр класса GeoObjectTapListener, в котором требуется переопределить onObjectTap. Метод onObjectTap позволяет извлечь краткую информацию затронутого геообъекта и возвращает булевское значение. Так, если мы вернём «false» – тогда событие клика распространится на карту, и его сможет перехватить другой слушатель. Если «true» – «дальше» событие никуда не пойдёт. Пример: если пользователь клацает на объект, а в проекте имеется дополнительный слушатель, обрабатывающий действия по всей карте (как, например, в пункте 8), то при значении «true» для onObjectTap данное событие более перехвачено не будет.

Давайте подсветим какое-либо здание при тапе на него, иначе говоря, отобразим для пользователя «выделение» объекта. Для этого нам понадобятся идентификаторы объекта и слоя. Получим геообъект из geoObjectTapEvent методом getGeoObject. Информация про геообъект хранится в метаданных. Метаданные бывают разных видов, более подробно можно ознакомиться в «Поиск в MapKit: Tips & Tricks». Доступ к информации можно получить с помощью метода getMetadataContainer(), для которого с помощью метода getItem указываем ключ для этого контейнера - тип необходимых метаданных. У нас данный ключ – GeoObjectSelectionMetadata.

После того как мы получили метаданные, для карты mapview используем метод selectGeoObject, в который передаем необходимые идентификаторы объекта и слоя:

private val tapListener = object : GeoObjectTapListener < override fun onObjectTap(geoObjectTapEvent: GeoObjectTapEvent): Boolean < val selectionMetadata: GeoObjectSelectionMetadata = geoObjectTapEvent .geoObject .metadataContainer .getItem(GeoObjectSelectionMetadata::class.java) binding.mapview.map.selectGeoObject(selectionMetadata.id, selectionMetadata.layerId) return false >>

Подключаем данный слушатель:

binding.mapview.map.addTapListener(tapListener) // Добавляем карте слушатель тапов по объектам

Теперь, при клике на здание, оно выделится следующим образом:

Ага, теперь я тебя точно не потеряю из виду!

8) Получаем информацию об объекте при тапе на него

Осуществим следующую идею: при тапе в любую область карты будет появляться всплывающее окно с информацией об улице в данном месте. Если по каким-то причинам улицы нет, например, если тапнули по реке или не пришел ответ от сервера – будем выводить соответствующее сообщение.

В переопределённой функции onSearchResponse, последовательно используя различные вызовы, мы сможем докопаться до интересующей нас сущности – будь то улица, дом, маршрут, страна и прочее. А данную информацию можем использовать уже как угодно, например, поместить в Toast:

private val searchListener = object : Session.SearchListener < override fun onSearchResponse(response: Response) < val street = response.collection.children.firstOrNull()?.obj ?.metadataContainer ?.getItem(ToponymObjectMetadata::class.java) ?.address ?.components ?.firstOrNull < it.kinds.contains(Address.Component.Kind.STREET)>?.name ?: "Информация об улице не найдена" Toast.makeText(applicationContext, street, Toast.LENGTH_SHORT).show() > override fun onSearchError(p0: Error) < >>

Предварительно создадим две новые переменные: поисковую сессию searchSession и интерфейс для начала поиска searchManager, которые проинициализируем далее:

lateinit var searchManager: SearchManager lateinit var searchSession: Session

Теперь searchListener надо поместить в другой слушатель – inputListener, который обрабатывает тапы по всей карте. В нем переопределяются два метода – короткое и длинное нажатие. onMapTap - вызывается при быстром касании, если оно не было обработано геообъектами или объектами карты. Как уже говорилось ранее в пункте 7: если касание было обработано onObjectTap, то onMapTap может не сработать. Чтобы метод адекватно обработал тап – в onObjectTap необходимо вернуть «false». В самом методе onMapTap инициализируем поисковую сессию searchSession:

private val inputListener = object : InputListener < override fun onMapTap(map: Map, point: Point) < searchSession = searchManager.submit(point, 20, SearchOptions(), searchListener) >override fun onMapLongTap(map: Map, point: Point) <> >

Метод обратного поиска submit требует на вход точку с координатами, величину зума (в окрестности которой будет происходить поиск), настройки поиска и слушатель.

После, в методе onCreate инициализируем searchManager и добавляем к нашей карте слушатель тапов по карте с извлечением информации:

searchManager = SearchFactory.getInstance().createSearchManager(SearchManagerType.ONLINE) binding.mapview.map.addInputListener(inputListener) // Добавляем слушатель тапов по карте с извлечением информации

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

Окей, Яндекс, а где тут самые вкусные пышки, не подскажешь?

Заключение

Yandex MapKit предоставляет гигантское количество возможностей, с помощью которых можно реализовать самые различные интересные и полезные идеи. Сегодня мы познакомились с основными моментами использования Яндекс-карт: были показаны часто используемые методы, даны различные рекомендации и хитрости для проблемных мест, ответы на вероятно возникающие вопросы при первом знакомстве с данной библиотекой.

Данная статья не является исчерпывающей, наоборот - с помощью Yandex MapKit’а можно решить множество разнообразных задач: построить маршрут для пешей прогулки иль поездки на общественном транспорте; отобразить на карте ближайший к пользователю банкомат; найти нужную организацию; узнать о пробках на дорогах в реальном времени; предоставить местоположение пользователя; использовать панорамы; получить какую-либо информацию об объекте на карте и многое, многое другое.

Дополнительно ознакомиться с примерами реализации части функционала можно здесь.

Искренне надеюсь, что полученные сегодня знания ускорили ваш порог вхождения в Яндекс MapKit, дали понимание, каким образом можно взаимодействовать и работать с Яндекс-картами в плане разработки.

Дерзайте! И помните: «Дорогу осилит идущий».

Список используемой литературы:

  • Руководство MapKit;
  • Условия использования MapKit;
  • Статья «Поиск в MapKit: Tips & Tricks»;
  • Примеры некоторых возможностей Mapkit;
  • Проект на Github.

Код программы

Код программы

class MainActivity : AppCompatActivity(), CameraListener < private lateinit var binding: ActivityMainBinding private lateinit var mapObjectCollection: MapObjectCollection // Коллекция различных объектов на карте private lateinit var placemarkMapObject: PlacemarkMapObject // Геопозиционированный объект (метка со значком) на карте private val startLocation = Point(59.9402, 30.315) // Координаты Эрмитажа private var zoomValue: Float = 16.5f // Величина зума lateinit var searchManager: SearchManager lateinit var searchSession: Session private val mapObjectTapListener = object : MapObjectTapListener < override fun onMapObjectTap(mapObject: MapObject, point: Point): Boolean < Toast.makeText(applicationContext, "Эрмитаж — музей изобразительных искусств", Toast.LENGTH_SHORT).show() return true >> private val geoObjectTapListener = object : GeoObjectTapListener < override fun onObjectTap(geoObjectTapEvent: GeoObjectTapEvent): Boolean < val selectionMetadata: GeoObjectSelectionMetadata = geoObjectTapEvent .geoObject .metadataContainer .getItem(GeoObjectSelectionMetadata::class.java) binding.mapview.map.selectGeoObject(selectionMetadata.id, selectionMetadata.layerId) return false >> private val searchListener = object : Session.SearchListener < override fun onSearchResponse(response: Response) < val street = response.collection.children.firstOrNull()?.obj ?.metadataContainer ?.getItem(ToponymObjectMetadata::class.java) ?.address ?.components ?.firstOrNull < it.kinds.contains(Address.Component.Kind.STREET) >?.name ?: "Информация об улице не найдена" Toast.makeText(applicationContext, street, Toast.LENGTH_SHORT).show() > override fun onSearchError(p0: Error) < >> private val inputListener = object : InputListener < override fun onMapTap(map: Map, point: Point) < searchSession = searchManager.submit(point, 20, SearchOptions(), searchListener) >override fun onMapLongTap(map: Map, point: Point) <> > override fun onCreate(savedInstanceState: Bundle?) < super.onCreate(savedInstanceState) setApiKey(savedInstanceState) // Проверяем: был ли уже ранее установлен API-ключ в приложении. Если нет - устанавливаем его. MapKitFactory.initialize(this) // Инициализация библиотеки для загрузки необходимых нативных библиотек. binding = ActivityMainBinding.inflate(layoutInflater) // Раздуваем макет только после того, как установили API-ключ setContentView(binding.root) // Размещаем пользовательский интерфейс в экране активности moveToStartLocation() // Перемещаем камеру в определенную область на карте setMarkerInStartLocation() // Устанавливаем маркер на карте binding.mapview.map.addCameraListener(this) // Добавляем карте слушатель камеры для слежки за изменением величины зума binding.mapview.map.addTapListener(geoObjectTapListener) // Добавляем слушатель тапов по объектам searchManager = SearchFactory.getInstance().createSearchManager(SearchManagerType.ONLINE) binding.mapview.map.addInputListener(inputListener) // Добавляем слушатель тапов по карте с извлечением информации >override fun onCameraPositionChanged( map: Map, cameraPosition: CameraPosition, cameraUpdateReason: CameraUpdateReason, finished: Boolean ) < if (finished) < // Если камера закончила движение when < cameraPosition.zoom >= ZOOM_BOUNDARY && zoomValue  < placemarkMapObject.setIcon(ImageProvider.fromBitmap(createBitmapFromVector(R.drawable.ic_pin_blue_svg))) >cameraPosition.zoom = ZOOM_BOUNDARY -> < placemarkMapObject.setIcon(ImageProvider.fromBitmap(createBitmapFromVector(R.drawable.ic_pin_red_svg))) >> zoomValue = cameraPosition.zoom // После изменения позиции камеры сохраняем величину зума > > private fun setMarkerInStartLocation() < val marker = createBitmapFromVector(R.drawable.ic_pin_black_svg) mapObjectCollection = binding.mapview.map.mapObjects // Инициализируем коллекцию различных объектов на карте placemarkMapObject = mapObjectCollection.addPlacemark(startLocation, ImageProvider.fromBitmap(marker)) // Добавляем метку со значком placemarkMapObject.opacity = 0.5f // Устанавливаем прозрачность метке placemarkMapObject.setText("Обязательно к посещению!") // Устанавливаем текст сверху метки placemarkMapObject.addTapListener(mapObjectTapListener) >private fun createBitmapFromVector(art: Int): Bitmap? < val drawable = ContextCompat.getDrawable(this, art) ?: return null val bitmap = Bitmap.createBitmap( drawable.intrinsicWidth, drawable.intrinsicHeight, Bitmap.Config.ARGB_8888 ) ?: return null val canvas = Canvas(bitmap) drawable.setBounds(0, 0, canvas.width, canvas.height) drawable.draw(canvas) return bitmap >private fun moveToStartLocation() < binding.mapview.map.move( CameraPosition(startLocation, zoomValue, 0.0f, 0.0f), // Позиция камеры Animation(Type.SMOOTH, 2f), // Красивая анимация при переходе на стартовую точку null ) >private fun setApiKey(savedInstanceState: Bundle?) < val haveApiKey = savedInstanceState?.getBoolean("haveApiKey") ?: false // При первом запуске приложения всегда false if (!haveApiKey) < MapKitFactory.setApiKey(MAPKIT_API_KEY) // API-ключ должен быть задан единожды перед инициализацией MapKitFactory >> // Если Activity уничтожается (например, при нехватке памяти или при повороте экрана) - сохраняем информацию, что API-ключ уже был получен ранее override fun onSaveInstanceState(outState: Bundle) < super.onSaveInstanceState(outState) outState.putBoolean("haveApiKey", true) >// Отображаем карты перед тем моментом, когда активити с картой станет видимой пользователю: override fun onStart() < super.onStart() MapKitFactory.getInstance().onStart() binding.mapview.onStart() >// Останавливаем обработку карты, когда активити с картой становится невидимым для пользователя: override fun onStop() < binding.mapview.onStop() MapKitFactory.getInstance().onStop() super.onStop() >companion object < const val MAPKIT_API_KEY = "Ваш API-ключ" const val ZOOM_BOUNDARY = 16.4f >>

activity_main.xml

Также код можно посмотреть в GitHub.

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

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