@tslsmart/map_adapter
Version:
an adapter for maps,基于高德JSAPI 2.0,百度JavaScript API GL,arcgis api for javascript 3.23,光辉城市及51world sdk
602 lines (559 loc) • 19.9 kB
JavaScript
import * as turf from '@turf/turf'
import { MapFeatureType } from './BasicClass'
import { MapCoordTrans } from '../export/MapCoordTrans'
/**
*@class GeospatialAnalysis
*@classdesc 空间分析,坐标系为wgs84
*/
export class GeospatialAnalysis {
/**
* 获取要素集合范围(多点,多线,多面 或者组合)
* @param {object[]} geoObj 要素集合
* @param {MapFeatureType} geoObj.type 要素类型
* @param {number[]} geoObj.features 要素集合
* @returns 边界范围[minX, minY, maxX, maxY]
*/
getBoundingBox(geoObj) {
var collection = this._getFeatureCollection(geoObj)
var features = turf.featureCollection(collection)
return turf.bbox(features)
}
/**
* 获取要素集合中心点(多点,多线,多面 或者组合)
* @param {object[]} geoObj 要素集合
* @param {MapFeatureType} geoObj.type 要素类型
* @param {number[]} geoObj.features 要素集合
* @returns 中心点坐标[centerX, centerY]
*/
getBoundingCenter(geoObj) {
var collection = this._getFeatureCollection(geoObj)
var features = turf.featureCollection(collection)
var center = turf.center(features)
return center.geometry.coordinates
}
//geoObj =[{type:'point',features:[]},{type:'line',features:[]},{type:'polygon',features:[]}]
_getFeatureCollection(geoObj) {
var collection = []
for (var i = 0; i < geoObj.length; i++) {
if (geoObj[i].type == MapFeatureType.Point) {
collection.push(turf.multiPoint(geoObj[i].features))
} else if (geoObj[i].type == MapFeatureType.Line) {
collection.push(turf.multiLineString(geoObj[i].features))
} else if (geoObj[i].type == MapFeatureType.Polygon) {
var mpoly = []
for (var j = 0; j < geoObj[i].features.length; j++) {
mpoly.push([geoObj[i].features[j]])
}
collection.push(turf.multiPolygon(mpoly))
}
}
return collection
}
/**
* 单个多边形面积
* @param {Number[][]} boundary 多边形点
* @returns 面积,单位m2
*/
getArea(boundary) {
if (!this.booleanEqual(boundary[0], boundary[boundary.length - 1], MapFeatureType.Point)) {
boundary.push(boundary[0])
}
var polygon = turf.polygon([boundary])
return turf.area(polygon)
}
/**
* 获取两个点之间从正北算起的角度(0度),顺时针为正,逆时针为负
* @param {number[]} start 起始点
* @param {Number[]} end 终点
* @returns 角度 [-180,180]
*/
getAngle(start, end) {
var point1 = turf.point(start)
var point2 = turf.point(end)
return turf.bearing(point1, point2)
}
/**
* 获取两点距离
* @param {number[]} from 起点
* @param {number[]} to 终点
* @returns 距离,单位km
*/
getPointDistance(from, to) {
var from = turf.point(from)
var to = turf.point(to)
return turf.distance(from, to)
}
/**
* 返回点到直线的最小距离
* @param {number[]} pt 点
* @param {number[][]} path 线
* @returns 距离,单位km
*/
getNearestPathDistance(pt, path) {
var pt = turf.point(pt)
var line = turf.lineString(path)
return turf.pointToLineDistance(pt, line)
}
/**
* 获取线上离目标点最近的点
* @param {number[]} target 目标点
* @param {number[][]} path 线
* @returns 线上距离目标点最近的点
*/
getNearestPathPoint(target, path) {
var line = turf.lineString(path)
var pt = turf.point(target)
var snapped = turf.nearestPointOnLine(line, pt)
return snapped.geometry.coordinates
}
/**
* 获取点集里距离目标点最近的点
* @param {number[]} target 目标点
* @param {number[][]} points
* @returns
*/
getNearestPoint(target, points) {
var targetPoint = turf.point(target)
var mpoints = []
points.forEach((p) => {
mpoints.push(turf.point(p))
})
var pts = turf.featureCollection(mpoints)
var nearest = turf.nearestPoint(targetPoint, pts)
return nearest.geometry.coordinates
}
/**
* 获取线长度
* @param {number[][]} path 线
* @returns 长度,单位km
*/
getPathLength(path) {
var line = turf.lineString(path)
return turf.length(line)
}
/**
* 获取大圆路线
* @param {number[]} from 起点
* @param {number[]} to 终点
* @returns 路线点
*/
getGreatCircle(from, to) {
var start = turf.point(from)
var end = turf.point(to)
var gcircle = turf.greatCircle(start, end)
return gcircle.geometry.coordinates
}
/**
* 平滑路径(贝塞尔曲线)
* @param {number[][]} path 路径
* @returns 平滑后路径
*/
smoothPath(path, sharpness, resolution) {
var line = turf.lineString(path)
var spath = turf.bezierSpline(line, { sharpness: sharpness, resolution: resolution })
return spath.geometry.coordinates
}
/**
* 获取缓冲区(支持多个同类型要素)
* @param {object[]} geoObj
* @param {number} radius 缓冲区半径,单位km
* @returns 缓冲区
*/
getBufferArea(geoObj, radius) {
var collection = this._getFeatureCollection(geoObj)
var features = turf.featureCollection(collection)
var buf = turf.buffer(features, radius)
var area = []
buf.features.forEach((x) => {
area.push(this._loadoffMulti(x.geometry))
})
return area
}
_loadoffMulti(geometry) {
var items = []
if (geometry.type.startsWith('Multi')) {
for (var i = 0; i < geometry.coordinates.length; i++) {
items.push(geometry.coordinates[i][0])
}
} else {
items = geometry.coordinates
}
return items
}
/**
* 获取两个多边形交集
* @param {number[][]} poly1 多边形1
* @param {number[][]} poly2 多边形2
* @returns 交集存在,返回多边形数组;交集不存在,返回null
*/
getIntersect(poly1, poly2) {
var p1 = turf.polygon([poly1])
var p2 = turf.polygon([poly2])
var intersection = turf.intersect(p1, p2)
if (intersection) {
return intersection.geometry.coordinates
} else {
return intersection
}
}
/**
* 返回具有指定距离偏移量的线
* @param {number[][]} path 路径
* @param {number} offset 偏移距离,单位开km,可有负值
* @returns 偏移后路径点
*/
getLinebyOffset(path, offset) {
var line = turf.lineString(path)
var offsetLine = turf.lineOffset(line, offset)
return offsetLine.geometry.coordinates
}
/**
* 返回两个多边形的组合多边形,如果输入的多边形没有交集,这个函数将返回这两个多边形
* @param {number[][]} poly1 多边形1
* @param {number[][]} poly2 多边形2
* @returns 组合多边形或两个多边形
*/
getUnionArea(poly1, poly2) {
var p1 = turf.polygon([poly1])
var p2 = turf.polygon([poly2])
var union = turf.union(p1, p2)
var unionarea = this._loadoffMulti(union.geometry)
return unionarea
}
/**
* 获取两点间避开障碍物的最短路径
* @param {number[]} from 起点
* @param {number[]} to 终点
* @param {number[]} obstacles 障碍(多边形数组)
* @returns 最短路径
*/
getShortestPath(from, to, obstacles) {
var mpoly = []
var collection = []
for (var j = 0; j < obstacles.length; j++) {
mpoly.push([obstacles[j]])
}
collection.push(turf.multiPolygon(mpoly))
var feature = turf.featureCollection(collection)
var options = {
obstacles: feature
}
var path = turf.shortestPath(from, to, options)
return path.geometry.coordinates
}
/**
* idw插值
* @param {number[]} points 插值点集 [x,y,value]
* @param {number} gridsize 网格宽度,单位km
* @returns 插值结果 [{features:[],value}]
*/
interpolateIDW(points, gridsize) {
var collection = []
for (var i = 0; i < points.length; i++) {
collection.push(turf.point([points[i][0], points[i][1]], { value: points[i][2] }))
}
var feature = turf.featureCollection(collection)
var options = { gridType: 'triangle', property: 'value' }
var grid = turf.interpolate(feature, gridsize, options)
var out = []
turf.featureEach(grid, function (g) {
out.push({ features: g.geometry.coordinates[0], value: g.properties.value })
})
return out
}
/**
* 获得多边形内点
* @param {number[][]} points 要筛选的点集
* @param {number[][]} polygon 多边形
* @returns 在多边形内的点
*/
getPointsWithinPolygon(points, polygon) {
var pts = turf.multiPoint(points)
var searchWithin = turf.polygon([polygon])
var ptsW = turf.pointsWithinPolygon(pts, searchWithin)
var ptsWithin = []
if (ptsW.features.length > 0) {
for (var i = 0; i < ptsW.features[0].geometry.coordinates.length; i++) {
ptsWithin.push(ptsW.features[0].geometry.coordinates[i])
}
}
return ptsWithin
}
/**
* 获取两个多边形差集
* @param {number[][]} inputPoly 计算差集多边形
* @param {number[][]} overlayPoly 参照多边形
* @returns 差集多边形 inputPoly-overlayPoly
*/
getDifference(inputPoly, overlayPoly) {
var polygon1 = turf.polygon([inputPoly])
var polygon2 = turf.polygon([overlayPoly])
var difference = turf.difference(polygon1, polygon2)
return difference.geometry.coordinates
}
/**
* 点聚合
* @param {object[]} points 点集
* @param {number} distance 聚合距离
* @returns object[],聚合结果
*/
clustersDbscan(points, distance) {
var collection = []
for (var i = 0; i < points.length; i++) {
collection.push(turf.point(points[i].position, { id: points[i].id }))
}
var feature = turf.featureCollection(collection)
var clustered = turf.clustersDbscan(feature, distance)
var levels = []
turf.clusterEach(clustered, 'cluster', function (cluster, clusterValue, currentIndex) {
var centerCollection = turf.featureCollection(cluster.features)
var center = turf.center(centerCollection)
levels.push({ cluster: clusterValue, coord: center.geometry.coordinates, count: cluster.features.length })
})
var fIds = []
turf.geomEach(clustered, function (currentGeometry, featureIndex, featureProperties, featureBBox, featureId) {
if (featureProperties.cluster == undefined) {
fIds.push(featureProperties.id)
}
})
if (fIds.length > 0) {
levels.push({ cluster: -1, ids: fIds })
}
return levels
}
/**
* 点是否在多边形内
* @param {number[]} point 点
* @param {number[][]} polygon 多边形
* @returns bool
*/
booleanPointInPolygon(point, polygon) {
var pt = turf.point(point)
var poly = turf.polygon([polygon])
return turf.booleanPointInPolygon(pt, poly)
}
/**
* 点是否在线上
* @param {number[]} point 点
* @param {number[][]} line 线
* @returns bool
*/
booleanPointOnLine(point, line, accuracy) {
var pt = turf.point(point)
var linestr = turf.lineString(line)
return turf.booleanPointOnLine(pt, linestr, { epsilon: accuracy })
}
/**
* 相同类型的两要素是否相同
* @param {Number[]} feature1 要素1
* @param {Number[]} feature2 要素2
* @param {MapFeatureType} type 要素类型(点、线、面)
* @returns bool
*/
booleanEqual(feature1, feature2, type) {
var f1, f2
switch (type) {
case MapFeatureType.Point:
f1 = turf.point(feature1)
f2 = turf.point(feature2)
break
case MapFeatureType.Line:
f1 = turf.lineString(feature1)
f2 = turf.lineString(feature2)
break
case MapFeatureType.Polygon:
f1 = turf.polygon([feature1])
f2 = turf.polygon([feature2])
break
}
return turf.booleanEqual(f1, f2)
}
/**
* 面积单位转换
* @param {number} number 面积
* @param {string} oriUnit 当前面积单位,(kilometers, metres, centimetres, millimeters, acres, miles, yards, feet, inches, hectares)
* @param {string} desUnit 转换面积单位,(kilometers, metres, centimetres, millimeters, acres, miles, yards, feet, inches, hectares)
* @returns 转换后数据
*/
convertArea(number, oriUnit, desUnit) {
return turf.convertArea(number, oriUnit, desUnit)
}
/**
* 长度单位转换
* @param {number} number
* @param {string} oriUnit 当前长度单位,(miles, nauticalmiles, inches, yards, meters, metres, kilometers, centimeters, feet)
* @param {string} desUnit 转换面积单位,(miles, nauticalmiles, inches, yards, meters, metres, kilometers, centimeters, feet)
* @returns 转换后数据
*/
convertLength(number, oriUnit, desUnit) {
return turf.convertLength(number, oriUnit, desUnit)
}
/**
* 角度转弧度
* @param {number} degree 角度,(0-360),radians=degree*PI/180
* @returns 弧度
*/
degreesToRadians(degree) {
return turf.degreesToRadians(degree)
}
/**
* 弧度转角度
* @param {number} radians 弧度,超过PI,radians=radians-n*2PI,degree=radians*180/PI
* @returns 角度,(0-360)
*/
radiansToDegrees(radians) {
return turf.radiansToDegrees(radians)
}
/**
* 路径平滑插值
* @param {number[][]} paths 路径点
* @param {number} speed 行驶路径速度,m/s
* @param {number} seed 定时器间隔,单位ms
* @param {number} iconAngle 图片角度
* @return {number[]} 插值后路径
*/
getPathStepPoints(paths, speed, seed, iconAngle) {
var pathPoints = []
var pathLastIndex = paths.length - 1
for (var i = 0; i < pathLastIndex; i++) {
var longitude1 = paths[i][0]
var latitude1 = paths[i][1]
var longitude2 = paths[i + 1][0]
var latitude2 = paths[i + 1][1]
//两点之间的图标倾斜角度
var angle = this._angleByLongLat(longitude1, latitude1, longitude2, latitude2, iconAngle)
// console.log(angle)
//计算两点之间的方向角(单位:度)
var azimuth = this.getAngle([longitude1, latitude1], [longitude2, latitude2])
//将起点添加到数组中
pathPoints.push({ longitude: longitude1, latitude: latitude1, angle: angle })
//计算两点间的距离(单位:米)
var distance = this.getPointDistance([longitude1, latitude1], [longitude2, latitude2])
//定时器平均每次能运行的距离(单位:米/次)
var avg_distance = (speed * seed) / 1000000
//如果两点间得距离小于定时器每次运行的距离,则不用在两个经纬度点之间选取分割点
if (distance <= avg_distance) {
continue
}
//计算两点间,定时器需要执行的次数
var times = distance / avg_distance
for (var j = 1; j < times; j++) {
var curr_distance = avg_distance * j
var pt = this._getNextPoint(longitude1, latitude1, curr_distance, azimuth)
pt.angle = angle
pathPoints.push(pt)
}
}
var ptLast = {
longitude: paths[pathLastIndex][0],
latitude: paths[pathLastIndex][1],
angle: pathPoints[pathPoints.length - 1].angle
}
pathPoints.push(ptLast)
return pathPoints
}
_angleByLongLat(longitude1, latitude1, longitude2, latitude2, iconAngle) {
var coordTrans = new MapCoordTrans()
var ptTemp1 = coordTrans.lonLatToMercator([longitude1, latitude1])
var ptTemp2 = coordTrans.lonLatToMercator([longitude2, latitude2])
var x = ptTemp2[0] - ptTemp1[0]
var y = ptTemp2[1] - ptTemp1[1]
var angle = Math.atan2(y, x)
var angleRadians = (iconAngle * Math.PI) / 180
angle = ((angle - angleRadians) / Math.PI) * 180
// var point1 = turf.point([longitude1, latitude1]);
// var point2 = turf.point([longitude2, latitude2]);
// var angleRadians = iconAngle * Math.PI / 180
// var bearing = turf.bearing(point1, point2);
// var angle1 = 90 - bearing
// var angle = angle1 * Math.PI / 180
// angle = (angle - angleRadians) / Math.PI * 180;
return angle
}
_getNextPoint(longitude1, latitude1, distance, azimuth) {
// var EARTH_ARC = 111.199
// // distance表示两点间得距离(单位:km)
// azimuth = azimuth * Math.PI / 180.0
// // 将距离转换成经度的计算公式
// var lon = longitude1 + (distance * Math.sin(azimuth)) / (EARTH_ARC * Math.cos(latitude1 * Math.PI / 180.0));
// // 将距离转换成纬度的计算公式
// var lat = latitude1 + (distance * Math.cos(azimuth)) / EARTH_ARC;
// return { "longitude": lon, "latitude": lat };
var point = turf.point([longitude1, latitude1])
var destination = turf.destination(point, distance, azimuth)
return { longitude: destination.geometry.coordinates[0], latitude: destination.geometry.coordinates[1] }
}
// /**************地图服务查询*********/
// 需跟api强绑定,是否接入待定
// getFeaturesFromService() {
// }
/**************3D坐标*********/
/**
* 获取要素集合范围(多点,多线,多面 或者组合)
* @param {object[]} geoObj 要素集合
* @param {MapFeatureType} geoObj.type 要素类型
* @param {number[]} geoObj.features 要素集合
* @returns 边界范围[minX, minY,minZ, maxX, maxY,maxZ]
*/
getBoundingBox3D(geoObj) {
var collection = this._getFeatureCollection3D(geoObj)
if (collection.length == 0) {
return
}
var box = {
xmin: collection[0][0],
ymin: collection[0][1],
zmin: collection[0][2],
xmax: collection[0][0],
ymax: collection[0][1],
zmax: collection[0][2]
}
for (var i = 1; i < collection.length; i++) {
if (collection[i][0] < box.xmin) {
box.xmin = collection[i][0]
}
if (collection[i][0] > box.xmax) {
box.xmax = collection[i][0]
}
if (collection[i][1] < box.ymin) {
box.ymin = collection[i][1]
}
if (collection[i][1] > box.ymax) {
box.ymax = collection[i][1]
}
if (collection[i][2] < box.zmin) {
box.zmin = collection[i][2]
}
if (collection[i][2] > box.zmax) {
box.zmax = collection[i][2]
}
}
return box
}
/**
* 获取要素集合中心点(多点,多线,多面 或者组合)
* @param {object[]} geoObj 要素集合
* @param {MapFeatureType} geoObj.type 要素类型
* @param {number[]} geoObj.features 要素集合
* @returns 中心点坐标[centerX, centerY,centerZ]
*/
getBoundingCenter3D(geoObj) {
var box = this.getBoundingBox3D(geoObj)
var center = [(box.xmin + box.xmax) / 2, (box.ymin + box.ymax) / 2, (box.zmin + box.zmax) / 2]
return center
}
//geoObj =[{type:'point',features:[]},{type:'line',features:[]},{type:'polygon',features:[]}]
_getFeatureCollection3D(geoObj) {
var collection = []
for (var i = 0; i < geoObj.length; i++) {
if (geoObj[i].type == MapFeatureType.Point) {
collection.push(...geoObj[i].features)
} else if (geoObj[i].type == MapFeatureType.Line || geoObj[i].type == MapFeatureType.Polygon) {
for (var j = 0; j < geoObj[i].features.length; j++) {
collection.push(...geoObj[i].features[j])
}
}
}
return collection
}
}