Определение вхождения координат в заданную область на карте OSM. Взаимодействие JavaScript и 1С

04.03.22

Интеграция - WEB-интеграция

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

Скачать файл

ВНИМАНИЕ: Файлы из Базы знаний - это исходный код разработки. Это примеры решения задач, шаблоны, заготовки, "строительные материалы" для учетной системы. Файлы ориентированы на специалистов 1С, которые могут разобраться в коде и оптимизировать программу для запуска в базе данных. Гарантии работоспособности нет. Возврата нет. Технической поддержки нет.

Наименование По подписке [?] Купить один файл
: Определение вхождения координат в заданную область
.epf 11,46Kb
7
7 Скачать (1 SM) Купить за 1 850 руб.

Здравствуйте! 

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

Данный способ реализован с помощью карт OpenStreetMap и библиотеки Leaflet. На инфостарте встречаются десятки статей, описывающих взаимодействие данной карты с 1С. Но т.к. подобных тем я не встречал, делюсь с форумчанами.

Итак, для начала необходимо создать текстовый макет "Карта", где будет храниться выполняемы JS код. Код с комментариями привожу ниже:

<!DOCTYPE html>
<html lang="en">

<head>
	<meta charset="UTF-8">
	<meta http-equiv="X-UA-Compatible" content="IE=edge">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>Document</title>
	<link rel="stylesheet" href="/redirect.php?url=aHR0cHM6Ly91bnBrZy5jb20vbGVhZmxldEAxLjcuMS9kaXN0L2xlYWZsZXQuY3Nz"
		integrity="sha512-xodZBNTC5n17Xt2atTPuE1HxjVMSvLVW9ocqUKLsCC5CXdbqCmblAshOMAS6/keqq/sMZMZ19scR4PsZChSR7A=="
		crossorigin="" />
	<link rel="stylesheet" href="/redirect.php?url=aHR0cHM6Ly91bnBrZy5jb20vbGVhZmxldC1yb3V0aW5nLW1hY2hpbmVAbGF0ZXN0L2Rpc3QvbGVhZmxldC1yb3V0aW5nLW1hY2hpbmUuY3Nz" />
	<script src="https://unpkg.com/leaflet@1.7.1/dist/leaflet.js"
		integrity="sha512-XQoYMqMTK8LvdxXYG3nZ448hOEQiglfqkJs1NOQV44cWnUrBc8PkAOcXy20w0vlaXaVUearIOBhiXZ5V3ynxwA=="
		crossorigin=""></script>
	<script src="https://unpkg.com/leaflet-routing-machine@latest/dist/leaflet-routing-machine.js"></script>
</head>

<body>
	<div id="map" class="map" style="position: absolute; top: 0px; right: 0px; bottom: 0px; left: 0px;"></div>

	<script type="text/javascript">

		//Установка начальных координат (широта и долгота и (13 - это зум))
		var map = L.map('map').setView([53.2030600, 50.1594980], 13); // Координаты г. Самара
		var markers = L.layerGroup().addTo(map);
		var circles = L.layerGroup().addTo(map);
		
		L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
			attribution: '&copy; <a href="/redirect.php?url=aHR0cHM6Ly93d3cub3BlbnN0cmVldG1hcC5vcmcvY29weXJpZ2h0">OpenStreetMap</a> contributors'
		}).addTo(map);

		map.on("click", onClick)
		//map.on("dblclick", onClickduble)

		let lat = 0;
		let lng = 0;
		let title = "";

		//Выбор точки на карте
		function onClick(e = e) {
			lat = e.latlng.lat;
			lng = e.latlng.lng;
			refreshMap();
			newMarker(lat, lng)
		}
        
        //Создает новый слой окружности на карте. Вызывается из 1С. 
		function createRadius(latitude, longitude, rad) {
			circles.clearLayers();
			let circle = new L.circle([latitude, longitude], {radius: rad});/**/
			circle.addTo(circles);
			SetViewOffice(latitude, longitude)
		} 
		
        //Отрисовка нового маркера при нажатии на карту 
		function newMarker(latitude, longitude, title) {
			lat = latitude;
			lng = longitude;
			refreshMap()
			SetViewOffice(lat, lng)
			let marker = new L.Marker([lat, lng]);/**/
			marker.bindPopup(title).openPopup();
			marker.addTo(markers);
		}

        //Функция вызывается из 1С. Возвращает координаты установленного маркера
		function returnLatLng() {
			coordinate = {
				lat,
				lng,
				title
			}

			jsonString = JSON.stringify(coordinate)
			return jsonString;
		}

		//function onClickduble(e) {
		//}

		//Очищаем карту
		function refreshMap() {
			markers.clearLayers();
		}

		//Установка отображение на текущем адресе
		function SetViewOffice(latitude, longitude) {
			map.setView([latitude, longitude], 15);
		}
	</script>
</body>
</html>
 
 Небольшое пояснение:::

 

 
 Далее, необходимо создать реквизиты формы:

 

Затем в процедуре ПриСозданииНаСервере необходимо присвоить код html, описанный выше, переменной Карта. В данной обработке, я также заполняю ТЗ "Адреса" тестовыми данными и сразу формирую список выбора для переменной "Адрес". 

&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
	МакетКарта = РеквизитФормыВЗначение("Объект").ПолучитьМакет("Карта");
	Карта = МакетКарта.ПолучитьТекст();
	
	///// Заполнение ТЗ "Адреса" тестовыми данными
	СтрокаТЗ = Адреса.Добавить();
	СтрокаТЗ.Адрес = "Самарская область, г. Самара";
	СтрокаТЗ.Широта = 53.203060;
	СтрокаТЗ.Долгота = 50.159498;
	
	СтрокаТЗ = Адреса.Добавить();
	СтрокаТЗ.Адрес = "Свердловская область, г. Екатеринбург";
	СтрокаТЗ.Широта = 56.835095;
	СтрокаТЗ.Долгота = 60.613329;
	
	СтрокаТЗ = Адреса.Добавить();
	СтрокаТЗ.Адрес = "Челябинская область, г. Челябинск";
	СтрокаТЗ.Широта = 55.165798;
	СтрокаТЗ.Долгота = 61.434271;
	
	///// Заполнение списка выбора реквизита Адрес
	ЗаполнитьСписокВыбораАдресов();
	
КонецПроцедуры

Процедура ЗаполнитьСписокВыбораАдресов()
	Для каждого Стр Из Адреса Цикл
		Элементы.Адрес.СписокВыбора.Добавить(Стр.Адрес);	
	КонецЦикла;
КонецПроцедуры 

 

Следующим пунктом, необходимо добавить событие "ПриНажатии" реквизита Карта. Туда мы пропишем следующий код:

&НаКлиенте
Процедура КартаПриНажатии(Элемент, ДанныеСобытия, СтандартнаяОбработка)
	Попытка
		ДокументПервогоБраузера = Элементы.Карта.Документ;
		
		ОкноПервогоБраузера = ДокументПервогоБраузера.defaultView; 	
		КоординатыСозданногоМаркера = ОкноПервогоБраузера.returnLatLng();
		СтруктураКоординатВыбраннойТочки = ПрочитатьJSONВСтруктуру(КоординатыСозданногоМаркера);
		
		Широта1 = СтруктураКоординатВыбраннойТочки.lat;
		Долгота1 = СтруктураКоординатВыбраннойТочки.lng;
	Исключение
		Сообщить("Карта еще не сформирована");	
	КонецПопытки;
КонецПроцедуры

Здесь как раз таки и пригодится "костыль", описанный выше. В момент нажатия переменным lat & lng уже присвоены значения, и при обращении к функции  returnLatLng() мы получаем JSON со значением координат только что созданного маркера. 

 
 ПрочитатьJSONВСтруктуру(JSON)

 

Теперь, когда координаты маркера получены и записаны в реквизиты формы, необходимо отрисовать область, относительно которой и будет происходить проверка вхождения созданного маркера. Для этого при нажатии на команду "ОтрисоватьНаКарте" мы будем вызывать функцию createRadius(Широта, Долгота, РадиусОхвата).

&НаКлиенте
Процедура ОтрисоватьНаКарте(Команда)
	Если Не ЗначениеЗаполнено(Адрес) Тогда
		ВызватьИсключение "Адрес не заполнен";	
	КонецЕсли;
	
	Попытка
		ДокументПервогоБраузера = Элементы.Карта.Документ;
		ОкноПервогоБраузера = ДокументПервогоБраузера.defaultView; 	
		ОкноПервогоБраузера.createRadius(Широта, Долгота, РадиусОхвата);
	Исключение
		Сообщить("Карта еще не сформирована");	
	КонецПопытки;
	
КонецПроцедуры

По итогу, при нажатии на карту, у вас должен создавать маркер, а при нажатии на команду "Отрисовать на карте" должна появляться выделенная область с заданным радиусом, где центром окружности является выбранный адрес.

 

Ну и наконец, самое важное в рамках данной статьи. Это определение вхождение маркера в заданную область.

Для этого я использовал формулу гаверсинуса (определяет расстояние по дуге между двумя точками на сфера с учетом их долготы и широты). Расчет в радианах. Расстояние в метрах. 

Для команды "ОпределитьВхождение" определяем процедуру и размещаем в ней следующий код:

&НаКлиенте
Процедура ОпределитьВхождение(Команда)
	Радиана = 57.29577951308;
	ШиротаРад = Широта / Радиана;
	Широта1Рад = Широта1 / Радиана;
	ДолготаРад = Долгота / Радиана;
	Долгота1Рад = Долгота1 / Радиана;
	
	R = 6371;  // Радиус планеты
	sin1 = sin((ШиротаРад - Широта1Рад) / 2);
	sin2 = sin((ДолготаРад - Долгота1Рад) / 2);
	
	РасстояниеМаркераОтОкружностиКм = 2 * R * asin(sqrt(sin1*sin1+sin2*sin2*cos(ШиротаРад)*cos(Широта1Рад)));
	РасстояниеМаркераОтОкружностиМ = РасстояниеМаркераОтОкружностиКм * 1000;
	
	Если РасстояниеМаркераОтОкружностиМ <= РадиусОхвата Тогда
		РезультатВхождения = "Есть вхождение";
	Иначе
		РезультатВхождения = "Нет вхождений";	
	КонецЕсли;
	
	ОчиститьСообщения();
	Сообщить(РезультатВхождения);
КонецПроцедуры

 Пример работы:

 
 Важное пояснение 

 

P.S. Это моя первая публикация на Инфостарт. Прошу не судить строго) 

Готовую обработку прикладываю (платформа 8.3.14)! Всем добра! 

Координаты OpenStreetmap JavaScript Обработка Транспорт Маршрут

См. также

WEB-интеграция Платформа 1С v8.3 1С:ERP Управление предприятием 2 1С:Управление торговлей 11 1С:Комплексная автоматизация 2.х 1С:Управление нашей фирмой 3.0 1С:Розница 3.0 Россия Платные (руб)

Функциональное решение для торговли на всех популярных маркетплейсах. Работает со схемами FBO и FBS. Простое в использовании и установке, не вносит изменения в код программы. Существенно упрощает работу с товарным ассортиментом, обработку заказов с площадок, работу с поставками, а также ведение аналитики по продажам и остаткам.

72000 руб.

19.07.2024    1045    1    0    

2

WEB-интеграция 8.3.8 Конфигурации 1cv8 Автомобили, автосервисы Беларусь Украина Россия Казахстан Управленческий учет Платные (руб)

Расширение предназначено для конфигурации "1С:Предприятие 8. Управление Автотранспортом. ПРОФ". Функционал модуля: 1. Заполнение регистров сведений по подсистеме "Мониторинг", а именно: события по мониторингу, координаты по мониторингу, пробег и расход по мониторингу, текущее местоположение ТС по мониторингу 2. Заполнение путевого листа: пробег по мониторингу, время выезда/заезда, табличная часть ГСМ, места стоянок по геозонам. 3. Отчеты по данным загруженным в регистры сведений. 4. Предусмотрена автоматическая загрузка данных в фоновом режиме (условия работы данной загрузке читайте в описании товара) Модуль работает без включенной константы по настройкам мониторинга. Модуль формы предоставляется с открытым кодом, общий модуль защищен. Любой заинтересованный пользователь, имеет возможность скачать демо-версию расширения.

22656 руб.

25.05.2021    13891    39    8    

15

WEB-интеграция Программист Платформа 1С v8.3 Бухгалтерский учет 1С:Бухгалтерия 3.0 Бытовые услуги, сервис Платные (руб)

Внешняя обработка разрабатывалась для загрузки документов из Ветменеджер в 1С: Бухгалтерия 3.0

12000 руб.

02.02.2021    17522    47    50    

28
Комментарии
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
1. Woody56RF 15 04.03.22 11:38 Сейчас в теме
Готовая обработка!
Прикрепленные файлы:
Определение вхождения координат в заданную область.epf
HansGlorias; serverstar; vipchep; akR00b; Viska; Vasvas05; +6 Ответить
2. akR00b 24 28.04.22 09:59 Сейчас в теме
3. PLAstic 296 27.07.22 10:43 Сейчас в теме
Обомлей: напиши в Ctrl-F1 "ПрочитатьJSON".

Глобальный контекст (Global context)
ПрочитатьJSON (ReadJSON)
Синтаксис:
ПрочитатьJSON(<ЧтениеJSON>, <ПрочитатьВСоответствие>, <ИменаСвойствСоЗначениямиДата>, <ОжидаемыйФорматДаты>, <ИмяФункцииВосстановления>, <МодульФункцииВосстановления>, <ДополнительныеПараметрыФункцииВосстановления>, <ИменаСвойствДляОбработкиВосстановления>, <МаксимальнаяВложенность>)

И выкинь свою функцию ПрочитатьJSONВСтруктуру().
Более того, внимательно изучи синтаксис - тут есть очень интересные особенности.

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