TurfWorker.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336
  1. /* Copyright© 2000 - 2018 SuperMap Software Co.Ltd. All rights reserved.
  2. * This program are made available under the terms of the Apache License, Version 2.0
  3. * which accompanies this distribution and is available at http://www.apache.org/licenses/LICENSE-2.0.html.*/
  4. importScripts('https://iclient.supermap.io/web/libs/turf/5.1.6/turf.min.js')
  5. /**
  6. * 空间分析所需工具类
  7. */
  8. onmessage = function (event) {
  9. if (event.data) {
  10. let params = event.data;
  11. postMessage(analysis(params))
  12. }
  13. }
  14. //IDW 插值
  15. function interpolate(points, cellSize, options) {
  16. options = options || {};
  17. if (typeof options !== 'object') {
  18. throw new Error('options is invalid');
  19. }
  20. var gridType = options.gridType;
  21. var property = options.property;
  22. var weight = options.weight;
  23. if (!points) {
  24. throw new Error('points is required');
  25. }
  26. turf.collectionOf(points, 'Point', 'input must contain Points');
  27. if (!cellSize) {
  28. throw new Error('cellSize is required');
  29. }
  30. if (weight !== undefined && typeof weight !== 'number') {
  31. throw new Error('weight must be a number');
  32. }
  33. property = property || 'elevation';
  34. gridType = gridType || 'square';
  35. weight = weight || 1;
  36. var box = options.bbox || turf.bbox(points);
  37. var grid;
  38. switch (gridType) {
  39. case 'point':
  40. case 'points':
  41. grid = squareGrid(box, cellSize, options, gridType);
  42. break;
  43. case 'square':
  44. case 'squares':
  45. grid = squareGrid(box, cellSize, options, gridType);
  46. break;
  47. case 'hex':
  48. case 'hexes':
  49. grid = turf.hexGrid(box, cellSize, options);
  50. break;
  51. case 'triangle':
  52. case 'triangles':
  53. grid = turf.triangleGrid(box, cellSize, options);
  54. break;
  55. default:
  56. throw new Error('invalid gridType');
  57. }
  58. var results = [];
  59. var gridFeatures = grid.features;
  60. var pointFeatures = points.features;
  61. for (var i = 0, len = gridFeatures.length; i < len; i++) {
  62. var zw = 0;
  63. var sw = 0;
  64. var gridFeature = gridFeatures[i];
  65. for (var j = 0, leng = pointFeatures.length; j < leng; j++) {
  66. var point = pointFeatures[j];
  67. var gridPoint = (gridType === 'point') ? gridFeature : turf.centroid(gridFeature);
  68. var d = turf.distance(gridPoint, point, options);
  69. var zValue;
  70. if (point.properties[property]) {
  71. zValue = point.properties[property];
  72. }
  73. if (zValue === undefined) {
  74. zValue = point.geometry.coordinates[2];
  75. }
  76. if (zValue === undefined) {
  77. throw new Error('zValue is missing');
  78. }
  79. if (d === 0) {
  80. zw = zValue;
  81. }
  82. var w = 1.0 / Math.pow(d, weight);
  83. sw += w;
  84. zw += w * zValue;
  85. }
  86. var newFeature = turf.clone(gridFeature);
  87. newFeature.properties[property] = zw / sw;
  88. results.push(newFeature);
  89. }
  90. return turf.featureCollection(results);
  91. }
  92. function squareGrid(bbox, cellSide, options, gridType) {
  93. options = options || {};
  94. if (!turf.isObject(options)) {
  95. throw new Error('options is invalid');
  96. }
  97. var properties = options.properties;
  98. var mask = options.mask;
  99. var results = [];
  100. if (cellSide === null || cellSide === undefined) {
  101. throw new Error('cellSide is required');
  102. }
  103. if (!turf.isNumber(cellSide)) {
  104. throw new Error('cellSide is invalid');
  105. }
  106. if (!bbox) {
  107. throw new Error('bbox is required');
  108. }
  109. if (!Array.isArray(bbox)) {
  110. throw new Error('bbox must be array');
  111. }
  112. if (bbox.length !== 4) {
  113. throw new Error('bbox must contain 4 numbers');
  114. }
  115. if (mask && ['Polygon', 'MultiPolygon'].indexOf(turf.getType(mask)) === -1) {
  116. throw new Error('options.mask must be a (Multi)Polygon');
  117. }
  118. var west = bbox[0];
  119. var south = bbox[1];
  120. var east = bbox[2];
  121. var north = bbox[3];
  122. var bboxWidth = (east - west);
  123. var bboxHeight = (north - south);
  124. var cellWidth = cellSide / 111.94;
  125. var cellHeight = cellSide / 111.94;
  126. var columns = Math.floor(bboxWidth / cellWidth);
  127. var rows = Math.floor(bboxHeight / cellHeight);
  128. var deltaX = (bboxWidth - columns * cellWidth) / 2;
  129. var deltaY = (bboxHeight - rows * cellHeight) / 2;
  130. var currentX = west + deltaX;
  131. if (gridType === "square" || gridType === "squares") {
  132. // for (var column = 0; column < columns; column++) {
  133. // var currentY = south + deltaY;
  134. // for (var row = 0; row < rows; row++) {
  135. // var cellPoly = turf.polygon([[
  136. // [currentX, currentY],
  137. // [currentX, currentY + cellHeight],
  138. // [currentX + cellWidth, currentY + cellHeight],
  139. // [currentX + cellWidth, currentY],
  140. // [currentX, currentY]
  141. // ]], properties);
  142. // if (mask) {
  143. // if (intersect(mask, cellPoly)) results.push(cellPoly);
  144. // } else {
  145. // results.push(cellPoly);
  146. // }
  147. // currentY += cellHeight;
  148. // }
  149. // currentX += cellWidth;
  150. // }
  151. return null;
  152. } else {
  153. while (currentX <= east) {
  154. var currentY1 = south + deltaY;
  155. while (currentY1 <= north) {
  156. var cellPt = turf.point([currentX, currentY1], properties);
  157. if (mask) {
  158. if (turf.booleanWithin(cellPt, mask)) {
  159. results.push(cellPt);
  160. }
  161. } else {
  162. results.push(cellPt);
  163. }
  164. currentY1 += cellHeight;
  165. }
  166. currentX += cellWidth;
  167. }
  168. }
  169. return turf.featureCollection(results);
  170. }
  171. function processBuffer(buffer, saveAttrs) {
  172. var featureCollection = [];
  173. //var maxBounds = [-180, -90, 180, 90];
  174. //获取缓冲区异常feature, 并从原featureCollection中删除
  175. for (var i = 0, len = buffer.features.length; i < len; i++) {
  176. var feature = buffer.features[i];
  177. //不保留原有的属性值
  178. if (!saveAttrs) {
  179. //对字段属性进行for循环
  180. for (var pro in feature.properties) {
  181. var shouldDeleted = true;
  182. //序号和参考地点保留
  183. if (pro === 'ID') {
  184. shouldDeleted = false;
  185. }
  186. //删除除了位置和序号字段的其他字段属性
  187. if (shouldDeleted) delete feature.properties[pro];
  188. }
  189. }
  190. var bbox = turf.bbox(buffer.features[i]);
  191. //bounds的x轴距离作为判断依据,看数据误差<=1,这里写大一点防止意外
  192. if (parseInt(bbox[2] - bbox[0]) > 5) {
  193. //if(util.isRectOverlap(maxBounds, turf.bbox(buffer.features[i]))) {
  194. //删除功能,第一个参数为第一项位置,第二个参数为要删除几个。 array.splice(index, num) ,返回值为删除内容,array为结果值。
  195. //删除位置为i的一个要素
  196. featureCollection.push(buffer.features.splice(i, 1)[0]);
  197. i--;
  198. len--;
  199. }
  200. }
  201. //将异常feature分割为两个正常feature,重新添加到featureCollextion中
  202. var newCod;
  203. for (var k = 0; k < featureCollection.length; k++) {
  204. newCod = [];
  205. //获取不正常features
  206. var abnormalFeature = featureCollection[k];
  207. //获取不正常features的坐标
  208. var coordinates = turf.getCoords(abnormalFeature)[0];
  209. //对坐标进行循环
  210. for (var j = 0, leng = coordinates.length; j < leng; j++) {
  211. if (coordinates[j][0] < 0) {
  212. newCod.push(coordinates.splice(j, 1)[0]);
  213. j--;
  214. leng--;
  215. }
  216. }
  217. //闭合polygon
  218. if (newCod.length > 3) {
  219. if (newCod[newCod.length - 1][0] !== newCod[0][0] || newCod[newCod.length - 1][1] !== newCod[0][1]) {
  220. newCod.push(newCod[0]);
  221. }
  222. //两个feature属性相同
  223. buffer.features.push(turf.polygon([newCod], abnormalFeature.properties));
  224. }
  225. //闭合polygon
  226. if (coordinates.length > 3) {
  227. if (coordinates[coordinates.length - 1][0] !== coordinates[0][0] || coordinates[coordinates.length - 1][1] !== coordinates[0][1]) {
  228. coordinates.push(coordinates[0]);
  229. }
  230. buffer.features.push(abnormalFeature);
  231. }
  232. }
  233. }
  234. //feature合并
  235. function unionFeature(featureCollection, isFirst) {
  236. var results = [];
  237. var features = featureCollection.features;
  238. var featureLength = features.length;
  239. var oneceTotal = 2; //两两合并 直到最后剩一个多面对象为止(分网格 合并)
  240. var total = Math.round(featureLength / oneceTotal);
  241. //数组顺序打乱
  242. if (!isFirst) this.random(features);
  243. for (var i = 0; i <= total; i++) {
  244. var start = i * oneceTotal;
  245. var result = featureCollection.features[start];
  246. for (var j = 1; j < oneceTotal; j++) {
  247. var index = start + j;
  248. if (featureCollection.features[index]) {
  249. try {
  250. result = this.union(result, featureCollection.features[index]);
  251. } catch (e) {
  252. results.push(featureCollection.features[index]);
  253. }
  254. }
  255. }
  256. if (result) results.push(result);
  257. }
  258. if (results && results.length > 1) {
  259. //结果还是多个 继续合并
  260. return this.unionFeature(turf.featureCollection(results), false);
  261. } else {
  262. return results[0];
  263. }
  264. }
  265. //数组顺序打乱
  266. function random(arr) {
  267. arr.sort(function () { return 0.5 - Math.random() });
  268. }
  269. function union(features, polys) {
  270. let result = turf.union(features, polys);
  271. return result;
  272. }
  273. //多面转单面
  274. function toPolygons(multiPolygon) {
  275. var polygons = [];
  276. if (turf.getType(multiPolygon) === "Polygon") {
  277. polygons = [multiPolygon];
  278. } else {
  279. var coords = turf.getCoords(multiPolygon);
  280. polygons = coords.map(function (coord) {
  281. var poly = turf.polygon(coord);
  282. poly.bbox = turf.bbox(poly);
  283. poly.properties = multiPolygon.properties;
  284. return poly;
  285. });
  286. }
  287. return polygons;
  288. }
  289. function analysis(params) {
  290. let analysisMethod = params.analysisMethod;
  291. if (analysisMethod === "isolines") {
  292. let grid = interpolate(params.pointGrid, params.analysisCellSize, params.options);
  293. return turf.isolines(grid, params.breaks, { zProperty: params.zProperty });
  294. } else if (analysisMethod === "buffer") {
  295. let buffer = turf.buffer(params.geoJson, params.radius, { unit: params.unit });
  296. this.processBuffer(buffer, params.isSave);
  297. if (params.isUnion) {
  298. if (buffer.features.length > 0) {
  299. var unied = this.unionFeature(buffer, true);
  300. var result = this.toPolygons(unied);
  301. return turf.featureCollection(result);
  302. }
  303. return null;
  304. }
  305. return buffer;
  306. }
  307. }