PostGIS系列课程之空间约束(二)

34 篇文章 9 订阅

空间数据质量通常涉及几何之间的更高阶关系。 正如强大的非空间模型将强制执行外键关系一样,空间约束可用于强制执行空间关系。

触发器约束

地块"地籍" 的形式,反映土地合法划分的空间层。 地籍的核心业务规则之一是,一块土地不能同时位于两个地籍中。

两种不一致违反了上述原则:

地块重叠示意图

  • 一个宗地与另一个宗地部分重叠,例如右下角的红色宗地。
  • 一个宗地完全包含在另一个宗地中,如左侧的红色宗地。

创建一个检查规则(插入和更新时候使用):

CREATE OR REPLACE FUNCTION overlapping_parcel_trigger()
  RETURNS trigger AS
  $$
    DECLARE
      c bigint;
    BEGIN
      SELECT Count(*)
      INTO c
      FROM parcels
      WHERE ST_Intersects(parcels.geom, NEW.geom)
      AND parcels.pk != NEW.pk;
      AND ST_Relate(parcels.geom, NEW.geom, '2********')

      IF c > 0 THEN
        RAISE EXCEPTION 'parcel % shares 
            area with another parcel', NEW.pk;
      END IF;

      RETURN NEW;
    END;
  $$
  LANGUAGE 'plpgsql';

此触发器内的查询将查找共享区域的宗地。
如果宗地共享区域大于零,则存在问题,因此我们引发异常以中止交易。

注意三个 WHERE 子句:

  • 首先 ST_Intersects 快速查找可能共享区域的地块。
  • 然后进行主键检查,以排除包裹与其自身重复的情况。
  • 最后,调用 ST_Relate 函数,以检查几何之间的关系是否包括跨区域问题。

我们无法对 ST_Overlaps 的简单调用来测试跨区域问题,因为 “重叠”仅测试多边形重叠但不包含的情况 ( 左侧的多边形)。

尺寸扩展的9交叉模型(DE9IM)

ST_Relate 计算两个输入几何的“尺寸扩展的9交叉模型”(DE9IM)。

DE9IM 精确地描述了两个几何之间的关系。

每个几何都有三个组成部分:

  • 它具有几何图形所包含的平面的“内部”部分。
  • 具有 外部 几何所不包含的部分。
  • 它具有将内部与外部分隔的平面的“边界”部分。

通过填写指示几何对象如何相互作用的矩阵,可以得出两个几何的DE9IM代码。 例如,对于两个重叠的多边形:

DE9IM-覆盖1

每个图形交互根据其交集的维数进行编码。 内部有一个2维(区域)交叉点,因此I/I单元获得一个“2”。 边界和内部具有一维(线性)交点,因此B/I单元为“1”,依此类推。

通过附加行将最终矩阵转换为相关字符串,因此生成DE9IM的SQL返回单个字符串值:

SELECT ST_Relate(
         'POLYGON ((0 100, 100 100, 100 0, 0 0, 0 100))', 
         'POLYGON ((200 0, 100 0, 91 55, 100 100, 200 100, 200 0))'
         );
------------------
 st_relate 
-----------
 212101212

覆盖多边形的情况矩阵如下所示。 请注意,在多边形没有交集的情况下,单元格将填充“ F”。

de9im-覆盖2

两种矩阵都完全不同,但是它们有一个共同的关键点:在两种情况下,内部的交集都是一个区域。 因此,在I/I单元中具有两个 “2” 的两个多边形的任何相关矩阵都表示该多边形具有某些重叠的区域,因此它们不是合法的地块。

幸运的是,有一种 ST_Relate 形式,它与模式相关,类似正则表达式,因此我们不需要进行字符串详细的解读或者解析。

ST_Relate(parcels.geom, NEW.geom, '2********')

ST_Relate的三参数形式针对字符串参数测试两个几何对象的关联矩阵,并在模式一致的情况下返回 true 其中 标记"*"与任何单元格值匹配。 因此,模式“ 2 ********”匹配I/I单元为 2 的任何关联。

约束触发

要在宗地表上启用宗地重叠检查,我们需要将触发函数与实际触发相关联。

-- 创建我们自己的表
CREATE TABLE parcels (
   pk bigint PRIMARY KEY,
   geom geometry(Polygon, 3005) 
      NOT NULL CHECK (ST_IsValid(geom))
);

-- 增加约束触发器(此时触发器才和表的操作关联起来了)
CREATE CONSTRAINT TRIGGER overlapping_parcel 
    AFTER INSERT OR UPDATE ON parcels
    FOR EACH ROW EXECUTE FUNCTION overlapping_parcel_trigger();

测试一下。 首先,添加三个不重叠的宗地:

INSERT INTO parcels VALUES (1, 
    'POLYGON((0 100, 100 100, 100 0, 0 0, 0 100))');
INSERT INTO parcels VALUES (2, 
    'POLYGON((100 100, 200 100, 200 0, 100 0, 100 100))');
INSERT INTO parcels VALUES (3, 
    'POLYGON((200 100, 300 100, 300 0, 200 0, 200 100))');

正确!

重叠

插入重叠地块:

INSERT INTO parcels VALUES (4, 
    'POLYGON ((300 100, 400 100, 400 0, 
        300 0, 290 50, 300 100))'
    );
--------------------------------
ERROR:  parcel 4 shares area with another parcel
CONTEXT:  PL/pgSQL function overlapping_parcel_trigger() 
    line 14 at RAISE

出错了!

对于简单的触发约束,重叠是一个很好的测试用例,但是对于某些结构,有些结构需要更高的质量来控制:连接的网络。

在后面一部分教程中,将研究如何使用约束和延迟来增强道路网络的连接性和其他数据质量。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

丷丩

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值