m1rvi
@m1rvi
Отметь блин решением, если помог

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

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

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

Как это реализовать?
  • Вопрос задан
  • 126 просмотров
Решения вопроса 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...
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

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

Войти через центр авторизации
Похожие вопросы