• Как использовать LEFT JOIN вместе с LIMIT?

    @MaximaXXl
    Вот для старой версии написал, через переменные.
    SELECT
      u.*,
      ui.`image_name`,
      (SELECT COUNT(il.`id`) FROM images_likes AS il WHERE `il`.image_id = `ui`.id) AS count_likes,
    FROM users AS u
    LEFT JOIN (SELECT id, user_id,  image_name,
           @row_num :=  CASE WHEN @row_num_val = user_id THEN @row_num + 1
                             WHEN (@row_num_val := user_id) IS NOT NULL THEN 1
                        END   rn
    FROM users_images, (SELECT @row_num := null, @row_num_val := null) AS x
    ORDER BY user_id, id
    --select row_number() over(partition by user_id order by id) rn, user_id , id, image_name
    --from users_images
    ) AS ui ON ui.user_id = u.id and ui.rn <= 5
    WHERE u.flag > 0


    P.S. должно работать, но писал по памяти, не тестил, лень ;-)
    Ответ написан
    2 комментария
  • Как проверить, попадает ли географическая точка в правильный шестиугольник?

    wataru
    @wataru Куратор тега Математика
    Разработчик на С++, экс-олимпиадник.
    Вычтите координаты центра из координат точки. Теперь шестиугольник лежит центром в (0, 0).

    Составьте 6 уравнений сторон шестиугольника в виде Ax+By+C=0, так что C положительно (если нет - домножте на -1). Подставьте в эти 6 уравнений координаты точки, все они должны дать положительные значения (или нули, если точка на границе считается лежащей внутри в вашей задаче).

    Почему это работает? Мы просто проверяем, что точка лежит с той же стороны от всех 6 прямых, что и центр (0, 0).

    Как составить уравнения? Найдите координаты 6-ти углов. Если сторона = a, то координаты точек (a, 0), (a/2, sqrt(3)*a/2), (-a/2, sqrt(3)*a/2), (-a, 0) ...

    Для уравнения одной из сторон возьмите в виде A разность по у у соседних точек, а в виде B разность по x (но с другим знаком). Потом подставьте туда координаты одной из точек и возьмите C так, чтобы был 0.

    Можно все 6 уравнений составить на бумажке и закодировать в программе.

    Пример для первой стороны:
    A = sqrt(3)*a/2-0 = sqrt(3)*a/2
    B = a - a/2 = a/2
    C = -A*a - B*0 = -sqrt(3)*a*a/2.

    Поскольку C отрицательно, меняем знаки:
    A = -sqrt(3)*a/2
    B = -a/2
    C = sqrt(3)*a*a/2

    Для второй прямой будет 0*x-a*y+sqrt(3)*a*a/2 = 0

    И да, это работает, если предположить, что шестиугольник маленький или на плоскости. если у вас кривизна земли играет роль, то все сильно усложняется.
    Ответ написан
  • Как разделить карту мира на равные части (квадраты)?

    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...если под твои задачи это логика подходит...то дальше покажу ещё пример...

    Мне просто код переписывать приходится прежде, чем выложить...))

    P.S.: Все координаты тупо из головы...на реальных данных лучше тестить...
    Ответ написан