UNPKG

@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
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 } }