@m1rvi

Как выбрать зону яндекс.карт исходя из адреса юзера?

Делаю сайт для пиццерии

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

Как это реализовать?
  • Вопрос задан
  • 201 просмотр
Решения вопроса 2
freeExec
@freeExec
Участник OpenStreetMap
1) Геокодировать адрес - получаем координаты
2) Проверяем эти координаты на принадлежность многоугольнику зоны
3) Выставляем цену.
Ответ написан
Fernus
@Fernus
Техник - Механик :)
Когда-то решал похожее...

У меня была такая задача:
1. Есть точка на карте;
2. Есть полигоны (многоугольники) на карте;
3. Есть внутри каждого многоугольника точка на случай, если точка из п.1 не попала ни в один многоугольник, то нужно найти ближайшую точку из п.3 для точки из п.1...

Ниже пример как проверять вхождение точки из п.1 в полигоны (многоугольники) из п.2...

class Polygon {
    /**
     * @var array
     */
    var $polygon = [];
    /**
     * Polygon itself, with basic vector-based structure
     * Array: [ [1,1], [2,1], [3,0], [2,-1] ]
     *
     * @var $polygon array
     */
    function setPolygon($polygon) {
        if (count($polygon) < 3) {
            return false;
        }

        if (!isset($polygon[0]['x'])) {
            foreach ($polygon as &$point) {
                //$point = ['x' => round($point[0] + 300, 4), 'y' => round($point[1] + 300, 4)];
                //$point = ['x' => round($point[0], 4), 'y' => round($point[1], 4)];

                if($point[0] < 0)
                    $point[0] = 90 + 90 - abs($point[0]);
                if($point[1] < 0)
                    $point[1] = 180 + 180 - abs($point[1]);

                $point = ['x' => round($point[0], 4), 'y' => round($point[1], 4)];
            }
        }
        $this->polygon = $polygon;
    }
    /**
     * Check if $polygon contains $test value
     *
     * @var $test array(x=>decimal, y=>decimal)
     */
    function calc($test) {

        if($test['x'] < 0)
            $test['x'] = 90 + 90 - abs($test['x']);
        if($test['y'] < 0)
            $test['y'] = 180 + 180 - abs($test['y']);

        $q_patt= [[0, 1], [3, 2]];
        $end = end($this->polygon);

        $pred_pt = end($this->polygon);
        $pred_pt['x'] -= $test['x'];
        $pred_pt['y'] -= $test['y'];
        $pred_q = $q_patt[$pred_pt['y'] < 0][$pred_pt['x'] < 0];
        $w = 0;

        for ($iter = reset($this->polygon); $iter !== false; $iter = next($this->polygon)) {
            $cur_pt = $iter;
            $cur_pt['x'] -= $test['x'];
            $cur_pt['y'] -= $test['y'];
            $q = $q_patt[$cur_pt['y'] < 0][$cur_pt['x'] < 0];

            switch ($q - $pred_q) {
                case -3:
                    ++$w;
                    break;
                case 3:
                    --$w;
                    break;
                case -2:
                    if ($pred_pt['x'] * $cur_pt['y'] >= $pred_pt['y'] * $cur_pt['x']) {
                        ++$w;
                    }
                    break;
                case 2:
                    if (!($pred_pt['x'] * $cur_pt['y'] >= $pred_pt['y'] * $cur_pt['x'])) {
                        --$w;
                    }
                    break;
            }
            $pred_pt = $cur_pt;
            $pred_q = $q;
        }

        return $w != 0;
    }

    public static function distance($lat1, $lng1, $lat2, $lng2) {

        $lat1=deg2rad($lat1);
        $lng1=deg2rad($lng1);
        $lat2=deg2rad($lat2);
        $lng2=deg2rad($lng2);

        $delta_lat=($lat2 - $lat1);
        $delta_lng=($lng2 - $lng1);

        return round( 6378137 * acos( cos( $lat1 ) * cos( $lat2 ) * cos( $lng1 - $lng2 ) + sin( $lat1 ) * sin( $lat2 ) ) );
    }

    public static function closestPoint($x, $y, $arPoints) {

        $RESULT = false;

        $x = floatval($x);
        $y = floatval($y);

        if(!empty($arPoints) && is_array($arPoints) && count($arPoints) > 0) {

            $arRes = array();

            foreach ($arPoints as $KEY => $VAL) {

                $x2 = floatval($VAL[0]);
                $y2 = floatval($VAL[1]);

                $distance = self::distance($x, $y, $x2, $y2);

                $arRes[$KEY] = $distance;

            }

            if(count($arRes) > 0) {

                natsort($arRes);
                reset($arRes);

                //$RESULT[key($arRes)] = current($arRes);

                $RESULT = array(
                    'ID' => key($arRes),
                    'DISTANCE' => current($arRes)
                );

            }

        }

        return $RESULT;
    }
}

/* Ипользование */

// Координаты точки, которую проверяем на вхождение в "полигон"
$X = 33.45;
$Y = 44.25;

// "Полигоны"
$arCheckPoints = [
    'КЛЮЧ_МНОГОУГОЛЬНИКА' => [22.45, 44.55, 11.22, 55.66], // Координаты вершин
    'КЛЮЧ_МНОГОУГОЛЬНИКА_2' => [33.45, 66.55, 77.22, 99.66], // Координаты вершин
    'КЛЮЧ_МНОГОУГОЛЬНИКА_3' => [12.45, 15.55, 17.22, 54.66], // Координаты вершин
];

$arResults = [];

$p = new \App\Helpers\Polygon();

foreach ($arCheckPoints as $KEY_POLYGON => $arPolygon) {

    $p->setPolygon($arPolygon);

    if($p->calc(array('x' => $X, 'y' => $Y)))
        $arResults[$KEY_POLYGON] = $arPolygon;

}


Для решения п.3 используется функция distance...
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы
YCLIENTS Москва
от 200 000 до 350 000 ₽
Ведисофт Екатеринбург
от 25 000 ₽
ИТЦ Аусферр Магнитогорск
от 100 000 до 160 000 ₽