Первый вопрос первый ...
Я хотел бы знать, почему это происходит ...
Использование ST_MAKEPOLYGON с вводом линейных строк (через ST_MAKELINE) требует, чтобы линия была правильно собрана, чтобы не было пересечений с вашими данными (поскольку линия строится с использованием точек в [случайном] порядке появления)
Вместо этого вам понадобится линия, как показано ниже * синяя - где все географические точки расположены так, что они образуют несамопересекающуюся линию
Примечание: Строка линии должна быть закрыта, то есть первая и последняя вершины должны быть одинаковыми. Если первая и последняя вершины отличаются, функция строит конечное ребро от первой вершины до последней.
Построение полигона с использованием «Proper_line» будет отлично работать и даст результат ниже
Второй вопрос сейчас ...
… и хотел бы узнать некоторые идеи, чтобы решить эту проблему
Итак, очевидно, нам нужно как-то правильно упорядочить гео-точки
Это можно сделать вручную (получайте удовольствие от этой опции) или программно
Ниже приведена идея, как это сделать в BigQuery (Standard SQL), а также подробности реализации
Итак, мы хотим назначить правильный порядковый номер каждой точке, выполнив следующие шаги:
Шаг 1 - давайте определим центроид ( зеленый штифт на изображении ниже) для всех точек ( красный штифты)
Мы можем использовать нижеприведенное утверждение для этого:
SELECT ST_CENTROID(ST_UNION_AGG(ST_GEOGPOINT(lon, lat))) centroid FROM `data`
Шаг 2 - Затем для каждой точки мы должны рассчитать угол между линией центроида к точке и горизонтальной линией, пересекающей центроид
Мы используем якоря ( синие круги на изображении)
WITH stats AS (
SELECT ST_CENTROID(ST_UNION_AGG(ST_GEOGPOINT(lon, lat))) centroid FROM `data`
)
SELECT point, centroid, anchor,
ACOS(ST_DISTANCE(centroid, anchor) / ST_DISTANCE(centroid, point)) angle
FROM (
SELECT centroid,
ST_GEOGPOINT(lon, lat) point,
ST_GEOGPOINT(lon, ST_Y(centroid)) anchor
FROM `data`, stats
)
Шаг 3 - Теперь мы хотим преобразовать эти углы в правильную последовательность, отражающую квадранты соответствующих точек
SELECT point, centroid, anchor,
CASE
WHEN ST_X(point) > ST_X(centroid) AND ST_Y(point) > ST_Y(centroid) THEN 3.14 - angle
WHEN ST_X(point) > ST_X(centroid) AND ST_Y(point) < ST_Y(centroid) THEN 3.14 + angle
WHEN ST_X(point) < ST_X(centroid) AND ST_Y(point) < ST_Y(centroid) THEN 6.28 - angle
ELSE angle
END sequence
FROM (.. previous subquery here …)
Шаг 4 - Итак, теперь, наконец, мы можем использовать столбец последовательности, чтобы правильно упорядочить точки
Окончательный запрос ниже:
WITH `data` AS (
SELECT 61680 AS id, 139.74862575531006 AS lon, 35.674973127377314 AS lat UNION ALL SELECT 61680, 139.75087881088257, 35.673909836018375 UNION ALL SELECT 61680, 139.747037887573, 35.6765767531247 UNION ALL SELECT 61680, 139.75308895111, 35.6813525780394 UNION ALL SELECT 61680, 139.747509956359, 35.6798884869144 UNION ALL SELECT 61680, 139.754590988159, 35.6799930657428 UNION ALL SELECT 61680, 139.754977226257, 35.6762281415729 UNION ALL SELECT 61680, 139.750170707702, 35.6815268728124 UNION ALL SELECT 61680, 139.755363464355, 35.6782500673754
), stats AS (
SELECT ST_CENTROID(ST_UNION_AGG(ST_GEOGPOINT(lon, lat))) centroid FROM `data`
)
SELECT ST_MAKEPOLYGON(ST_MAKELINE(ARRAY_AGG(point ORDER BY sequence))) AS polygon
FROM (
SELECT point,
CASE
WHEN ST_X(point) > ST_X(centroid) AND ST_Y(point) > ST_Y(centroid) THEN 3.14 - angle
WHEN ST_X(point) > ST_X(centroid) AND ST_Y(point) < ST_Y(centroid) THEN 3.14 + angle
WHEN ST_X(point) < ST_X(centroid) AND ST_Y(point) < ST_Y(centroid) THEN 6.28 - angle
ELSE angle
END sequence
FROM (
SELECT point, centroid,
ACOS(ST_DISTANCE(centroid, anchor) / ST_DISTANCE(centroid, point)) angle
FROM (
SELECT centroid,
ST_GEOGPOINT(lon, lat) point,
ST_GEOGPOINT(lon, ST_Y(centroid)) anchor
FROM `data`, stats
)
)
)
Окончательный результат:
Примечание: эта идея / решение - все еще может быть ограничено только некоторыми очевидными случаями, подобными вашему - у меня не было возможности исследовать и / или проверить его для общих случаев