TerrainCutFillAnalysis.vue 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396
  1. <template>
  2. <div v-show="isCutFill" class="cut_fill_box">
  3. <el-radio v-model="radio" label="cut">地形填挖方分析</el-radio>
  4. <el-radio v-model="radio" label="smooth">地形平整分析</el-radio>
  5. <div v-show="radio == 'cut'">
  6. <div class="cut_fill_centent1">
  7. 填挖深度(米):
  8. <el-input
  9. class="cut_fill_input"
  10. v-model="height"
  11. placeholder=""
  12. ></el-input>
  13. <br />
  14. 土石方量(立方米):
  15. <el-input
  16. class="cut_fill_input"
  17. v-model="result"
  18. placeholder=""
  19. ></el-input>
  20. </div>
  21. </div>
  22. <div v-show="radio == 'smooth'">
  23. <div class="cut_fill_centent1">
  24. 平整深度(米):
  25. <el-input
  26. class="cut_fill_input"
  27. v-model="smooth_height"
  28. placeholder=""
  29. readonly="readonly"
  30. ></el-input>
  31. <br />
  32. 土石方量(立方米):
  33. <el-input
  34. class="cut_fill_input"
  35. v-model="result"
  36. placeholder=""
  37. ></el-input>
  38. <br />
  39. <br />
  40. 土石面积(平方米):
  41. <el-input
  42. class="cut_fill_input"
  43. v-model="result_area"
  44. placeholder=""
  45. ></el-input>
  46. </div>
  47. </div>
  48. <div class="cut_fill_Buttons">
  49. <el-button size="mini" type="primary" @click="draw">绘制</el-button>
  50. <el-button size="mini" type="primary" @click="clear">清除</el-button>
  51. </div>
  52. </div>
  53. </template>
  54. <script>
  55. //这里可以导入其他文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
  56. import CutFillAnalysis from "./CutFillAnalysis.js";
  57. let cutFillAnalysis = null;
  58. import { getDsm } from "@/api/analse";
  59. import * as turf from "@turf/turf";
  60. export default {
  61. name: "TerrainCutFillAnalysis",
  62. components: {},
  63. data() {
  64. return {
  65. radio: "cut",
  66. input: "",
  67. sharedState: store.state,
  68. height: 300,
  69. result: null,
  70. handler_Cut_fill: null,
  71. array3D: [],
  72. smooth_height: 0,
  73. };
  74. },
  75. //监听属性 类似于data概念
  76. computed: {
  77. isCutFill: function () {
  78. return this.sharedState.terrain[4];
  79. },
  80. },
  81. //监控data中的数据变化
  82. watch: {},
  83. //方法集合
  84. methods: {
  85. //地形抽出部分
  86. extract(positions) {
  87. viewer.scene.globe.removeAllExtractRegion();
  88. viewer.scene.globe.addExtractRegion({
  89. name: "extract", //名称
  90. position: positions, //区域
  91. height: this.height, //开挖深度
  92. transparent: false, //封边是否透明
  93. extractHeight: Number(this.height), //抽出高度
  94. granularity: 1, //精度
  95. });
  96. },
  97. cutana(positions) {
  98. viewer.scene.globe.removeAllExcavationRegion();
  99. viewer.scene.globe.addExcavationRegion({
  100. name: "ggg",
  101. position: positions,
  102. height: Number(-this.height),
  103. transparent: false,
  104. });
  105. },
  106. coordsToWktPolygon(coords) {
  107. // 检查坐标数组的长度是否为偶数
  108. if (coords.length % 2 !== 0) {
  109. throw new Error("Coordinate array length must be even.");
  110. }
  111. // 构建WKT Polygon字符串
  112. let wktPolygon = "POLYGON((";
  113. for (let i = 0; i < coords.length; i += 2) {
  114. // 添加经度和纬度对
  115. wktPolygon += `${coords[i]} ${coords[i + 1]}`;
  116. // 如果不是最后一对坐标,则添加逗号
  117. if (i + 2 < coords.length) {
  118. wktPolygon += ", ";
  119. }
  120. }
  121. // 闭合多边形,添加第一个点
  122. wktPolygon += `, ${coords[0]} ${coords[1]}))`;
  123. return wktPolygon;
  124. },
  125. async smooth_ana(positions, positions_noHeight, threeArray, height) {
  126. let data = await getDsm({
  127. geom: this.coordsToWktPolygon(positions_noHeight),
  128. type: "min",
  129. });
  130. viewer.scene.globe.removeAllExcavationRegion();
  131. viewer.scene.globe.addExcavationRegion({
  132. name: "ggg",
  133. position: positions,
  134. height: data.data,
  135. transparent: false,
  136. });
  137. this.smooth_height = data.data.toFixed(2);
  138. let cutVolume = cutFillAnalysis.VolumeAnalysis(threeArray, height);
  139. that.result = cutVolume.toFixed(2);
  140. },
  141. async smooth_ana1(positions, positions_noHeight, threeArray, height) {
  142. console.log("positions: ", positions);
  143. let data = await getDsm({
  144. geom: this.coordsToWktPolygon(positions_noHeight),
  145. type: "max",
  146. });
  147. let newArr = positions.map((item, index) => {
  148. return (index + 1) % 3 === 0 ? data.data : item;
  149. });
  150. viewer.scene.globe.removeAllModifyRegion();
  151. viewer.scene.globe.addModifyRegion({
  152. name: "ggg",
  153. position: newArr,
  154. });
  155. this.smooth_height = data.data.toFixed(2);
  156. // let cutVolume = cutFillAnalysis.VolumeAnalysis1(threeArray, Number(height));
  157. // console.log('cutVolume: ', cutVolume);
  158. let newArray = [];
  159. for (let i = 0; i < positions_noHeight.length; i += 2) {
  160. // 将每两个连续的元素组合成一个新的数组,并添加到新数组中
  161. newArray.push([positions_noHeight[i], positions_noHeight[i + 1]]);
  162. }
  163. newArray.push(newArray[0]);
  164. var polygon = turf.polygon([newArray]);
  165. this.result_area = turf.area(polygon).toFixed(2);
  166. },
  167. draw() {
  168. const that = this;
  169. that.clear();
  170. if (that.handler_Cut_fill == null) {
  171. that.handler_Cut_fill = new Cesium.DrawHandler(
  172. viewer,
  173. Cesium.DrawMode.Polygon,
  174. 0
  175. );
  176. }
  177. var tooltip = createTooltip(viewer._element);
  178. //绘制多边形
  179. that.handler_Cut_fill.activeEvt.addEventListener(function (isActive) {
  180. if (isActive == true) {
  181. viewer.enableCursorStyle = false;
  182. viewer._element.style.cursor = "";
  183. // $('body').removeClass('drawCur').addClass('drawCur');
  184. } else {
  185. viewer.enableCursorStyle = true;
  186. // $('body').removeClass('drawCur');
  187. }
  188. });
  189. that.handler_Cut_fill.movingEvt.addEventListener(function (
  190. windowPosition
  191. ) {
  192. if (windowPosition.x < 200 && windowPosition.y < 150) {
  193. tooltip.setVisible(false);
  194. return;
  195. }
  196. if (that.handler_Cut_fill.isDrawing) {
  197. tooltip.showAt(
  198. windowPosition,
  199. "<p>点击确定开挖区域中间点</p><p>右键单击结束绘制,进行开挖</p>"
  200. );
  201. } else {
  202. tooltip.showAt(windowPosition, "<p>点击绘制开挖区域第一个点</p>");
  203. }
  204. });
  205. that.handler_Cut_fill.drawEvt.addEventListener(function (result) {
  206. if (!result.object.positions) {
  207. tooltip.showAt(result, "<p>请绘制正确的多边形</p>");
  208. that.handler_Cut_fill.polygon.show = false;
  209. that.handler_Cut_fill.polyline.show = false;
  210. that.handler_Cut_fill.deactivate();
  211. that.handler_Cut_fill.activate();
  212. return;
  213. }
  214. var array = [].concat(result.object.positions);
  215. tooltip.setVisible(false);
  216. that.array = array;
  217. var positions = [];
  218. var positions_noHeight = [];
  219. for (var i = 0, len = array.length; i < len; i++) {
  220. var cartographic = Cesium.Cartographic.fromCartesian(array[i]);
  221. var longitude = Cesium.Math.toDegrees(cartographic.longitude);
  222. var latitude = Cesium.Math.toDegrees(cartographic.latitude);
  223. var h = cartographic.height;
  224. if (
  225. positions.indexOf(longitude) == -1 &&
  226. positions.indexOf(latitude) == -1
  227. ) {
  228. positions.push(longitude);
  229. positions.push(latitude);
  230. positions.push(h);
  231. positions_noHeight.push(longitude);
  232. positions_noHeight.push(latitude);
  233. }
  234. }
  235. let threeArray = null;
  236. if (positions.length % 2 == 0) {
  237. threeArray = positions;
  238. } else {
  239. threeArray = that.appendLastThree(positions);
  240. }
  241. if (that.radio == "smooth") {
  242. // that.smooth_ana(positions, positions_noHeight, threeArray, -that.height);
  243. that.smooth_ana1(
  244. positions,
  245. positions_noHeight,
  246. threeArray,
  247. -that.height
  248. );
  249. } else if (that.radio == "cut") {
  250. if (that.height < 0) {
  251. that.cutana(threeArray);
  252. } else {
  253. that.extract(threeArray);
  254. }
  255. }
  256. that.handler_Cut_fill.polygon.show = false;
  257. that.handler_Cut_fill.polyline.show = false;
  258. that.handler_Cut_fill.deactivate();
  259. // that.handler_Cut_fill.activate();
  260. let cutVolume = cutFillAnalysis.VolumeAnalysis(
  261. that.array,
  262. -that.height
  263. );
  264. that.result = cutVolume.toFixed(2);
  265. });
  266. that.handler_Cut_fill.activate();
  267. },
  268. clear() {
  269. const that = this;
  270. if (that.handler_Cut_fill != null) {
  271. that.handler_Cut_fill.clear();
  272. viewer.scene.globe.removeAllExcavationRegion();
  273. viewer.scene.globe.removeAllExtractRegion();
  274. viewer.scene.globe.removeAllModifyRegion();
  275. that.handler_Cut_fill.deactivate();
  276. that.handler_Cut_fill = null;
  277. that.result = null;
  278. that.smooth_height = null;
  279. that.result_area = null;
  280. }
  281. },
  282. appendLastThree(arr) {
  283. // 创建一个新数组来存储结果
  284. let result = [...arr]; // 使用扩展运算符复制原始数组
  285. // 检查数组长度是否至少有三个元素
  286. // if (arr.length >= 3) {
  287. // 获取后三个元素并添加到结果数组末尾
  288. result.push(...arr.slice(-3));
  289. // }
  290. // 返回结果数组
  291. return result;
  292. },
  293. },
  294. beforeCreate() {}, //生命周期 - 创建之前
  295. created() {
  296. // const terrainP = new Cesium.CesiumTerrainProvider({
  297. // url: 'http://192.168.60.3:8099/iserver/services/3D-local3DCache-SanYaDSMHuanCun/rest/realspace/datas/dsm@dsm',
  298. // isSct: true//地形服务源自SuperMap iServer发布时需设置isSct为true
  299. // });
  300. // const terrainP = new Cesium.CesiumTerrainProvider({
  301. // url: 'https://www.supermapol.com/realspace/services/3D-stk_terrain/rest/realspace/datas/info/data/path',
  302. // requestWaterMask: true,
  303. // requestVertexNormals: true,
  304. // isSct: false,
  305. // });
  306. // // 设置相机视角
  307. // viewer.scene.camera.setView({
  308. // destination: Cesium.Cartesian3.fromDegrees(88.3648, 29.0946, 90000),
  309. // orientation: {
  310. // heading: 6.10547067016156,
  311. // pitch: -0.8475077031996778,
  312. // roll: 6.2831853016686185
  313. // }
  314. // });
  315. // viewer.terrainProvider = terrainP;
  316. }, //生命周期 - 创建完成(可以访问当前this实例)
  317. beforeMount() {}, //生命周期 - 挂载之前
  318. mounted() {
  319. this.$nextTick((res) => {
  320. cutFillAnalysis = new CutFillAnalysis(viewer, 80);
  321. // viewer.scene.globe.depthTestAgainstTerrain = false;
  322. // const terrainP = new Cesium.CesiumTerrainProvider({
  323. // url: 'http://192.168.60.2:8090/iserver/services/3D-local3DCache-SanYaShi_GaoCheng_Level_16DataSource/rest/realspace/datas/%E4%B8%89%E4%BA%9A%E5%B8%82_%E9%AB%98%E7%A8%8B_Level_16%40DataSource',
  324. // isSct: true//地形服务源自SuperMap iServer发布时需设置isSct为true
  325. // });
  326. // viewer.terrainProvider = terrainP;
  327. });
  328. }, //生命周期 - 挂在完成
  329. beforeUpdate() {}, //生命周期 - 更新之前
  330. updated() {}, //生命周期 - 更新之后
  331. beforeDestroy() {}, //生命周期 - 销毁之前
  332. destroy() {}, //生命周期 - 销毁完成
  333. activated() {}, //若组件实例是 <KeepAlive> 缓存树的一部分,当组件被插入到 DOM 中时调用。
  334. deactivated() {}, //若组件实例是 <KeepAlive> 缓存树的一部分,当组件从 DOM 中被移除时调用。
  335. };
  336. </script>
  337. <style lang="scss" scoped>
  338. .el-radio {
  339. color: white;
  340. }
  341. .cut_fill_centent1 {
  342. width: 100%;
  343. text-align: left;
  344. margin-left: 10%;
  345. margin-top: 5%;
  346. margin-bottom: 6%;
  347. }
  348. .cut_fill_input {
  349. display: inline-block;
  350. width: 50%;
  351. }
  352. .cut_fill_input:first-child {
  353. margin-left: 7%;
  354. margin-bottom: 5%;
  355. }
  356. .cut_fill_Buttons {
  357. margin-bottom: 2%;
  358. float: right;
  359. }
  360. </style>