惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
美团技术团队
Last Week in AI
Last Week in AI
WordPress大学
WordPress大学
博客园 - 三生石上(FineUI控件)
博客园 - 聂微东
雷峰网
雷峰网
阮一峰的网络日志
阮一峰的网络日志
博客园 - 叶小钗
IT之家
IT之家
Google DeepMind News
Google DeepMind News
D
Docker
J
Java Code Geeks
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
Apple Machine Learning Research
Apple Machine Learning Research
博客园 - 【当耐特】
V
V2EX
Hugging Face - Blog
Hugging Face - Blog
博客园 - Franky
月光博客
月光博客
宝玉的分享
宝玉的分享
酷 壳 – CoolShell
酷 壳 – CoolShell
aimingoo的专栏
aimingoo的专栏
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More

博客园 - 我才是银古

第16章:常见问题、排错与最佳实践 第15章:扩展生态、MCAD 与外部集成 第12章:实战案例:机械结构与 3D 打印零件 第14章:构建、测试、调试与贡献流程 第13章:OpenSCAD 源码架构与核心执行流程 第11章:预览、渲染、网格精度与性能优化 第09章:列表推导、递归与算法建模 第08章:参数化零件库与复用设计 第10章:导入导出、命令行与自动化 第06章:CSG 布尔建模方法 第07章:二维图形、拉伸、旋转与投影 第05章:基础几何、坐标系与变换 第04章:参数、变量、函数、模块与作用域 OpenSCAD 教程目录 第03章:OpenSCAD 语言基础 第02章:安装、环境配置与开发工作流 第01章:OpenSCAD 项目全景与学习路线 第02章:源码获取、编译与开发环境配置 第01章:OCCT项目全景与学习路线 第18章:二次开发实战与综合案例 第18章:综合实战案例 第17章:数据交换与协同 第16章:源码架构与二次开发 第15章:插件与自定义工作台开发 第14章:Python脚本宏与自动化 第13章:FEM仿真分析 第12章:CAM数控加工 第11章:SurfaceMesh与逆向工程 第10章:Draft二维绘图与BIM建筑 第09章:工程图TechDraw
空间关系分析
我才是银古 · 2026-06-22 · via 博客园 - 我才是银古

空间关系分析

概述

空间关系分析是GIS的核心功能之一。通过判断几何对象之间的空间关系,可以实现空间查询、叠加分析、选址分析等常见GIS功能。

基本空间关系

相交(Intersects)

两个几何对象有任意公共部分(点、线或面)时,称为相交:

/**
 * 判断几何是否相交
 */
public static boolean intersects(Geometry a, Geometry b) {
    return a.intersects(b);
}

应用场景

  • 空间查询:找出与指定区域相交的所有要素
  • 碰撞检测:判断两个对象是否发生空间重叠
  • 路线规划:判断路线是否经过某个区域

相离(Disjoint)

两个几何对象没有任何公共点时,称为相离:

/**
 * 判断几何是否相离
 * 一个公共点都没有
 */
public static boolean disjoint(Geometry a, Geometry b) {
    return a.disjoint(b);
}

说明disjointintersects互为反义关系,即:

disjoint(a, b) == !intersects(a, b)

接触(Touches)

两个几何对象有公共点但没有公共内部区域时,称为接触:

/**
 * 判断几何是否接触
 * 有公共点但没有公共区域
 */
public static boolean touches(Geometry a, Geometry b) {
    return a.touches(b);
}

典型情况

  • 两个相邻的地块共享边界
  • 道路与地块的边界相接
  • 点落在线或面的边界上

交叉(Crosses)

两个几何对象的内部有公共部分,但既不相等也不包含,称为交叉:

/**
 * 判断几何是否交叉
 * 有公共区域但不是包含关系
 */
public static boolean crosses(Geometry a, Geometry b) {
    return a.crosses(b);
}

典型情况

  • 道路穿过区域(线与面交叉)
  • 两条道路相交(线与线交叉)

包含(Contains)与被包含(Within)

包含关系描述一个几何完全位于另一个几何内部:

/**
 * 判断几何A是否包含几何B
 */
public static boolean contains(Geometry a, Geometry b) {
    return a.contains(b);
}

/**
 * 判断几何A是否在几何B内部
 */
public static boolean within(Geometry a, Geometry b) {
    return a.within(b);
}

关系说明

contains(a, b) == within(b, a)

应用场景

  • 判断点是否在某个区域内
  • 判断某个地块是否完全位于行政区划内
  • 空间过滤:只保留完全落入指定范围的要素

重叠(Overlaps)

两个同维度的几何对象有公共区域,但又不完全相同,称为重叠:

/**
 * 判断几何是否重叠
 * 有公共区域且包含关系不成立
 */
public static boolean overlaps(Geometry a, Geometry b) {
    return a.overlaps(b);
}

说明:重叠只发生在同维度几何之间(面与面、线与线)。

距离计算

最短距离

计算两个几何对象之间的最短距离:

/**
 * 计算几何之间的距离
 * 不论点线面都是几何间最短距离
 */
public static double distance(Geometry a, Geometry b) {
    return a.distance(b);
}

注意:返回值的单位与坐标系单位一致。地理坐标系返回的是度,投影坐标系返回的是米。

距离判断

快速判断两个几何是否在指定距离内:

/**
 * 判断几何间最短距离是否小于给定距离
 */
public static boolean isWithinDistance(Geometry a, Geometry b, double distance) {
    return a.isWithinDistance(b, distance);
}

应用场景

  • 近邻搜索:查找指定距离内的设施
  • 缓冲区分析:判断要素是否在某要素的影响范围内
  • 预警系统:判断两个移动目标是否过于接近

DE-9IM模型

DE-9IM(Dimensionally Extended 9-Intersection Model)是空间关系的标准描述模型,提供了更精确的空间关系判断。

关系矩阵

         Interior  Boundary  Exterior
Interior    II        IB        IE
Boundary    BI        BB        BE
Exterior    EI        EB        EE

每个位置的值表示两个几何对应部分的交集维度:

  • T:有交集(任意维度)
  • F:无交集
  • 0:交集为点
  • 1:交集为线
  • 2:交集为面
  • *:任意(不关心)

获取关系矩阵

/**
 * 获取几何关系矩阵
 */
public static String relate(Geometry a, Geometry b) {
    return a.relate(b).toString();
}

模式匹配

使用模式字符串判断特定空间关系:

/**
 * 判断几何是否符合给定关系
 * @param pattern 关系模式,如"T*T***FF*"
 */
public static boolean relatePattern(Geometry a, Geometry b, String pattern) {
    return a.relate(b, pattern);
}

常用模式

关系 模式
内部相交 T********
边界相交 *T*******
A完全包含B T*****FF*
相邻(共享边界) FF*FT****

几何相等判断

精确相等

判断两个几何是否结构完全相同:

/**
 * 判断几何是否对象结构相等
 * 必须有相同的节点和相同的节点顺序
 */
public static boolean equalsExact(Geometry a, Geometry b) {
    return a.equalsExact(b);
}

/**
 * 带容差的结构相等判断
 */
public static boolean equalsExactTolerance(Geometry a, Geometry b, double tolerance) {
    return a.equalsExact(b, tolerance);
}

规范化相等

判断两个几何在规范化后是否相同:

/**
 * 判断几何是否对象结构相等(不判断节点顺序)
 */
public static boolean equalsNorm(Geometry a, Geometry b) {
    return a.equalsNorm(b);
}

拓扑相等

判断两个几何是否表示相同的点集:

/**
 * 判断几何是否拓扑相等
 */
public static boolean equalsTopo(Geometry a, Geometry b) {
    return a.equalsTopo(b);
}

区别说明

  • equalsExact:节点顺序、数量都必须完全相同
  • equalsNorm:规范化后比较,忽略节点顺序
  • equalsTopo:只比较几何表示的空间是否相同

ESRI几何引擎

除了JTS,还可以使用ESRI几何引擎进行空间关系分析,其API基于WKT字符串:

空间关系判断

/**
 * 几何是否相交
 */
public static boolean intersects(String awkt, String bwkt, Integer wkid) {
    Geometry a = EsriUtil.createGeometryByWkt(awkt);
    Geometry b = EsriUtil.createGeometryByWkt(bwkt);
    SpatialReference sr = SpatialReference.create(wkid);
    return OperatorIntersects.local().execute(a, b, sr, null);
}

/**
 * 判断几何是否相离
 */
public static boolean disjoint(String awkt, String bwkt, Integer wkid) {
    Geometry a = EsriUtil.createGeometryByWkt(awkt);
    Geometry b = EsriUtil.createGeometryByWkt(bwkt);
    SpatialReference sr = SpatialReference.create(wkid);
    return OperatorDisjoint.local().execute(a, b, sr, null);
}

/**
 * 判断几何是否接触
 */
public static boolean touches(String awkt, String bwkt, Integer wkid) {
    Geometry a = EsriUtil.createGeometryByWkt(awkt);
    Geometry b = EsriUtil.createGeometryByWkt(bwkt);
    SpatialReference sr = SpatialReference.create(wkid);
    return OperatorTouches.local().execute(a, b, sr, null);
}

/**
 * 判断几何是否包含
 */
public static boolean contains(String awkt, String bwkt, Integer wkid) {
    Geometry a = EsriUtil.createGeometryByWkt(awkt);
    Geometry b = EsriUtil.createGeometryByWkt(bwkt);
    SpatialReference sr = SpatialReference.create(wkid);
    return OperatorContains.local().execute(a, b, sr, null);
}

选择建议

  • JTS:内存中的几何对象操作,性能更好
  • ESRI:基于WKT字符串操作,接口更简洁

实践案例

案例1:空间查询

查找与指定区域相交的所有要素:

/**
 * 空间查询:找出与指定区域相交的要素
 */
public List<WktFeature> spatialQuery(WktLayer layer, String queryWkt) {
    List<WktFeature> result = new ArrayList<>();
    Geometry queryGeom = GeometryConverter.wkt2Geometry(queryWkt);
    
    for (WktFeature feature : layer.getFeatures()) {
        Geometry featureGeom = GeometryConverter.wkt2Geometry(feature.getWkt());
        if (featureGeom.intersects(queryGeom)) {
            result.add(feature);
        }
    }
    return result;
}

案例2:点在面内判断

判断一个点是否位于某个多边形内部:

/**
 * 判断点是否在面内
 */
public boolean isPointInPolygon(double x, double y, String polygonWkt) {
    GeometryFactory factory = new GeometryFactory();
    Point point = factory.createPoint(new Coordinate(x, y));
    Geometry polygon = GeometryConverter.wkt2Geometry(polygonWkt);
    
    // 使用contains判断(严格在内部)
    // 或使用intersects判断(含边界上的点)
    return polygon.contains(point);
}

案例3:相邻要素查找

查找与指定要素相邻(共享边界)的所有要素:

/**
 * 查找相邻要素
 */
public List<WktFeature> findAdjacentFeatures(WktLayer layer, WktFeature target) {
    List<WktFeature> result = new ArrayList<>();
    Geometry targetGeom = GeometryConverter.wkt2Geometry(target.getWkt());
    
    for (WktFeature feature : layer.getFeatures()) {
        if (feature.getWfId().equals(target.getWfId())) {
            continue;  // 跳过自己
        }
        
        Geometry featureGeom = GeometryConverter.wkt2Geometry(feature.getWkt());
        
        // 相邻:接触但不重叠
        if (featureGeom.touches(targetGeom)) {
            result.add(feature);
        }
    }
    return result;
}

案例4:缓冲区范围查询

查找指定位置周边一定距离内的设施:

/**
 * 缓冲区范围查询
 * @param centerWkt 中心点WKT
 * @param distance 查询距离(米)
 * @param layer 要素图层
 */
public List<WktFeature> bufferQuery(String centerWkt, double distance, WktLayer layer) {
    List<WktFeature> result = new ArrayList<>();
    
    // 转换到投影坐标系计算缓冲区
    int projWkid = CrsUtil.getProjectedWkid(CrsUtil.getDh(centerWkt));
    String projWkt = CrsUtil.transform(centerWkt, 4490, projWkid);
    
    // 创建缓冲区
    Geometry center = GeometryConverter.wkt2Geometry(projWkt);
    Geometry buffer = center.buffer(distance);
    
    // 将缓冲区转回地理坐标系进行查询
    buffer = CrsUtil.transform(buffer, projWkid, layer.getWkid());
    
    // 查询相交要素
    for (WktFeature feature : layer.getFeatures()) {
        Geometry featureGeom = GeometryConverter.wkt2Geometry(feature.getWkt());
        if (featureGeom.intersects(buffer)) {
            result.add(feature);
        }
    }
    return result;
}

案例5:空间关系矩阵分析

使用DE-9IM进行精确的空间关系分析:

/**
 * 分析两个地块的空间关系
 */
public String analyzeRelation(String wkt1, String wkt2) {
    Geometry geom1 = GeometryConverter.wkt2Geometry(wkt1);
    Geometry geom2 = GeometryConverter.wkt2Geometry(wkt2);
    
    // 获取关系矩阵
    String matrix = relate(geom1, geom2);
    
    // 解析关系类型
    if (geom1.equals(geom2)) {
        return "相等";
    } else if (geom1.contains(geom2)) {
        return "A包含B";
    } else if (geom1.within(geom2)) {
        return "A在B内";
    } else if (geom1.overlaps(geom2)) {
        return "部分重叠";
    } else if (geom1.touches(geom2)) {
        return "相邻(共享边界)";
    } else if (geom1.crosses(geom2)) {
        return "穿越";
    } else if (geom1.intersects(geom2)) {
        return "相交";
    } else {
        return "相离";
    }
}

性能优化

空间索引

对于大数据量的空间查询,使用空间索引可以显著提升性能:

// 构建R树索引
STRtree index = new STRtree();
for (WktFeature feature : layer.getFeatures()) {
    Geometry geom = GeometryConverter.wkt2Geometry(feature.getWkt());
    index.insert(geom.getEnvelopeInternal(), feature);
}
index.build();

// 使用索引查询
Geometry queryGeom = GeometryConverter.wkt2Geometry(queryWkt);
List<?> candidates = index.query(queryGeom.getEnvelopeInternal());

// 对候选要素进行精确判断
for (Object obj : candidates) {
    WktFeature feature = (WktFeature) obj;
    Geometry featureGeom = GeometryConverter.wkt2Geometry(feature.getWkt());
    if (featureGeom.intersects(queryGeom)) {
        // 真正相交的要素
    }
}

外包矩形预筛选

在进行精确空间关系判断前,先用外包矩形快速过滤:

// 先判断外包矩形是否相交
if (!geomA.getEnvelopeInternal().intersects(geomB.getEnvelopeInternal())) {
    return false;  // 外包矩形不相交,几何必定不相交
}
// 再进行精确判断
return geomA.intersects(geomB);

小结

本章介绍了空间关系分析的核心内容:

  1. 基本空间关系:相交、相离、接触、交叉、包含、重叠
  2. 距离计算:最短距离计算和距离判断
  3. DE-9IM模型:精确的空间关系描述和模式匹配
  4. 几何相等:精确相等、规范化相等、拓扑相等
  5. 性能优化:空间索引和外包矩形预筛选

下一章将介绍空间计算操作,学习如何进行缓冲区分析、叠加分析等操作。