/////////////////////////////////////////////////////////////////////////// // Copyright © 2022 guoshilong. All Rights Reserved. // 模块描述:洪水淹没分析 /////////////////////////////////////////////////////////////////////////// define([ 'dojo/_base/declare', 'dojo/_base/lang', 'dojo/_base/array', 'dojo/_base/html', 'dojo/topic', 'jimu/BaseWidget', './Tooltip-div', './FloodAnalysis', 'libs/layer/layer.js', 'libs/turf/turf.min.js' ], function (declare, lang, array, html, topic, BaseWidget, tooltip, flood, layer, turf, ) { return declare([BaseWidget], { baseClass: 'jimu-widget-FloodAnalysis', name: 'FloodAnalysis', riverWidth: 300, riverHeight: 10, speed: 10, positions: [], sideRes: null, riverPrimitive: null, material: null, drawingPolyline: null, //绘制的多边形数组 polygonCartesianArray:[], //canvas转换后的图片 canvasImage:null, //房屋人口 peoplePositionArray:[], myWaterPrimitive:null, startup: function () { this.inherited(arguments); var self = this; this.map.scene.globe.depthTestAgainstTerrain = true; //取消双击事件 this.map.cesiumWidget.screenSpaceEventHandler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK); //绘制水面事件 $("#flood_hzsm_headtab").click(function () { DrawDynamicClampGround.startDrawingPolyline(self.map, function (cartesians) { if (self.drawingPolyline != undefined) self.map.entities.remove(self.drawingPolyline); var lineOpts = { polyline: { positions: cartesians, clampToGround: true, width: 3, color: "#279a9a" } }; self.drawingPolyline = self.map.entities.add(lineOpts); cartesians.splice(cartesians.length - 1, cartesians.length); self.drawLines(cartesians); self.movehandLer() self.showDetail(true) }); }); $('#flood_qcsmx_headtab').click(function () { self.map.entities.remove(self.drawingPolyline); self.map.scene.primitives.remove(self.riverPrimitive); self.showDetail(false) }) // $("#thematic_hlkd_headtab").change(function (e) { // self.riverWidth = Number($(this).val()); // self.resetPos(); // }); $("#flood_analysis_sw_headtab").change(function (e) { self.riverHeight = Number($(this).val()); self.resetPos(); }); // $("#thematic_sls_headtab").change(function (e) { // self.speed = Number($(this).val()); // self.resetPos(); // }); // // $("#thematic_smsz_headtab").click(function () { // self.offsetHeight(Number($("#thematic_bhz_headtab").val()), 5); // }); // // $("#thematic_smxj_headtab").click(function () { // self.offsetHeight(-Number($("#thematic_bhz_headtab").val()), 5); // }); $('#flood-detail-ckxq').click(function () { self.floodAnalysisPopup() }) }, init: function () { this.prepareVertex(); if (this.sideRes) { this.material = this.prepareMaterial(); this.riverPrimitive && this.map.scene.primitives.remove(this.riverPrimitive); this.riverPrimitive = this.createPrimitive(); this.myWaterPrimitive = this.map.scene.primitives.add(this.riverPrimitive); } }, prepareVertex: function () { if (this.positions.length > 0) { this.sideRes = this._lines2Plane(this.positions, this.riverWidth, this.riverHeight); } }, setPositions: function (e) { this.positions = e; this.init(); }, resetPos: function () { this.sideRes = this._lines2Plane(this.positions, this.riverWidth, this.riverHeight); if (this.sideRes) { this.material = this.prepareMaterial(); this.riverPrimitive && this.map.scene.primitives.remove(this.riverPrimitive); this.riverPrimitive = this.createPrimitive(); this.map.scene.primitives.add(this.riverPrimitive); } }, drawLines: function (r) { this.setPositions(r); }, prepareMaterial: function () { var e = new Cesium.Material({ fabric: { uniforms: { image: "widgets/ThematicDynamicRiver/images/movingRiver.png", alpha: 0.5, moveVar: new Cesium.Cartesian3(50, 1, 100), reflux: -1, speed: this.speed, move: true, flipY: false }, source: "czm_material czm_getMaterial(czm_materialInput materialInput) { \n czm_material material = czm_getDefaultMaterial(materialInput); \n vec2 st = materialInput.st;\n if(move){\n float r = sqrt((st.x-0.8)*(st.x-0.8) + (st.y-0.8)*(st.y-0.8));\n float r2 = sqrt((st.x-0.2)*(st.x-0.2) + (st.y-0.2)*(st.y-0.2));\n float z = cos(moveVar.x*r + czm_frameNumber/100.0*moveVar.y)/moveVar.z;\n float z2 = cos(moveVar.x*r2 + czm_frameNumber/100.0*moveVar.y)/moveVar.z;\n st += sqrt(z*z+z2*z2);\n st.s += reflux * czm_frameNumber/1000.0 * speed;\n st.s = mod(st.s,1.0);\n }\n if(flipY){\n st = vec2(st.t,st.s);\n }\n vec4 colorImage = texture2D(image, st);\n material.alpha = alpha;\n material.diffuse = colorImage.rgb; \n return material; \n }" } }); return e }, createPrimitive: function () { var t = new Float64Array(this.sideRes.vertexs), i = new Cesium.GeometryAttributes; i.position = new Cesium.GeometryAttribute({ componentDatatype: Cesium.ComponentDatatype.DOUBLE, componentsPerAttribute: 3, values: t }), i.st = new Cesium.GeometryAttribute({ componentDatatype: Cesium.ComponentDatatype.FLOAT, componentsPerAttribute: 2, values: this.sideRes.uvs }); var r = new Cesium.Geometry({ attributes: i, indices: this.sideRes.indexs, primitiveType: Cesium.PrimitiveType.TRIANGLES, boundingSphere: Cesium.BoundingSphere.fromVertices(t) }), n = new Cesium.GeometryInstance({ geometry: r }), o = new Cesium.RenderState; return o.depthTest.enabled = !0, new Cesium.Primitive({ geometryInstances: n, appearance: new Cesium.Appearance({ material: this.material, renderState: o, vertexShaderSource: "attribute vec3 position3DHigh;\n attribute vec3 position3DLow;\n attribute vec2 st;\n attribute float batchId;\n \n varying vec3 v_positionMC;\n varying vec3 v_positionEC;\n varying vec2 v_st;\n \n void main()\n {\n vec4 p = czm_computePosition();\n \n v_positionMC = position3DHigh + position3DLow; // position in model coordinates\n v_positionEC = (czm_modelViewRelativeToEye * p).xyz; // position in eye coordinates\n v_st = st;\n \n gl_Position = czm_modelViewProjectionRelativeToEye * p;\n }\n ", fragmentShaderSource: "varying vec3 v_positionMC;\n varying vec3 v_positionEC;\n varying vec2 v_st;\n \n void main()\n {\n czm_materialInput materialInput;\n \n vec3 normalEC = normalize(czm_normal3D * czm_geodeticSurfaceNormal(v_positionMC, vec3(0.0), vec3(1.0)));\n #ifdef FACE_FORWARD\n normalEC = faceforward(normalEC, vec3(0.0, 0.0, 1.0), -normalEC);\n #endif\n \n materialInput.s = v_st.s;\n materialInput.st = v_st;\n materialInput.str = vec3(v_st, 0.0);\n \n // Convert tangent space material normal to eye space\n materialInput.normalEC = normalEC;\n materialInput.tangentToEyeMatrix = czm_eastNorthUpToEyeCoordinates(v_positionMC, materialInput.normalEC);\n \n // Convert view vector to world space\n vec3 positionToEyeEC = -v_positionEC;\n materialInput.positionToEyeEC = positionToEyeEC;\n \n czm_material material = czm_getMaterial(materialInput);\n \n #ifdef FLAT\n gl_FragColor = vec4(material.diffuse + material.emission, material.alpha);\n #else\n gl_FragColor = czm_phong(normalize(positionToEyeEC), material,czm_lightDirectionEC);\n #endif\n }\n " }) }) }, offsetHeight: function (height, time) { this.startDH(height, time) }, startDH: function (height, time) { if (height && time && this.riverPrimitive) { for (var i = this, r = 0, n = height / (20 * time), o = this.sideRes.self, s = new Cesium.Cartesian3, l = 0, u = o.length; l < u; l++) { var c = Cesium.Cartesian3.normalize(o[l], new Cesium.Cartesian3); Cesium.Cartesian3.add(s, c, s) } Cesium.Cartesian3.normalize(s, s); var h = Cesium.clone(this.riverPrimitive.modelMatrix); this.dhEvent = function () { if (Math.abs(r) <= Math.abs(height)) { var t = Cesium.Cartesian3.multiplyByScalar(s, r, new Cesium.Cartesian3); i.riverPrimitive.modelMatrix = Cesium.Matrix4.multiplyByTranslation(h, t, new Cesium.Matrix4) } else i.map.clock.onTick.removeEventListener(i.dhEvent); r += n }, this.map.clock.onTick.addEventListener(this.dhEvent) } }, //水面线转成水面 _lines2Plane: function (positions, width, height) { function n(point, height) { if (!(point instanceof Cesium.Cartesian3)) return void console.log("请确认点是Cartesian3类型!"); if (!height || 0 == height) return void console.log("请确认高度是非零数值!"); var i = Cesium.Cartesian3.normalize(point, new Cesium.Cartesian3), r = new Cesium.Ray(point, i);//射线 return Cesium.Ray.getPoint(r, height) } function o(point, point1, height) { var r = Cesium.Cartesian3.normalize(Cesium.Cartesian3.subtract(point1, point, new Cesium.Cartesian3), new Cesium.Cartesian3), n = Cesium.Cartesian3.normalize(point, new Cesium.Cartesian3), o = Cesium.Cartesian3.cross(n, r, new Cesium.Cartesian3), a = Cesium.Cartesian3.cross(r, n, new Cesium.Cartesian3), l = new Cesium.Ray(point, o), u = new Cesium.Ray(point, a); return { left: Cesium.Ray.getPoint(l, height), right: Cesium.Ray.getPoint(u, height) } } if (!positions || positions.length <= 1 || !width || 0 == width) return void console.log("请确认参数符合规则:数组长度大于1,宽高不能为0!"); for (var r = positions.length, a = [], l = [], u = width / 2, c = 0; c < r; c++) { var h = void 0, d = void 0, f = void 0, p = void 0, m = void 0; if (0 == c ? (h = positions[c], d = positions[c], f = positions[c + 1]) : c == r - 1 ? (h = positions[c - 1], d = positions[c], f = positions[c - 1]) : (h = positions[c - 1], d = positions[c], f = positions[c + 1]), 0 != height && (h = n(h, height), d = n(d, height), f = n(f, height)), h && d && f) { var g = o(d, f, u); if (p = g.left, m = g.right, 0 == c) { a.push(p), l.push(m), a.push(p), l.push(m); continue } if (!(c < r - 1)) { a.push(m), l.push(p), a.push(m), l.push(p); continue } a.push(p), l.push(m), g = o(d, h, u), p = g.left, m = g.right, a.push(m), l.push(p) } } var v = [], y = []; if (a.length != 2 * r) return void console.log("计算左右侧点出问题!"); for (var _ = 0; _ < r; _++) { var w = positions[_], b = a[2 * _ + 0], C = a[2 * _ + 1], x = Cesium.Cartesian3.subtract(b, w, new Cesium.Cartesian3), P = Cesium.Cartesian3.subtract(C, w, new Cesium.Cartesian3), M = Cesium.Cartesian3.add(x, P, new Cesium.Cartesian3), E = Cesium.Cartesian3.add(w, M, new Cesium.Cartesian3); v.push(Cesium.clone(E)); var T = l[2 * _ + 0], S = l[2 * _ + 1]; x = Cesium.Cartesian3.subtract(T, w, new Cesium.Cartesian3), P = Cesium.Cartesian3.subtract(S, w, new Cesium.Cartesian3), M = Cesium.Cartesian3.add(x, P, new Cesium.Cartesian3), E = Cesium.Cartesian3.add(w, M, new Cesium.Cartesian3), y.push(Cesium.clone(E)) } for (var O = [], D = [], k = [], A = [], R = [], F = 0; F < r; F++) { var L = Cesium.EncodedCartesian3.fromCartesian(y[F]); D.push(y[F].x), D.push(y[F].y), D.push(y[F].z), k.push(L.high.x), k.push(L.high.y), k.push(L.high.z), A.push(L.low.x), A.push(L.low.y), A.push(L.low.z), O.push(1, 1), F < r - 1 && (R.push(F + 2 * r), R.push(F + 1), R.push(F + 1 + r), R.push(F + 2 * r), R.push(F + 1 + r), R.push(r + F + 2 * r)) } for (var I = 0; I < r; I++) { var N = Cesium.EncodedCartesian3.fromCartesian(v[I]); D.push(v[I].x), D.push(v[I].y), D.push(v[I].z), k.push(N.high.x), k.push(N.high.y), k.push(N.high.z), A.push(N.low.x), A.push(N.low.y), A.push(N.low.z), O.push(1, 0) } for (var V = 0; V < r; V++) { var z = Cesium.EncodedCartesian3.fromCartesian(y[V]); D.push(y[V].x), D.push(y[V].y), D.push(y[V].z), k.push(z.high.x), k.push(z.high.y), k.push(z.high.z), A.push(z.low.x), A.push(z.low.y), A.push(z.low.z), O.push(0, 1) } for (var H = 0; H < r; H++) { var B = Cesium.EncodedCartesian3.fromCartesian(v[H]); D.push(v[H].x), D.push(v[H].y), D.push(v[H].z), k.push(B.high.x), k.push(B.high.y), k.push(B.high.z), A.push(B.low.x), A.push(B.low.y), A.push(B.low.z), O.push(0, 0) } this.polygonCartesianArray = [] for (let i = 0; i < y.length; i++) { this.polygonCartesianArray.push(y[i]) } for (let i = 0; i < v.length; i++) { this.polygonCartesianArray.push(v[i]) } //计算polygon面积 this.getPolygonArea(this.getPositionArray(this.polygonCartesianArray),this.polygonCartesianArray) return { left: v, right: y, self: positions, vertexs: new Float32Array(D), vertexsH: new Float32Array(k), vertexsL: new Float32Array(A), indexs: new Uint16Array(R), uvs: new Float32Array(O) } }, onOpen: function () { //面板打开的时候触发 (when open this panel trigger) this.map.scene.globe.baseColor = Cesium.Color.BLACK; //初始化点 this.addPoint() //切换底图 $($('div.cesium-viewer').find('.cesium-baseLayerPicker-choices')[0]).children('div:eq(0)').trigger('click'); $($('div.cesium-viewer').find('.cesium-baseLayerPicker-choices')[1]).children('div:eq(2)').trigger('click'); this.map.camera.setView({ destination: Cesium.Cartesian3.fromDegrees(116.016905,25.884684, 10000), }); this.showDetail(false) }, onClose: function () { //面板关闭的时候触发 (when this panel is closed trigger) this.map.entities.remove(this.drawingPolyline); this.map.scene.primitives.remove(this.riverPrimitive); this.map.entities.removeAll() }, onMinimize: function () { this.resize(); }, onMaximize: function () { this.resize(); }, resize: function () { }, destroy: function () { //销毁的时候触发 //todo //do something before this func this.inherited(arguments); }, //Cartesian3转换为经纬度 getPositionArray:function (cartesiansArray){ var positionArray = [] if (cartesiansArray.length>0){ for (let i = 0; i < cartesiansArray.length; i++) { //获取的对象中的经纬度为弧度 let cartographic= Cesium.Cartographic.fromCartesian(cartesiansArray[i]) //弧度转换 let longitude = Cesium.Math.toDegrees(cartographic.longitude) let latitude = Cesium.Math.toDegrees(cartographic.latitude) let height = cartographic.height positionArray.push({ lon:longitude, lat:latitude, hei:height, }) } } return positionArray }, //获取多边形面积 getPolygonArea:function (points,positions){ let radiansPerDegree = Math.PI / 180.0;//角度转化为弧度(rad) let degreesPerRadian = 180.0 / Math.PI;//弧度转化为角度 //计算多边形面积 function getArea(points) { let res = 0; //拆分三角曲面 for (let i = 0; i < points.length - 2; i++) { let j = (i + 1) % points.length; let k = (i + 2) % points.length; let totalAngle = Angle(points[i], points[j], points[k]); let dis_temp1 = distance(positions[i], positions[j]); let dis_temp2 = distance(positions[j], positions[k]); res += dis_temp1 * dis_temp2 * Math.abs(Math.sin(totalAngle)) ; } return (res/1000000.0).toFixed(4); } /*角度*/ function Angle(p1, p2, p3) { let bearing21 = Bearing(p2, p1); let bearing23 = Bearing(p2, p3); let angle = bearing21 - bearing23; if (angle < 0) { angle += 360; } return angle; } /*方向*/ function Bearing(from, to) { let lat1 = from.lat * radiansPerDegree; let lon1 = from.lon * radiansPerDegree; let lat2 = to.lat * radiansPerDegree; let lon2 = to.lon * radiansPerDegree; let angle = -Math.atan2(Math.sin(lon1 - lon2) * Math.cos(lat2), Math.cos(lat1) * Math.sin(lat2) - Math.sin(lat1) * Math.cos(lat2) * Math.cos(lon1 - lon2)); if (angle < 0) { angle += Math.PI * 2.0; } angle = angle * degreesPerRadian;//角度 return angle; } //计算距离 function distance(point1,point2){ let point1cartographic = Cesium.Cartographic.fromCartesian(point1); let point2cartographic = Cesium.Cartographic.fromCartesian(point2); /**根据经纬度计算出距离**/ let geodesic = new Cesium.EllipsoidGeodesic(); geodesic.setEndPoints(point1cartographic, point2cartographic); let s = geodesic.surfaceDistance; //console.log(Math.sqrt(Math.pow(distance, 2) + Math.pow(endheight, 2))); //返回两点之间的距离 s = Math.sqrt(Math.pow(s, 2) + Math.pow(point2cartographic.height - point1cartographic.height, 2)); return s; } console.log(getArea(points)+"平方公里","777") }, //鼠标事件 movehandLer: function movehandLer() { // 取消默认双击事件 this.map.cesiumWidget.screenSpaceEventHandler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK); // 获取鼠标事件 this.mountainHandler = new Cesium.ScreenSpaceEventHandler(this.map.scene.canvas); // 给鼠标左键添加事件函数 // this.mountainHandler.setInputAction(lang.hitch(this, this.clickHand), Cesium.ScreenSpaceEventType.LEFT_CLICK); }, //点击事件 clickHand:function (click){ var pickedObjects = this.map.scene.pick(click.position); if (pickedObjects && pickedObjects.primitive instanceof Cesium.Primitive) { // this.canvasToImage() this.floodAnalysisPopup() } }, //洪水分析弹窗 floodAnalysisPopup:function (){ var self = this var inPolygon = [] for (let i = 0; i < this.peoplePositionArray.length; i++) { let isIn = this.isPointInPolygon(this.peoplePositionArray[i]) if (isIn){ inPolygon.push(this.peoplePositionArray[i]) } } var jsonStr = JSON.stringify(inPolygon) var url = './corelib/common/popup/floodAnalysis.html'; var urlEvaluate = './corelib/common/popup/evaluateAnalysis.html' var top = ($(window).height() - 600) / 2; var left = ($(window).width() - 1300 - 340) / 2 + 340; layer.open({ title:'评估分析', type: 2, maxmin: false, //开启最大化最小化按钮 area: ['1100px', '600px'], skin: 'floodAnalysis', offset: [top, left], content: urlEvaluate + "?data=" + encodeURIComponent(jsonStr),//使用encodeURIComponent转码,避免中文字符乱码,避免url截取错误 id: "floodAnalysisLayer", closeBtn: 1, //把父页面数据传递给子弹窗并渲染 success: function(layero, index) { //绑定父子之间的关系,用于数据传递,缺少则无法传递 var body = layer.getChildFrame("body",index); //得到iframe页的窗口对象 var iframeWin = window[layero.find('iframe')[0]['name']]; // //渲染子页面中的img // iframeWin.$('#canvasImage')[0].src = self.canvasImage; var table = "" var house = 0 var people = 0 var area = 0 var money = 0 for (let i = 0; i < inPolygon.length; i++) { table += ''+ '
' + inPolygon[i].name + '
' + '
' + inPolygon[i].house + '
' + '
' + inPolygon[i].people + '
' + '
' + inPolygon[i].area + '
' + '
' + inPolygon[i].money + '
' + '' house += inPolygon[i].house people += inPolygon[i].people area += inPolygon[i].area money += inPolygon[i].money } iframeWin.$('#evaluate-tbody').html(table) iframeWin.$(".house").html(house + '户') iframeWin.$(".people").html(people + '人') iframeWin.$(".area").html(area + 'km²') iframeWin.$(".money").html(money + '万元') }, }); }, //添加点 addPoint:function (){ const url = './widgets/FloodAnalysis/data.json' this.getJsonUrl(url) }, showDetail:function(show){ //显示详情 if (show){ $('.flood-detail').show() }else { $('.flood-detail').hide() } }, //判断点是否在多边形内部 isPointInPolygon : function (point){ //获取经纬度 var polygonPosition = this.getPositionArray(this.polygonCartesianArray) //turf要求首尾闭合 var turfPolygon = [] polygonPosition.forEach(e=>{ var temp = [e.lon,e.lat] turfPolygon.push(temp) }) turfPolygon.push([polygonPosition[0].lon,polygonPosition[0].lat]) var poly= turf.polygon([turfPolygon]) var pt = turf.point([point.LGTD,point.LTTD]) return turf.booleanPointInPolygon(pt,poly) }, //获取json对象,测试用 getJsonUrl: function getJsonUrl(url) { var self = this; $.ajax({ url: url, dataType: 'json', type: 'get', success: function success(data) { const viewer = self.map var dataArray = data.data dataArray.forEach(e=>{ e.house = Number(e.house) e.people = Number(e.people) e.area = Number(e.area) e.money = Number(e.money) }) self.peoplePositionArray = [] self.peoplePositionArray = dataArray for (let i = 0; i < dataArray.length; i++) { var temp = viewer.entities.add({ position: Cesium.Cartesian3.fromDegrees(dataArray[i].LGTD, dataArray[i].LTTD), point: { color: Cesium.Color.RED, pixelSize: 16, //防止地形遮挡住点 disableDepthTestDistance: Number.POSITIVE_INFINITY }, }); } } }); }, //canvas转换为image canvasToImage:function (){ var canvas = this.map.scene.canvas let image = canvas.toDataURL("image/png").replace("image/png", "image/octet-stream"); this.canvasImage = image // //导出看效果 // let link = document.createElement("a"); // let blob = this.dataURLtoBlob(image); // let objurl = URL.createObjectURL(blob); // link.download = "scene.png"; // link.href = objurl; // link.click(); }, dataURLtoBlob:function (dataurl) { let arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1], bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n); while (n--) { u8arr[n] = bstr.charCodeAt(n); } return new Blob([u8arr], { type: mime }); }, }); });