API маршрутов Google – это служба, которая рассчитывает маршруты между пунктами на карте с помощью HTTP-запроса. Поддерживается поиск маршрутов для различных способов перемещения, в том числе на общественном транспорте, автомобиле, велосипеде или пешком. При поиске маршрутов пункты отправления, назначения, а также путевые точки могут указываться либо в виде текстовых запросов (например, "Химки, Мега" или "Химки, Дубки, 6"), либо в виде значений координат — широты и долготы. API маршрутов может возвращать составные маршруты в виде последовательности путевых точек.
Добавьте на форму следующие элементы управления:
button1 – элемент управления необходимый для запуска процесса формирования и чтения ответы о службы API маршрутов Google;
textBox1 – текстовое поле для ввода адреса отправления;
textBox2 – текстовое поле для ввода адреса назначения;
dataGridView1 – элемент управления для вывода контрольных точек маршрута с описанием каждого шага;
textBox3 – текстовое поле для вывода времени, которое обычно требуется для выполнения этого маршрута;
textBox4 - текстовое поле для вывода расстояния, от начальной точки маршрута до конечной;
textBox5 - текстовое поле для вывода координат начальной точки отправления;
textBox6 - текстовое поле для вывода координат конечной точки прибытия;
comboBox1 – элемент управления для определения способа перемещения;
А так же в соответствии с инструкцией «Работа с картами в Windows Form с использованием GMap.NET», добавьте визуальный компонент «GMap.NET». У вас получится приведенный ниже пример.
Сделайте двойной клик по пустому пространству главной формы, вы перейдете в автоматически созданный метод загрузки главной формы «Form1_Load». Добавьте в него приведенный ниже код установки настроек для элемента управления «gMapControl1», создания таблицы для хранения контрольных точек маршрута и заполнением элемента управления «comboBox1», способами передвижения.
Эта служба разработана для вычисления маршрутов к статическим (известным заранее) адресам для места размещения содержимого приложения на карте. Она не рассчитана, например, на то, чтобы в режиме реальном времени отвечать на ввод пользователя. На использование службы API маршрутов Google накладывается ограничение, составляющее 2500 запросов маршрутов в день. Поиск автомобильного, велосипедного или пешеходного маршрута учитывается при расчете ежедневной квоты как один запрос. Поиск маршрута общественного транспорта учитывается как 4 запроса. Отдельные запросы автомобильных, велосипедных или пешеходных маршрутов могут содержать до 8 промежуточных путевых точек. Пользователи API Google Карт для организаций в течение дня могут запрашивать до 100 000 маршрутов, для каждого из которых допускается до 23 путевых точек. Для маршрутов общественного транспорта путевые точки не поддерживаются.
Кроме того, прежде чем выполнять кодирование адресов URL, убедитесь в том, что адреса URL для API маршрутов содержат не более 2048 символов. Помните об этом ограничении, формируя адреса URL, поскольку некоторые адреса URL, используемые службой маршрутов, могут привести к включению в маршрут нескольких пунктов.
Примечание. API маршрутов можно применять только для отображения результатов на карте Google. Использование данных службы маршрутов без отображения карты, для которой они запрашивались, запрещено. Кроме того, при вычислении маршрутов формируются данные об авторских правах и предупреждения, которые каким-либо способом должны быть показаны пользователю. Дополнительную информацию по использованию данного сервиса вы можете получить по следующему адресу: https://developers.google.com/maps/.
Запустите Microsoft Visual Studio и создайте новый проект Windows Form.Кроме того, прежде чем выполнять кодирование адресов URL, убедитесь в том, что адреса URL для API маршрутов содержат не более 2048 символов. Помните об этом ограничении, формируя адреса URL, поскольку некоторые адреса URL, используемые службой маршрутов, могут привести к включению в маршрут нескольких пунктов.
Примечание. API маршрутов можно применять только для отображения результатов на карте Google. Использование данных службы маршрутов без отображения карты, для которой они запрашивались, запрещено. Кроме того, при вычислении маршрутов формируются данные об авторских правах и предупреждения, которые каким-либо способом должны быть показаны пользователю. Дополнительную информацию по использованию данного сервиса вы можете получить по следующему адресу: https://developers.google.com/maps/.
Добавьте на форму следующие элементы управления:
button1 – элемент управления необходимый для запуска процесса формирования и чтения ответы о службы API маршрутов Google;
textBox1 – текстовое поле для ввода адреса отправления;
textBox2 – текстовое поле для ввода адреса назначения;
dataGridView1 – элемент управления для вывода контрольных точек маршрута с описанием каждого шага;
textBox3 – текстовое поле для вывода времени, которое обычно требуется для выполнения этого маршрута;
textBox4 - текстовое поле для вывода расстояния, от начальной точки маршрута до конечной;
textBox5 - текстовое поле для вывода координат начальной точки отправления;
textBox6 - текстовое поле для вывода координат конечной точки прибытия;
comboBox1 – элемент управления для определения способа перемещения;
А так же в соответствии с инструкцией «Работа с картами в Windows Form с использованием GMap.NET», добавьте визуальный компонент «GMap.NET». У вас получится приведенный ниже пример.
Сделайте двойной клик по пустому пространству главной формы, вы перейдете в автоматически созданный метод загрузки главной формы «Form1_Load». Добавьте в него приведенный ниже код установки настроек для элемента управления «gMapControl1», создания таблицы для хранения контрольных точек маршрута и заполнением элемента управления «comboBox1», способами передвижения.
//Настройки для компонента GMap. gMapControl1.Bearing = 0; //CanDragMap - Если параметр установлен в True, //пользователь может перетаскивать карту //с помощью правой кнопки мыши. gMapControl1.CanDragMap = true; //Указываем, что перетаскивание карты осуществляется //с использованием левой клавишей мыши. //По умолчанию - правая. gMapControl1.DragButton = MouseButtons.Left; gMapControl1.GrayScaleMode = true; //MarkersEnabled - Если параметр установлен в True, //любые маркеры, заданные вручную будет показаны. //Если нет, они не появятся. gMapControl1.MarkersEnabled = true; //Указываем значение максимального приближения. gMapControl1.MaxZoom = 18; //Указываем значение минимального приближения. gMapControl1.MinZoom = 2; //Устанавливаем центр приближения/удаления для //курсора мыши. gMapControl1.MouseWheelZoomType = GMap.NET.MouseWheelZoomType.MousePositionAndCenter; //Отказываемся от негативного режима. gMapControl1.NegativeMode = false; //Разрешаем полигоны. gMapControl1.PolygonsEnabled = true; //Разрешаем маршруты. gMapControl1.RoutesEnabled = true; //Скрываем внешнюю сетку карты //с заголовками. gMapControl1.ShowTileGridLines = false; //Указываем, что при загрузке карты будет использоваться //2х кратное приближение. gMapControl1.Zoom = 2; //Указываем что будем использовать карты Google. gMapControl1.MapProvider = GMap.NET.MapProviders.GMapProviders.GoogleMap; GMap.NET.GMaps.Instance.Mode = GMap.NET.AccessMode.ServerOnly; //Если вы используете интернет через прокси сервер, //указываем свои учетные данные. GMap.NET.MapProviders.GMapProvider.WebProxy = System.Net.WebRequest.GetSystemWebProxy(); GMap.NET.MapProviders.GMapProvider.WebProxy.Credentials = System.Net.CredentialCache.DefaultCredentials; //инициализируем новую таблицу, //для хранения данных о маршруте. dtRouter = new DataTable(); //Добавляем в инициализированную таблицу, //новые колонки. dtRouter.Columns.Add("Шаг"); dtRouter.Columns.Add("Нач. точка (latitude)"); dtRouter.Columns.Add("Нач. точка (longitude)"); dtRouter.Columns.Add("Кон. точка (latitude)"); dtRouter.Columns.Add("Кон. точка (longitude)"); dtRouter.Columns.Add("Время пути"); dtRouter.Columns.Add("Расстояние"); dtRouter.Columns.Add("Описание маршрута"); //Задаем источник данных, для объекта //System.Windows.Forms.DataGridView. dataGridView1.DataSource = dtRouter; //Задаем ширину седьмого столбца. dataGridView1.Columns[7].Width = 250; //Задаем значение, указывающее, что необходимо скрыть //для пользователя параметр добавления строк. dataGridView1.AllowUserToAddRows = false; //Задаем значение, указывающее, что пользователю //запрещено удалять строки. dataGridView1.AllowUserToDeleteRows = false; //Задаем значение, указывающее, что пользователь //не может изменять ячейки элемента управления. dataGridView1.ReadOnly = false; //Добавляем способы перемещения. comboBox1.Items.Add("Автомобильные маршруты"); comboBox1.Items.Add("Пешеходные маршруты"); comboBox1.Items.Add("Велосипедные маршруты"); comboBox1.Items.Add("Маршруты общественного транспорта"); //Выставляем по умолчанию способ перемещения: //Автомобильные маршруты по улично-дорожной сети. comboBox1.SelectedIndex = 0;Перейдите в Конструктор главной формы и сделайте двойной клик левой клавишей мыши по элементу управления «button1». Вы перейдете в автоматически созданный метод «button1_Click», события «Click», возникающего при нажатии на данный элемент управления. Добавьте приведенный ниже код реализующего отправку запроса и чтения ответа службы API маршрутов Google, в тело данного метода. А так же глобальную переменную инициализации таблицы и метод удаления HTML тегов из текста описания маршрута.
DataTable dtRouter; private void button1_Click(object sender, EventArgs e) { //Очищаем таблицу перед загрузкой данных. dtRouter.Rows.Clear(); //Создаем список способов перемещения. ListЗапустите проект, нажав на клавиатуре клавишу «F5». После полной загрузки вашего проекта, вы увидите в минимальном масштабе карту. Введите в текстовое поле «Куда» адрес отправления, например: «Москва, Красная площадь», а в текстовое поле «От Куда» адрес отправления, например: «Химки, МЕГА». У вас откроется карта с найденными адресами и проложенным маршрутом. Ниже представлены примеры работы тестового проекта.mode = new List (); //Автомобильные маршруты по улично-дорожной сети. mode.Add("driving"); //Пешеходные маршруты по прогулочным дорожкам и тротуарам. mode.Add("walking"); //Велосипедные маршруты по велосипедным дорожкам и предпочитаемым улицам. mode.Add("bicycling"); //Маршруты общественного транспорта. mode.Add("transit"); //Фомируем запрос к API маршрутов Google. string url = string.Format( "http://maps.googleapis.com/maps/api/directions/xml?origin={0},&destination={1}&sensor=false&language=ru&mode={2}", Uri.EscapeDataString(textBox1.Text), Uri.EscapeDataString(textBox2.Text), Uri.EscapeDataString(mode[comboBox1.SelectedIndex])); //Выполняем запрос к универсальному коду ресурса (URI). System.Net.HttpWebRequest request = (System.Net.HttpWebRequest)System.Net.WebRequest.Create(url); //Получаем ответ от интернет-ресурса. System.Net.WebResponse response = request.GetResponse(); //Экземпляр класса System.IO.Stream //для чтения данных из интернет-ресурса. System.IO.Stream dataStream = response.GetResponseStream(); //Инициализируем новый экземпляр класса //System.IO.StreamReader для указанного потока. System.IO.StreamReader sreader = new System.IO.StreamReader(dataStream); //Считываем поток от текущего положения до конца. string responsereader = sreader.ReadToEnd(); //Закрываем поток ответа. response.Close(); System.Xml.XmlDocument xmldoc = new System.Xml.XmlDocument(); xmldoc.LoadXml(responsereader); if (xmldoc.GetElementsByTagName("status")[0].ChildNodes[0].InnerText == "OK") { System.Xml.XmlNodeList nodes = xmldoc.SelectNodes("//leg//step"); //Формируем строку для добавления в таблицу. object[] dr; for (int i = 0; i < nodes.Count; i++) { //Указываем что массив будет состоять из //восьми значений. dr = new object[8]; //Номер шага. dr[0] = i; //Получение координат начала отрезка. dr[1] = xmldoc.SelectNodes("//start_location").Item(i).SelectNodes("lat").Item(0).InnerText.ToString(); dr[2] = xmldoc.SelectNodes("//start_location").Item(i).SelectNodes("lng").Item(0).InnerText.ToString(); //Получение координат конца отрезка. dr[3] = xmldoc.SelectNodes("//end_location").Item(i).SelectNodes("lat").Item(0).InnerText.ToString(); dr[4] = xmldoc.SelectNodes("//end_location").Item(i).SelectNodes("lng").Item(0).InnerText.ToString(); //Получение времени необходимого для прохождения этого отрезка. dr[5] = xmldoc.SelectNodes("//duration").Item(i).SelectNodes("text").Item(0).InnerText.ToString(); //Получение расстояния, охватываемое этим отрезком. dr[6] = xmldoc.SelectNodes("//distance").Item(i).SelectNodes("text").Item(0).InnerText.ToString(); //Получение инструкций для этого шага, представленные в виде текстовой строки HTML. dr[7] = HtmlToPlainText(xmldoc.SelectNodes("//html_instructions").Item(i).InnerText.ToString()); //Добавление шага в таблицу. dtRouter.Rows.Add(dr); } //Выводим в текстовое поле адрес начала пути. textBox1.Text = xmldoc.SelectNodes("//leg//start_address").Item(0).InnerText.ToString(); //Выводим в текстовое поле адрес конца пути. textBox2.Text = xmldoc.SelectNodes("//leg//end_address").Item(0).InnerText.ToString(); //Выводим в текстовое поле время в пути. textBox3.Text = xmldoc.GetElementsByTagName("duration")[nodes.Count].ChildNodes[1].InnerText; //Выводим в текстовое поле расстояние от начальной до конечной точки. textBox4.Text = xmldoc.GetElementsByTagName("distance")[nodes.Count].ChildNodes[1].InnerText; //Переменные для хранения координат начала и конца пути. double latStart = 0.0; double lngStart = 0.0; double latEnd = 0.0; double lngEnd = 0.0; //Получение координат начала пути. latStart = System.Xml.XmlConvert.ToDouble(xmldoc.GetElementsByTagName("start_location")[nodes.Count].ChildNodes[0].InnerText); lngStart = System.Xml.XmlConvert.ToDouble(xmldoc.GetElementsByTagName("start_location")[nodes.Count].ChildNodes[1].InnerText); //Получение координат конечной точки. latEnd = System.Xml.XmlConvert.ToDouble(xmldoc.GetElementsByTagName("end_location")[nodes.Count].ChildNodes[0].InnerText); lngEnd = System.Xml.XmlConvert.ToDouble(xmldoc.GetElementsByTagName("end_location")[nodes.Count].ChildNodes[1].InnerText); //Выводим в текстовое поле координаты начала пути. textBox5.Text = latStart + ";" + lngStart; //Выводим в текстовое поле координаты конечной точки. textBox6.Text = latEnd + ";" + lngEnd; //Устанавливаем заполненную таблицу в качестве источника. dataGridView1.DataSource = dtRouter; //Устанавливаем позицию карты на начало пути. gMapControl1.Position = new GMap.NET.PointLatLng(latStart, lngStart); //Создаем новый список маркеров, с указанием компонента //в котором они будут использоваться и названием списка. GMap.NET.WindowsForms.GMapOverlay markersOverlay = new GMap.NET.WindowsForms.GMapOverlay(gMapControl1, "marker"); //Инициализация нового ЗЕЛЕНОГО маркера, с указанием координат начала пути. GMap.NET.WindowsForms.Markers.GMapMarkerGoogleGreen markerG = new GMap.NET.WindowsForms.Markers.GMapMarkerGoogleGreen( new GMap.NET.PointLatLng(latStart, lngStart)); markerG.ToolTip = new GMap.NET.WindowsForms.ToolTips.GMapRoundedToolTip(markerG); //Указываем, что подсказку маркера, необходимо отображать всегда. markerG.ToolTipMode = GMap.NET.WindowsForms.MarkerTooltipMode.Always; //Формируем подсказку для маркера. string[] wordsG = textBox1.Text.Split(','); string dataMarkerG = string.Empty; foreach (string word in wordsG) { dataMarkerG += word + ";\n"; } //Устанавливаем текст подсказки маркера. markerG.ToolTipText = dataMarkerG; //Инициализация нового Красного маркера, с указанием координат конца пути. GMap.NET.WindowsForms.Markers.GMapMarkerGoogleRed markerR = new GMap.NET.WindowsForms.Markers.GMapMarkerGoogleRed( new GMap.NET.PointLatLng(latEnd, lngEnd)); markerG.ToolTip = new GMap.NET.WindowsForms.ToolTips.GMapRoundedToolTip(markerG); //Указываем, что подсказку маркера, необходимо отображать всегда. markerR.ToolTipMode = GMap.NET.WindowsForms.MarkerTooltipMode.Always; //Формируем подсказку для маркера. string[] wordsR = textBox2.Text.Split(','); string dataMarkerR = string.Empty; foreach (string word in wordsR) { dataMarkerR += word + ";\n"; } //Текст подсказки маркера. markerR.ToolTipText = dataMarkerR; //Добавляем маркеры в список маркеров. markersOverlay.Markers.Add(markerG); markersOverlay.Markers.Add(markerR); //Очищаем список маркеров компонента. gMapControl1.Overlays.Clear(); //Создаем список контрольных точек для прокладки маршрута. List list = new List (); //Проходимся по определенным столбцам для получения //координат контрольных точек маршрута и занесением их //в список координат. for (int i = 0; i < dtRouter.Rows.Count; i++) { double dbStartLat = double.Parse(dtRouter.Rows[i].ItemArray[1].ToString(), System.Globalization.CultureInfo.InvariantCulture); double dbStartLng = double.Parse(dtRouter.Rows[i].ItemArray[2].ToString(), System.Globalization.CultureInfo.InvariantCulture); list.Add(new GMap.NET.PointLatLng(dbStartLat, dbStartLng)); double dbEndLat = double.Parse(dtRouter.Rows[i].ItemArray[3].ToString(), System.Globalization.CultureInfo.InvariantCulture); double dbEndLng = double.Parse(dtRouter.Rows[i].ItemArray[4].ToString(), System.Globalization.CultureInfo.InvariantCulture); list.Add(new GMap.NET.PointLatLng(dbEndLat, dbEndLng)); } //Очищаем все маршруты. markersOverlay.Routes.Clear(); //Создаем маршрут на основе списка контрольных точек. GMap.NET.WindowsForms.GMapRoute r = new GMap.NET.WindowsForms.GMapRoute(list, "Route"); //Указываем, что данный маршрут должен отображаться. r.IsVisible = true; //Устанавливаем цвет маршрута. r.Stroke.Color = Color.DarkGreen; //Добавляем маршрут. markersOverlay.Routes.Add(r); //Добавляем в компонент, список маркеров и маршрутов. gMapControl1.Overlays.Add(markersOverlay); //Указываем, что при загрузке карты будет использоваться //9ти кратное приближение. gMapControl1.Zoom = 9; //Обновляем карту. gMapControl1.Refresh(); } } //Удаляем HTML теги. public string HtmlToPlainText(string html) { html = html.Replace("/b",""); return html.Replace("b", ""); }
Ссылка для скачивания примера: Яндекс.Диск
Супер! То, что я искал! Вы просто молодцы
ОтветитьУдалитьв 1 примере вылетает постоянно ошибка "Не удается выполнить привязки исполняющей среды по нулевой ссылке"
ОтветитьУдалитьЗдравствуйте,Евгений, при выполнении отладки кода из примера №1, на какую строку выпадает ошибка?
ОтветитьУдалитьа при этом клавиши TAB или например Space отдельно работать будут?
ОтветитьУдалитьЗдравствуйте, Ден, да будут, как вы могли заметить, блокировка выполняется только при выполнении условия нажатия определенных сочетаний клавиш. Например : objKeyInfo.key == Keys.RWin || objKeyInfo.key == Keys.LWin .
ОтветитьУдалитьВсё отлично, благодарю за урок.
ОтветитьУдалитьОднако вот это забыли - dataGridView1.Columns.Add(ButtonColumn);
И условие лучше уже такое использовать (при условии что столбец-кнопка обязательно долен быть последним)
if (e.ColumnIndex == dataGridView1.ColumnCount - 1)
{
MessageBox.Show("Нажата кнопка на строке "+ e.RowIndex.ToString());
}
Спасибо, за вашу помощь, примем во внимание.
ОтветитьУдалитьCrf
ОтветитьУдалитьСкажите как можно нарисовать сектор таким образом, чтобы при изменении масштаба он оставался неизменным.
ОтветитьУдалить31,32 в полном листинге программы
ОтветитьУдалитьЗдравствуйте, не могли бы вы выслать нам, ваш проект, через форму обратной связи или часть проекта.
ОтветитьУдалитьИсходники можно скачать где нибудь??
ОтветитьУдалитьЗдравствуйте, ссылка для скачивания примера: http://csharpcoderr.rusfolder.net/files/43049565
ОтветитьУдалитьНа Win7 Ctrl+Alt+Del не блочится, чего и следовало ожидать :)
ОтветитьУдалитьЗдравствуйте, данная инструкция и прилагаемый к ней пример создавался и тестировался на Windows 7 x64, все прекрасно работает!
ОтветитьУдалитьСкачайте пример и протестируйте!
Ну я же не просто так говорю :)
ОтветитьУдалитьЯ на Win7 64x Professional тестировал, Ctrl+Alt+Del спокойно работает, а остальное блокируется.
Привет. Да у меня тоже на win8 блокировка Ctrl+Alt+Del не отрабатывает. Все равно появляется окно с выбором действий : "..Выход. Диспетчер задач " Кто-нибудь решил данную проблему?
ОтветитьУдалитьа если кнопка находиться к примеру по индексам [1,1]?
ОтветитьУдалитькакой более приемлемы, если данных много? (к примеру в одном листе у меня массив данных порядка 500 на 300 и такх "гридов" у меня 3 штуки )? Заранее спасибо
ОтветитьУдалитьЗдравствуйте, Арсентий Щербаков. Следует отметить, что при
ОтветитьУдалитьработе с большими объемами данных Interop-механизм(Пример №1) часто «падает»
сопровождая свой крах множеством одному Microsoft’у понятных сообщений. Из
этого следует, что для оформления небольших красивых отчетов идеально подходит
Interop-механизм, в то время как для импорта/экспорта больших данных лучшем
решением будет OldeDB (Пример №2), с использованием класса «OleDbConnection» и
поставщика Microsoft.ACE.OLEDB.12.0. Примеры №3 и 4 не тестировались на больших
объемах данных.
Спасибо за материал.
ОтветитьУдалитьПопробовал и пример 1 и пример 2, второй работает явно быстрее, но меня смущает настройка провайдера. Я нашел описание, что для Excel до 2007го нужно использовать Extended Properties='Excel 8.0', после 2007го либо 'Excel 12.0 XML' для xlsx и 'Excel 12.0 macro' для xlsm. Я потестил разные комбинации настроек и документов, на импорт данных это не влияет. Но ничего же не бывает просто так, где-то должно это аукнуться? Мне кажется, что нужно делать проверку на формат документа: xls, xlsx, xlsm и xlsb(хотя последние в живой природе не встречал) ну и настройки провайдера оформлять соответственно или я не прав?
И еще вопрос, не получается найти описание формата таблицы метаданных, которая получается после метода GetOleDbSchemaTable(), Вы берете имя листа вот здесь schemaTable.Rows[0].ItemArray[2], а что там есть еще?
Добрый день, я внимательно прочитал вашу статью, но на ваших скриншотах видно что маршрут(зеленая полоска) проходит не через дороги и магистрали, то есть можно сказать что она просто связывает по какому-то алгоритму маркеры, можно ли сделать так что бы маршрут прокладывался четко по дорогам ? Заранее спасибо! Еще раз спасибо вам за статью, очень познавательно!
ОтветитьУдалитьИ еще вопрос, по всей видимости этот маршрут прокладывается по контрольным точкам, они не всегда срабатывают корректно, влияет ли это на расстояние которое вычисляется программой, или это просто проблема отрисовки маршрута ?
ОтветитьУдалитьпосмотрите тут
ОтветитьУдалитьскрин приложил
ОтветитьУдалитьЗдравствуйте, точки маршрута дает Google, карта тоже Google. Почему маршрут не по дорогам, пока неизвестно.
ОтветитьУдалитьЗдравствуйте, что вы имеете ввиду под "они не всегда срабатывают корректно"?
ОтветитьУдалитьЯ разобрался с проблемой. У меня возник другой вопрос, как мне задать промежуточные точки в маршруте ?
ОтветитьУдалитьТо есть есть начальная и конечная точка, но я хотел бы задать еще и промежуточные точки.
Заранее спасибо.
Здравствуйте, посмотрите следующие ссылки:
ОтветитьУдалить1) https://productforums.google.com/forum/#!topic/maps-ru/1eKTsyL6L3w
2) https://developers.google.com/maps/documentation/directions/intro?hl=ru-Ru
3) http://infostart.ru/public/305584/
4) https://tech.yandex.ru/maps/jsbox/2.1/multiroute_edit