SlopeAspect.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414
  1. /* 引入Cesium */
  2. // import * as Cesium from 'Cesium';
  3. /* 引入算法 */
  4. import * as turf from "@turf/turf";
  5. import CreateRemindertip from "../common/ReminderTip.js";
  6. import CoordTransform from "../common/CoordTransform.js";
  7. import {
  8. setSessionid
  9. } from "../common/common.js";
  10. /**
  11. * 坡度坡向分析类
  12. */
  13. class SlopeAspect {
  14. /**
  15. * 默认初始化
  16. * @param {Object} viewer 三维场景
  17. */
  18. constructor(viewer) {
  19. if (!viewer) throw new Cesium.DeveloperError('no viewer object!');
  20. this._viewer = viewer;
  21. this.result = []; //存储创建的坡度分析结果,primitive集合
  22. this.handler = undefined;
  23. this.toolTip = "";
  24. }
  25. /**
  26. * 坡度提示信息
  27. * @ignore
  28. */
  29. _openTip() {
  30. let _self = this;
  31. this.handler = new Cesium.ScreenSpaceEventHandler(_self._viewer.canvas);
  32. this.handler.setInputAction(function(movement) {
  33. let endPos = movement.endPosition;
  34. var pick = _self._viewer.scene.pick(endPos);
  35. if (pick && pick.id && pick.id.type === "SlopeAspect") {
  36. _self.toolTip = pick.id.value.toFixed(2);
  37. CreateRemindertip(_self.toolTip, endPos, true);
  38. } else {
  39. _self.toolTip = "";
  40. CreateRemindertip(_self.toolTip, endPos, false);
  41. }
  42. }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
  43. }
  44. /**
  45. * @ignore
  46. * @param {Object} gridSquare
  47. */
  48. _createEllipse(gridSquare) {
  49. let _self = this;
  50. let boxResults = [];
  51. for (let index = 0; index < gridSquare.features.length; index++) {
  52. const feature = gridSquare.features[index];
  53. const coordinates = feature.geometry.coordinates[0];
  54. const centerdegree = [
  55. (coordinates[0][0] + coordinates[2][0]) / 2,
  56. (coordinates[0][1] + coordinates[2][1]) / 2,
  57. ];
  58. let centerCartographic = Cesium.Cartographic.fromDegrees(
  59. centerdegree[0],
  60. centerdegree[1]
  61. );
  62. boxResults.push(centerCartographic);
  63. for (let i = 0; i < coordinates.length; i++) {
  64. const coord = coordinates[i];
  65. let cartographic = Cesium.Cartographic.fromDegrees(coord[0], coord[1]);
  66. boxResults.push(cartographic);
  67. const coord1 = coordinates[i + 1];
  68. if (coord1) {
  69. let newCoord = [(coord[0] + coord1[0]) / 2, (coord[1] + coord1[1]) / 2];
  70. let newCartographic = Cesium.Cartographic.fromDegrees(newCoord[0], newCoord[1]);
  71. boxResults.push(newCartographic);
  72. }
  73. }
  74. }
  75. Cesium.sampleTerrainMostDetailed(
  76. _self._viewer.scene.terrainProvider,
  77. boxResults
  78. ).then((updatePositions) => {
  79. let arrr = [];
  80. let ellipseResults = updatePositions.reduce(function(pre, item, index, updatePositions) {
  81. var begin = index * 10;
  82. var end = begin + 10;
  83. var res = updatePositions.slice(begin, end);
  84. if (res.length != 0) {
  85. arrr[index] = res;
  86. }
  87. return arrr;
  88. }, []);
  89. _self._calculateSlope(ellipseResults);
  90. _self._openTip();
  91. });
  92. }
  93. /**
  94. * @ignore
  95. * @param {Object} points
  96. * @param {Object} color
  97. */
  98. _createPolygonInsrance(points, color) {
  99. let positions = [];
  100. for (let index = 1; index < points.length - 1; index++) {
  101. const element = points[index];
  102. positions.push(Cesium.Cartographic.toCartesian(element));
  103. }
  104. let polygon = new Cesium.PolygonGeometry({
  105. polygonHierarchy: new Cesium.PolygonHierarchy(positions),
  106. });
  107. let polygonInstance = new Cesium.GeometryInstance({
  108. geometry: polygon,
  109. attributes: {
  110. color: Cesium.ColorGeometryInstanceAttribute.fromColor(
  111. Cesium.Color.fromCssColorString(color)
  112. ),
  113. show: new Cesium.ShowGeometryInstanceAttribute(true), //显示或者隐藏
  114. },
  115. });
  116. return polygonInstance;
  117. }
  118. /**
  119. * 箭头
  120. * @ignore
  121. * @param {Object} targetPoint
  122. * @param {Object} center
  123. * @param {Object} diagonalPoint
  124. * @param {Object} heightDifference
  125. * @param {Object} curSlope
  126. */
  127. _createArrowInstance(targetPoint, center, diagonalPoint, heightDifference, curSlope) {
  128. let cartographic_0 = new Cesium.Cartographic(
  129. (targetPoint.longitude + center.longitude) / 2,
  130. (targetPoint.latitude + center.latitude) / 2,
  131. (targetPoint.height + center.height) / 2
  132. );
  133. let cartographic_1 = new Cesium.Cartographic(
  134. (diagonalPoint.longitude + center.longitude) / 2,
  135. (diagonalPoint.latitude + center.latitude) / 2,
  136. (diagonalPoint.height + center.height) / 2
  137. );
  138. //偏移的
  139. let positions1 =
  140. heightDifference > 0 ? [
  141. Cesium.Cartographic.toCartesian(cartographic_0),
  142. Cesium.Cartographic.toCartesian(cartographic_1)
  143. ] : [
  144. Cesium.Cartographic.toCartesian(cartographic_1),
  145. Cesium.Cartographic.toCartesian(cartographic_0)
  146. ];
  147. //箭头线
  148. const instance = new Cesium.GeometryInstance({
  149. id: {
  150. type: "SlopeAspect",
  151. value: curSlope,
  152. },
  153. geometry: new Cesium.GroundPolylineGeometry({
  154. positions: positions1,
  155. width: this.arrowWidth,
  156. }),
  157. attributes: {
  158. color: Cesium.ColorGeometryInstanceAttribute.fromColor(
  159. Cesium.Color.BLUE.withAlpha(0.6)
  160. ),
  161. show: new Cesium.ShowGeometryInstanceAttribute(true), //显示或者隐藏
  162. },
  163. });
  164. return instance;
  165. }
  166. /**
  167. * @ignore
  168. * @param {Object} ellipseResults
  169. */
  170. _calculateSlope(ellipseResults) {
  171. let _self = this;
  172. let instances = [];
  173. let polygonInstance = [];
  174. for (let index = 0; index < ellipseResults.length; index++) {
  175. const ellipse = ellipseResults[index];
  176. const center = ellipse[0];
  177. let heightDifference = 0;
  178. let maxIndex = 0;
  179. for (let i = 1; i < ellipse.length - 1; i++) {
  180. const point = ellipse[i];
  181. let curHD = point.height - center.height;
  182. if (Math.abs(curHD) > heightDifference) {
  183. heightDifference = curHD;
  184. maxIndex = i;
  185. }
  186. }
  187. let pos0 = new Cesium.Cartographic(center.longitude, center.latitude, 0);
  188. let pos1 = new Cesium.Cartographic(
  189. ellipse[maxIndex].longitude,
  190. ellipse[maxIndex].latitude,
  191. 0
  192. );
  193. let distance = Cesium.Cartesian3.distance(
  194. Cesium.Cartographic.toCartesian(pos0),
  195. Cesium.Cartographic.toCartesian(pos1)
  196. );
  197. let curSlope = Math.abs(heightDifference / distance); //坡度的tan值
  198. let curColor = _self._calculateSlopeColor(curSlope, 0.4);
  199. const curPolygonInstance = _self._createPolygonInsrance(ellipse, curColor);
  200. polygonInstance.push(curPolygonInstance);
  201. let diagonalPoint = maxIndex > 4 ? ellipse[maxIndex - 4] : ellipse[maxIndex + 4]; //对角点
  202. let targetPoint = ellipse[maxIndex];
  203. const arrowInstance = _self._createArrowInstance(targetPoint, center, diagonalPoint, heightDifference, curSlope);
  204. instances.push(arrowInstance);
  205. }
  206. const mapPrimitive = _self._viewer.scene.primitives.add(
  207. new Cesium.GroundPrimitive({
  208. geometryInstances: polygonInstance,
  209. appearance: new Cesium.PerInstanceColorAppearance({
  210. translucent: true, //false时透明度无效
  211. closed: false,
  212. }),
  213. })
  214. );
  215. const arrowPrimitive = _self._viewer.scene.primitives.add(
  216. new Cesium.GroundPolylinePrimitive({
  217. geometryInstances: instances,
  218. appearance: new Cesium.PolylineMaterialAppearance({
  219. material: new Cesium.Material({
  220. fabric: {
  221. type: "PolylineArrow",
  222. uniforms: {
  223. color: new Cesium.Color(1.0, 1.0, 0.0, 0.8),
  224. },
  225. },
  226. }),
  227. }),
  228. })
  229. );
  230. _self.result.push(arrowPrimitive, mapPrimitive);
  231. }
  232. /**
  233. * 根据坡度值赋值颜色
  234. * @ignore
  235. * @param {Object} value
  236. * @param {Object} alpha
  237. */
  238. _calculateSlopeColor(value, alpha) {
  239. // 0°~0.5°为平原0.00872686779075879,rgb(85,182,43)
  240. // 0.5°~2°为微斜坡0.03492076949174773,rgb(135,211,43)
  241. // 2°~5°为缓斜坡0.08748866352592401,rgb(204,244,44)
  242. // 5°~15°为斜坡0.2679491924311227,rgb(245,233,44)
  243. // 15°~35°为陡坡0.7002075382097097,rgb(255,138,43)
  244. // 35°~55°为峭坡1.4281480067421144,rgb(255,84,43)
  245. // 55°~90°为垂直壁,rgb(255,32,43)
  246. if (value < 0.00872686779075879) {
  247. return "rgba(85,182,43," + alpha + ")";
  248. } else if (value < 0.03492076949174773) {
  249. return "rgba(135,211,43," + alpha + ")";
  250. } else if (value < 0.08748866352592401) {
  251. return "rgba(204,244,44," + alpha + ")";
  252. } else if (value < 0.2679491924311227) {
  253. return "rgba(245,233,44," + alpha + ")";
  254. } else if (value < 0.7002075382097097) {
  255. return "rgba(255,138,43," + alpha + ")";
  256. } else if (value < 1.4281480067421144) {
  257. return "rgba(255,84,43," + alpha + ")";
  258. } else {
  259. return "rgba(255,32,43," + alpha + ")";
  260. }
  261. }
  262. }
  263. /**
  264. * 通用对外公开函数
  265. */
  266. Object.assign(SlopeAspect.prototype, /** @lends SlopeAspect.prototype */ {
  267. /**
  268. * 等距离切分网格
  269. * @param {Object} points
  270. * @param {Object} polygon
  271. * @param {Object} options
  272. * @param {Object} options.distance 默认0.1km精度
  273. */
  274. createNew4Distance(points, polygon, options) {
  275. let _self = this;
  276. options = options || {};
  277. options.distance = options.distance || 0.1;//默认0.1km精度
  278. let width = options.distance * 200 > 35 ? 35 : options.distance * 200;
  279. _self.arrowWidth = width < 15 ? 15 : width;
  280. /* 转换坐标 */
  281. let positions = points.map(point => {
  282. return Cesium.Cartesian3.fromDegrees(point[0], point[1], point[2] || 0);
  283. });
  284. _self.clearAll();
  285. let degrees = CoordTransform.Cartesian3ListToWGS84(positions);
  286. // _self._viewer.entities.remove(polygon);
  287. let boundary = [];
  288. let minX = 10000,
  289. minY = 10000,
  290. maxX = -10000,
  291. maxY = -1000;
  292. for (let index = 0; index < degrees.length; index++) {
  293. const element = degrees[index];
  294. const x = element.lng;
  295. const y = element.lat;
  296. boundary.push([x, y]);
  297. minX = x < minX ? x : minX;
  298. minY = y < minY ? y : minY;
  299. maxX = x > maxX ? x : maxX;
  300. maxY = y > maxY ? y : maxY;
  301. }
  302. boundary.push(boundary[0]);
  303. let bbox = [minX, minY, maxX, maxY];
  304. let mask = turf.polygon([boundary]);
  305. let gridSquare = turf.squareGrid(bbox, options.distance, {
  306. // mask: mask,//加上这个参数分析不出来
  307. });
  308. _self._createEllipse(gridSquare);
  309. },
  310. /**
  311. * 等分切分网格,切分成一个num*num的网格
  312. * @param {Object} points
  313. * @param {Object} polygon
  314. * @param {Object} options.num=10
  315. */
  316. createNew4Num(points, polygon, options) {
  317. let _self = this;
  318. options = options || {};
  319. options.num = Cesium.defaultValue(options.num, 10);
  320. /* 转换坐标 */
  321. let positions = points.map(point => {
  322. return Cesium.Cartesian3.fromDegrees(point[0], point[1], point[2] || 0);
  323. });
  324. _self.clearAll();
  325. let degrees = CoordTransform.Cartesian3ListToWGS84(positions);
  326. // _self._viewer.entities.remove(polygon);
  327. let boundary = [];
  328. let minX = 10000,
  329. minY = 10000,
  330. maxX = -10000,
  331. maxY = -1000;
  332. for (let index = 0; index < degrees.length; index++) {
  333. const element = degrees[index];
  334. const x = element.lng;
  335. const y = element.lat;
  336. boundary.push([x, y]);
  337. minX = x < minX ? x : minX;
  338. minY = y < minY ? y : minY;
  339. maxX = x > maxX ? x : maxX;
  340. maxY = y > maxY ? y : maxY;
  341. }
  342. boundary.push(boundary[0]);
  343. let bbox = [minX, minY, maxX, maxY];
  344. let a = maxX - minX;
  345. let b = maxY - minY;
  346. b = b > a ? b : a;
  347. const step = b / options.num;
  348. let width = step * 2000 > 35 ? 35 : step * 2000;
  349. _self.arrowWidth = width < 15 ? 15 : width;
  350. let mask = turf.polygon([boundary]);
  351. let gridSquare = turf.squareGrid(bbox, step, {
  352. units: "degrees",
  353. // mask: mask,//加上这个参数分析不出来
  354. });
  355. _self._createEllipse(gridSquare);
  356. },
  357. /**
  358. * 清除
  359. */
  360. clearAll() {
  361. this.result.forEach((element) => {
  362. this._viewer.scene.primitives.remove(element);
  363. });
  364. this.result = [];
  365. if (this.handler) {
  366. this.handler.destroy();
  367. this.handler = undefined;
  368. }
  369. },
  370. });
  371. export default SlopeAspect;