第一个问题先……
我想知道为什么会这样……
将 ST_MAKEPOLYGON 与线串输入一起使用(通过 ST_MAKELINE)需要正确组装线,这样您的数据就不会发生交叉(因为线是使用 [随机] 出现顺序中的点构建的)
相反,您需要像下面 blue 中的线 - 所有地理点都经过排序以形成非自交叉线
注意:线串必须闭合:即第一个和最后一个顶点必须相同。如果第一个和最后一个顶点不同,则该函数构造从第一个顶点到最后一个顶点的最终边。
使用“proper_line”构建多边形将完美地工作并产生以下结果
现在第二个问题……
…想知道解决这个问题的一些想法
因此,显然,我们需要以某种方式正确排序地理点
这可以手动完成(玩这个选项很有趣)或可以通过编程完成
以下是如何在 BigQuery(标准 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
)
)
)
最终结果是:
注意:这个想法/解决方案 - 仍然可以仅限于像你这样的一些明显案例 - 我没有机会探索和/或测试它的通用案例