永川圭*_*川圭介 3 gis postgis google-bigquery
我在 BigQuery 中使用 ST_MAKEPOLYGON 函数如下:
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
)
SELECT
ST_makepolygon(ST_MAKELINE(ARRAY_AGG(st_geogpoint(lon,
lat)))) AS valid
FROM
`w_nagakawa.geo_test`
GROUP BY
id
Run Code Online (Sandbox Code Playgroud)
我得到如下错误:
Error: ST_MakePolygon failed: Invalid polygon loop: Edge 3 has duplicate vertex with edge 10
Run Code Online (Sandbox Code Playgroud)
ST_MAKEPOLYGON 中的地理参数没问题,所有经纬度似乎都不一样。
我想知道它为什么会发生,并想知道一些解决这个问题的想法。
谢谢。
首先第一个问题……
我想知道为什么会这样……
将 ST_MAKEPOLYGON 与线串输入(通过 ST_MAKELINE)一起使用需要正确组装线,以便您的数据不会发生相交(因为线是使用 [随机] 出现顺序中的点构建的)
相反,您需要像下面这样的蓝色线 - 所有地理点都按顺序排列,以便它们形成非自交叉线
注意:线串必须是封闭的:即第一个和最后一个顶点必须相同。如果第一个顶点和最后一个顶点不同,则该函数构造从第一个顶点到最后一个顶点的最终边。
使用“proper_line”构建多边形将完美地工作并产生以下结果
现在第二个问题……
......并想知道一些解决这个问题的想法
所以,很明显,我们需要以某种方式正确地对地理点进行排序
这可以手动完成(享受这个选项的乐趣)或以编程方式完成
以下是如何在 BigQuery(标准 SQL)中这样做的想法以及实现细节
因此,我们希望通过以下步骤为每个点分配适当的序列号:
第 1 步- 让我们为所有点(红色引脚)确定质心(下图中的绿色引脚)
我们可以使用以下语句:
SELECT ST_CENTROID(ST_UNION_AGG(ST_GEOGPOINT(lon, lat))) centroid FROM `data`
Run Code Online (Sandbox Code Playgroud)
第 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
)
Run Code Online (Sandbox Code Playgroud)
第 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 …)
Run Code Online (Sandbox Code Playgroud)
第 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
)
)
)
Run Code Online (Sandbox Code Playgroud)
最终结果是:
注意:这个想法/解决方案 - 仍然可以仅限于像你这样的一些明显案例 - 我没有机会探索和/或测试它的通用案例
| 归档时间: |
|
| 查看次数: |
1268 次 |
| 最近记录: |