/* Copyright© 2000 - 2018 SuperMap Software Co.Ltd. All rights reserved. * This program are made available under the terms of the Apache License, Version 2.0 * which accompanies this distribution and is available at http://www.apache.org/licenses/LICENSE-2.0.html.*/ importScripts('https://iclient.supermap.io/web/libs/turf/5.1.6/turf.min.js') /** * 空间分析所需工具类 */ onmessage = function (event) { if (event.data) { let params = event.data; postMessage(analysis(params)) } } //IDW 插值 function interpolate(points, cellSize, options) { options = options || {}; if (typeof options !== 'object') { throw new Error('options is invalid'); } var gridType = options.gridType; var property = options.property; var weight = options.weight; if (!points) { throw new Error('points is required'); } turf.collectionOf(points, 'Point', 'input must contain Points'); if (!cellSize) { throw new Error('cellSize is required'); } if (weight !== undefined && typeof weight !== 'number') { throw new Error('weight must be a number'); } property = property || 'elevation'; gridType = gridType || 'square'; weight = weight || 1; var box = options.bbox || turf.bbox(points); var grid; switch (gridType) { case 'point': case 'points': grid = squareGrid(box, cellSize, options, gridType); break; case 'square': case 'squares': grid = squareGrid(box, cellSize, options, gridType); break; case 'hex': case 'hexes': grid = turf.hexGrid(box, cellSize, options); break; case 'triangle': case 'triangles': grid = turf.triangleGrid(box, cellSize, options); break; default: throw new Error('invalid gridType'); } var results = []; var gridFeatures = grid.features; var pointFeatures = points.features; for (var i = 0, len = gridFeatures.length; i < len; i++) { var zw = 0; var sw = 0; var gridFeature = gridFeatures[i]; for (var j = 0, leng = pointFeatures.length; j < leng; j++) { var point = pointFeatures[j]; var gridPoint = (gridType === 'point') ? gridFeature : turf.centroid(gridFeature); var d = turf.distance(gridPoint, point, options); var zValue; if (point.properties[property]) { zValue = point.properties[property]; } if (zValue === undefined) { zValue = point.geometry.coordinates[2]; } if (zValue === undefined) { throw new Error('zValue is missing'); } if (d === 0) { zw = zValue; } var w = 1.0 / Math.pow(d, weight); sw += w; zw += w * zValue; } var newFeature = turf.clone(gridFeature); newFeature.properties[property] = zw / sw; results.push(newFeature); } return turf.featureCollection(results); } function squareGrid(bbox, cellSide, options, gridType) { options = options || {}; if (!turf.isObject(options)) { throw new Error('options is invalid'); } var properties = options.properties; var mask = options.mask; var results = []; if (cellSide === null || cellSide === undefined) { throw new Error('cellSide is required'); } if (!turf.isNumber(cellSide)) { throw new Error('cellSide is invalid'); } if (!bbox) { throw new Error('bbox is required'); } if (!Array.isArray(bbox)) { throw new Error('bbox must be array'); } if (bbox.length !== 4) { throw new Error('bbox must contain 4 numbers'); } if (mask && ['Polygon', 'MultiPolygon'].indexOf(turf.getType(mask)) === -1) { throw new Error('options.mask must be a (Multi)Polygon'); } var west = bbox[0]; var south = bbox[1]; var east = bbox[2]; var north = bbox[3]; var bboxWidth = (east - west); var bboxHeight = (north - south); var cellWidth = cellSide / 111.94; var cellHeight = cellSide / 111.94; var columns = Math.floor(bboxWidth / cellWidth); var rows = Math.floor(bboxHeight / cellHeight); var deltaX = (bboxWidth - columns * cellWidth) / 2; var deltaY = (bboxHeight - rows * cellHeight) / 2; var currentX = west + deltaX; if (gridType === "square" || gridType === "squares") { // for (var column = 0; column < columns; column++) { // var currentY = south + deltaY; // for (var row = 0; row < rows; row++) { // var cellPoly = turf.polygon([[ // [currentX, currentY], // [currentX, currentY + cellHeight], // [currentX + cellWidth, currentY + cellHeight], // [currentX + cellWidth, currentY], // [currentX, currentY] // ]], properties); // if (mask) { // if (intersect(mask, cellPoly)) results.push(cellPoly); // } else { // results.push(cellPoly); // } // currentY += cellHeight; // } // currentX += cellWidth; // } return null; } else { while (currentX <= east) { var currentY1 = south + deltaY; while (currentY1 <= north) { var cellPt = turf.point([currentX, currentY1], properties); if (mask) { if (turf.booleanWithin(cellPt, mask)) { results.push(cellPt); } } else { results.push(cellPt); } currentY1 += cellHeight; } currentX += cellWidth; } } return turf.featureCollection(results); } function processBuffer(buffer, saveAttrs) { var featureCollection = []; //var maxBounds = [-180, -90, 180, 90]; //获取缓冲区异常feature, 并从原featureCollection中删除 for (var i = 0, len = buffer.features.length; i < len; i++) { var feature = buffer.features[i]; //不保留原有的属性值 if (!saveAttrs) { //对字段属性进行for循环 for (var pro in feature.properties) { var shouldDeleted = true; //序号和参考地点保留 if (pro === 'ID') { shouldDeleted = false; } //删除除了位置和序号字段的其他字段属性 if (shouldDeleted) delete feature.properties[pro]; } } var bbox = turf.bbox(buffer.features[i]); //bounds的x轴距离作为判断依据,看数据误差<=1,这里写大一点防止意外 if (parseInt(bbox[2] - bbox[0]) > 5) { //if(util.isRectOverlap(maxBounds, turf.bbox(buffer.features[i]))) { //删除功能,第一个参数为第一项位置,第二个参数为要删除几个。 array.splice(index, num) ,返回值为删除内容,array为结果值。 //删除位置为i的一个要素 featureCollection.push(buffer.features.splice(i, 1)[0]); i--; len--; } } //将异常feature分割为两个正常feature,重新添加到featureCollextion中 var newCod; for (var k = 0; k < featureCollection.length; k++) { newCod = []; //获取不正常features var abnormalFeature = featureCollection[k]; //获取不正常features的坐标 var coordinates = turf.getCoords(abnormalFeature)[0]; //对坐标进行循环 for (var j = 0, leng = coordinates.length; j < leng; j++) { if (coordinates[j][0] < 0) { newCod.push(coordinates.splice(j, 1)[0]); j--; leng--; } } //闭合polygon if (newCod.length > 3) { if (newCod[newCod.length - 1][0] !== newCod[0][0] || newCod[newCod.length - 1][1] !== newCod[0][1]) { newCod.push(newCod[0]); } //两个feature属性相同 buffer.features.push(turf.polygon([newCod], abnormalFeature.properties)); } //闭合polygon if (coordinates.length > 3) { if (coordinates[coordinates.length - 1][0] !== coordinates[0][0] || coordinates[coordinates.length - 1][1] !== coordinates[0][1]) { coordinates.push(coordinates[0]); } buffer.features.push(abnormalFeature); } } } //feature合并 function unionFeature(featureCollection, isFirst) { var results = []; var features = featureCollection.features; var featureLength = features.length; var oneceTotal = 2; //两两合并 直到最后剩一个多面对象为止(分网格 合并) var total = Math.round(featureLength / oneceTotal); //数组顺序打乱 if (!isFirst) this.random(features); for (var i = 0; i <= total; i++) { var start = i * oneceTotal; var result = featureCollection.features[start]; for (var j = 1; j < oneceTotal; j++) { var index = start + j; if (featureCollection.features[index]) { try { result = this.union(result, featureCollection.features[index]); } catch (e) { results.push(featureCollection.features[index]); } } } if (result) results.push(result); } if (results && results.length > 1) { //结果还是多个 继续合并 return this.unionFeature(turf.featureCollection(results), false); } else { return results[0]; } } //数组顺序打乱 function random(arr) { arr.sort(function () { return 0.5 - Math.random() }); } function union(features, polys) { let result = turf.union(features, polys); return result; } //多面转单面 function toPolygons(multiPolygon) { var polygons = []; if (turf.getType(multiPolygon) === "Polygon") { polygons = [multiPolygon]; } else { var coords = turf.getCoords(multiPolygon); polygons = coords.map(function (coord) { var poly = turf.polygon(coord); poly.bbox = turf.bbox(poly); poly.properties = multiPolygon.properties; return poly; }); } return polygons; } function analysis(params) { let analysisMethod = params.analysisMethod; if (analysisMethod === "isolines") { let grid = interpolate(params.pointGrid, params.analysisCellSize, params.options); return turf.isolines(grid, params.breaks, { zProperty: params.zProperty }); } else if (analysisMethod === "buffer") { let buffer = turf.buffer(params.geoJson, params.radius, { unit: params.unit }); this.processBuffer(buffer, params.isSave); if (params.isUnion) { if (buffer.features.length > 0) { var unied = this.unionFeature(buffer, true); var result = this.toPolygons(unied); return turf.featureCollection(result); } return null; } return buffer; } }