问题描述
我使用 truf.js 提取一个 lineString 的 bbox ,再根据 bbox 得到一个 bboxPolygon,最后将数据写入带 2dsphere
索引的文档,这时有些特定的 lineString 会出现入库失败,原因是 MongoDb 提示 polygon 至少需要3个点。
// 计算 lineString 对象的矩形边界
const turf = require("@turf/turf");
let lineString = {
type : "LineString",
coordinates : [ [10,25],
[11,25],
[12,25],
[15,25],
[20,25]]
}
const bbox = turf.bbox(lineString);
const bboxPolygon = turf.bboxPolygon(bbox);
// TODO: 写库
原因分析:
在检查 bbox 的数据时发现:
[[10,25],[20,25]]
这是一个直线
,两个Y坐标是一致的,结果导致 bbox
生成的 bboxPolygon
数据也不对:
[
[10,25],
[20,25],
[20,25],
[10,25],
[10,25]
]
排重后只有两个点,这在 MongoDb 入库时的 2dsphere
索引判定就会报错。
解决方案:
对 bbox 的第二个点做微小位移,防止
bboxPolygon
的点少于3个
/**
* 计算 lineString 对象的矩形边界
* 对 bbox 做检查,防止 bbox 成为直线
* 如果 bboxPolygon 使用 bbox 生成,在入库到mongoDb 时会报错
*/
calculateRectangleBounds(turfLineString) {
// 计算 lineString 对象的矩形边界
let bbox = turf.bbox(turfLineString);
// 检查 bbox 点集合被压缩成直线的情况
let [x1, y1, x2, y2] = bbox;
// 如果被压缩成直线,对后一个点的坐标做微小的位移
let isFixed = false;
if (x1 === x2) {
x2 = this.floatTinyOffset(x2);
isFixed = true;
}
if (y1 === y2) {
y2 = this.floatTinyOffset(y2);
isFixed = true;
}
if (isFixed) {
bbox = [x1, y1, x2, y2];
}
const bboxPolygon = turf.bboxPolygon(bbox);
return bboxPolygon;
}
/**
* 对浮点数做微小的加法
* eg: 38.1280970893173 -> 38.1280970893174
* @param {Number} floatNumber
* @returns Number
*/
floatTinyOffset(floatNumber) {
floatNumber = _.toNumber(floatNumber);
let [zs, xs] = floatNumber.toString().split(".");
return _.toNumber(zs + "." + (_.toInteger(xs) + 1));
}