JSTS是一个符合OGC标准的,包含空间拓扑功能的JavaScript类库。和turf类似,区别在于,JSTS是通过原始JTS Java 源代码翻译来的,保留了JTSAPI;而turf来自MapBox。个人感觉JSTS的文档不如turf明了(一些网址还404了),但是可以直接适用OpenLayers(以下简称OL)的几何对象,对JTS API熟悉的话在OL工程里可能会更方便。
JSTS的参考文档比较分散,GitHub库里有比较全面的简介,这个地址里有一些简单的示例,JTS API直接用的JavaAPI,看起来并不直观,另外使用了一些空间数据类型读取类代替JavaAPI里的IO部分。
所以若想比较完整的了解JSTS类库和基础使用,建议按照顺序,先浏览Github库的README.md,直接用谷歌浏览器的机翻大概看一遍,然后看一下简单示例,到具体的代码编写时,数据读写部分参考http://bjornharrtell.github.io/jsts/1.6.1/doc/index.html,空间功能部分参考JavaAPI。
注,以下个人应用示例用的是Vue2+TS,若你的环境不一样请自行修改
安装和调用
没啥好说的,使用npm/yarn啥的自行安装,或者引用在线地址
引用时,若使用npm包,由于jsts没有类型声明文件,固然有一些比较好的方法,我这里还是图省事直接用的require。调用代码如下
// 引入OL几何类
import Geometry from "ol/geom/Geometry";
import { LineString, LinearRing, MultiLineString, MultiPoint, MultiPolygon, Point, Polygon } from "ol/geom";
// 引入jsts
const jsts = require("jsts/dist/jsts.min.js");
// 实例化OL解析类
const OLParser = new jsts.io.OL3Parser();
// 注入OL几何对象
OLParser.inject(Point, LineString, LinearRing, Polygon, MultiPoint, MultiLineString, MultiPolygon);
功能示例
先定义了一个函数类型
type TopoFunc = (...params: any) => Geometry | null;
缓冲区
/**
* 缓冲区
* @param geom
* @param len 缓冲区距离,单位米
* @returns
*/
const getBuffer: TopoFunc = (geom: Geometry, len: number) => {
const jstsGeom = OLParser.read(geom);
if (!jstsGeom.isValid()) {
console.error("几何对象出现拓扑错误,请检查修复");
return null;
}
const buffered = jstsGeom.buffer(len);
return OLParser.write(buffered);
};
取交
/**
* 取交
* @param geom
* @param geomB
* @returns
*/
const intersects: TopoFunc = (geom: Geometry, geomB: Geometry) => {
const jstsGeom = OLParser.read(geom);
const jstsGeomB = OLParser.read(geomB);
if (!jstsGeom.isValid() || !jstsGeomB.isValid()) {
console.error("几何对象出现拓扑错误,请检查修复");
return null;
}
const difference = jstsGeom.intersection(jstsGeomB);
return OLParser.write(difference);
};
取补
/**
* 取geom中geomB的补集
* @param geom
* @param geomB
* @returns
*/
const getDifference: TopoFunc = (geom: Geometry, geomB: Geometry) => {
const jstsGeom = OLParser.read(geom);
const jstsGeomB = OLParser.read(geomB);
if (!jstsGeom.isValid() || !jstsGeomB.isValid()) {
console.error("几何对象出现拓扑错误,请检查修复");
return null;
}
const difference = jstsGeom.difference(jstsGeomB);
return OLParser.write(difference);
};
融合
/**
* 融合
* @param geom
* @param geomB
* @returns
*/
const union: TopoFunc = (geom: Geometry, geomB: Geometry) => {
const jstsGeom = OLParser.read(geom);
const jstsGeomB = OLParser.read(geomB);
if (!jstsGeom.isValid() || !jstsGeomB.isValid()) {
console.error("几何对象出现拓扑错误,请检查修复");
return null;
}
const difference = jstsGeom.union(jstsGeomB);
return OLParser.write(difference);
};
对等差分
/**
* 对等差分
* @param geom
* @param geomB
* @returns
*/
const symDifference: TopoFunc = (geom: Geometry, geomB: Geometry) => {
const jstsGeom = OLParser.read(geom);
const jstsGeomB = OLParser.read(geomB);
if (!jstsGeom.isValid() || !jstsGeomB.isValid()) {
console.error("几何对象出现拓扑错误,请检查修复");
return null;
}
const difference = jstsGeom.symDifference(jstsGeomB);
return OLParser.write(difference);
};
备注
工作中遇到个拓扑错误,多边形自相交
尝试使用GeometryPrecisionReducer降低精度,但还是有问题,就索性代码里直接抛出,手动修改数据来修复吧。GeometryPrecisionReducer的代码也附下,执行没啥问题,但是结果依然不好,感兴趣可以研究下
function topoFix(jstsGeom: any) {
if (jstsGeom.isValid()) {
return jstsGeom;
}
const reducer = new jsts.precision.GeometryPrecisionReducer();
// 这里直接使用reduce方法会直接报错
// 若使用reducer.fixPolygonalTopology会正常执行,但返回的几何不大对,后面使用会报一样的错
return reducer.reduce(jstsGeom);
}
错误