基于PostGIS的相邻图形方位计算,东南西北相邻计算
有一个场景,有一份地块表,需要计算每个地块的东南西北分别是哪个人的地块,允许有多个人。
目前数据已经录入PostgreSQL数据库中,之前从没有想过这个问题,觉得地块方向都不是正南正北的,觉得不知从何下手,经过研究与测试,发现根据地块中心点计算方位角的计算结果,还是比较准备的。这里分享一下。
计算流程
┌─────────────────┐
│ 开始 │
└────────┬────────┘│
┌────────▼────────┐
│ 前提条件检查 │
│ 1. 表含 geom 字段│
│ 2. 已装 PostGIS │
└────────┬────────┘│ (未满足则先执行 CREATE EXTENSION postgis)
┌────────▼────────┐
│ 数据准备 │
│ 1. 创建空间索引 │
│ (GIST 类型) │
│ 2. 计算地块中心点│
│ ST_Centroid(geom)│
└────────┬────────┘│
┌────────▼────────┐
│ 筛选相邻地块 │
│ 1. 排除自身 │
│ a.gid ≠ b.gid│
│ 2. 空间相交 │
│ ST_Intersects(a.geom, b.geom)│
│ 3. 交集为线 │
│ ST_Dimension(交集) = 1│
└────────┬────────┘│
┌────────▼────────┐
│ 计算方位角 │
│ ST_Azimuth(中心点A, 中心点B) × 180/PI()│
└────────┬────────┘│
┌────────▼─────────────────────────────────────┐
│ 判断方向(按角度范围匹配) │
├───────────────┬───────────────┬──────────────┤
│ 0°±30°/360°±45°│ 90°±45° │ 180°±45° │
│ → 北侧(north) │ → 东侧(east) │ → 南侧(south)│
├───────────────┼───────────────┼──────────────┤
│ 270°±45° │ 其他角度 │ │
│ → 西侧(west) │ → 排除 │ │
└────────┬───────┴───────────────┴──────────────┘││
┌────────▼────────┐
│ 优化结果表 │
│ 创建索引 │
│ (如 source_gid + direction)│
└────────┬────────┘│
┌────────▼────────┐
│ 结束 │
└─────────────────┘
计算代码
create table xice as WITH center AS (-- 计算每个地块的中心点(用于方向判断)SELECTobjectid as gid, -- 假设gid为地块唯一标识shape as geom,ST_Centroid(shape) AS centroid -- 中心点坐标FROM "我的表"
)SELECTa.gid AS origin,b.gid AS xi,-- 可添加距离等辅助信息ST_Distance(a.centroid, b.centroid) AS 中心距离,CASEWHEN ST_Azimuth(a.centroid, b.centroid) * 180 / PI() BETWEEN 315 AND 360 OR ST_Azimuth(a.centroid, b.centroid) * 180 / PI() BETWEEN 0 AND 45 THEN 'north' -- 北WHEN ST_Azimuth(a.centroid, b.centroid) * 180 / PI() BETWEEN 45 AND 135 THEN 'east' -- 东WHEN ST_Azimuth(a.centroid, b.centroid) * 180 / PI() BETWEEN 135 AND 225 THEN 'south' -- 南WHEN ST_Azimuth(a.centroid, b.centroid) * 180 / PI() BETWEEN 225 AND 315 THEN 'west' -- 西ELSE 'other' -- 其他方向(如对角线)END AS direction
FROM center a
JOIN center b ONa.gid <> b.gid -- 排除自身AND ST_Intersects(a.geom, b.geom) -- 两地块空间相交AND ST_Dimension(ST_Intersection(a.geom, b.geom)) = 1 -- 交集为线(确保相邻而非点接触)
ORDER BY a.gid, 中心距离;
-- 更新西字段
update "我的表" a set dkxz=(select string_agg(nhmc,',') from "我的表" where objectid in (SELECT xi from xice where xice.origin=a.objectid and direction='west'));
-- 更新东字段
update "我的表" a set dkdz=(select string_agg(nhmc,',') from "我的表" where objectid in (SELECT xi from xice where xice.origin=a.objectid and direction='east'));
-- 更新南字段
update "我的表" a set dknz=(select string_agg(nhmc,',') from "我的表" where objectid in (SELECT xi from xice where xice.origin=a.objectid and direction='south'));
-- 更新北字段
update "我的表" a set dkbz=(select string_agg(nhmc,',') from "我的表" where objectid in (SELECT xi from xice where xice.origin=a.objectid and direction='north'));
核心方法
主要是利用PostGIS的ST_Azimuth函数计算方位角
北 (0°/360°)↑|
西 (270°) ← — — → 东 (90°)|↓南 (180°)示例:
- 若 pointB 在 pointA 的正东方 → 方位角=90°
- 若 pointB 在 pointA 的西南方 → 方位角=225°(180°+45°)
- 若 pointB 在 pointA 的东北方 → 方位角=45°
注意
- sql需要根据自己的表结构进行调整
- 两个图形不相邻,有间隔的话,用上面的sql是无法计算的,需要调整
- 大量数据时,计算较慢