空间要素并非孤立存在。每一个点、每一条线、每一个面,都是地理世界中相互关联的实体。理解它们之间的空间关系——距离、方位、包含、相交、邻近——是地理认知的起点,也是所有空间决策的基础。
空间分析的深层意义,在于将零散的地理坐标转化为有结构的关系网络。当数据之间的空间联系被系统地揭示出来,原本沉寂的位置信息便获得了语义:一个点位是否落在某个区域之内,两条路径是否交汇于某处,两个边界之间是否存在重叠。这些关系一旦被量化与显化,便能够支撑起从资源规划到灾害评估、从物流优化到生态保护等广泛领域的实际决策。这正是空间关系分析作为一个独立领域而存在的根本原因。
空间数据分析遵循"解析—分类—度量—关联—输出"的递进式方法论,每一步都是对空间认知的深化。
空间数据解析:从地理标记文件中读取并提取空间要素的几何信息与属性信息。这一步骤需要识别不同的几何类型,将文本描述的结构化地理数据转换为可计算的空间对象。
几何类型分类:根据要素的几何形态将其归入点、线、面三大类别。分类的目的是为后续分析建立明确的类型上下文——不同类型的要素需采用不同的度量方法和关系判定逻辑。
单体属性度量:对每个独立要素计算其内在的几何属性。对于点,提取其经纬度坐标;对于线,计算其总长度、首尾端点位置;对于面,计算其面积、几何中心(质心)位置以及边界信息(如是否存在孔洞)。这些基础度量为后续的关系分析提供参照基准。
空间关系判定:在两两要素之间执行空间谓词计算,这是整个分析流程的核心。具体包括:
结果聚合与输出:将所有分析结果按类型组织为结构化的表格数据,支持多格式导出,确保分析成果可被下游系统或人工审阅直接使用。
本工具集成了以下技术组件实现空间数据的解析、分析与导出。
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 的语义转换。
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 包裹以应对无交集或几何异常情况,确保分析流程不被单对数据的错误中断。
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 类型将自动归入对应的基础类型。
上传文件:拖拽 KML 或 KMZ 文件到页面中央的上传区域,或点击该区域选择文件。系统会自动识别文件格式并显示解析进度条。
查看解析结果:解析完成后,页面会展示文件中包含的点、线、面要素数量统计。如有解析警告,会在页面底部以黄色提示框列出具体问题。
选择分析类型:系统会根据文件中实际的要素数量自动勾选可执行的分析类型,你也可以手动勾选或使用"全选/取消全选/反选"按钮调整。灰色的选项表示当前文件不满足该分析的最低要素数量要求。
执行分析与导出:点击"开始分析"按钮,系统在弹窗中展示总体进度和当前任务进度。分析完成后,点击"导出数据"下拉按钮,选择 CSV 或 Excel 格式下载结果。
| 分析类型 | 最低要素要求 | 说明 |
|---|---|---|
| 单点分析 | 1个点 | 提取每个点的名称、经纬度 |
| 单线分析 | 1条线 | 计算每条线的长度、端点坐标、节点数量 |
| 单面分析 | 1个面 | 计算每个面的面积、质心坐标、顶点数、是否有孔洞 |
| 点与点关系 | 2个点 | 两两点之间的直线距离、方位角、是否重合 |
| 点与线关系 | 1个点+1条线 | 点到线的距离、是否在线上、线上最近点坐标 |
| 点与面关系 | 1个点+1个面 | 点是否在面内/边界上、点到面的距离 |
| 线与线关系 | 2条线 | 是否相交/交叉/平行/相等/重叠、交点数量 |
| 线与面关系 | 1条线+1个面 | 是否相交/穿越/包含、交点数量 |
| 面与面关系 | 2个面 | 是否相交/重叠/包含/分离/相等、交叠面积 |
.kml 和 .kmz 后缀的文件,其他格式将被拒绝.kml 文件,否则解析失败文件大小限制:较大的 KML/KMZ 文件(如超过 50MB)可能导致浏览器解析缓慢或内存溢出,建议拆分后再上传。对于包含数千个要素的文件,点与点、面与面的两两关系分析耗时较长(时间复杂度为 O(n²)),请耐心等待或适时使用取消按钮。
坐标系默认:工具假定所有输入的经纬度坐标采用 WGS84 坐标系。如果您的 KML 文件中使用了其他坐标系,计算结果将存在偏差。建议在导出 KML 时确保坐标系为 WGS84。
几何精度:距离和面积计算基于球面几何模型(考虑地球曲率),结果保留 4 位小数。该精度适用于一般的地理信息分析场景,但对于高精度测绘或工程测量,建议使用专业 GIS 软件进行复核。
Multi 几何类型的处理:文件中包含的 MultiPoint、MultiLineString、MultiPolygon 类型会被自动转换为对应的基础类型(Point、LineString、Polygon)进行统计和分析。请注意这种转换可能导致集几何的内部结构信息丢失。
分析取消机制:在分析过程中点击"取消"按钮后,已完成的分析类型结果会保留,未开始的任务会被跳过。取消操作无法撤销,如需恢复需重新点击"开始分析"。
导出文件兼容性:CSV 导出使用 UTF-8 编码并带 BOM 头,可直接在 Microsoft Excel 中正常打开中文内容。Excel (.xlsx) 导出中每个分析类型对应一个独立工作表,以分析类型名称命名。
鼠标悬停查看各省份的访问数据统计
所有评论均为匿名发布
您上传的文件存在以下问题,请检查后重新上传: