KML 文件始终为纬度/经度并使用 SRID=4326。如果您使用,则隐含此 SRIDgeography
。地理是将 4 公里公制测量值与纬度/经度数据混合在一起的好方法...您尝试过,非常棒!
尝试使用此语句来修复强制转换,并使用参数化点构造函数:
SELECT ST_Buffer(ST_MakePoint(21.304116745663165, 38.68607570952619)::geography, 4000);
如果您需要将其转换回几何体,请添加::geometry
投到最后。
准确性更新
前面的答案在内部将几何图形(通常)重新投影到该点适合的 UTM 区域(请参阅ST_缓冲区)。如果该点位于两个 UTM 边界的边缘上,这可能会导致轻微的扭曲。大多数人不会关心这些误差的大小,但它通常会达到几米。但是,如果您需要亚毫米精度,请考虑构建动态方位等距投影。这需要 PostGIS 2.3ST_Transform,并改编自另一个答案:
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