У компании, заказавшей голосового робота приема заказов, несколько районов доставки, причем районы могут не совпадать с административным делением, а сформированы непосредственно компанией с точки зрения своей логистики.
Была поставлена задача: определять район доставки по адресу и по списку полигонов, а затем по району предлагать расписание доставки.
Задача решена.
Решение состоит из составных частей:
1. Определить координаты по названному адресу
2. Определить принадлежность точки к полигону из списка.
3. Предложить интервалы доставки
Определение координат по адресу
Применили dadata
Код DSL
var string = "..."; // записать адрес var token = "..."; // получить в dadata var secret = "..."; // получить в dadata var url = "https://cleaner.dadata.ru/api/v1/clean/address"; var response = $http.query(url, { method: "POST", mode: "cors", headers: { "Content-Type": "application/json", "Authorization": "Token " + token, "X-Secret": secret }, body: JSON.stringify([string]) }); if (response.isOk) { $session.adres = response.data[0].result; $session.geo_lat = response.data[0].geo_lat; $session.geo_lon = response.data[0].geo_lon; }
Определение района и расписания
Название и расписание заложили в массив по шаблону:
Шаблон
[ ['Кемерово.Кировский'], [ [ 'понедельник', [10,14],[18,21] ], [ 'вторник', [10,14] ], [ 'среда', [10,14] ], [ 'четверг', [10,14],[18,21] ], [ 'пятница', [10,14] ], [ 'суббота', [12,15] ] ] ] ],
Полигоны также заложили в массивы по шаблону:
Шаблон
polygon[2] = [ [55.5398240358901,86.06198408166499], [55.53923998368585,86.18901350061027], [55.498529562499215,86.23501874963371], [55.47260090273308,86.2381086544189], [55.48839408166666,86.14300825158683], [55.500478393141144,86.05649091760245], [55.5398240358901,86.06198408166499] ];
По полученным координатам определяем, к какому полигону принадлежит точка, и берем расписание из соответствующего массива.
Вызов функции
if ( $session.geo_lat && $session.geo_lon ) { $session.district_params = district($session.geo_lat, $session.geo_lon); if ( $session.district_params) { $session.district_name = $session.district_params[0]; // наименование $session.district_hours = $session.district_params[1]; // расписание } } else { // действия при ошибке }
Код функции, возвращает название и расписание по координатам
function district(geo_lat, geo_lon) { var points = [[geo_lat,geo_lon]]; var result = []; // названия и расписание var polygon_names = [ [ ['Кемерово.Кировский'], [ [ 'понедельник', [10,14],[18,21] ], [ 'вторник', [10,14] ], [ 'среда', [10,14] ], [ 'четверг', [10,14],[18,21] ], [ 'пятница', [10,14] ], [ 'суббота', [12,15] ] ] ], [ ['Кемерово.Радуга'], [ [ 'понедельник', [10,14],[14,18],[18,21] ], [ 'вторник', [10,14],[14,18],[18,21] ], [ 'среда', [10,14],[14,18],[18,21] ], [ 'четверг', [10,14],[14,18],[18,21] ], [ 'пятница', [10,14],[14,18],[18,21] ], [ 'суббота', [12,15] ], ['воскресенье', [12,15] ] ] ], ], // ... прочие полигоны с названием и расписанием ]; var polygon = []; polygon[0] = [ [55.42750307297217,85.93685730782616], [55.38981354859305,85.97984902439056], [55.378594859351665,86.04587682244856], [55.38056186384528,86.0456944322355], [55.38262650202426,86.04516871926862], [55.38682874474446,86.04647763726787], [55.38935720376095,86.04795821664413], [55.40497630378339,86.07192643640128], [55.4188901124165,86.06766124872678], [55.44031962335255,86.0563132052135], [55.448267003432456,86.02649640699367], [55.42750307297217,85.93685730782616] ]; polygon[1] = [ [55.3885222555803,86.04759752581676], [55.38520274198388,86.04606748301846], [55.38249377900722,86.04538671249684], [55.37908230144541,86.04637025774781], [55.374457678540296,86.06354712427918], [55.36381348508429,86.09004734934626], [55.36278679775203,86.13133191050358], [55.37373675048737,86.16223095835511], [55.376473763211486,86.17656468333061], [55.38257624038314,86.1833867308621], [55.39138026872829,86.1834955712357], [55.40086997256217,86.18043779309843], [55.41321392641188,86.17574923188013], [55.437341244016444,86.16240244010166], [55.45646086831123,86.11169800579165], [55.45567594400442,86.05138053437237], [55.405689292353934,86.07425450266653], [55.39020483091502,86.05069397867979], [55.3885222555803,86.04759752581676] ]; // ... прочие полигоны по списку // определяем район polygon.forEach(function(entry, k) { var points_counter = [0]; polygon[k].forEach(function(item_polygon, i_polygon) { if ( i_polygon < (polygon[k].length-1) ) { var polyline = [item_polygon, polygon[k][i_polygon + 1]]; // пускаем бесконечный луч вправо // косая линия if ( polyline[0][0] != polyline[1][0] & polyline[0][1] != polyline[1][1] ) { points.forEach(function(item_points, i) { var check1 = ( item_points[0] - polyline[0][0] ) * ( item_points[0] - polyline[1][0] ); var check2 = ( item_points[1] - polyline[0][1] ) * ( item_points[1] - polyline[1][1] ); //слева по горизонтали и между по вертикали if ( check2 < 0 & item_points[0] < polyline[0][0] & item_points[0] < polyline[1][0]) { points_counter[i]++; } // между по горизонтли и междупо вертикали if ( check1 < 0 & check2 < 0) { var delta0 = (item_points[0] - polyline[0][0])/(polyline[1][0]-polyline[0][0]); var coord1 = (polyline[1][1]- polyline[0][1]) * delta0 + polyline[0][1]; var check3 = ( coord1 - item_points[1]) * ( polyline[1][1] - polyline[0][1] ); if ( check3 < 0) { points_counter[i]++; } } }); } // перпендикулярная вертикальная линия if ( polyline[0][0] == polyline[1][0] ) { points.forEach(function(item_points, i) { // совсем слева от линии по горизонтали и между по вертикали var check = ( item_points[1] - polyline[0][1] ) * (item_points[1] - polyline[1][1] ); if ( item_points[0] < polyline[0][0] && check < 0 ) { points_counter[i]++; } }); } // проверяем пересечение с вершиной points.forEach(function(item_points, i) { // если равны по вертикали и левее по горизонтали, то +1 пересечение, если внутри угла if ( item_points[1] == item_polygon[1] && item_points[0] < item_polygon[0] ) { //проверяем, точки внутри угла или снаружи if ( i_polygon == 0) { var check = (item_points[1] - polygon[polygon.length-2][1]) * (item_points[1] - polygon[i_polygon+1][1]); } if ( i_polygon > 0) { var check = (item_points[1] - polygon[i_polygon-1][1]) * (item_points[1] - polygon[i_polygon+1][1]); } if (check < 0) { points_counter[i]++; } } }); } }); points_counter.forEach(function(item, i) { if ( item % 2 != 0 ) ) { result = [points[i][0], points[i][1], k, item]; } }); }); return polygon_names[result[2]]; }
Заполнение массивов начал и окончаний интервалов
if ( $session.district_name ) { $session.district_hours.forEach(function(entry, k) { $session.correct_days = $session.correct_days + " " + entry[0] + "."; if ( entry[0] == $session.dayOfWeek_speech) { // действия, если день совпал $session.this_day_hours = new Array(); $session.this_day_hours = entry; $session.interval_begin = $session.district_hours[k][1][0]; $session.interval_end = $session.district_hours[k][1][1]; } }); }
Итог
В итоге робот после получения адреса определяет район доставки согласно списку полигонов, по району берет из массива доступные интервалы на заданный день и предлагает их по очередности.
ссылка на оригинал статьи https://habr.com/ru/post/685074/
Добавить комментарий