空间要素并非孤立存在。每一个点、每一条线、每一个面,都是地理世界中相互关联的实体。理解它们之间的空间关系——距离、方位、包含、相交、邻近——是地理认知的起点,也是所有空间决策的基础。

空间分析的深层意义,在于将零散的地理坐标转化为有结构的关系网络。当数据之间的空间联系被系统地揭示出来,原本沉寂的位置信息便获得了语义:一个点位是否落在某个区域之内,两条路径是否交汇于某处,两个边界之间是否存在重叠。这些关系一旦被量化与显化,便能够支撑起从资源规划到灾害评估、从物流优化到生态保护等广泛领域的实际决策。这正是空间关系分析作为一个独立领域而存在的根本原因。

空间数据分析遵循"解析—分类—度量—关联—输出"的递进式方法论,每一步都是对空间认知的深化。

分析流程

  1. 空间数据解析:从地理标记文件中读取并提取空间要素的几何信息与属性信息。这一步骤需要识别不同的几何类型,将文本描述的结构化地理数据转换为可计算的空间对象。

  2. 几何类型分类:根据要素的几何形态将其归入点、线、面三大类别。分类的目的是为后续分析建立明确的类型上下文——不同类型的要素需采用不同的度量方法和关系判定逻辑。

  3. 单体属性度量:对每个独立要素计算其内在的几何属性。对于点,提取其经纬度坐标;对于线,计算其总长度、首尾端点位置;对于面,计算其面积、几何中心(质心)位置以及边界信息(如是否存在孔洞)。这些基础度量为后续的关系分析提供参照基准。

  4. 空间关系判定:在两两要素之间执行空间谓词计算,这是整个分析流程的核心。具体包括:

    • 距离与方位:计算两点之间的大地线距离和方位角,采用球面几何模型以考虑地球曲率的影响。
    • 邻近关系:计算点到线的最短距离,并定位线上最近点;计算点到面的最短距离,同时判定点是否位于面的边界之上。
    • 包含关系:采用射线法判定点是否位于多边形内部;基于集合关系判定一条线或一个面是否完全位于另一个面之内。
    • 相交与拓扑关系:判定线线之间是否相交、交叉、平行、重叠或相等;判定线与面之间是否穿越、包含或相交;判定面与面之间是否重叠、包含、分离或相等,并计算交叠区域的面积。
  5. 结果聚合与输出:将所有分析结果按类型组织为结构化的表格数据,支持多格式导出,确保分析成果可被下游系统或人工审阅直接使用。

设计原则

  • 类型安全:严格区分点、线、面三种几何类型,避免不同类型之间的误操作
  • 计算效率:对同一类型要素的两两关系分析,仅计算上三角矩阵以避免重复运算
  • 容错性:对解析过程中遇到的异常数据予以记录并继续处理,而非整体中断

本工具集成了以下技术组件实现空间数据的解析、分析与导出。

核心技术依赖

@turf/turf — 空间分析引擎

  • 用途:提供完整的空间几何计算与布尔关系判定功能,包括距离、方位角、面积、质心、线上最近点、线交点,以及包含、相交、交叉、平行、重叠、分离、相等、点在线判断、点在面内判断等空间谓词。
  • 官网:https://www.npmjs.com/package/@turf/turf
  • GitHub:https://github.com/Turfjs/turf
  • 项目角色:承担全部空间分析计算的底层实现,从简单属性度量到复杂拓扑关系判断均由 Turf.js 完成。

togeojson — KML 格式转换

  • 用途:将 KML(Keyhole Markup Language)格式的地理标记文档转换为 GeoJSON 标准的地理要素集合。
  • 官网:https://www.npmjs.com/package/togeojson
  • GitHub:https://github.com/mapbox/togeojson
  • 项目角色:作为 KML 文件解析的核心桥梁,将 XML 结构的 KML 文档转换为标准化的 GeoJSON FeatureCollection,供后续分析使用。

jszip — KMZ 压缩文件处理

  • 用途:读取并解压 KMZ 格式文件(本质上是一个包含 KML 文件的 ZIP 压缩包),从中提取 KML 内容。
  • 官网:https://www.npmjs.com/package/jszip
  • GitHub:https://github.com/Stuk/jszip
  • 项目角色:用于处理 KMZ 格式的上传文件,解压后提取其中包含的 .kml 文件,再交由 togeojson 进行解析。

xlsx (SheetJS) — 表格数据导出

  • 用途:将分析结果导出为 Excel (.xlsx) 和 CSV 格式的电子表格文件。
  • 官网:https://www.npmjs.com/package/xlsx
  • GitHub:https://github.com/SheetJS/sheetjs
  • 项目角色:将分析结果的结构化数据写入工作簿并触发浏览器下载,支持多工作表和多格式导出。

关键实现

KML 文件解析与 GeoJSON 转换

const parser = new DOMParser()
const xmlDoc = parser.parseFromString(content, 'text/xml')

const parseError = xmlDoc.querySelector('parsererror')
if (parseError) {
  errors.push('KML 文件格式不正确,无法解析')
  return { success: false, features: [], errors, totalPoints: 0, totalLines: 0, totalPolygons: 0 }
}

const geojson = toGeoJson.kml(xmlDoc)

设计思路:使用浏览器原生的 DOMParser 解析 XML 内容,通过检查 parsererror 节点快速判定格式合法性,再交由 togeojson 完成 KML 到 GeoJSON 的语义转换。

KMZ 文件解压与提取

const zip = await JSZip.loadAsync(arrayBuffer)

// 查找 KML 文件
const kmlFile = zip.file(/\.kml$/i)[0]
if (!kmlFile) {
  errors.push('KMZ 文件中未找到 KML 文件')
  return { success: false, features: [], errors, totalPoints: 0, totalLines: 0, totalPolygons: 0 }
}

const kmlContent = await kmlFile.async('string')

设计思路:使用正则匹配在 ZIP 包中定位 .kml 文件而非硬编码文件名,增强了容错性。将 ArrayBuffer 加载、文件查找、内容提取分为三个清晰的异步步骤。

点与点关系分析(两两笛卡尔积,上三角优化)

for (let i = 0; i < points.length; i++) {
  for (let j = i + 1; j < points.length; j++) {
    const ptA = turf.point(pointA.coordinates)
    const ptB = turf.point(pointB.coordinates)
    const distance = turf.distance(ptA, ptB, { units: 'kilometers' })
    const bearing = turf.bearing(ptA, ptB)

    data.push({
      距离_km: distance.toFixed(4),
      方位角_度: bearing.toFixed(2),
      是否重合: turf.booleanEqual(ptA, ptB) ? '是' : '否',
    })
  }
}

设计思路:内层循环从 j = i + 1 开始,仅遍历上三角矩阵,使计算次数从 n² 降为 n(n-1)/2,避免重复计算 A→B 和 B→A。距离采用公里单位并保留 4 位小数,方位角保留 2 位小数。

线与线拓扑关系判定

const intersections = turf.lineIntersect(lineA, lineB)

data.push({
  是否相交: turf.booleanIntersects(lineA, lineB) ? '是' : '否',
  是否交叉: turf.booleanCrosses(lineA, lineB) ? '是' : '否',
  是否平行: turf.booleanParallel(lineA, lineB) ? '是' : '否',
  是否相等: turf.booleanEqual(lineA, lineB) ? '是' : '否',
  是否重叠: turf.booleanOverlap(lineA, lineB) ? '是' : '否',
  交点数量: intersections.features.length,
})

设计思路:通过 Turf.js 的多种布尔谓词函数一次性覆盖所有线线关系维度,每个判断互不依赖、并行可读。交点数量通过 lineIntersect 返回的 FeatureCollection 的 features 数量直接获取。

面与面交叠面积计算

let intersectionArea = '0'
try {
  const fcA = turf.featureCollection([polyA])
  const fcB = turf.featureCollection([polyB])
  const intersection = turf.intersect(fcA, fcB)
  if (intersection && intersection.features && intersection.features.length > 0) {
    intersectionArea = (turf.area(intersection) / 1000000).toFixed(4)
  }
} catch {
  intersectionArea = '0'
}

设计思路:将两个多边形分别包装为 FeatureCollection 后调用 turf.intersect 计算交集区域,再使用 turf.area 获取交叠面积。使用 try-catch 包裹以应对无交集或几何异常情况,确保分析流程不被单对数据的错误中断。

XLSX 多工作表导出

const workbook = XLSX.utils.book_new()

for (const result of results) {
  if (selectedTypes.includes(result.type)) {
    const worksheet = XLSX.utils.json_to_sheet(result.data)
    XLSX.utils.book_append_sheet(workbook, worksheet, result.label)
  }
}

XLSX.writeFile(workbook, `空间分析报告_${timestamp}.xlsx`)

设计思路:每种分析类型对应一个独立工作表,工作表名使用分析类型的中文标签。文件以"空间分析报告"加日期时间戳命名,直观可追溯。

几何类型分类与标准化接口

export interface GeoFeature {
  id: string
  name: string
  type: 'Point' | 'LineString' | 'Polygon'
  coordinates: number[] | number[][] | number[][][]
  properties: Record<string, unknown>
  feature: GeoJSON.Feature
}

export interface PointFeature extends GeoFeature {
  type: 'Point'
  coordinates: number[]
}

设计思路:定义统一的 GeoFeature 基础接口,再通过 TypeScript 的类型派生细化三种几何类型的坐标结构(一维数组/二维数组/三维数组),确保类型系统在编译期即可捕获不匹配的几何操作。

技术架构

整体数据流为单向流水线:

文件上传 (KML/KMZ)
  → 格式识别(扩展名检测)
    → [KML] DOMParser 解析 XML → togeojson 转 GeoJSON
    → [KMZ] JSZip 解压 → 提取 .kml → DOMParser 解析 → togeojson 转 GeoJSON
  → 几何类型分类(Point/LineString/Polygon,含 Multi 类型拍平)
  → 可用分析类型筛选(根据要素数量阈值)
  → 逐类型空间分析(Turf.js 计算)
  → 结果聚合 → 表格导出(SheetJS: XLSX/CSV)

每条分析任务支持进度回调与取消信号,确保长耗时计算(如大量要素的笛卡尔积分析)的用户体验可控。

空间分析

基于Turf.js的地理空间分析工具,支持点线面要素测量和空间关系判断

拖拽 KML/KMZ 文件到此处

或点击选择文件

工具简介

空间分析工具用于解析地理标记文件(KML/KMZ)中的空间要素,并对要素进行多维度空间关系分析与属性计算。支持点、线、面三类几何要素,覆盖单体属性度量和两两要素之间的空间关系判定(距离、方位、包含、相交、重叠等),分析结果可导出为 CSV 或 Excel 格式。

支持的输入类型与格式

格式 说明
KML (.kml) Keyhole Markup Language,地理标记语言文件
KMZ (.kmz) 压缩的 KML 文件(ZIP 格式),内部需包含 .kml 文件

支持的几何类型:Point(点)、MultiPoint(多点)、LineString(线)、MultiLineString(多线)、Polygon(面)、MultiPolygon(多面)。Multi 类型将自动归入对应的基础类型。

操作步骤

  1. 上传文件:拖拽 KML 或 KMZ 文件到页面中央的上传区域,或点击该区域选择文件。系统会自动识别文件格式并显示解析进度条。

  2. 查看解析结果:解析完成后,页面会展示文件中包含的点、线、面要素数量统计。如有解析警告,会在页面底部以黄色提示框列出具体问题。

  3. 选择分析类型:系统会根据文件中实际的要素数量自动勾选可执行的分析类型,你也可以手动勾选或使用"全选/取消全选/反选"按钮调整。灰色的选项表示当前文件不满足该分析的最低要素数量要求。

  4. 执行分析与导出:点击"开始分析"按钮,系统在弹窗中展示总体进度和当前任务进度。分析完成后,点击"导出数据"下拉按钮,选择 CSV 或 Excel 格式下载结果。

可选分析类型

分析类型 最低要素要求 说明
单点分析 1个点 提取每个点的名称、经纬度
单线分析 1条线 计算每条线的长度、端点坐标、节点数量
单面分析 1个面 计算每个面的面积、质心坐标、顶点数、是否有孔洞
点与点关系 2个点 两两点之间的直线距离、方位角、是否重合
点与线关系 1个点+1条线 点到线的距离、是否在线上、线上最近点坐标
点与面关系 1个点+1个面 点是否在面内/边界上、点到面的距离
线与线关系 2条线 是否相交/交叉/平行/相等/重叠、交点数量
线与面关系 1条线+1个面 是否相交/穿越/包含、交点数量
面与面关系 2个面 是否相交/重叠/包含/分离/相等、交叠面积

输入约束

  • 仅接受 .kml.kmz 后缀的文件,其他格式将被拒绝
  • KMZ 文件内部必须包含至少一个 .kml 文件,否则解析失败
  • KML 文件必须是合法的 XML 格式,存在语法错误的文件无法解析
  • 文件中至少需要包含一个有效地理要素(点、线或面),无要素的文件将被视为无效
  • 分析类型根据要素数量自动判断可用性,不满足最低数量要求的类型无法选择

注意事项

  1. 文件大小限制:较大的 KML/KMZ 文件(如超过 50MB)可能导致浏览器解析缓慢或内存溢出,建议拆分后再上传。对于包含数千个要素的文件,点与点、面与面的两两关系分析耗时较长(时间复杂度为 O(n²)),请耐心等待或适时使用取消按钮。

  2. 坐标系默认:工具假定所有输入的经纬度坐标采用 WGS84 坐标系。如果您的 KML 文件中使用了其他坐标系,计算结果将存在偏差。建议在导出 KML 时确保坐标系为 WGS84。

  3. 几何精度:距离和面积计算基于球面几何模型(考虑地球曲率),结果保留 4 位小数。该精度适用于一般的地理信息分析场景,但对于高精度测绘或工程测量,建议使用专业 GIS 软件进行复核。

  4. Multi 几何类型的处理:文件中包含的 MultiPoint、MultiLineString、MultiPolygon 类型会被自动转换为对应的基础类型(Point、LineString、Polygon)进行统计和分析。请注意这种转换可能导致集几何的内部结构信息丢失。

  5. 分析取消机制:在分析过程中点击"取消"按钮后,已完成的分析类型结果会保留,未开始的任务会被跳过。取消操作无法撤销,如需恢复需重新点击"开始分析"。

  6. 导出文件兼容性:CSV 导出使用 UTF-8 编码并带 BOM 头,可直接在 Microsoft Excel 中正常打开中文内容。Excel (.xlsx) 导出中每个分析类型对应一个独立工作表,以分析类型名称命名。

中国各省访问量分布图

鼠标悬停查看各省份的访问数据统计

用户评论

所有评论均为匿名发布

1 浏览0 条评论
vzrk
暂无评论,来说两句吧