【问题标题】:How to create a circle in meters in postgis?如何在postgis中创建一个以米为单位的圆圈?
【发布时间】:2012-12-01 22:35:06
【问题描述】:

我想问如何用radius=4km创建一个圈子。我尝试了ST_Buffer 函数,但它创建了一个更大的圆圈。 (我通过将多边形插入新的 kml 文件来查看创建的圆。)

这就是我正在尝试的。

INSERT INTO camera(geom_circle) VALUES(geometry(ST_Buffer(georgaphy(ST_GeomFromText('POINT(21.304116745663165 38.68607570952619)')), 4000)))

圆的中心是一个 lon lat 点,但我不知道它的 SRID,因为我是从 kml 文件中导入它的。 我需要SRID 来转换几何图形等吗?

【问题讨论】:

    标签: postgis geometry srid


    【解决方案1】:

    KML 文件始终是纬度/经度并使用 SRID=4326。如果您使用 geography,则隐含此 SRID。地理是在纬度/经度数据上混合 4 公里公制度量的好方法……你试过这个太好了!

    试试这个语句来修复强制转换,并使用参数化点构造函数:

    SELECT ST_Buffer(ST_MakePoint(21.304116745663165, 38.68607570952619)::geography, 4000);
    

    如果您需要将其转换回几何,请在末尾添加 ::geometry 转换。


    准确性更新

    上一个答案在内部将几何图形(通常)重新投影到该点适合的 UTM 区域(请参阅ST_Buffer)。如果该点位于两个 UTM 边界的边缘,这可能会导致轻微失真。大多数人不会关心这些错误的大小,但通常会是几米。但是,如果您需要亚毫米精度,请考虑构建动态azimuthal equidistant projection。这需要PostGIS 2.3的ST_Transform,改编自another answer

    CREATE OR REPLACE FUNCTION geodesic_buffer(geom geometry, dist double precision,
                                               num_seg_quarter_circle integer)
      RETURNS geometry AS $$
      SELECT ST_Transform(
        ST_Buffer(ST_Point(0, 0), $2, $3),
          ('+proj=aeqd +x_0=0 +y_0=0 +lat_0='
           || ST_Y(ST_Centroid($1))::text || ' +lon_0=' || ST_X(ST_Centroid($1))::text),
          ST_SRID($1))
      $$ LANGUAGE sql IMMUTABLE STRICT COST 100;
    CREATE OR REPLACE FUNCTION geodesic_buffer(geom geometry, dist double precision)
      RETURNS geometry AS 'SELECT geodesic_buffer($1, $2, 8)'
      LANGUAGE sql IMMUTABLE STRICT COST 100;
    -- Optional warppers for geography type
    CREATE OR REPLACE FUNCTION geodesic_buffer(geog geography, dist double precision)
      RETURNS geography AS 'SELECT geodesic_buffer($1::geometry, $2)::geography'
    LANGUAGE sql IMMUTABLE STRICT COST 100;
    CREATE OR REPLACE FUNCTION geodesic_buffer(geog geography, dist double precision,
                                               num_seg_quarter_circle integer)
      RETURNS geography AS 'SELECT geodesic_buffer($1::geometry, $2, $3)::geography'
      LANGUAGE sql IMMUTABLE STRICT COST 100;
    

    运行其中一个功能的简单示例是:

    SELECT geodesic_buffer(ST_MakePoint(21.304116745663165, 38.68607570952619)::geography, 4000);
    

    为了比较每个缓冲点的距离,这里是每个geodesic 的长度(旋转椭圆体上的最短路径,即 WGS84)。首先这个函数:

    SELECT count(*), min(buff_dist), avg(buff_dist), max(buff_dist)
    FROM (
      SELECT ST_Distance((ST_DumpPoints(geodesic_buffer(poi, dist)::geometry)).geom, poi) AS buff_dist
      FROM (SELECT ST_MakePoint(21.304116745663165, 38.68607570952619)::geography AS poi, 4000 AS dist) AS f
    ) AS f;
    
     count |      min       |       avg       |      max
    -------+----------------+-----------------+----------------
        33 | 3999.999999953 | 3999.9999999743 | 4000.000000001
    

    将此与 ST_Buffer(答案的第一部分)进行比较,这表明它偏离了大约 1.56 m:

    SELECT count(*), min(buff_dist), avg(buff_dist), max(buff_dist)
    FROM (
      SELECT ST_Distance((ST_DumpPoints(ST_Buffer(poi, dist)::geometry)).geom, poi) AS buff_dist
      FROM (SELECT ST_MakePoint(21.304116745663165, 38.68607570952619)::geography AS poi, 4000 AS dist) AS f
    ) AS f;
    
     count |      min       |       avg        |      max
    -------+----------------+------------------+----------------
        33 | 4001.560675049 | 4001.56585986067 | 4001.571105793
    

    【讨论】:

    • 这是一个很好的答案,对我有用。如果您尝试仅使用几何进行计算,取决于您在世界上的位置,您最终会得到一个椭圆。测试您存储在几何列中的信息的一个好方法是选择 ST_AsText(geoshape) AS geom 并将其呈现在您的地图上。
    • @RyanCharmley 尽管它在笛卡尔空间(平面地图)中可能看起来像一个椭圆,但它们始终是球体上的圆圈。例如,在 Google 地球中查看输出,您应该会看到圆圈,甚至远离赤道。
    • 您好,很久以前,但问题仍然相关。该方法不是那么准确,因为您所拥有的仍然是一个内接多边形,它是一个圆的近似值。 st_segmentize 在相邻点上,取一个中间点,然后 st_distance 与圆心在 200 公里的圆上产生高达 940 米的差异,如果我在不通过 num_seg_quarter_circle 的情况下调用你的函数。我还没有找到任何可以为我提供真实地理圈的东西(或不太近似但仍然表现出色的圈子),所以我将改用st_dwithin
    • @1valdis 正确,这个答案提供了圆形几何的多边形近似,因此会有差异。可能有一种方法可以在 WKT 中描述这种圆形几何图形,但实际上,当今大多数 GIS 软件很少使用圆形几何图形。是的,ST_DWithin 是在距另一点半径精确距离内查找几何图形的正确且最有效的方法。
    猜你喜欢
    • 2019-07-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-27
    • 2017-06-13
    相关资源
    最近更新 更多