瀏覽代碼

Merge branch 'master' of http://114.244.114.158:8802/siwei/real3d-portalsite

maxiaoxiao 2 周之前
父節點
當前提交
322a25effa
共有 29 個文件被更改,包括 7281 次插入405 次删除
  1. 1 0
      package.json
  2. 11 1
      src/api/zt/ztApi.js
  3. 12 5
      src/views/ConstructionApplication3D/BenchmarkLandPriceAnalysis/BenchmarkLandPrice.vue
  4. 2 0
      src/views/ConstructionApplication3D/BuildingStretchingAnalysis/BuildingStretchingAnalysis.vue
  5. 2 2
      src/views/ConstructionApplication3D/ConstructionModelInfo/addConstructionModelInfo.vue
  6. 17 5
      src/views/ConstructionApplication3D/Demolition/CQSetInfo.vue
  7. 78 58
      src/views/ConstructionApplication3D/Demolition/DemolitionList.vue
  8. 13 2
      src/views/ConstructionApplication3D/Demolition/zdAnalyse.js
  9. 31 1
      src/views/ConstructionApplication3D/MXDBinfo/MXDBinfo.vue
  10. 163 39
      src/views/ConstructionApplication3D/RSAnalysis/RSAnalysis.vue
  11. 700 0
      src/views/ConstructionApplication3D/SunlightAnalysis/CesiumVideo3d.js
  12. 219 0
      src/views/ConstructionApplication3D/SunlightAnalysis/CoordinateTranslate.js
  13. 426 184
      src/views/ConstructionApplication3D/SunlightAnalysis/SunlightAnalysis.vue
  14. 1648 0
      src/views/ConstructionApplication3D/SunlightAnalysis/SunlightAnalysisCT.vue
  15. 1401 0
      src/views/ConstructionApplication3D/SunlightAnalysis/SunlightAnalysisSX.vue
  16. 158 0
      src/views/ConstructionApplication3D/SunlightAnalysis/SunshineAnalysisBySX.js
  17. 323 0
      src/views/ConstructionApplication3D/SunlightAnalysis/SunshineAnalysisSDT.js
  18. 710 0
      src/views/ConstructionApplication3D/SunlightAnalysis/SunshineAnalysisSDTSD.js
  19. 322 0
      src/views/ConstructionApplication3D/SunlightAnalysis/SunshineAnalysisdb.js
  20. 273 0
      src/views/ConstructionApplication3D/SunlightAnalysis/ViewShed.js
  21. 117 0
      src/views/ConstructionApplication3D/SunlightAnalysis/glsl.js
  22. 121 0
      src/views/ConstructionApplication3D/SunlightAnalysis/glsl2.js
  23. 176 0
      src/views/ConstructionApplication3D/SunlightAnalysis/yytt.js
  24. 1 1
      src/views/ConstructionApplication3D/ZBFXAnalysisinfo/ZBFXAnalysisinfo.vue
  25. 1 1
      src/views/ConstructionApplication3D/backLineAnalysis/backLineAnalysisinfo.vue
  26. 44 27
      src/views/ConstructionApplication3D/billboard/billboardDesign.vue
  27. 43 14
      src/views/ConstructionApplication3D/billboard/billboardJTList.vue
  28. 26 29
      src/views/ConstructionApplication3D/projectManagement/projectManagement.vue
  29. 242 36
      static/Config/config.js

+ 1 - 0
package.json

@@ -11,6 +11,7 @@
         "deploy": "deploy dev"
     },
     "dependencies": {
+        "@maphubs/tokml": "^0.6.1",
         "@sakitam-gis/kriging": "^0.1.0",
         "@turf/turf": "^6.5.0",
         "axios": "^0.19.2",

+ 11 - 1
src/api/zt/ztApi.js

@@ -199,7 +199,7 @@ export async function getJZDJWord(data) {
  */
 export async function getZDBCWord(data) {
   let response = await request({
-    url: "/model/exportWord/exportWord4",
+    url: "/model/exportWord/exportWord3",
     method: "post",
     responseType: "blob",
     data: data,
@@ -447,6 +447,16 @@ export function delZtBenchmarkLandPriceResults(id) {
 /*************************基准地价******************** end */
 
 /*************************征收补偿******************** start */
+
+// 征收补偿分析
+export async function getZDAnalyseResult(data) {
+  return request({
+    url: "/model/zdanalyse/getAnalyseResult",
+    method: "post",
+    data: data,
+  });
+}
+
 // 01 征地补偿标准列表 list
 export function getZdBcbzList(query) {
   return request({

+ 12 - 5
src/views/ConstructionApplication3D/BenchmarkLandPriceAnalysis/BenchmarkLandPrice.vue

@@ -390,8 +390,8 @@ export default {
 
             debugger
             let data = JSON.parse(JSON.stringify(that.form));
-            // let response = await getAnalyseResult(data);
-            BenchmarkLandPrice.calculateLandPrice(data, true, async function (response) {
+            let response = await getAnalyseResult(data);
+            // BenchmarkLandPrice.calculateLandPrice(data, true, async function (response) {
               that.loading = false;
               if (response) {
                 response.id = uuidv4();
@@ -411,7 +411,7 @@ export default {
               }
               that.resetForm(formName);
               that.init();
-            });
+            // });
             that.init();
             that.$message({
               message: "开始分析",
@@ -556,14 +556,21 @@ return textarea;
      * @param BenchmarkLandPriceid 基准地价id
      */
     async deleteAnalyzeResults(BenchmarkLandPriceid) {
+
+      var that = this
+      var confirmid = that.$layer.confirm("确定要删除吗?", {}, async function () {
+        that.$layer.close(confirmid)
       let data = await delBenchmarkLandPrices(BenchmarkLandPriceid);
       if (data.code == 200) {
-        this.$message({
+        that.$message({
           message: "删除成功",
           type: "success",
         });
       }
-      this.init();
+      that.init();
+      }, function () {
+        return
+      });
     },
     /**
      *  打开分析结果弹窗

+ 2 - 0
src/views/ConstructionApplication3D/BuildingStretchingAnalysis/BuildingStretchingAnalysis.vue

@@ -11,6 +11,7 @@
             <el-input-number
               size="mini"
               step="1"
+              :min="1"
               v-model="form.BuildingHeight"
               @change="XYChange"
             ></el-input-number>
@@ -20,6 +21,7 @@
             <el-input-number
               size="mini"
               step="0.1"
+              :min="1"
               v-model="form.FLOORH"
               @change="XYChange"
             ></el-input-number>

+ 2 - 2
src/views/ConstructionApplication3D/ConstructionModelInfo/addConstructionModelInfo.vue

@@ -22,7 +22,7 @@
               class="item"
               effect="dark"
               content="http://超图服务ip:超图服务端口/iserver/services/模型服务名称/rest/realspace"
-              placement="top-start"
+              placement="right"
             >
               <el-input
                 v-model="form.url"
@@ -35,7 +35,7 @@
               class="item"
               effect="dark"
               content="http://超图服务ip:超图服务端口/iserver/services/数据服务名称/rest/data"
-              placement="top-start"
+              placement="right"
             >
               <el-input
                 v-model="form.dataurl"

+ 17 - 5
src/views/ConstructionApplication3D/Demolition/CQSetInfo.vue

@@ -659,11 +659,23 @@ export default {
       debugger;
       var that = this;
       if (row == undefined) return;
-      var index = that.curBCBZ.bcbz.findIndex((t) => t.id == row.id);
-      if (index > -1) {
-        that.TemporarilyDeleteIds.push(row.id);
-        that.curBCBZ.bcbz.splice(index, 1);
-      }
+
+      var confirmId = that.$layer.confirm(
+        "确定要删除吗?",
+        {},
+        function () {
+          var index = that.curBCBZ.bcbz.findIndex((t) => t.id == row.id);
+          if (index > -1) {
+            that.TemporarilyDeleteIds.push(row.id);
+            that.curBCBZ.bcbz.splice(index, 1);
+          }
+          that.$layer.close(confirmId);
+        },
+        function () {
+          return;
+        }
+      );
+
       // var formId = that.$layer.confirm(
       //   "确定要删除吗?",
       //   {},

+ 78 - 58
src/views/ConstructionApplication3D/Demolition/DemolitionList.vue

@@ -182,6 +182,9 @@
               <el-tab-pane label="国有房产" name="GYFC">
                 <ul style="width: 25rem;height: 25rem;overflow-y: auto;">
                   <!-- item = { id: smid, cqr: cqrVal, jg: fwjgVal, fwdj: fwdjVal, floor: floorVal, jzmj: jzmjVal, zdmj: zdmjVal, address: addressVal, pay: pay, single: BZ } -->
+                  <li v-if="cqResult.gyList&&cqResult.gyList.length==0">
+                    <el-empty description="未占用国有房产"></el-empty>
+                  </li>
                   <li v-for="(cqItem, index) in cqResult.gyList" :key="index"
                     style="margin-bottom: 0.5rem; font-size: 0.8rem">
                     <el-row>
@@ -190,7 +193,7 @@
                       </el-col>
                       <el-col :span="4">
                         <el-image src="../../../../static/images/location1.png" style="height: 1.5rem; width: 1.5rem"
-                          @click="cqLocation(true, cqItem.smid, cqItem.cqr)"></el-image>
+                          @click="cqLocation(true, cqItem.id, cqItem.cqr)"></el-image>
                       </el-col>
 
                     </el-row>
@@ -495,7 +498,7 @@
                         <span style="color: #fff"> 预计补偿(万元)</span>
                       </div>
                       <div>
-                        <span color="#2d8cf0">{{ formatterArea(cqResult.totalPay) }}</span>
+                        <span color="#2d8cf0">{{ formatterArea(cqResult.jtPay) }}</span>
                       </div>
                     </div>
                   </div>
@@ -517,6 +520,9 @@
 
                 <ul style="width: 25rem;height: 25rem;overflow-y: auto;">
                   <!-- item = { id: smid, cqr: cqrVal, jg: fwjgVal, fwdj: fwdjVal, floor: floorVal, jzmj: jzmjVal, zdmj: zdmjVal, address: addressVal, pay: pay, single: BZ } -->
+                  <li v-if="cqResult.jtList&&cqResult.jtList.length==0">
+                    <el-empty description="未占用集体房产"></el-empty>
+                  </li>
                   <li v-for="(cqItem, index) in cqResult.jtList" :key="index"
                     style="margin-bottom: 0.5rem; font-size: 0.8rem">
                     <el-row>
@@ -525,7 +531,7 @@
                       </el-col>
                       <el-col :span="4">
                         <el-image src="../../../../static/images/location1.png" style="height: 1.5rem; width: 1.5rem"
-                          @click="cqLocation(false, cqItem.smid, cqItem.cqr)"></el-image>
+                          @click="cqLocation(false, cqItem.id, cqItem.cqr)"></el-image>
                         <!-- <img src="imgs.zd1" /> -->
                         <!-- <i class="el-icon-s-operation"></i> -->
                       </el-col>
@@ -576,7 +582,7 @@ import Property from "./Property.vue";
 import {
   getCqBcbzList, getZdBcbzList, getQmbcbzList,
   getZdProjectList, getZdProjectById, addZdProject, delZdProject,
-  addQmResult, addCqResult, addZdResult, expotZDBCWord
+  addQmResult, addCqResult, addZdResult, expotZDBCWord,getZDAnalyseResult
 } from "@/api/zt/ztApi.js";
 import zdAnalyse from './zdAnalyse.js';
 import Popup from "../Popup.js";
@@ -1041,6 +1047,8 @@ export default {
         count: 0,
         totalJZMJ: 0,
         totalPay: 0,
+        gyPay: 0,
+        jtPay: 0,
         average: 0,
         gyJZMJ: 0,
         jtJZMJ: 0,
@@ -1202,7 +1210,7 @@ export default {
      * @param {Object} event
      */
     handleClick(tab, event) {
-      debugger
+     
       if (this.activeName == "third") {
         // this.pageClick();
         this.activePage1='GY';
@@ -1321,7 +1329,6 @@ export default {
         endDate = ""
       }
       else {
-        debugger
         startDate = that.formatDateTime(that.dateVal[0]);
         var dateTime= new Date(that.dateVal[1]);
         dateTime= dateTime.setDate(that.dateVal[1].getDate()+1);
@@ -1342,7 +1349,6 @@ export default {
           }
         }
         that.data_loading=true;
-        debugger
         getZdProjectList(queryParams).then((res) => {
           that.data_loading=false;
           that.projectList = res.rows;
@@ -1429,7 +1435,6 @@ export default {
      * @param item 报告信息
      */
     async handleGetBG(item) {
-      debugger;
       if (item) {
         await getZDBCWord(item);
       }
@@ -1616,7 +1621,6 @@ export default {
       this.activePage1='GY';
         this.activePage2='GYQS';
         this.activePage3='ZDPG';
-      debugger
       that.curProjectInfo = projectInfo;
       that.regions = JSON.parse(that.curProjectInfo.regions)
       var nPositions = [];
@@ -1720,6 +1724,8 @@ export default {
         average: projectInfo.cqResult.average,
         gyJZMJ: projectInfo.cqResult.gyJZMJ,
         jtJZMJ: projectInfo.cqResult.jtJZMJ,
+        jtPay: projectInfo.cqResult.jtPay,
+        gyPay: projectInfo.cqResult.gyPay,
         gyCount: projectInfo.cqResult.gyCount,
         jtCount: projectInfo.cqResult.jtCount,
         gyList: JSON.parse(projectInfo.cqResult.gyList),
@@ -1782,7 +1788,6 @@ export default {
       var id = that.$layer.confirm("确定要删除吗?", {}, function () {
         delZdProject([projectInfo.id]).then((res) => {
           if (res)
-            debugger
           that.$layer.close(id)
           that.$message({
           message: '数据已删除',
@@ -1839,7 +1844,6 @@ export default {
     handleUpload(event) {
       var element = document.getElementById('fileInput')
       // element.files=[];
-      debugger
       if (polygonEntity) {
         viewer.entities.remove(polygonEntity)
       }
@@ -1859,7 +1863,6 @@ export default {
 
       reader.readAsArrayBuffer(fileName);
       reader.onload = function (e) {
-        debugger;
         let res = e.target.result; //ArrayBuffer
         shp(res)
           .then(function (res) {
@@ -1881,7 +1884,6 @@ export default {
     addGeometry(geojson) {
       var that = this;
       proj4.defs("EPSG:4490", "+proj=longlat +ellps=GRS80 +no_defs +type=crs");
-      debugger
       var coordinates = geojson.features[0].geometry.coordinates;
       var box = geojson.features[0].geometry.bbox;
       var centerX = (box[0] + box[2]) / 2;
@@ -1942,7 +1944,6 @@ export default {
      * 上传成功
      */
     uploadSuccess(response, file, fileList) {
-      debugger;
       console.log("上传成功");
     },
     /**
@@ -1980,7 +1981,7 @@ export default {
               fieldValues = pick.id.attributes.fieldValues;
               for (var i = 0; i < fieldNames.length; i++) {
                 if (
-                  fieldNames[i].name.toUpperCase() == "SMID" ||
+                  fieldNames[i].name.toUpperCase() == "ID0" ||
                   fieldNames[i].name.toUpperCase() == "SMUSERID" ||
                   fieldNames[i].name.toUpperCase() == "SMAREA" ||
                   fieldNames[i].name.toUpperCase() == "SMPERIMETER" ||
@@ -2144,6 +2145,8 @@ export default {
       dlmcIndex = that.getfldIndex(that.zdResult.fieldInfos, dlmcFld);
       var dlmc = "";
       var features = that.zdResult.jtfeatures;
+      if(features==null)
+      features=[];
       var attributes = {};
       var color = "";
       var colorArr = [3];
@@ -2154,7 +2157,7 @@ export default {
         }
         if (name != null && dlmc != name)
           continue;
-        var simIndex = features[i].fieldNames.findIndex(t => t.toUpperCase() == "SMID")
+        var simIndex = features[i].fieldNames.findIndex(t => t.toUpperCase() == "ID0")
         var smid = features[i].fieldValues[simIndex];
         var ff = that.entities.find(t => t.id == "ZDJTYD_" + smid)
         var entity;
@@ -2312,12 +2315,11 @@ export default {
       var shaowOrHide = isLayerShow!=null?isLayerShow:false;
       that.GYDLLoad(null, shaowOrHide);
  
-      debugger
       myChart.on("legendselectchanged", function (parmas) {
         if(that.$refs['GYDL_button'].classList.contains("el-icon-openeyes")){
           // that.pickEntity('ZDGYDL');
-        var name = parmas.name
-        shaowOrHide = parmas.selected[name]
+        var name = parmas.name;
+        shaowOrHide = parmas.selected[name];
         that.GYDLLoad(name, shaowOrHide);
         }
         
@@ -2342,6 +2344,8 @@ export default {
 
       var entity;
       var features = that.zdResult.gyfeatures;
+      if(features==null)
+      features=[];
       var attributes = {};
       for (var i = 0; i < features.length; i++) {
         fieldValues = features[i].fieldValues;
@@ -2355,7 +2359,7 @@ export default {
           .replace("(", "")
           .replace(")", "");
         var colorArr = color.split(",");
-        var simIndex = features[i].fieldNames.findIndex(t => t.toUpperCase() == "SMID")
+        var simIndex = features[i].fieldNames.findIndex(t => t.toUpperCase() == "ID0")
         var smid = features[i].fieldValues[simIndex]
         var ff = that.entities.find(t => t.id == "ZDGYDL_" + smid)
 
@@ -2427,7 +2431,6 @@ export default {
       var color1 = window.ZSBC.ZDBCJS.DLTB.nzwfl.color;
       var colors = [color1, color2, color3];
       var datas1 = [];
-      debugger
       if (that.qmResult) {
         datas1 = [
           { value: this.qmResult.nzwMJ, name: nzwfl },
@@ -2521,7 +2524,6 @@ export default {
       var chartDom2 = document.getElementById("QMFYChart");
       var myChart2 = window.echarts.init(chartDom2);
       var datas2 = [];
-      debugger
       if (that.qmResult) {
         datas2 = [
           { value: that.qmResult.nzwPay, name: nzwfl },
@@ -2607,7 +2609,6 @@ export default {
     QMBCLoad(name, showOrHide) {
       var that = this;
       var dlmcIndex = -1;
-      debugger;
       var dlmcFld = window.ZSBC.ZDBCJS.DLTB.dlmc.field;
       dlmcIndex = that.getfldIndex(that.qmResult.fieldInfos, dlmcFld);
       // var smfl = window.ZSBC.ZDBCJS.DLTB.smfl.dlmc;
@@ -2624,6 +2625,8 @@ export default {
       var fieldValues;
       var color;
       var features = that.qmResult.features;
+      if(features==null)
+      features=[];
       for (var i = 0; i < features.length; i++) {
         geometry = features[i].geometry;
         fieldValues = features[i].fieldValues;
@@ -2653,7 +2656,7 @@ export default {
           .replace("(", "")
           .replace(")", "");
         var colorArr = color.split(",");
-        var simIndex = features[i].fieldNames.findIndex(t => t.toUpperCase() == "SMID")
+        var simIndex = features[i].fieldNames.findIndex(t => t.toUpperCase() == "ID0")
         var smid = features[i].fieldValues[simIndex]
         var ff = that.entities.find(t => t.id == "ZDQMBC_" + smid)
 
@@ -2865,6 +2868,9 @@ export default {
       var entity;
       var geometry;
       var features = that.qsResult.stateUsedFeatures;
+
+      if(features==null)
+      features=[];
       var attributes = {};
       for (var i = 0; i < features.length; i++) {
 
@@ -2880,7 +2886,7 @@ export default {
           .replace("(", "")
           .replace(")", "");
         var colorArr = color.split(",");
-        var simIndex = features[i].fieldNames.findIndex(t => t.toUpperCase() == "SMID")
+        var simIndex = features[i].fieldNames.findIndex(t => t.toUpperCase() == "ID0")
         var smid = features[i].fieldValues[simIndex]
         var ff = that.qsEntities.find(t => t.id == "ZDGYQS_" + smid)
         if (ff != null) {
@@ -3104,6 +3110,8 @@ export default {
       var geometry;
       var entity;
       var features = that.qsResult.collectiveUsedFeatures;
+      if(features==null)
+      features=[];
       var attributes = {};
       for (var i = 0; i < features.length; i++) {
         fieldValues = features[i].fieldValues;
@@ -3112,7 +3120,7 @@ export default {
         }
         if (name != null && collectiveUsedfldVal != name)
           continue;
-        var simIndex = features[i].fieldNames.findIndex(t => t.toUpperCase() == "SMID")
+        var simIndex = features[i].fieldNames.findIndex(t => t.toUpperCase() == "ID")
         var smid = features[i].fieldValues[simIndex]
         var ff = that.qsEntities.find(t => t.id == "ZDJTUSE_" + smid)
 
@@ -3343,6 +3351,8 @@ export default {
       var colors = ["rgb(63,177,227)", "rgb(107,230,193)", "rgb(196,235,173)", "rgb(150,222,232)"];
       var entity;
       var features = that.qsResult.collectiveOwnerFeatures;
+      if(features==null)
+      features=[];
       var attributes = {};
       // //集体使用信息
       var collectiveUsedownerfldVal = "";
@@ -3355,7 +3365,7 @@ export default {
         }
         if (name != null && collectiveUsedownerfldVal != name)
           continue;
-        var simIndex = features[i].fieldNames.findIndex(t => t.toUpperCase() == "SMID")
+        var simIndex = features[i].fieldNames.findIndex(t => t.toUpperCase() == "ID")
         var smid = features[i].fieldValues[simIndex]
         var ff = that.qsEntities.find(t => t.id == "ZDJTOWNER_" + smid)
         if (ff != null) {
@@ -3465,7 +3475,6 @@ export default {
      */
     startPolygon() {
       var that = this;
-      debugger
       if (handleInput) {
         handleInput.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK);
         handleInput.destroy();
@@ -3632,7 +3641,7 @@ export default {
       //   for (var i = 0; i < features.length; i++) {
       //     fieldNames = features[i].fieldNames;
       //     fieldValues = features[i].fieldValues;
-      //     smidIndex = fieldNames.findIndex(t => t.toUpperCase() == "SMID")
+      //     smidIndex = fieldNames.findIndex(t => t.toUpperCase() == "ID0")
       //     attributes = {
       //       fieldNames: fieldNames,
       //       fieldValues: fieldValues,
@@ -3719,10 +3728,12 @@ export default {
       }
       
       var curID;
+      if(features==null)
+      features=[];
       for (var i = 0; i < features.length; i++) {
         fieldNames = features[i].fieldNames;
         fieldValues = features[i].fieldValues;
-        smidIndex = fieldNames.findIndex(t => t.toUpperCase() == "SMID")
+        smidIndex = fieldNames.findIndex(t => t.toUpperCase() == "GID")
         attributes = {
           fieldNames: fieldNames,
           fieldValues: fieldValues,
@@ -3857,7 +3868,6 @@ export default {
         return false;
       }
       console.log(JSON.stringify(that.regions));
-      debugger
       var area = that.getRegionArea() / 666.66;
       if (area > 3000) {
         that.$alert("项目范围不要超过3000亩,请重新输入项目范围", "警告");
@@ -3876,14 +3886,25 @@ export default {
         if (valid) {
           //alert('submit!');
           // that.doQuery();
-          //脚本函数
+          // //脚本函数
+          // var param = {
+          //   geometry: that.regions,
+          //   zdValue: that.ruleForm.zdValue,
+          //   cqValue: that.ruleForm.cqValue,
+          //   qmValue: that.ruleForm.qmValue
+          // }
+          // //js端分析
+          // var jdResult = await zdAnalyse.doQuery(param);
+//后台分析
           var param = {
-            geometry: that.regions,
+            regions: JSON.stringify(that.regions),
             zdValue: that.ruleForm.zdValue,
             cqValue: that.ruleForm.cqValue,
             qmValue: that.ruleForm.qmValue
           }
-          var jdResult = await zdAnalyse.doQuery(param);
+          let dataparam = JSON.parse(JSON.stringify(param));
+var jdResult = await getZDAnalyseResult(dataparam);
+
           if (jdResult) {
             that.zdResult = jdResult.zdResult;
             that.cqResult = jdResult.cqResult;
@@ -3896,7 +3917,6 @@ export default {
             type: "success",
           });
           var date = new Date();
-          debugger
           var projectName = that.ruleForm.projectName;
           var item = {
             "id": that.projectList.length + 1,
@@ -3932,16 +3952,18 @@ export default {
               "count": that.cqResult.count,
               "totalJZMJ": parseFloat(that.cqResult.totalJZMJ.toFixed(2)),
               "totalPay": parseFloat(that.cqResult.totalPay.toFixed(2)),
+              "jtPay": parseFloat(that.cqResult.jtPay.toFixed(2)),
+              "gyPay": parseFloat(that.cqResult.gyPay.toFixed(2)),
               "average": parseFloat(that.cqResult.average.toFixed(2)),
               "gyJZMJ": parseFloat(that.cqResult.gyJZMJ.toFixed(2)),
               "jtJZMJ": parseFloat(that.cqResult.jtJZMJ.toFixed(2)),
               "gyCount": that.cqResult.gyCount,
               "jtCount": that.cqResult.jtCount,
-              "gyList": JSON.stringify(that.cqResult.gyList),
-              "jtList": JSON.stringify(that.cqResult.jtList),
-              "gyfeatures": JSON.stringify(that.cqResult.gyfeatures),
-              "jtfeatures": JSON.stringify(that.cqResult.jtfeatures),
-              "fieldInfos": JSON.stringify(that.cqResult.fieldInfos)
+              "gyList": typeof that.cqResult.gyList === 'string' ? that.cqResult.gyList:JSON.stringify(that.cqResult.gyList),
+              "jtList": typeof that.cqResult.jtList === 'string' ? that.cqResult.jtList:JSON.stringify(that.cqResult.jtList),
+              "gyfeatures": typeof that.cqResult.gyfeatures === 'string' ? that.cqResult.gyfeatures:JSON.stringify(that.cqResult.gyfeatures),
+              "jtfeatures": typeof that.cqResult.jtfeatures === 'string' ? that.cqResult.jtfeatures:JSON.stringify(that.cqResult.jtfeatures),
+              "fieldInfos": typeof that.cqResult.fieldInfos === 'string' ? that.cqResult.fieldInfos:JSON.stringify(that.cqResult.fieldInfos)
             },
             /**
              * 青苗分析结果
@@ -3957,8 +3979,8 @@ export default {
               "jjzwPay": parseFloat(that.qmResult.jjzwPay.toFixed(2)),
               "smMJ": parseFloat(that.qmResult.smMJ.toFixed(2)),
               "smPay": parseFloat(that.qmResult.smPay.toFixed(2)),
-              "fieldInfos": JSON.stringify(that.qmResult.fieldInfos),
-              "features": JSON.stringify(that.qmResult.features),
+              "fieldInfos": typeof that.qmResult.fieldInfos === 'string' ? that.qmResult.fieldInfos:JSON.stringify(that.qmResult.fieldInfos),
+              "features": typeof that.qmResult.features === 'string' ? that.qmResult.features:JSON.stringify(that.qmResult.features),
             },
             /**
              * 征地分析结果
@@ -3979,12 +4001,12 @@ export default {
               //安置补偿
               "totalAZPay": parseFloat(that.zdResult.totalAZPay.toFixed(2)),
               //国有地类及面积
-              "gydlList": JSON.stringify(that.zdResult.gydlList),
+              "gydlList": typeof that.zdResult.gydlList === 'string' ?  that.zdResult.gydlList:JSON.stringify(that.zdResult.gydlList),
               //地类及面积
-              "jtdlList": JSON.stringify(that.zdResult.jtdlList),
-              "gyfeatures": JSON.stringify(that.zdResult.gyfeatures),
-              "jtfeatures": JSON.stringify(that.zdResult.jtfeatures),
-              "fieldInfos": JSON.stringify(that.zdResult.fieldInfos),
+              "jtdlList": typeof that.zdResult.jtdlList === 'string' ?  that.zdResult.jtdlList:JSON.stringify(that.zdResult.jtdlList),
+              "gyfeatures": typeof that.zdResult.gyfeatures === 'string' ?  that.zdResult.gyfeatures:JSON.stringify(that.zdResult.gyfeatures),
+              "jtfeatures": typeof that.zdResult.jtfeatures === 'string' ?  that.zdResult.jtfeatures:JSON.stringify(that.zdResult.jtfeatures),
+              "fieldInfos": typeof that.zdResult.fieldInfos === 'string' ?  that.zdResult.fieldInfos:JSON.stringify(that.zdResult.fieldInfos),
             },
             /**
              * 权属结果
@@ -3993,19 +4015,19 @@ export default {
               "id": null,
               "projectId": null,
               "stateUsedMJ": parseFloat(that.qsResult.stateUsedMJ.toFixed(2)),
-              "stateUsedFeatures": JSON.stringify(that.qsResult.stateUsedFeatures),
-              "stateUsedList": JSON.stringify(that.qsResult.stateUsedList),
-              "stateUsedFieldInfos": JSON.stringify(that.qsResult.stateUsedFieldInfos),
+              "stateUsedFeatures": typeof that.qsResult.stateUsedFeatures === 'string' ? that.qsResult.stateUsedFeatures:JSON.stringify(that.qsResult.stateUsedFeatures),
+              "stateUsedList": typeof that.qsResult.stateUsedList === 'string' ? that.qsResult.stateUsedList:JSON.stringify(that.qsResult.stateUsedList),
+              "stateUsedFieldInfos": typeof that.qsResult.stateUsedFieldInfos === 'string' ?that.qsResult.stateUsedFieldInfos: JSON.stringify(that.qsResult.stateUsedFieldInfos),
 
               "collectiveOwnerMJ": parseFloat(that.qsResult.collectiveOwnerMJ.toFixed(2)),
-              "collectiveOwnerFeatures": JSON.stringify(that.qsResult.collectiveOwnerFeatures),
-              "collectiveOwnerList": JSON.stringify(that.qsResult.collectiveOwnerList),
-              "collectiveOwnerFieldInfos": JSON.stringify(that.qsResult.collectiveOwnerFieldInfos),
+              "collectiveOwnerFeatures": typeof that.qsResult.collectiveOwnerFeatures === 'string' ?that.qsResult.collectiveOwnerFeatures: JSON.stringify(that.qsResult.collectiveOwnerFeatures),
+              "collectiveOwnerList": typeof that.qsResult.collectiveOwnerList === 'string' ?that.qsResult.collectiveOwnerList: JSON.stringify(that.qsResult.collectiveOwnerList),
+              "collectiveOwnerFieldInfos": typeof that.qsResult.collectiveOwnerFieldInfos === 'string' ? that.qsResult.collectiveOwnerFieldInfos:JSON.stringify(that.qsResult.collectiveOwnerFieldInfos),
 
               "collectiveUsedMJ": parseFloat(that.qsResult.collectiveUsedMJ.toFixed(2)),
-              "collectiveUsedList": JSON.stringify(that.qsResult.collectiveUsedList),
-              "collectiveUsedFeatures": JSON.stringify(that.qsResult.collectiveUsedFeatures),
-              "collectiveUsedFieldInfos": JSON.stringify(that.qsResult.collectiveUsedFieldInfos)
+              "collectiveUsedList": typeof that.qsResult.collectiveUsedList === 'string' ? that.qsResult.collectiveUsedList:JSON.stringify(that.qsResult.collectiveUsedList),
+              "collectiveUsedFeatures": typeof that.qsResult.collectiveUsedFeatures === 'string' ? that.qsResult.collectiveUsedFeatures:JSON.stringify(that.qsResult.collectiveUsedFeatures),
+              "collectiveUsedFieldInfos": typeof that.qsResult.collectiveUsedFieldInfos === 'string' ? that.qsResult.collectiveUsedFieldInfos:JSON.stringify(that.qsResult.collectiveUsedFieldInfos)
             }
           };
           // 保存项目
@@ -4021,7 +4043,6 @@ export default {
           }
           that.removePolygonEntity();
           var date = new Date()
-          debugger
           that.ruleForm.projectName = "拆迁补偿项目_" + that.formatDateTimeToLong(date);
           
         } else {
@@ -4142,7 +4163,6 @@ export default {
     },
     //范围面积
     getRegionArea() {
-      debugger
       var points1 = this.regions;
       var parts1 = [];
       var poly1;

+ 13 - 2
src/views/ConstructionApplication3D/Demolition/zdAnalyse.js

@@ -11,6 +11,8 @@ var cqResult = {
   count: 0,
   totalJZMJ: 0,
   totalPay: 0,
+  gyPay: 0,
+  jtPay: 0,
   average: 0,
   gyJZMJ: 0,
   jtJZMJ: 0,
@@ -169,6 +171,8 @@ const zdAnalyse = {
       count: 0,
       totalJZMJ: 0,
       totalPay: 0,
+      gyPay: 0,
+      jtPay: 0,
       average: 0,
       gyJZMJ: 0,
       jtJZMJ: 0,
@@ -285,6 +289,7 @@ const zdAnalyse = {
         qsResult.collectiveUsedFeatures = collectiveUsedFeatures;
       }
     });
+    debugger;
     if (bdcFeatures != null && bdcFeatures.length > 0) {
       //建筑计算
       zdAnalyse.jzComputer(
@@ -840,6 +845,8 @@ const zdAnalyse = {
       count: 0,
       totalJZMJ: 0,
       totalPay: 0,
+      jtPay: 0,
+      gyPay: 0,
       average: 0,
       jtCount: 0,
       gyCount: 0,
@@ -866,12 +873,12 @@ const zdAnalyse = {
     };
     var qsdwmc = "";
     var pay = 0;
+    var gypay = 0;
+    var jtpay = 0;
     var isGY = false;
     var isJT = false;
     var gyfeatures = [];
     var jtfeatures = [];
-    var jtJZMJ = 0;
-    var gyJZMJ = 0;
     try {
       features.forEach((curFeature, index) => {
         var points = curFeature.geometry;
@@ -1007,9 +1014,11 @@ const zdAnalyse = {
         if (isGY == true) {
           cqResult.gyList.push(item);
           gyfeatures.push(curFeature);
+          gypay += parseFloat(((jzmjVal * BZ) / 10000).toFixed(2));
         } else {
           jtfeatures.push(curFeature);
           cqResult.jtList.push(item);
+          jtpay += parseFloat(((jzmjVal * BZ) / 10000).toFixed(2));
         }
         cqResult.totalJZMJ += jzmjVal;
         cqResult.totalPay += pay;
@@ -1019,6 +1028,8 @@ const zdAnalyse = {
       );
       cqResult.totalJZMJ = parseFloat(cqResult.totalJZMJ.toFixed(2));
       cqResult.totalPay = parseFloat(cqResult.totalPay.toFixed(2));
+      cqResult.jtPay = parseFloat(jtpay.toFixed(2));
+      cqResult.gyPay = parseFloat(gyPay.toFixed(2));
       cqResult.count = features.length;
       // cqResult.features = features;
       cqResult.jtfeatures = jtfeatures;

+ 31 - 1
src/views/ConstructionApplication3D/MXDBinfo/MXDBinfo.vue

@@ -60,6 +60,12 @@ export default {
         return {};
       },
     },
+    pinfo: {
+      type: Object,
+      default: () => {
+        return {};
+      },
+    },
     layerid: {
       type: String,
       default: "",
@@ -92,7 +98,7 @@ export default {
     },
     openSunlightAnalysis() {
       this.removeAll();
-      this.lyoption.content.parent.openSunlightAnalysis();
+      this.lyoption.content.parent.openSunlightAnalysis(this.info);
     },
     //指标分析
     normAnalysis() {
@@ -100,7 +106,31 @@ export default {
       this.$layer.close("BJTC");
       let that = this;
       let tableDataList = [];
+      if (!that.pinfo.plotnumber) {
+        that.$message({
+          message: "请先在项目信息中补全项目地块编码",
+          type: "warning",
+        });
+        return;
+      }
+
       this.getGuiHuaDiKuai(async function () {
+        for (let index = 0; index < that.LandPlanningList.length; index++) {
+          const LandPlanning = that.LandPlanningList[index];
+          let DKBM = LandPlanning.data.find((c) => c.label == "DKBM")
+            ? LandPlanning.data.find((c) => c.label == "DKBM").value
+            : "";
+          let plotnumbers = that.pinfo.plotnumber.split(",");
+          let isInclude = plotnumbers.some((element) => element.includes(DKBM));
+          if (!isInclude || !DKBM) {
+            that.removeLandPlanningList();
+            that.$message({
+              message: "请选择项目内的地块进行查询",
+              type: "warning",
+            });
+            return;
+          }
+        }
         for (let index = 0; index < that.info.modelsloadData.length; index++) {
           const element = that.info.modelsloadData[index];
           let data = await that.getnorm(element.Minfo);

+ 163 - 39
src/views/ConstructionApplication3D/RSAnalysis/RSAnalysis.vue

@@ -13,10 +13,10 @@
         <el-input-number
           size="small"
           label="观察者高度:"
-          min="0"
-          max="50"
+          :min="0"
+          :max="50"
           :step="0.5"
-          precision="1"
+          :precision="1"
           v-model="personH"
         ></el-input-number>
         <el-col :span="8"
@@ -55,8 +55,9 @@
           <el-input-number
             size="mini"
             v-model="circlePitch"
-            min="75"
-            max="100"
+            :min="20"
+            :max="160"
+            :step="5"
             @change="circlePitchChange"
           ></el-input-number
         ></el-col>
@@ -67,8 +68,9 @@
           <el-input-number
             size="mini"
             v-model="circleH"
-            min="0"
-            max="5000"
+            :min="0"
+            :max="5000"
+            :step="10"
             @change="circlePitchChange"
           ></el-input-number>
         </el-col>
@@ -168,7 +170,7 @@ export default {
       addCircleFlag: false, //环视点标志
       flyCircleLoop: false,
       flyCircleText: "环视漫游",
-      circlePitch: 90,
+      circlePitch: 45,
       circleH: 500,
       flyHOld: 20,
       flyH: 20,
@@ -531,20 +533,20 @@ export default {
           that.circlPoint[1],
           that.circlPoint[2]
         );
-        // scene.camera.setView({
-        //   destination: position,
-        //   orientation: {
-        //     heading: Cesium.Math.toRadians(90.0), // east, default value is 0.0 (north)
-        //     pitch: Cesium.Math.toRadians(that.circlePitch * -1), // default value (looking down)
-        //     roll: 0.0, // default value
-        //   },
-        // });
-        scene.camera.lookAt(
-          position,
-          new Cesium.HeadingPitchRange(0, that.circlePitch * -1, that.circleH)
-        );
-        scene.camera.flyCircle(position);
+        // // scene.camera.setView({
+        // //   destination: position,
+        // //   orientation: {
+        // //     heading: Cesium.Math.toRadians(90.0), // east, default value is 0.0 (north)
+        // //     pitch: Cesium.Math.toRadians(that.circlePitch * -1), // default value (looking down)
+        // //     roll: 0.0, // default value
+        // //   },
+        // // });
+        // scene.camera.lookAt(
+        //   position,
+        //   new Cesium.HeadingPitchRange(0, that.circlePitch * -1, that.circleH)
+        // );
         that.circlePitchChange();
+
         // scene.camera.setView({
         //   destination: position,
         //   orientation: {
@@ -553,41 +555,163 @@ export default {
         //     roll: 0.0, // default value
         //   },
         // });
+        scene.camera.flyCircle(position);
         scene.camera.speedRatio = 0.2;
       } else {
         that.$message.warning("请添加环视点!");
         return;
       }
-      // scene.camera.flyCircleLoop = that.flyCircleLoop;
+      scene.camera.flyCircleLoop = that.flyCircleLoop;
       if (that.flyCircleLoop == true) {
         that.flyCircleText = "停止环视";
       } else {
         that.flyCircleText = "环视漫游";
         scene.camera.stopFlyCircle();
-        scene.camera.lookAtTransform(Cesium.Matrix4.IDENTITY);
+        // scene.camera.lookAtTransform(Cesium.Matrix4.IDENTITY);
       }
     },
 
+    // 转换中心点
+    SETP3() {
+      var that = this;
+      let p = { lng: that.circlPoint[0], lat: that.circlPoint[1] }; //测试点
+      let h = that.circleH; //高度
+
+      let angle = that.circlePitch; //俯视角度,默认90°,可手动更改
+      let brng = -300; //heading -180
+      let obj = this.getCenterLatlng(
+        p.lng,
+        p.lat,
+        brng,
+        h / Math.tan((angle * Math.PI) / 180)
+      );
+
+      // //描绘中心点2
+      // var point = viewer.entities.add({
+      //   position: Cesium.Cartesian3.fromDegrees(obj.lng, obj.lat, h),
+      //   point: {
+      //     color: Cesium.Color.YELLOW,
+      //     pixelSize: 10,
+      //     heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
+      //     disableDepthTestDistance: Number.POSITIVE_INFINITY,
+      //   },
+      // });
+      // //描绘中心点2
+      // var poinwt = viewer.entities.add({
+      //   position: Cesium.Cartesian3.fromDegrees(
+      //     p.lng,
+      //     p.lat,
+      //     that.circlPoint[2]
+      //   ),
+      //   point: {
+      //     color: Cesium.Color.RED,
+      //     pixelSize: 10,
+      //     heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
+      //     disableDepthTestDistance: Number.POSITIVE_INFINITY,
+      //   },
+      // });
+
+      viewer.scene.camera.setView({
+        destination: Cesium.Cartesian3.fromDegrees(obj.lng, obj.lat, h),
+        orientation: {
+          heading: Cesium.Math.toRadians(-120),
+          pitch: Cesium.Math.toRadians(-that.circlePitch),
+        },
+      });
+    },
+
+    //参数 lng、lat为90俯视时的中心,bring为 heading 角度,取反方向,dist
+    getCenterLatlng(lng, lat, brng, dist) {
+      var a = 6378137;
+      var b = 6356752.3142;
+      var f = 1 / 298.257223563;
+
+      var lon1 = lng * 1;
+      var lat1 = lat * 1;
+      var s = dist;
+      var alpha1 = brng * (Math.PI / 180);
+      var sinAlpha1 = Math.sin(alpha1);
+      var cosAlpha1 = Math.cos(alpha1);
+      var tanU1 = (1 - f) * Math.tan(lat1 * (Math.PI / 180));
+      var cosU1 = 1 / Math.sqrt(1 + tanU1 * tanU1),
+        sinU1 = tanU1 * cosU1;
+      var sigma1 = Math.atan2(tanU1, cosAlpha1);
+      var sinAlpha = cosU1 * sinAlpha1;
+      var cosSqAlpha = 1 - sinAlpha * sinAlpha;
+      var uSq = (cosSqAlpha * (a * a - b * b)) / (b * b);
+      var A =
+        1 + (uSq / 16384) * (4096 + uSq * (-768 + uSq * (320 - 175 * uSq)));
+      var B = (uSq / 1024) * (256 + uSq * (-128 + uSq * (74 - 47 * uSq)));
+      var sigma = s / (b * A),
+        sigmaP = 2 * Math.PI;
+      while (Math.abs(sigma - sigmaP) > 1e-12) {
+        var cos2SigmaM = Math.cos(2 * sigma1 + sigma);
+        var sinSigma = Math.sin(sigma);
+        var cosSigma = Math.cos(sigma);
+        var deltaSigma =
+          B *
+          sinSigma *
+          (cos2SigmaM +
+            (B / 4) *
+              (cosSigma * (-1 + 2 * cos2SigmaM * cos2SigmaM) -
+                (B / 6) *
+                  cos2SigmaM *
+                  (-3 + 4 * sinSigma * sinSigma) *
+                  (-3 + 4 * cos2SigmaM * cos2SigmaM)));
+        sigmaP = sigma;
+        sigma = s / (b * A) + deltaSigma;
+      }
+
+      var tmp = sinU1 * sinSigma - cosU1 * cosSigma * cosAlpha1;
+      var lat2 = Math.atan2(
+        sinU1 * cosSigma + cosU1 * sinSigma * cosAlpha1,
+        (1 - f) * Math.sqrt(sinAlpha * sinAlpha + tmp * tmp)
+      );
+      var lambda = Math.atan2(
+        sinSigma * sinAlpha1,
+        cosU1 * cosSigma - sinU1 * sinSigma * cosAlpha1
+      );
+      var C = (f / 16) * cosSqAlpha * (4 + f * (4 - 3 * cosSqAlpha));
+      var L =
+        lambda -
+        (1 - C) *
+          f *
+          sinAlpha *
+          (sigma +
+            C *
+              sinSigma *
+              (cos2SigmaM + C * cosSigma * (-1 + 2 * cos2SigmaM * cos2SigmaM)));
+
+      var revAz = Math.atan2(sinAlpha, -tmp); // final bearing
+
+      var lngLatObj = {
+        lng: lon1 + L * (180 / Math.PI),
+        lat: lat2 * (180 / Math.PI),
+      };
+      return lngLatObj;
+    },
+
     /**
      * 修改环视角度 修改环视高度
      */
     circlePitchChange() {
-      scene.camera.setView({
-        destination: Cesium.Cartesian3.fromDegrees(
-          this.circlPoint[0],
-          this.circlPoint[1],
-          this.circlPoint[2] + Number(this.circleH)
-        ),
-        orientation: {
-          heading: Cesium.Math.toRadians(90.0), // east, default value is 0.0 (north)
-          pitch: Cesium.Math.toRadians(this.circlePitch * -1), // default value (looking down)
-          roll: 0.0, // default value
-        },
-      });
-      // var position = new Cesium.Cartesian3.fromDegrees(this.circlPoint[0],
-      //   this.circlPoint[1],
-      //   this.circlPoint[2])
-      // scene.camera.lookAt(position, new Cesium.HeadingPitchRange(0, this.circlePitch * -1, this.circleH));
+      this.SETP3();
+      // scene.camera.setView({
+      //   destination: Cesium.Cartesian3.fromDegrees(
+      //     this.circlPoint[0],
+      //     this.circlPoint[1],
+      //     this.circlPoint[2] + Number(this.circleH)
+      //   ),
+      //   orientation: {
+      //     heading: Cesium.Math.toRadians(90.0), // east, default value is 0.0 (north)
+      //     pitch: Cesium.Math.toRadians(this.circlePitch * -1), // default value (looking down)
+      //     roll: 0.0, // default value
+      //   },
+      // });
+      // // var position = new Cesium.Cartesian3.fromDegrees(this.circlPoint[0],
+      // //   this.circlPoint[1],
+      // //   this.circlPoint[2])
+      // // scene.camera.lookAt(position, new Cesium.HeadingPitchRange(0, this.circlePitch * -1, this.circleH));
     },
     /**
      * 绘制飞行线

+ 700 - 0
src/views/ConstructionApplication3D/SunlightAnalysis/CesiumVideo3d.js

@@ -0,0 +1,700 @@
+import ECEF from "./CoordinateTranslate";
+import glsl from "./glsl";
+let CesiumVideo3d = (function () {
+  var videoShed3dShader = glsl;
+  var Cesium = null;
+
+  var videoShed3d = function (cesium, viewer, param) {
+    Cesium = cesium;
+    this.ECEF = new ECEF();
+    this.param = param;
+    var option = this._initCameraParam();
+    this.optionType = {
+      Color: 1,
+      Image: 2,
+      Video: 3,
+    };
+    this.near = option.near ? option.near : 0.1;
+    if (
+      (option || (option = {}),
+      (this.viewer = viewer),
+      (this._cameraPosition = option.cameraPosition),
+      (this._position = option.position),
+      (this.type = option.type),
+      (this._alpha = option.alpha || 1),
+      (this.url = option.url),
+      (this.color = option.color),
+      (this._debugFrustum = Cesium.defaultValue(option.debugFrustum, !0)),
+      (this._aspectRatio = option.aspectRatio || this._getWinWidHei()),
+      (this._camerafov =
+        option.fov ||
+        Cesium.Math.toDegrees(this.viewer.scene.camera.frustum.fov)),
+      (this.texture =
+        option.texture ||
+        new Cesium.Texture({
+          context: this.viewer.scene.context,
+          source: {
+            width: 1,
+            height: 1,
+            arrayBufferView: new Uint8Array([255, 255, 255, 255]),
+          },
+          flipY: !1,
+        })),
+      (this._videoPlay = Cesium.defaultValue(option.videoPlay, !0)),
+      (this.defaultShow = Cesium.defaultValue(option.show, !0)),
+      !this.cameraPosition || !this.position)
+    )
+      return void console.log("初始化失败:请确认相机位置与视点位置正确!");
+    switch (this.type) {
+      default:
+      case this.optionType.Video:
+        this.activeVideo(this.url);
+        break;
+      case this.optionType.Image:
+        this.activePicture(this.url);
+        this.deActiveVideo();
+        break;
+      case this.optionType.Color:
+        this.activeColor(this.color);
+        this.deActiveVideo();
+    }
+    this._createShadowMap(), this._getOrientation(), this._addCameraFrustum();
+    this._addPostProcess();
+    this.viewer.scene.primitives.add(this);
+  };
+  Object.defineProperties(videoShed3d.prototype, {
+    alpha: {
+      get: function () {
+        return this._alpha;
+      },
+      set: function (e) {
+        return (this._alpha = e);
+      },
+    },
+    aspectRatio: {
+      get: function () {
+        return this._aspectRatio;
+      },
+      set: function (e) {
+        (this._aspectRatio = e), this._changeVideoWidHei();
+      },
+    },
+    debugFrustum: {
+      get: function () {
+        return this._debugFrustum;
+      },
+      set: function (e) {
+        (this._debugFrustum = e), (this.cameraFrustum.show = e);
+      },
+    },
+    fov: {
+      get: function () {
+        return this._camerafov;
+      },
+      set: function (e) {
+        (this._camerafov = e), this._changeCameraFov();
+      },
+    },
+    cameraPosition: {
+      get: function () {
+        return this._cameraPosition;
+      },
+      set: function (e) {
+        e && ((this._cameraPosition = e), this._changeCameraPos());
+      },
+    },
+    position: {
+      get: function () {
+        return this._position;
+      },
+      set: function (e) {
+        e && ((this._position = e), this._changeViewPos());
+      },
+    },
+    videoPlay: {
+      get: function () {
+        return this._videoPlay;
+      },
+      set: function (e) {
+        (this._videoPlay = Boolean(e)),
+          this._videoEle &&
+            (this.videoPlay ? this._videoEle.paly() : this._videoEle.pause());
+      },
+    },
+    params: {
+      get: function () {
+        var t = {};
+        return (
+          (t.type = this.type),
+          this.type == this.optionType.Color
+            ? (t.color = this.color)
+            : (t.url = this.url),
+          (t.position = this.position),
+          (t.cameraPosition = this.cameraPosition),
+          (t.fov = this.fov),
+          (t.aspectRatio = this.aspectRatio),
+          (t.alpha = this.alpha),
+          (t.debugFrustum = this.debugFrustum),
+          t
+        );
+      },
+    },
+    show: {
+      get: function () {
+        return this.defaultShow;
+      },
+      set: function (e) {
+        (this.defaultShow = Boolean(e)), this._switchShow();
+      },
+    },
+  });
+  videoShed3d.prototype._initCameraParam = function () {
+    var viewPoint = this.ECEF.enu_to_ecef(
+      {
+        longitude: this.param.position.x * 1,
+        latitude: this.param.position.y * 1,
+        altitude: this.param.position.z * 1,
+      },
+      {
+        distance: this.param.far,
+        azimuth: this.param.rotation.y * 1,
+        elevation: this.param.rotation.x * 1,
+      }
+    );
+    var position = Cesium.Cartesian3.fromDegrees(
+      viewPoint.longitude,
+      viewPoint.latitude,
+      viewPoint.altitude
+    );
+    var cameraPosition = Cesium.Cartesian3.fromDegrees(
+      this.param.position.x * 1,
+      this.param.position.y * 1,
+      this.param.position.z * 1
+    );
+    return {
+      type: 1,
+      url: this.param.url,
+      cameraPosition: cameraPosition,
+      position: position,
+      alpha: this.param.alpha,
+      near: this.param.near,
+      fov: this.param.fov,
+      debugFrustum: this.param.debugFrustum,
+    };
+  };
+  /**
+   * 旋转
+   */
+  videoShed3d.prototype._changeRotation = function (e) {
+    if (e) {
+      this.param.rotation = e;
+      var option = this._initCameraParam();
+      this.position = option.position;
+    }
+  };
+  /**
+   * 相机位置
+   */
+  videoShed3d.prototype._changeCameraPosition = function (e) {
+    if (e) {
+      this.param.position = e;
+      var option = this._initCameraParam();
+      this.cameraPosition = option.cameraPosition;
+    }
+  };
+  videoShed3d.prototype._changeFar = function (e) {
+    if (e) {
+      this.param.far = e;
+      var option = this._initCameraParam();
+      this.position = option.position;
+    }
+  };
+  videoShed3d.prototype._changeNear = function (e) {
+    if (e) {
+      this.param.near = e;
+      this.near = this.param.near;
+      this._changeCameraPos();
+    }
+  };
+  /**获取三维地图容器像素大小
+   */
+  videoShed3d.prototype._getWinWidHei = function () {
+    var viewer = this.viewer.scene;
+    return viewer.canvas.clientWidth / viewer.canvas.clientHeight;
+  };
+  videoShed3d.prototype._changeCameraFov = function () {
+    this.viewer.scene.postProcessStages.remove(this.postProcess);
+    this.viewer.scene.primitives.remove(this.cameraFrustum),
+      this._createShadowMap(this.cameraPosition, this.position),
+      this._getOrientation(),
+      this._addCameraFrustum(),
+      this._addPostProcess();
+  };
+  videoShed3d.prototype._changeVideoWidHei = function () {
+    this.viewer.scene.postProcessStages.remove(this.postProcess),
+      this.viewer.scene.primitives.remove(this.cameraFrustum);
+    this._createShadowMap(this.cameraPosition, this.position),
+      this._getOrientation(),
+      this._addCameraFrustum(),
+      this._addPostProcess();
+  };
+  videoShed3d.prototype._changeCameraPos = function () {
+    this.viewer.scene.postProcessStages.remove(this.postProcess),
+      this.viewer.scene.primitives.remove(this.cameraFrustum),
+      this.viewShadowMap.destroy(),
+      this.cameraFrustum.destroy(),
+      this._createShadowMap(this.cameraPosition, this.position),
+      this._getOrientation(),
+      this._addCameraFrustum(),
+      this._addPostProcess();
+  };
+  videoShed3d.prototype._changeViewPos = function () {
+    this.viewer.scene.postProcessStages.remove(this.postProcess),
+      this.viewer.scene.primitives.remove(this.cameraFrustum),
+      this.viewShadowMap.destroy(),
+      this.cameraFrustum.destroy(),
+      this._createShadowMap(this.cameraPosition, this.position),
+      this._getOrientation(),
+      this._addCameraFrustum(),
+      this._addPostProcess();
+  };
+  videoShed3d.prototype._switchShow = function () {
+    this.show
+      ? !this.postProcess && this._addPostProcess()
+      : (this.viewer.scene.postProcessStages.remove(this.postProcess),
+        delete this.postProcess,
+        (this.postProcess = null)),
+      (this.cameraFrustum.show = this.show);
+  };
+  /** 创建视频Element
+   * @param {String} url 视频地址
+   **/
+  videoShed3d.prototype._createVideoEle = function (url) {
+    this.videoId = "visualDomId";
+    var t = document.createElement("SOURCE");
+    (t.type = "video/mp4"), (t.src = url);
+    var i = document.createElement("SOURCE");
+    (i.type = "video/quicktime"), (i.src = url);
+    var a = document.createElement("VIDEO");
+    return (
+      a.setAttribute("autoplay", !0),
+      a.setAttribute("loop", !0),
+      a.setAttribute("crossorigin", !0),
+      a.appendChild(t),
+      a.appendChild(i),
+      //document.body.appendChild(a),
+      (this._videoEle = a),
+      a
+    );
+  };
+  /** 视频投射
+   * @param {String} url 视频地址
+   */
+  videoShed3d.prototype.activeVideo = function (url) {
+    var video = this._createVideoEle(url),
+      that = this;
+    if (video) {
+      this.type = that.optionType.Video;
+      var viewer = this.viewer;
+      this.activeVideoListener ||
+        (this.activeVideoListener = function () {
+          that.videoTexture && that.videoTexture.destroy(),
+            (that.videoTexture = new Cesium.Texture({
+              context: viewer.scene.context,
+              source: video,
+              width: 1,
+              height: 1,
+              pixelFormat: Cesium.PixelFormat.RGBA,
+              pixelDatatype: Cesium.PixelDatatype.UNSIGNED_BYTE,
+            }));
+        }),
+        viewer.clock.onTick.addEventListener(this.activeVideoListener);
+    }
+  };
+  videoShed3d.prototype.deActiveVideo = function () {
+    if (this.activeVideoListener) {
+      this.viewer.clock.onTick.removeEventListener(this.activeVideoListener),
+        delete this.activeVideoListener;
+    }
+  };
+  /** 图片投放
+   * @param {String} url 图片地址
+   **/
+  videoShed3d.prototype.activePicture = function (url) {
+    this.videoTexture = this.texture;
+    var that = this,
+      img = new Image();
+    (img.onload = function () {
+      (that.type = that.optionType.Image),
+        (that.videoTexture = new Cesium.Texture({
+          context: that.viewer.scene.context,
+          source: img,
+        }));
+    }),
+      (img.onerror = function () {
+        console.log("图片加载失败:" + url);
+      }),
+      (img.src = url);
+  };
+  videoShed3d.prototype.locate = function () {
+    var cameraPosition = Cesium.clone(this.cameraPosition),
+      position = Cesium.clone(this.position);
+    (this.viewer.Camera.position = cameraPosition),
+      (this.viewer.camera.direction = Cesium.Cartesian3.subtract(
+        position,
+        cameraPosition,
+        new Cesium.Cartesian3(0, 0, 0)
+      )),
+      (this.viewer.camera.up = Cesium.Cartesian3.normalize(
+        cameraPosition,
+        new Cesium.Cartesian3(0, 0, 0)
+      ));
+  };
+  videoShed3d.prototype.update = function (e) {
+    this.viewShadowMap &&
+      this.viewer.scene.frameState.shadowMaps.push(this.viewShadowMap); // *重点* 多投影
+  };
+  videoShed3d.prototype.destroy = function () {
+    this.viewer.scene.postProcessStages.remove(this.postProcess),
+      this.viewer.scene.primitives.remove(this.cameraFrustum),
+      //this._videoEle && this._videoEle.parentNode.removeChild(this._videoEle),
+      this.activeVideoListener &&
+        this.viewer.clock.onTick.removeEventListener(this.activeVideoListener),
+      this.activeVideoListener && delete this.activeVideoListener,
+      delete this.postProcess,
+      delete this.viewShadowMap,
+      delete this.color,
+      delete this.viewDis,
+      delete this.cameraPosition,
+      delete this.position,
+      delete this.alpha,
+      delete this._camerafov,
+      delete this._cameraPosition,
+      delete this.videoTexture,
+      delete this.cameraFrustum,
+      delete this._videoEle,
+      delete this._debugFrustum,
+      delete this._position,
+      delete this._aspectRatio,
+      delete this.url,
+      delete this.orientation,
+      delete this.texture,
+      delete this.videoId,
+      delete this.type,
+      this.viewer.scene.primitives.remove(this),
+      delete this.viewer;
+  };
+  // 创建shadowmap
+  videoShed3d.prototype._createShadowMap = function () {
+    var e = this.cameraPosition,
+      t = this.position,
+      i = this.viewer.scene,
+      a = new Cesium.Camera(i);
+    (a.position = e),
+      (a.direction = Cesium.Cartesian3.subtract(
+        t,
+        e,
+        new Cesium.Cartesian3(0, 0, 0)
+      )), //计算两个笛卡尔的组分差异。
+      (a.up = Cesium.Cartesian3.normalize(e, new Cesium.Cartesian3(0, 0, 0))); // 归一化
+    var n = Cesium.Cartesian3.distance(t, e);
+    (this.viewDis = n),
+      (a.frustum = new Cesium.PerspectiveFrustum({
+        fov: Cesium.Math.toRadians(this.fov),
+        aspectRatio: this.aspectRatio,
+        near: this.near,
+        far: n,
+      }));
+    this.viewShadowMap = new Cesium.ShadowMap({
+      lightCamera: a,
+      enable: !1,
+      isPointLight: !1,
+      isSpotLight: !0,
+      cascadesEnabled: !1,
+      context: i.context,
+      pointLightRadius: n,
+    });
+  };
+  // 获取shadowmap位置
+  videoShed3d.prototype._getOrientation = function () {
+    var e = this.cameraPosition,
+      t = this.position,
+      i = Cesium.Cartesian3.normalize(
+        Cesium.Cartesian3.subtract(t, e, new Cesium.Cartesian3()),
+        new Cesium.Cartesian3()
+      ),
+      a = Cesium.Cartesian3.normalize(e, new Cesium.Cartesian3()),
+      n = new Cesium.Camera(this.viewer.scene);
+    (n.position = e),
+      (n.direction = i),
+      (n.up = a),
+      (i = n.directionWC),
+      (a = n.upWC);
+    var r = n.rightWC,
+      o = new Cesium.Cartesian3(),
+      l = new Cesium.Matrix3(),
+      u = new Cesium.Quaternion();
+    r = Cesium.Cartesian3.negate(r, o);
+    var d = l;
+    Cesium.Matrix3.setColumn(d, 0, r, d),
+      Cesium.Matrix3.setColumn(d, 1, a, d),
+      Cesium.Matrix3.setColumn(d, 2, i, d);
+    var c = Cesium.Quaternion.fromRotationMatrix(d, u);
+
+    /*var viewMatrix=n.viewMatrix;
+        var inverseViewMatrix=n.inverseViewMatrix;
+        console.log("视图矩阵=",viewMatrix);
+        console.log("逆视图矩阵=",inverseViewMatrix);
+        
+        var frustum = new Cesium.PerspectiveFrustum({
+            fov :20,
+            aspectRatio : 0.75,
+            near : 1.0,
+            far : 10.0
+        });
+ 
+        var projectionMatrix=frustum.projectionMatrix;
+        var infiniteProjectionMatrix=frustum.infiniteProjectionMatrix;
+        console.log("投影矩阵=",projectionMatrix);
+        console.log("透视投影矩阵=",infiniteProjectionMatrix);
+         
+        //透视投 影矩阵反转
+       var inverseInfiniteProjectionMatrix=new Cesium.Matrix4();
+       Cesium.Matrix4.inverse(infiniteProjectionMatrix,inverseInfiniteProjectionMatrix);
+       console.log("透视投 影矩阵反转=",inverseInfiniteProjectionMatrix);
+       
+       //逆视图投影矩阵
+       var inverseViewProjectionMatrix=new Cesium.Matrix4();
+       Cesium.Matrix4.multiply(inverseInfiniteProjectionMatrix,inverseViewMatrix,inverseViewProjectionMatrix)
+       console.log("逆视图投影矩阵=",inverseViewProjectionMatrix);
+       
+       //视图投影矩阵
+       var viewProjectionMatrix=new Cesium.Matrix4();
+       Cesium.Matrix4.inverse(inverseViewProjectionMatrix,viewProjectionMatrix);
+       console.log("视图投影矩阵=",viewProjectionMatrix);
+       
+       //远平面标准模型矩阵
+       var matrix4 = Cesium.Matrix4.fromUniformScale(10);
+       console.log("远平面标准模型矩阵=",matrix4);
+       
+       //模型矩阵
+       var modelMatrix=new Cesium.Matrix4();
+       Cesium.Matrix4.multiply(inverseViewMatrix,matrix4,modelMatrix)
+       console.log("模型矩阵=",modelMatrix);
+       
+       //视图矩阵与逆视图投影矩阵相乘得到立方体模型视图
+       var uBoxMV=new Cesium.Matrix4();
+       Cesium.Matrix4.multiply(viewMatrix,inverseViewProjectionMatrix,uBoxMV)
+       console.log("立方体模型视图=",uBoxMV);
+       
+       //逆立方体模型视图
+       var uInverseBoxMV=new Cesium.Matrix4();
+       Cesium.Matrix4.multiply(viewMatrix,viewProjectionMatrix,uInverseBoxMV)
+       console.log("立方体模型视图=",uInverseBoxMV);
+       
+       //将这两个模型视图赋予分类基元类的一致性映射 参数便可以最终实现视频监控图像与实景三维场景的融 合
+       
+         var geometry =this.creacteGeometry(5,5);
+         var instance = new Cesium.GeometryInstance({
+               // geometry: //new Cesium.Geometry({}),
+               // geometry: new Cesium.GeometryInstance({
+               //   geometry:new Cesium.FrustumOutlineGeometry ({
+               //     origin: Cesium.Cartesian3.fromDegrees(cameraLong,cameraLat, cameraHeight),
+               //     orientation:orientation,
+               //     frustum: perspectiveFrustum,
+               //     _drawNearPlane: true
+               //   }),
+               geometry:geometry,
+               classificationType:Cesium.ClassificationType.BOTH,
+               // modelMatrix: modelMatrix,
+               attributes : {
+                 color : Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.fromCssColorString('#ff0000').withAlpha(1.0)),
+                 show : new Cesium.ShowGeometryInstanceAttribute(true)
+               }
+               });
+         var videoElement = this._createVideoEle("http://localhost:7070/video/北京路与天马路交叉口高点枪机.mkv");
+         var material = Cesium.Material.fromType('Image');
+        material.uniforms.image = videoElement;
+         var _uniformMap ={
+                   u_boxMV:uBoxMV,
+                   u_inverseBoxMV:uInverseBoxMV
+                 };
+         this.viewer.scene.primitives.add(new Cesium.Primitive({
+               geometryInstances: instance,
+               appearance: new Cesium.MaterialAppearance ({
+                 material: material,
+                 close:false,
+               }),
+               modelMatrix: modelMatrix,
+               _uniformMap:_uniformMap,
+               asynchronous:false,
+               compressVertices:false,
+               allowPicking:false
+             }));*/
+
+    //ClassificationPrimitive
+    return (this.orientation = c), c;
+  };
+  (videoShed3d.prototype.creacteGeometry = function (width, height) {
+    var hwidth = width / 2.0;
+    var hheigt = height / 2.0;
+    var positions = new Float64Array([
+      hwidth,
+      0.0,
+      hheigt,
+      -hwidth,
+      0.0,
+      hheigt,
+      -hwidth,
+      0.0,
+      -hheigt,
+      hwidth,
+      0.0,
+      -hheigt,
+    ]);
+    var sts = new Float32Array([1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0]);
+    var indices = new Uint16Array([0, 1, 2, 0, 2, 3]);
+    var ge = this._createGeometry(positions, sts, indices);
+    return ge;
+  }),
+    (videoShed3d.prototype._createGeometry = function (
+      positions,
+      sts,
+      indices
+    ) {
+      /* var Cesium = this.Cesium;*/
+      return new Cesium.Geometry({
+        attributes: {
+          position: new Cesium.GeometryAttribute({
+            componentDatatype: Cesium.ComponentDatatype.DOUBLE,
+            componentsPerAttribute: 3,
+            values: positions,
+          }),
+          normal: new Cesium.GeometryAttribute({
+            componentDatatype: Cesium.ComponentDatatype.FLOAT,
+            componentsPerAttribute: 3,
+            values: new Float32Array([
+              255.0, 0.0, 0.0, 255.0, 0.0, 0.0, 255.0, 0.0, 0.0, 255.0, 0.0,
+              0.0,
+            ]),
+            // values: new Float32Array([0.0, 0.0, 0.0,0.0, 0.0, 0.0,0.0, 0.0, 0.0,0.0, 0.0, 0.0])
+          }),
+          st: new Cesium.GeometryAttribute({
+            componentDatatype: Cesium.ComponentDatatype.FLOAT,
+            componentsPerAttribute: 2,
+            values: sts,
+          }),
+        },
+        indices: indices,
+        primitiveType: Cesium.PrimitiveType.TRIANGLES,
+        vertexFormat: new Cesium.VertexFormat({
+          position: true,
+          color: true,
+        }),
+        boundingSphere: Cesium.BoundingSphere.fromVertices(positions),
+      });
+    }),
+    //创建视锥
+    (videoShed3d.prototype._addCameraFrustum = function () {
+      var e = this;
+      (this.cameraFrustum = new Cesium.Primitive({
+        geometryInstances: new Cesium.GeometryInstance({
+          geometry: new Cesium.FrustumOutlineGeometry({
+            origin: e.cameraPosition,
+            orientation: e.orientation,
+            frustum: this.viewShadowMap._lightCamera.frustum,
+            _drawNearPlane: !0,
+          }),
+          attributes: {
+            color: Cesium.ColorGeometryInstanceAttribute.fromColor(
+              new Cesium.Color(0, 0.5, 0.5)
+            ),
+          },
+        }),
+        appearance: new Cesium.PerInstanceColorAppearance({
+          translucent: !1,
+          flat: !0,
+        }),
+        asynchronous: !1,
+        show: this.debugFrustum && this.show,
+      })),
+        this.viewer.scene.primitives.add(this.cameraFrustum);
+    });
+  videoShed3d.prototype._addPostProcess = function () {
+    var e = this,
+      t = videoShed3dShader,
+      i = e.viewShadowMap._isPointLight
+        ? e.viewShadowMap._pointBias
+        : e.viewShadowMap._primitiveBias;
+    (this.postProcess = new Cesium.PostProcessStage({
+      fragmentShader: t,
+      uniforms: {
+        helsing_textureType: function () {
+          return e.type;
+        },
+        helsing_texture: function () {
+          return e.videoTexture;
+        },
+        helsing_alpha: function () {
+          return e.alpha;
+        },
+        helsing_visibleAreaColor: function () {
+          return e.visibleAreaColor;
+        },
+        helsing_invisibleAreaColor: function () {
+          return e.invisibleAreaColor;
+        },
+        // mixNum: function () {
+        //   return e.alpha;
+        // },
+        shadowMap_texture: function () {
+          return e.viewShadowMap._shadowMapTexture;
+        },
+        // videoTexture: function () {
+        //   return e.videoTexture;
+        // },
+        shadowMap_matrix: function () {
+          return e.viewShadowMap._shadowMapMatrix;
+        },
+        shadowMap_lightPositionEC: function () {
+          return e.viewShadowMap._lightPositionEC;
+        },
+        shadowMap_texelSizeDepthBiasAndNormalShadingSmooth: function () {
+          var t = new Cesium.Cartesian2();
+          return (
+            (t.x = 1 / e.viewShadowMap._textureSize.x),
+            (t.y = 1 / e.viewShadowMap._textureSize.y),
+            Cesium.Cartesian4.fromElements(
+              t.x,
+              t.y,
+              i.depthBias,
+              i.normalShadingSmooth,
+              this.combinedUniforms1
+            )
+          );
+        },
+        shadowMap_normalOffsetScaleDistanceMaxDistanceAndDarkness: function () {
+          return Cesium.Cartesian4.fromElements(
+            i.normalOffsetScale,
+            e.viewShadowMap._distance,
+            e.viewShadowMap.maximumDistance,
+            e.viewShadowMap._darkness,
+            this.combinedUniforms2
+          );
+        },
+      },
+    })),
+      this.viewer.scene.postProcessStages.add(this.postProcess);
+  };
+  videoShed3d.prototype.activeColor = function (color = undefined) {
+    if (color) {
+      this.visibleAreaColor = color;
+      this.invisibleAreaColor = "#00B457";
+    }
+
+    this.deActiveVideo();
+  };
+  return videoShed3d;
+})();
+
+export default CesiumVideo3d;

+ 219 - 0
src/views/ConstructionApplication3D/SunlightAnalysis/CoordinateTranslate.js

@@ -0,0 +1,219 @@
+let CoordinateTranslate = (function () {
+	var _=function () {
+		this.PI = 3.141592653589793238;
+		this.a = 6378137.0;
+		this.b = 6356752.3142
+		this.f = (this.a - this.b) / this.a;
+		this.e_sq = this.f * (2.0 - this.f);
+		this.ee = 0.00669437999013;
+		this.WGSF = 1 / 298.257223563;
+		this.WGSe2 = this.WGSF * (2 - this.WGSF);
+		this.WGSa = 6378137.00000;
+		this.EPSILON = 1.0e-12;
+	}
+	_.prototype.CalculateCoordinates = function (point, azimuth, elevation, distance) {
+		var vertical_height = distance * Math.sin(2 * this.PI / 360 * elevation);//垂直高度
+		var horizontal_distance = distance * Math.cos(2 * this.PI / 360 * elevation);//水平距离
+		if (azimuth > 360) azimuth = azimuth % 360;
+		if (azimuth < 0) azimuth = 360 + (azimuth % 360);
+
+		var point1 = this.lonLat2WebMercator(point);
+		var lnglat = null;
+		
+		var x_length , y_length
+		if (azimuth <= 90) {//第四象限
+			x_length = horizontal_distance * Math.cos(2 * this.PI / 360 * azimuth);
+			y_length = horizontal_distance * Math.sin(2 * this.PI / 360 * azimuth);
+			lnglat = {
+				x: point1.x + x_length,
+				y: point1.y - y_length
+			}
+		} else if (azimuth > 90 && azimuth <= 180) {//第三象限
+			x_length = horizontal_distance * Math.sin(2 * this.PI / 360 * (azimuth - 90));
+			y_length = horizontal_distance * Math.cos(2 * this.PI / 360 * (azimuth - 90));
+			lnglat = {
+				x: point1.x - x_length,
+				y: point1.y - y_length
+			}
+		} else if (azimuth > 180 && azimuth <= 270) {//第二象限
+			x_length = horizontal_distance * Math.cos(2 * this.PI / 360 * (azimuth - 180));
+			y_length = horizontal_distance * Math.sin(2 * this.PI / 360 * (azimuth - 180));
+			lnglat = {
+				x: point1.x - x_length,
+				y: point1.y + y_length
+			}
+		} else {//第一象限
+			x_length = horizontal_distance * Math.sin(2 * this.PI / 360 * (azimuth - 270));
+			y_length = horizontal_distance * Math.cos(2 * this.PI / 360 * (azimuth - 270));
+			lnglat = {
+				x: point1.x + x_length,
+				y: point1.y + y_length
+			}
+		}
+		lnglat = this.webMercator2LonLat(lnglat);
+		return {
+			lng: lnglat.x,
+			lat: lnglat.y,
+			height: vertical_height
+		}
+	}
+	/*
+	   *经纬度转Web墨卡托
+	   *@lonLat 经纬度
+	   */
+	_.prototype.lonLat2WebMercator = function (lonLat) {
+		let x = lonLat.x * this.a / 180;
+		let y = Math.log(Math.tan((90 + lonLat.y) * this.PI / 360)) / (this.PI / 180);
+		y = y * this.a / 180;
+		return {
+			x: x,
+			y: y
+		}
+	}
+
+	/*
+	   *Web墨卡托转经纬度
+	   *@mercator 平面坐标
+	   */
+	_.prototype.webMercator2LonLat = function (mercator) {
+		let x = mercator.x / this.a * 180;
+		let y = mercator.y / this.a * 180;
+		y = 180 / this.PI * (2 * (Math.exp(y * this.PI / 180)) - this.PI / 2);
+		return {
+			x: x,
+			y: y
+		}
+	}
+
+	_.prototype.get_atan = function (z, y) {
+		let x;
+		if (z == 0) {
+			x = this.PI / 2;
+		} else {
+			if (y == 0) {
+				x = this.PI;
+			} else {
+				x = Math.atan(Math.abs(y / z));
+				if ((y > 0) && (z < 0)) {
+					x = this.PI - x;
+				} else if ((y < 0) && (z < 0)) {
+					x = this.PI + x;
+				} else if ((y < 0) && (z > 0)) {
+					x = 2 * this.M_PI - x;
+				}
+			}
+		}
+		return x;
+	}
+	//WGS84转ECEF坐标系
+	_.prototype.ConvertLLAToXYZ = function (LLACoor) {
+		let lon = this.PI / 180 * LLACoor.longitude;
+		let lat = this.PI / 180 * LLACoor.latitude;
+		let H = LLACoor.altitude;
+		let N0 = this.a / Math.sqrt(1.0 - this.ee * Math.sin(lat) * Math.sin(lat));
+		let x = (N0 + H) * Math.cos(lat) * Math.cos(lon);
+		let y = (N0 + H) * Math.cos(lat) * Math.sin(lon);
+		let z = (N0 * (1.0 - this.ee) + H) * Math.sin(lat);
+		return {
+			x: x,
+			y: y,
+			z: z
+		}
+	}
+
+	//ECEF坐标系转WGS84
+	_.prototype.ConvertXYZToLLA = function (XYZCoor) {
+		let longitude = this.get_atan(XYZCoor.x, XYZCoor.y);
+		if (longitude < 0) {
+			longitude = longitude + this.PI;
+		}
+		let latitude = this.get_atan(Math.sqrt(XYZCoor.x * XYZCoor.x + XYZCoor.y * XYZCoor.y), XYZCoor.z);
+
+		let W = Math.sqrt(1 - this.WGSe2 * Math.sin(latitude) * Math.sin(latitude));
+		let N = this.WGSa / W;
+		let B1;
+		do {
+			B1 = latitude;
+			W = Math.sqrt(1 - this.WGSe2 * Math.sin(B1) * Math.sin(B1));
+			N = this.WGSa / W;
+			latitude = this.get_atan(Math.sqrt(XYZCoor.x * XYZCoor.x + XYZCoor.y * XYZCoor.y), (XYZCoor.z + N * this.WGSe2 * Math.sin(B1)));
+		}
+		while (Math.abs(latitude - B1) > this.EPSILON);
+
+		var altitude = Math.sqrt(XYZCoor.x * XYZCoor.x + XYZCoor.y * XYZCoor.y) / Math.cos(latitude) - this.WGSa / Math.sqrt(1 - this.WGSe2 * Math.sin(latitude) * Math.sin(latitude));
+
+		return {
+			longitude: longitude * 180 / this.PI,
+			latitude: latitude * 180 / this.PI,
+			altitude: altitude
+		}
+	}
+	/*北东天坐标系转WGS84
+	@ a A点坐标
+	@ p 相对参数,距离、方位角、仰角
+	*/
+	//	俯视角pitch -elevation 
+	//航向角heading(yaw) -azimuth 
+	_.prototype.enu_to_ecef = function (a, p) {
+		//距离
+		let distance = p.distance;
+		//方位角
+		let azimuth = p.azimuth;
+		//仰角
+		let elevation = p.elevation;
+
+		let zUp = elevation >= 0 ? distance * Math.sin(this.PI / 180 * elevation) : (-1) * distance * Math.sin(this.PI / 180 * Math.abs(elevation));
+
+		let d = distance * Math.cos(this.PI / 180 * Math.abs(elevation));
+		let xEast;
+		let yNorth;
+		if (azimuth <= 90) {
+			xEast = d * Math.sin(this.PI / 180 * azimuth);
+			yNorth = d * Math.cos(this.PI / 180 * azimuth);
+		} else if (azimuth > 90 && azimuth < 180) {
+			xEast = d * Math.cos(this.PI / 180 * (azimuth - 90));
+			yNorth = (-1) * d * Math.sin(this.PI / 180 * (azimuth - 90));
+		} else if (azimuth > 180 && azimuth < 270) {
+			xEast = (-1) * d * Math.sin(this.PI / 180 * (azimuth - 180));
+			yNorth = (-1) * d * Math.cos(this.PI / 180 * (azimuth - 180));
+		} else {
+			xEast = (-1) * d * Math.sin(this.PI / 180 * (360 - azimuth));
+			yNorth = d * Math.cos(this.PI / 180 * (360 - azimuth));
+		}
+
+		let lamb = this.radians(a.latitude);
+		let phi = this.radians(a.longitude);
+		let h0 = a.altitude;
+
+		let s = Math.sin(lamb);
+		let N = this.a / Math.sqrt(1.0 - this.e_sq * s * s);
+
+		let sin_lambda = Math.sin(lamb);
+		let cos_lambda = Math.cos(lamb);
+
+		let sin_phi = Math.sin(phi);
+		let cos_phi = Math.cos(phi);
+
+		let x0 = (h0 + N) * cos_lambda * cos_phi;
+		let y0 = (h0 + N) * cos_lambda * sin_phi;
+		let z0 = (h0 + (1 - this.e_sq) * N) * sin_lambda;
+
+		let t = cos_lambda * zUp - sin_lambda * yNorth;
+
+		let zd = sin_lambda * zUp + cos_lambda * yNorth;
+		let xd = cos_phi * t - sin_phi * xEast;
+		let yd = sin_phi * t + cos_phi * xEast;
+
+		return this.ConvertXYZToLLA({
+			x: xd + x0,
+			y: yd + y0,
+			z: zd + z0
+		})
+	}
+	_.prototype.radians = function (degree) {
+		return this.PI / 180 * degree;
+	}	
+	return _
+})()
+
+export default CoordinateTranslate

+ 426 - 184
src/views/ConstructionApplication3D/SunlightAnalysis/SunlightAnalysis.vue

@@ -242,16 +242,19 @@
       </el-col>
     </el-row> -->
     <el-dialog
-  title="提示"
-  :visible.sync="dialogVisible"
-  :append-to-body="true"
-  width="30%"
-  :before-close="handleClose">
-  <span style="color:#ffffff">为保证分析正确性,请先打开高程数据</span>
-  <span slot="footer" class="dialog-footer">
-    <el-button type="primary" @click="dialogVisible = false">确 定</el-button>
-  </span>
-</el-dialog>
+      title="提示"
+      :visible.sync="dialogVisible"
+      width="30%"
+      :append-to-body="true"
+      :before-close="handleClose"
+    >
+      <span>为保证分析正确性,请先打开高程数据</span>
+      <span slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="dialogVisible = false"
+          >确 定</el-button
+        >
+      </span>
+    </el-dialog>
   </div>
 </template>
 
@@ -296,6 +299,8 @@ import {
 import SunshineAnalysisByJS from "./SunshineAnalysis.js";
 import { v4 as uuidv4 } from "uuid";
 import moment from "moment";
+import * as tokml from "@maphubs/tokml";
+var eids = [];
 export default {
   data() {
     return {
@@ -338,7 +343,7 @@ export default {
       tableData: [],
       multiViewportMode: 0,
       radio: 0,
-      eids: [],
+
       //记录进入页面时的场景参数
       RecordInitializationScene: {},
       nIntervId: null,
@@ -347,7 +352,8 @@ export default {
       gd: 0,
       geopolygon: null,
       ProjectScope: { positions: [] },
-      dialogVisible:false
+      dialogVisible: false,
+      boxAll: [],
     };
   },
   props: {
@@ -502,6 +508,22 @@ export default {
       });
 
       viewer.entities.add(polygonEntity);
+
+      // var datasource = viewer.dataSources
+      //   .add(
+      //     Cesium.KmlDataSource.load("static/data/map.kml", {
+      //       camera: scene.camera,
+      //       canvas: scene.canvas,
+      //     })
+      //   )
+      //   .then(function (kmlDatasource) {
+      //     debugger;
+      //     kmlDatasource.entities.values.add(polygonEntity);
+      //     var entity = kmlDatasource.entities.values[0];
+      //     // kmlDatasource.setVisibleInViewport(0, false);
+      //     // kmlDatasource.setVisibleInViewport(1, true);
+      //   });
+
       viewer.flyTo(polygonEntity, {
         offset: {
           heading: Cesium.Math.toRadians(0),
@@ -699,8 +721,12 @@ export default {
       that.clear();
       that.tableData = [];
 
-      if (!viewer.terrainProvider||!viewer.terrainProvider.visible||viewer.terrainProvider.visible!=true) {
-        that.dialogVisible=true;
+      if (
+        !viewer.terrainProvider ||
+        !viewer.terrainProvider.visible ||
+        viewer.terrainProvider.visible != true
+      ) {
+        that.dialogVisible = true;
         return;
       }
       if (that.form.startTime == that.form.endTime) {
@@ -805,7 +831,7 @@ export default {
         points.push(longitude);
         points.push(latitude);
       }
-      that.loading = true;
+
       //转换面
       var trufpolygons = [];
       for (var pindex = 0; pindex < polygonsCopy.positions.length; pindex++) {
@@ -821,187 +847,402 @@ export default {
       }
       var polygonPs = turfpolygon([trufpolygons]);
       var box = turfbbox(polygonPs);
+      that.boxAll = box;
+      // 判断多视口模式,设置为单视口
+      if (scene.multiViewportMode != 0) {
+        scene.multiViewportMode = Cesium.MultiViewportMode.NONE;
+      }
+      that.loading = true;
+      try {
+        viewer.camera.flyTo({
+          destination: Cesium.Rectangle.fromDegrees(
+            box[0] - 0.001,
+            box[1] - 0.001,
+            box[2] + 0.001,
+            box[3] + 0.001
+          ),
+          complete: async function () {
+            //根据范围随机生成点
+            var polygons = polygonsCopy.positions;
+            var cartographic = Cesium.Cartographic.fromCartesian(polygons[0]);
 
-      viewer.camera.flyTo({
-        destination: Cesium.Rectangle.fromDegrees(
-          box[0] - 0.001,
-          box[1] - 0.001,
-          box[2] + 0.001,
-          box[3] + 0.001
-        ),
-        complete: async function () {
-          //根据范围随机生成点
-          var polygons = polygonsCopy.positions;
-          var cartographic = Cesium.Cartographic.fromCartesian(polygons[0]);
-
-          that.gd = Math.ceil(cartographic.height);
-
-          var sdsd = [];
-          for (var index = 0; index < polygons.length; index++) {
-            var a = polygons[index];
-            var e_cartographic = Cesium.Cartographic.fromCartesian(a);
-            var e_longitude = Cesium.Math.toDegrees(e_cartographic.longitude);
-            var e_latitude = Cesium.Math.toDegrees(e_cartographic.latitude);
-            // var e_height = e_cartographic.height;
-            let sd = point([e_longitude, e_latitude]);
-            sd.properties.value = 1;
-            sdsd.push(sd);
-          }
-          // 将散点合并成要素集
-          const points = featureCollection(sdsd);
-          var options = {
-            gridType: "points",
-            property: "value",
-            units: "degrees",
-          };
-          var grid = interpolate(points, that.form.spacing * 0.00001, options);
-
-          var Points = [];
-          for (var index = 0; index < grid.features.length; index++) {
-            var Point = grid.features[index];
-            var xy = Point.geometry.coordinates;
-            Points.push(xy);
-          }
-          var xyzs = await getXYZPoint(Points);
+            that.gd = Math.ceil(cartographic.height);
 
-          for (var index = 0; index < xyzs.length; index++) {
-            var xyz = xyzs[index];
-            if (xyz) {
-              xyz.z += 2;
-            } else {
-              xyz = { x: xyz[0], y: xyz[1], z: 2 };
+            var sdsd = [];
+            for (var index = 0; index < polygons.length; index++) {
+              var a = polygons[index];
+              var e_cartographic = Cesium.Cartographic.fromCartesian(a);
+              var e_longitude = Cesium.Math.toDegrees(e_cartographic.longitude);
+              var e_latitude = Cesium.Math.toDegrees(e_cartographic.latitude);
+              // var e_height = e_cartographic.height;
+              let sd = point([e_longitude, e_latitude]);
+              sd.properties.value = 1;
+              sdsd.push(sd);
             }
-            xyz = new Cesium.Cartesian3.fromDegrees(xyz.x, xyz.y, xyz.z);
-            xyz.rzsc = 0;
-            xyzs[index] = xyz;
-          }
-          // xyzs.forEach((element) => {
-          //   var ret = SunshineAnalysisByJS.PointSunshineAnalysis(
-          //     element,
-          //     that.form.selDate,
-          //     that.datavalue[0],
-          //     that.datavalue[1]
-          //   );
-          // });
-          //根据时间范围设置不同时间分段
-          var HourSegmentation =
-            that.datavalue[1] - that.datavalue[0] == 1 ? 6 : 1;
-          var ret = SunshineAnalysisByJS.PointSunshineAnalysis(
-            xyzs,
-            that.form.selDate,
-            that.datavalue[0],
-            that.datavalue[1],
-            HourSegmentation
-          );
+            // 将散点合并成要素集
+            const points = featureCollection(sdsd);
+            var options = {
+              gridType: "points",
+              property: "value",
+              units: "degrees",
+            };
+            var grid = interpolate(
+              points,
+              that.form.spacing * 0.00001,
+              options
+            );
 
-          // for (let index = 0; index < ret.length; index++) {
-          //   const cartographic = ret[index];
-
-          //   viewer.entities.add({
-          //     position: cartographic,
-          //     point: {
-          //       pixelSize: 4,
-          //       color: Cesium.Color.RED,
-          //       outlineColor: Cesium.Color.BLACK,
-          //       outlineWidth: 2,
-          //     },
-          //   });
-          // }
-          // return;
-
-          var trufPoints = [];
-          for (var index = 0; index < ret.length; index++) {
-            const a = ret[index];
-            var e_cartographic = Cesium.Cartographic.fromCartesian(a);
-            var e_longitude = Cesium.Math.toDegrees(e_cartographic.longitude);
-            var e_latitude = Cesium.Math.toDegrees(e_cartographic.latitude);
-
-            var trufPoint = point([e_longitude, e_latitude]);
-            trufPoint.properties.value = a.rzsc;
-            trufPoint.value = a.rzsc;
-            trufPoints.push(trufPoint);
-          }
+            var Points = [];
+            for (var index = 0; index < grid.features.length; index++) {
+              var Point = grid.features[index];
+              var xy = Point.geometry.coordinates;
+              Points.push(xy);
+            }
+            var xyzs = await getXYZPoint(Points);
 
-          let gsd = that.setIsoline(trufPoints, polygonsCopy);
-          for (
-            let featuresindex = 0;
-            featuresindex < gsd.features.length;
-            featuresindex++
-          ) {
-            var element = gsd.features[featuresindex];
-            if (element.geometry.type == "MultiPolygon") {
-              // continue;
-              var polygons = that.geoJSONMultiPolygonToCesiumPolygons(element);
-
-              polygons.forEach((polygonItem) => {
-                let id = uuidv4();
-                that.eids.push(id);
-                viewer.entities.add({
-                  id: id,
-                  polygon: {
-                    hierarchy: polygonItem,
-                    material: new Cesium.Color.fromCssColorString(
-                      element.properties.fill
-                    ).withAlpha(1),
-                    height: that.gd + 3 + featuresindex * 0.1,
-                    outline: false,
-                    // outlineColor: Cesium.Color.BLACK,
-                    // outlineWidth: 2.0,
-                    // classificationType: Cesium.ClassificationType.TERRAIN,
-                  },
-                });
-              });
-            } else {
-              // continue;
+            for (var index = 0; index < xyzs.length; index++) {
+              var xyz = xyzs[index];
+              if (xyz) {
+                xyz.z += 2;
+              } else {
+                xyz = { x: xyz[0], y: xyz[1], z: 2 };
+              }
+              xyz = new Cesium.Cartesian3.fromDegrees(xyz.x, xyz.y, xyz.z);
+              xyz.rzsc = 0;
+              xyzs[index] = xyz;
+            }
+            // xyzs.forEach((element) => {
+            //   var ret = SunshineAnalysisByJS.PointSunshineAnalysis(
+            //     element,
+            //     that.form.selDate,
+            //     that.datavalue[0],
+            //     that.datavalue[1]
+            //   );
+            // });
+            //根据时间范围设置不同时间分段
+            var HourSegmentation =
+              that.datavalue[1] - that.datavalue[0] == 1 ? 6 : 1;
+
+            if (
+              that.info &&
+              that.info.modelsloadData &&
+              that.info.modelsloadData.length > 1
+            ) {
+              var Minfoid1 = that.info.modelsloadData[0].Minfo.id;
               for (
-                var index = 0;
-                index < element.geometry.coordinates.length;
-                index++
+                let layerQueueI1 = 0;
+                layerQueueI1 < viewer.scene.layers.layerQueue.length;
+                layerQueueI1++
               ) {
-                var polygon = element.geometry.coordinates[index];
-                let ps = polygon.flat();
-
-                let id = uuidv4();
-                that.eids.push(id);
-                viewer.entities.add({
-                  id: id,
-                  polygon: {
-                    hierarchy: Cesium.Cartesian3.fromDegreesArray(ps),
-                    material: new Cesium.Color.fromCssColorString(
-                      element.properties.fill
-                    ).withAlpha(1),
-                    height: that.gd + 3 + featuresindex * 0.1,
-                    outline: false,
-                    // outlineColor: Cesium.Color.BLACK,
-                    // outlineWidth: 2.0,
-                    // classificationType: Cesium.ClassificationType.TERRAIN,
-                  },
-                });
+                var layer1 = viewer.scene.layers.layerQueue[layerQueueI1];
+                if (layer1.Minfoid && layer1.Minfoid == Minfoid1) {
+                  layer1.visible = true;
+                } else if (layer1.Minfoid && layer1.Minfoid != Minfoid1) {
+                  layer1.visible = false;
+                }
               }
-            }
-          }
+              setTimeout(function () {
+                var ret = SunshineAnalysisByJS.PointSunshineAnalysis(
+                  JSON.parse(JSON.stringify(xyzs)),
+                  that.form.selDate,
+                  that.datavalue[0],
+                  that.datavalue[1],
+                  HourSegmentation
+                );
+
+                // for (let index = 0; index < ret.length; index++) {
+                //   const cartographic = ret[index];
+
+                //   viewer.entities.add({
+                //     position: cartographic,
+                //     point: {
+                //       pixelSize: 4,
+                //       color: Cesium.Color.RED,
+                //       outlineColor: Cesium.Color.BLACK,
+                //       outlineWidth: 2,
+                //     },
+                //   });
+                // }
+                // return;
+
+                var trufPoints = [];
+                for (var index = 0; index < ret.length; index++) {
+                  var a = ret[index];
+                  var e_cartographic = Cesium.Cartographic.fromCartesian(a);
+                  var e_longitude = Cesium.Math.toDegrees(
+                    e_cartographic.longitude
+                  );
+                  var e_latitude = Cesium.Math.toDegrees(
+                    e_cartographic.latitude
+                  );
+
+                  var trufPoint = point([e_longitude, e_latitude]);
+                  trufPoint.properties.value = a.rzsc;
+                  trufPoint.value = a.rzsc;
+                  trufPoints.push(trufPoint);
+                }
+                var gsd1 = that.setIsoline(trufPoints, polygonsCopy);
+
+                var Minfoid2 = that.info.modelsloadData[1].Minfo.id;
+                for (
+                  var layerQueueI2 = 0;
+                  layerQueueI2 < viewer.scene.layers.layerQueue.length;
+                  layerQueueI2++
+                ) {
+                  var layer2 = viewer.scene.layers.layerQueue[layerQueueI2];
+                  if (layer2.Minfoid && layer2.Minfoid == Minfoid2) {
+                    layer2.visible = true;
+                  } else if (layer2.Minfoid && layer2.Minfoid != Minfoid2) {
+                    layer2.visible = false;
+                  }
+                }
+                setTimeout(function () {
+                  var ret = SunshineAnalysisByJS.PointSunshineAnalysis(
+                    JSON.parse(JSON.stringify(xyzs)),
+                    that.form.selDate,
+                    that.datavalue[0],
+                    that.datavalue[1],
+                    HourSegmentation
+                  );
+
+                  // for (let index = 0; index < ret.length; index++) {
+                  //   const cartographic = ret[index];
+
+                  //   viewer.entities.add({
+                  //     position: cartographic,
+                  //     point: {
+                  //       pixelSize: 4,
+                  //       color: Cesium.Color.RED,
+                  //       outlineColor: Cesium.Color.BLACK,
+                  //       outlineWidth: 2,
+                  //     },
+                  //   });
+                  // }
+                  // return;
+
+                  var trufPoints = [];
+                  for (var index = 0; index < ret.length; index++) {
+                    var a = ret[index];
+                    var e_cartographic = Cesium.Cartographic.fromCartesian(a);
+                    var e_longitude = Cesium.Math.toDegrees(
+                      e_cartographic.longitude
+                    );
+                    var e_latitude = Cesium.Math.toDegrees(
+                      e_cartographic.latitude
+                    );
+
+                    var trufPoint = point([e_longitude, e_latitude]);
+                    trufPoint.properties.value = a.rzsc;
+                    trufPoint.value = a.rzsc;
+                    trufPoints.push(trufPoint);
+                  }
+                  var gsd2 = that.setIsoline(trufPoints, polygonsCopy);
+
+                  //转blob
+                  var kml1 = tokml(gsd1, {
+                    name: "kmlSun",
+                    description: "",
+                  });
+                  var bytes1 = new TextEncoder().encode(kml1);
+                  // 创建一个Blob对象
+                  var blob1 = new Blob([bytes1], { type: "text/plain" });
+                  var kml2 = tokml(gsd2, {
+                    name: "kmlSun",
+                    description: "",
+                  });
+                  var bytes2 = new TextEncoder().encode(kml2);
+                  // 创建一个Blob对象
+                  var blob2 = new Blob([bytes2], { type: "text/plain" });
+                  debugger;
+                  //恢复原样
+                  for (
+                    var modelsloadDataindex = 0;
+                    modelsloadDataindex < that.info.modelsloadData.length;
+                    modelsloadDataindex++
+                  ) {
+                    var Minfoid =
+                      that.info.modelsloadData[modelsloadDataindex].Minfo.id;
+                    for (
+                      let layerQueueI = 0;
+                      layerQueueI < viewer.scene.layers.layerQueue.length;
+                      layerQueueI++
+                    ) {
+                      var layer = viewer.scene.layers.layerQueue[layerQueueI];
+                      if (layer.Minfoid && layer.Minfoid == Minfoid) {
+                        layer.visible = true;
+                      }
+                    }
+                  }
+                  scene.multiViewportMode = Cesium.MultiViewportMode.HORIZONTAL;
+
+                  //渲染图层
+                  viewer.dataSources
+                    .add(
+                      Cesium.KmlDataSource.load(blob1, {
+                        camera: scene.camera,
+                        canvas: scene.canvas,
+                      })
+                    )
+                    .then(function (kmlDatasource) {
+                      eids.push(kmlDatasource);
+                      debugger;
+                      // kmlDatasource.entities.values.add(polygonEntity);
+                      // var entity = kmlDatasource.entities.values[0];
+                      for (
+                        var entitieindex = 0;
+                        entitieindex < kmlDatasource.entities.values.length;
+                        entitieindex++
+                      ) {
+                        const entitie =
+                          kmlDatasource.entities.values[entitieindex];
+                        that.setEntitieParameter(entitie, entitieindex);
+                      }
+
+                      kmlDatasource.setVisibleInViewport(0, true);
+                      kmlDatasource.setVisibleInViewport(1, false);
+                    });
+                  viewer.dataSources
+                    .add(
+                      Cesium.KmlDataSource.load(blob2, {
+                        camera: scene.camera,
+                        canvas: scene.canvas,
+                      })
+                    )
+                    .then(function (kmlDatasource) {
+                      eids.push(kmlDatasource);
+                      debugger;
+                      // kmlDatasource.entities.values.add(polygonEntity);
+                      // var entity = kmlDatasource.entities.values[0];
+                      for (
+                        var entitieindex = 0;
+                        entitieindex < kmlDatasource.entities.values.length;
+                        entitieindex++
+                      ) {
+                        const entitie =
+                          kmlDatasource.entities.values[entitieindex];
+                        that.setEntitieParameter(entitie, entitieindex);
+                      }
+
+                      kmlDatasource.setVisibleInViewport(0, false);
+                      kmlDatasource.setVisibleInViewport(1, true);
+                    });
+                  that.loading = false;
+                }, 1000);
+              }, 1000);
+            } else {
+              var ret = SunshineAnalysisByJS.PointSunshineAnalysis(
+                JSON.parse(JSON.stringify(xyzs)),
+                that.form.selDate,
+                that.datavalue[0],
+                that.datavalue[1],
+                HourSegmentation
+              );
 
-          that.loading = false;
-        },
-      });
+              // for (let index = 0; index < ret.length; index++) {
+              //   const cartographic = ret[index];
+
+              //   viewer.entities.add({
+              //     position: cartographic,
+              //     point: {
+              //       pixelSize: 4,
+              //       color: Cesium.Color.RED,
+              //       outlineColor: Cesium.Color.BLACK,
+              //       outlineWidth: 2,
+              //     },
+              //   });
+              // }
+              // return;
+
+              var trufPoints = [];
+              for (var index = 0; index < ret.length; index++) {
+                var a = ret[index];
+                var e_cartographic = Cesium.Cartographic.fromCartesian(a);
+                var e_longitude = Cesium.Math.toDegrees(
+                  e_cartographic.longitude
+                );
+                var e_latitude = Cesium.Math.toDegrees(e_cartographic.latitude);
+
+                var trufPoint = point([e_longitude, e_latitude]);
+                trufPoint.properties.value = a.rzsc;
+                trufPoint.value = a.rzsc;
+                trufPoints.push(trufPoint);
+              }
+              let gsd = that.setIsoline(trufPoints, polygonsCopy);
+              //转blob
+              var kml = tokml(gsd, {
+                name: "kmlSun",
+                description: "",
+              });
+              var bytes = new TextEncoder().encode(kml);
+              // 创建一个Blob对象
+              var blob = new Blob([bytes], { type: "text/plain" });
+              viewer.dataSources
+                .add(
+                  Cesium.KmlDataSource.load(blob, {
+                    camera: scene.camera,
+                    canvas: scene.canvas,
+                  })
+                )
+                .then(function (kmlDatasource) {
+                  eids.push(kmlDatasource);
+                  debugger;
+                  // kmlDatasource.entities.values.add(polygonEntity);
+                  // var entity = kmlDatasource.entities.values[0];
+                  for (
+                    var entitieindex = 0;
+                    entitieindex < kmlDatasource.entities.values.length;
+                    entitieindex++
+                  ) {
+                    const entitie = kmlDatasource.entities.values[entitieindex];
+                    that.setEntitieParameter(entitie, entitieindex);
+                  }
+                });
+              that.loading = false;
+            }
+          },
+        });
+      } catch (error) {
+        that.loading = false;
+      }
+    },
+    //递归设置Entitie参数
+    setEntitieParameter(entitie, entitieindex) {
+      if (entitie.polygon) {
+        entitie.polygon.material = new Cesium.Color.fromCssColorString(
+          entitie.kml.extendedData.fill.value
+        ).withAlpha(1);
+        entitie.polygon.height = this.gd + 3; //+ entitieindex * 0.1;
+        entitie.polygon.outline = false;
+      }
+      if (entitie.children.length > 0) {
+        entitie.children.forEach((element) => {
+          this.setEntitieParameter(element, entitieindex);
+        });
+      }
     },
     ExportResult() {
       let that = this;
-      let entitys = [];
-      that.eids.forEach((id) => {
-        let entity = viewer.entities.getById(id);
-        if (entity) {
-          entitys.push(entity);
-        }
-      });
 
-      let box = that.squarePolygon(entitys);
+      if (!that.boxAll || that.boxAll.length == 0) {
+        this.$message.warning("请先执行分析功能再导出结果");
+        return;
+      }
+
+      // let entitys = [];
+      // eids.forEach((id) => {
+      //   let entity = viewer.entities.getById(id);
+      //   if (entity) {
+      //     entitys.push(entity);
+      //   }
+      // });
+
+      // let box = that.squarePolygon(entitys);
       viewer.camera.flyTo({
         destination: Cesium.Rectangle.fromDegrees(
-          box[0][0] + 0.0002,
-          box[0][1] - 0.0002,
-          box[2][0] - 0.0002,
-          box[2][1] + 0.0002
+          that.boxAll[0] - 0.001,
+          that.boxAll[1] - 0.001,
+          that.boxAll[2] + 0.001,
+          that.boxAll[3] + 0.001
         ),
         complete: function () {
           var promise = scene.outputSceneToFile();
@@ -1107,11 +1348,12 @@ export default {
 
       this.positions = [];
       this.points = [];
-      for (let i = 0; i < this.eids.length; i++) {
-        viewer.entities.removeById(this.eids[i]);
+      for (let i = 0; i < eids.length; i++) {
+        // viewer.entities.removeById(eids[i]);
+        viewer.dataSources.remove(eids[i]);
       }
       // this.sdh = [];
-      this.eids = [];
+      eids = [];
     },
     //结束时日照阴影
     setCurrentTime() {

+ 1648 - 0
src/views/ConstructionApplication3D/SunlightAnalysis/SunlightAnalysisCT.vue

@@ -0,0 +1,1648 @@
+<template>
+  <div
+    class="ZTGlobal"
+    style="width: 100%; padding: 1rem 1.1rem 0rem; color: white"
+    v-loading.fullscreen.lock="loading"
+    element-loading-text="正在分析中...."
+    element-loading-spinner="el-icon-loading"
+    element-loading-background="rgba(0, 0, 0, 0.8)"
+  >
+    <el-row :gutter="10">
+      <el-col :span="24">
+        <div class="titleHeader">
+          <h3>参数设置</h3>
+        </div>
+      </el-col>
+    </el-row>
+    <el-row :gutter="10">
+      <el-col :span="24">
+        <el-row :gutter="10" style="display: flex; align-items: center">
+          <el-col :span="24">
+            日 期:
+            <el-date-picker
+              size="mini"
+              v-model="form.selDate"
+              type="date"
+              placeholder="选择日期"
+            >
+            </el-date-picker>
+          </el-col>
+        </el-row>
+        <el-row :gutter="10" style="display: flex; align-items: center">
+          <el-col :span="6"> 日照时间范围: </el-col>
+          <el-col :span="18">
+            <el-slider
+              size="mini"
+              v-model="datavalue"
+              range
+              :marks="marks"
+              :max="24"
+              @change="datavalueChange"
+            >
+            </el-slider>
+          </el-col>
+        </el-row>
+        <el-row :gutter="10" style="display: flex; align-items: center">
+          <el-col :span="6"> 日照播放速度: </el-col>
+          <el-col :span="18">
+            <el-input-number
+              size="mini"
+              v-model="Intervalshijian"
+              :min="1"
+              :max="100"
+            ></el-input-number>
+          </el-col>
+        </el-row>
+        <el-row :gutter="10">
+          <el-col :span="24">
+            <div class="SaveCenter" style="padding: 0">
+              <el-button size="mini" type="primary" @click="statrSunlight"
+                >执行日照效果</el-button
+              >
+              <el-button size="mini" type="primary" @click="dqSunlight"
+                >当前日照</el-button
+              >
+            </div>
+          </el-col>
+        </el-row>
+        <el-divider></el-divider>
+        <!-- <el-row :gutter="10">
+          <el-col :span="12">
+            时间间隔:
+            <el-input-number
+              style="width: 50%"
+              size="mini"
+              v-model="form.timeInterval"
+            ></el-input-number>
+          </el-col>
+          <el-col :span="12">
+            间距(米):
+            <el-input-number
+              style="width: 50%"
+              size="mini"
+              v-model="form.spacing"
+            ></el-input-number>
+          </el-col>
+        </el-row> -->
+        <!-- <el-row :gutter="10">
+          <el-col :span="12" style="text-align: center">
+            X坐标(度):
+            <el-input-number
+              size="mini"
+              step="0.000001"
+              v-model="form.x"
+              @change="XYChange"
+            ></el-input-number>
+          </el-col>
+          <el-col :span="12" style="text-align: center">
+            Y坐标(度):
+            <el-input-number
+              size="mini"
+              step="0.000001"
+              v-model="form.y"
+              @change="XYChange"
+            ></el-input-number>
+          </el-col>
+        </el-row> -->
+
+        <!-- <el-row :gutter="10">
+          <el-col :span="12">
+            底部高程(米):
+            <el-input-number
+              style="width: 50%"
+              size="mini"
+              v-model="form.bottomHeight"
+            ></el-input-number>
+          </el-col>
+          <el-col :span="12">
+            拉伸高度(米):
+            <el-input-number
+              style="width: 50%"
+              size="mini"
+              v-model="form.extrudeHeight"
+            ></el-input-number>
+          </el-col>
+        </el-row> -->
+        <el-row :gutter="5">
+          <el-col :span="13">
+            <!-- 阴影分析时日照时间案范围重合时为时刻阴影,不重合时计算为时间范围内阴影率 -->
+            分析高度:
+            <el-tooltip
+              class="item"
+              effect="dark"
+              content="当分析高度为0时,自动读取绘制范围范围时第一个点的高度值。后续不为0时按设置高度分析。"
+              placement="top"
+            >
+              <el-input-number
+                size="mini"
+                v-model="gd"
+                :min="0"
+                :max="100"
+              ></el-input-number>
+            </el-tooltip>
+          </el-col>
+          <el-col :span="11">
+            <input @change="handleUpload" type="file" style="display:none" id="fileInput" accept=".geojson"></input> 
+            <el-button size="mini" type="primary" @click="inputGeometry"
+              >导入范围</el-button
+            >
+            <el-button size="mini" type="primary" @click="outGeometry"
+              >导出范围</el-button
+            >
+          </el-col>
+        </el-row>
+      </el-col>
+    </el-row>
+    <!-- <el-row :gutter="10" v-if="multiViewportMode > 1">
+      <el-col :span="24">
+        选择分析视口:<el-radio-group
+          v-model="radio"
+          v-for="item in multiViewportMode"
+          :key="item"
+        >
+          <el-radio :label="item - 1">窗口{{ item }}</el-radio>
+        </el-radio-group>
+      </el-col>
+    </el-row> -->
+    <div class="SaveCenter">
+      <el-row :gutter="10">
+        <el-col :span="24">
+          <el-button size="mini" type="primary" @click="onSubmit"
+            >自定义日照分析</el-button
+          >
+          <el-button size="mini" type="primary" @click="onDHSubmit"
+            >大寒日</el-button
+          >
+          <el-button size="mini" type="primary" @click="onDZSubmit"
+            >冬至日</el-button
+          >
+        </el-col>
+      </el-row>
+      <el-row :gutter="10">
+        <el-col :span="24">
+          <el-tooltip
+            effect="dark"
+            content="日照时长结果生成后,调整地图到合适位置,然后导出"
+            placement="bottom"
+          >
+            <el-button
+              size="mini"
+              type="primary"
+              :disabled="sdh.length == 0 ? true : false"
+              @click="ExportResult"
+              >导出结果</el-button
+            >
+          </el-tooltip>
+
+          <el-button size="mini" @click="resetForm">清除</el-button>
+        </el-col>
+      </el-row>
+    </div>
+    <el-row :gutter="10">
+      <el-col :span="24">
+        <el-descriptions border size="mini" :column="2">
+          <el-descriptions-item
+            v-for="item in sdh"
+            :key="item"
+            :label="item.scS + ' 小时'"
+            ><div
+              style="width: 4.5rem; height: 100%"
+              :style="{ 'background-color': item.fill }"
+            >
+              &nbsp;
+            </div>
+          </el-descriptions-item>
+        </el-descriptions>
+      </el-col>
+    </el-row>
+    <!-- <el-row :gutter="10">
+      <el-col :span="24">
+        <el-table
+          size="mini"
+          :data="tableData"
+          style="width: 100%"
+          :highlight-current-row="true"
+          @row-click="rowClick"
+        >
+          <el-table-column prop="heightText" label="高程"> </el-table-column>
+          <el-table-column prop="sunDate" label="日照时间"> </el-table-column>
+          <el-table-column
+            prop="shadowRadioText"
+            label="日照率"
+          ></el-table-column> 
+        </el-table>
+      </el-col>
+    </el-row> -->
+  </div>
+</template>
+
+<script>
+var handlerPolygon = null,
+  layers = null,
+  shadowQuery = null,
+  markedPoints = [];
+var sdfff = null;
+var czsj = { points1: null, dd1: null };
+import {
+  intersect,
+  flatten,
+  envelope,
+  point,
+  buffer,
+  bboxPolygon,
+  bbox,
+  square,
+  destination,
+  polygon,
+  featureCollection,
+  interpolate,
+  isobands,
+  area,
+  isolines,
+  pointGrid,
+  invariant
+} from "@turf/turf";
+// # 引入kriging-contour
+import {
+  getVectorContour,
+  drawCanvasContour,
+} from "kriging-contour/dist/kriging-contour.js";
+// import { getSunrise, getSunset } from "sunrise-sunset-js";
+import {
+  cartesian3ToWGS84,
+  mapQuery,
+  mercator2lonLat,
+  undergroundMode,
+} from "@/utils/MapHelper/MapHelper.js";
+import { v4 as uuidv4 } from "uuid";
+import moment from "moment";
+export default {
+  data() {
+    return {
+      tooltip: createTooltip(document.body),
+      form: {
+        timeInterval: 60,
+        spacing: 8,
+        selDate: new Date(),
+        startTime: 10,
+        endTime: 14,
+        bottomHeight: 0,
+        extrudeHeight: 100,
+        x: 0,
+        y: 0,
+      },
+      sdh: [
+        { scS: "0-1", fill: "#313695" },
+        { scS: "1-2", fill: "#1E90A8" },
+        { scS: "2-3", fill: "#00B457" },
+        { scS: "3-4", fill: "#B7FF01" },
+        { scS: "4-5", fill: "#F2A705" },
+        { scS: ">=5", fill: "#FF0000" },
+      ],
+      loading: false,
+      datavalue: [10, 14],
+      positions: [],
+      points: [],
+      // layers: null,
+      // shadowQuery: null,
+      marks: {
+        8: "8点",
+        12: {
+          style: {
+            color: "#1989FA",
+          },
+          label: this.$createElement("strong", "12点"),
+        },
+        20: "20点",
+      },
+      tableData: [],
+      multiViewportMode: 0,
+      radio: 0,
+      eids: [],
+      //记录进入页面时的场景参数
+      RecordInitializationScene: {},
+      nIntervId: null,
+      Intervalshijian: 10,
+      gd: 0,
+      geopolygon:null,
+      ProjectScope:{positions:[]}
+    };
+  },
+  props: {
+    info: {
+      type: Object,
+      default: () => {
+        return {};
+      },
+    },
+    layerid: {
+      type: String,
+      default: "",
+    },
+    lydata: {
+      type: Object,
+      default: () => {
+        return {};
+      },
+    },
+    lyoption: {
+      type: Object,
+      default: () => {
+        return {};
+      },
+    },
+  },
+  computed: {},
+  mounted() {
+    this.multiViewportMode = scene.multiViewportMode + 1;
+    document.oncontextmenu = function (e) {
+      e.preventDefault();
+    };
+    this.init();
+  },
+  methods: {
+    init() {
+      let scene = viewer.scene;
+      layers = scene.layers.layerQueue;
+
+      this.RecordInitializationScene.shadows = viewer.shadows;
+      this.RecordInitializationScene.layersshadowType = [];
+      for (let i = 0; i < layers.length; i++) {
+        this.RecordInitializationScene.layersshadowType.push({
+          name: layers[i].name,
+          shadowType: layers[i].shadowType,
+        });
+      }
+
+      if (viewer.shadows == false) {
+        viewer.shadows = true; //开启场景阴影
+      }
+
+      //图层模型设置阴影
+      for (let i = 0; i < layers.length; i++) {
+        // if (layers[i].shadowType !== 2) {
+        layers[i].shadowType = 2;
+        // layers[i].refresh();
+        // }
+      }
+
+      this.dqSunlight();
+    },
+
+    /**
+     * 导出范围
+     */
+    outGeometry(){
+      if(this.geopolygon){
+        this.exportRaw("绘制范围.geojson",JSON.stringify(this.geopolygon));
+      }else{
+        this.$message.warning("请先执行分析后再保存绘制的区域!!!");
+      }
+    },
+    /**
+    * 点击导入范围
+    */
+    inputGeometry() {
+      var element = document.getElementById('fileInput');
+      if (element)
+        element.click();
+    },
+    handleUpload(e) {
+      const file = e.target.files[0];
+      if (!file) {
+        return;
+      }
+      var that = this;
+      const reader = new FileReader();
+      reader.onload = function(e) {
+        var geojson =JSON.parse(e.target.result);
+        e.target.files=[];
+        document.getElementById('fileInput').value = '';
+        
+      if (!geojson || typeof geojson !== 'object' || geojson.geometry.type!="Polygon") {
+        that.$message.warning("导入的范围格式错误!!!");
+          return false;
+      }
+        that.addGeometry(geojson);
+      };
+      reader.onerror = function(error) {
+        e.target.files=[];
+        document.getElementById('fileInput').value = '';
+        console.error('Error: ', error);
+      };
+
+      reader.readAsText(file);
+    },
+
+   /**
+   * 导入范围添加图形
+   */
+    addGeometry(geojson) {
+      var that = this;
+      that.clear();
+      debugger
+      var coordinates = geojson.geometry.coordinates;
+      var positions = [];
+      that.ProjectScope.positions = [];
+      for (var i = 0; i < coordinates.length; i++) {
+        var coor = coordinates[i];
+        if (coor && coor.length > 0) {
+          for (var j = 0; j < coor.length; j++) {
+            var Cartesian3Posit=Cesium.Cartesian3.fromDegrees(
+              coor[j][0],
+              coor[j][1],
+              coor[j][2]
+          )
+            that.ProjectScope.positions.push(Cartesian3Posit)
+            positions.push(coor[j][0])
+            positions.push(coor[j][1])
+          }
+        }
+      }
+      viewer.entities.removeById('polygon');
+      var polygonEntity = new Cesium.Entity({
+        id: 'polygon',
+        polygon: {
+          hierarchy: new Cesium.PolygonHierarchy(
+            new Cesium.Cartesian3.fromDegreesArray(positions)
+          ),
+          // positions: new Cesium.Cartesian3.fromDegreesArray(positions),
+          material: Cesium.Color.WHITE.withAlpha(0.3),
+          outline: true,
+          outlineColor: Cesium.Color.RED,
+          outlineWidth: 2.0,
+        },
+      });
+
+      viewer.entities.add(polygonEntity);
+      viewer.flyTo(polygonEntity,{
+            offset: {
+              heading: Cesium.Math.toRadians(0),
+              pitch: Cesium.Math.toRadians(-90),
+              range: 220,
+            },
+          })
+    },
+
+    fakeClick(obj) {
+      var ev = document.createEvent("MouseEvents");
+      ev.initMouseEvent("click", true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
+      obj.dispatchEvent(ev);
+    },
+
+    exportRaw(name, data) {
+      var urlObject = window.URL || window.webkitURL || window;
+      var export_blob = new Blob([data]);
+      var save_link = document.createElementNS("http://www.w3.org/1999/xhtml", "a")
+      save_link.href = urlObject.createObjectURL(export_blob);
+      save_link.download = name;
+      this.fakeClick(save_link);
+    } ,
+
+    //自定义日照
+    onSubmit() {
+      this.analysis();
+    },
+    //大寒日
+    onDHSubmit() {
+      this.form.selDate = new Date(new Date().getFullYear() + "-01-20");
+      this.datavalue = [9, 15];
+      this.analysis();
+    },
+    //冬至日
+    onDZSubmit() {
+      //       冬至日期(东八区)的计算公式:(y×d+c)-l
+      //   公式解读:Y=年数后2位,D=0.2422,L=闰年数,21世纪C=21.94,20世纪=22.60。
+      //   举例说明:2088年冬至日期=[88×0.2422+21.94]-[88/4]=43-22=21,12月21日冬至。
+      //   例外:1918年和2021年的计算结果减1日。
+      let lastTwoDigitsOfYear = moment().format("YY");
+      let rns = lastTwoDigitsOfYear / 4;
+      let sjs = 21.94;
+      let dzr = Math.floor(lastTwoDigitsOfYear * 0.2422 + sjs - rns);
+      this.form.selDate = new Date(new Date().getFullYear() + "-12-" + dzr);
+
+      this.datavalue = [9, 15];
+      this.analysis();
+    },
+    //清空from
+    resetForm() {
+      this.ProjectScope.positions=[];
+      this.clear();
+      // this.clearmarkedPoints();
+    },
+    /**
+     * 开始分析
+     */
+    analysis1() {
+      let that = this;
+      that.tableData = [];
+      if (!handlerPolygon) {
+        handlerPolygon = new Cesium.DrawHandler(
+          viewer,
+          Cesium.DrawMode.Point,
+          Cesium.ClampMode.Space
+        );
+      }
+
+      handlerPolygon.activate();
+      handlerPolygon.activeEvt.addEventListener(function (isActive) {
+        // if (isActive == true) {
+        //   viewer.enableCursorStyle = false;
+        //   viewer._element.style.cursor = "";
+        //   document.body.classList.add("drawCur");
+        // } else {
+        //   viewer.enableCursorStyle = true;
+        //   document.body.classList.remove("drawCur");
+        // }
+        that.tooltip.setVisible(false);
+      });
+      handlerPolygon.movingEvt.addEventListener((windowPosition) => {
+        that.tooltip.showAt(
+          windowPosition,
+          "<p>点击鼠标左键开始选择分析区域</p>"
+        );
+      });
+      handlerPolygon.drawEvt.addEventListener((result) => {
+        that.resetForm();
+        // that.clickSunDate();
+        that.loading = true;
+        let scene = viewer.scene;
+
+        //创建阴影查询对象
+        if (!shadowQuery) {
+          shadowQuery = new Cesium.ShadowQueryPoints(scene);
+          shadowQuery.setVisibleInViewport(that.radio);
+          shadowQuery.queryPointsEvent.addEventListener(function (e) {
+            that.tableData = [];
+            that.loading = false;
+            e.forEach(function (a) {
+              var e_cartographic = Cesium.Cartographic.fromCartesian(
+                a.position
+              );
+              var e_shadowRadio = shadowQuery.getShadowRadio(e_cartographic);
+              var e_longitude = Cesium.Math.toDegrees(e_cartographic.longitude);
+              var e_latitude = Cesium.Math.toDegrees(e_cartographic.latitude);
+              var e_height = e_cartographic.height;
+              let sunForm = {};
+              sunForm.shadowRadioText =
+                (Number(e_shadowRadio.toFixed(2)) * 100).toFixed(2) + "%";
+              sunForm.longitudeText = Number(e_longitude.toFixed(6));
+              sunForm.latitudeText = Number(e_latitude.toFixed(6));
+              sunForm.heightText = Number(e_height.toFixed(2));
+              sunForm.dateScope =
+                that.datavalue[0] + "时--" + that.datavalue[1] + "时";
+              if (that.datavalue[0] != that.datavalue[1]) {
+                sunForm.sunDate =
+                  (
+                    (that.datavalue[1] + 1 - that.datavalue[0]) *
+                    e_shadowRadio
+                  ).toFixed(2) + "小时";
+              } else {
+                sunForm.sunDate = "";
+              }
+              that.tableData.push(sunForm);
+            });
+          });
+        }
+        that.tooltip.setVisible(false);
+        var position = result.object.position;
+        var cartographic = Cesium.Cartographic.fromCartesian(position);
+        var longitude = Cesium.Math.toDegrees(cartographic.longitude);
+        var latitude = Cesium.Math.toDegrees(cartographic.latitude);
+        var clickPoint = point([longitude, latitude]); //
+        var buffered = buffer(clickPoint, (that.form.spacing / 2 + 1) / 1000, {
+          units: "kilometers",
+        });
+
+        that.form.x = longitude;
+        that.form.y = latitude;
+        that.points = buffered.geometry.coordinates[0].flat();
+        //设置分析对象的开始结束时间
+        var dateValue = that.form.selDate;
+        var st = new Date(dateValue);
+        st.setHours(Number(that.form.startTime));
+        shadowQuery.startTime = Cesium.JulianDate.fromDate(st);
+
+        var et = new Date(dateValue);
+        et.setHours(Number(that.form.endTime));
+        shadowQuery.endTime = Cesium.JulianDate.fromDate(et);
+
+        //设置当前时间
+        that.setCurrentTime();
+
+        shadowQuery.spacing = that.form.spacing;
+        shadowQuery.timeInterval = that.form.timeInterval;
+
+        //设置分析区域、底部高程和拉伸高度
+        var bh = Number(that.form.bottomHeight);
+        var eh = Number(that.form.extrudeHeight);
+        shadowQuery.qureyRegion({
+          position: that.points,
+          bottom: bh,
+          extend: eh,
+        });
+        shadowQuery.build();
+      });
+    },
+    analysis() {
+      let that = this;
+      that.clear();
+      that.tableData = [];
+
+      if (that.form.startTime == that.form.endTime) {
+        this.$message.warning("请选择一个日照时间范围区间!!!");
+        return;
+      }
+      if (!handlerPolygon) {
+        handlerPolygon = new Cesium.DrawHandler(
+          viewer,
+          Cesium.DrawMode.Polygon,
+          0
+        );
+      }
+      if(that.ProjectScope.positions.length>0){
+        that.imptAnalysis(that.ProjectScope);
+      }else{
+        handlerPolygon.activate();
+        handlerPolygon.activeEvt.addEventListener(function (isActive) {
+          // if (isActive == true) {
+          //   // viewer.enableCursorStyle = false;
+          //   // viewer._element.style.cursor = "";
+          //   document.body.classList.add("drawCur");
+          // } else {
+          //   // viewer.enableCursorStyle = true;
+          //   document.body.classList.remove("drawCur");
+          // }
+          that.tooltip.setVisible(false);
+        });
+        handlerPolygon.movingEvt.addEventListener((windowPosition) => {
+          that.tooltip.showAt(
+            windowPosition,
+            "<p>点击鼠标左键开始绘制分析区域</p>"
+          );
+        });
+        handlerPolygon.drawEvt.addEventListener((result) => {
+
+          // if (sdfff == null) {
+          //   sdfff = result;
+          // } else {
+          //   result = sdfff;
+          // }
+          debugger;
+          that.tooltip.setVisible(false);
+          that.resetForm();
+          result.object.show = false;
+          that.imptAnalysis(result.object);
+        });
+      }
+
+    },
+
+    imptAnalysis(polygons){
+      var that=this;
+      var polygonsCopy=polygons;
+      that.loading = true;
+        let scene = viewer.scene;
+        // that.gd = 0;
+        //创建阴影查询对象
+        if (!shadowQuery) {
+          shadowQuery = new Cesium.ShadowQueryPoints(scene);
+          shadowQuery.setVisibleInViewport(that.radio);
+          shadowQuery.queryPointsEvent.addEventListener(function (e) {
+            console.log(new Date().getSeconds());
+            that.tableData = [];
+            that.loading = false;
+            let sdsd = [];
+
+            for (var index = 0; index < e.length; index++) {
+              const a = e[index];
+              var e_cartographic = Cesium.Cartographic.fromCartesian(
+                a.position
+              );
+              var e_shadowRadio = shadowQuery.getShadowRadio(e_cartographic);
+              var e_longitude = Cesium.Math.toDegrees(e_cartographic.longitude);
+              var e_latitude = Cesium.Math.toDegrees(e_cartographic.latitude);
+              var e_height = e_cartographic.height;
+
+              let sd = point([e_longitude, e_latitude]);
+              sd.properties.value = e_shadowRadio;
+              sdsd.push(sd);
+            }
+            console.log(new Date().getSeconds());
+
+            let gsd = that.setIsoline(sdsd, polygonsCopy);
+            var sssssd = [];
+            // that.sdh = [];
+            console.log(new Date().getSeconds());
+            for (
+              let featuresindex = 0;
+              featuresindex < gsd.features.length;
+              featuresindex++
+            ) {
+              var element = gsd.features[featuresindex];
+              if (element.geometry.type == "MultiPolygon") {
+                // continue;
+                var polygons =
+                  that.geoJSONMultiPolygonToCesiumPolygons(element);
+                sssssd.push(polygons);
+                polygons.forEach((polygonItem) => {
+                  let id = uuidv4();
+                  that.eids.push(id);
+                  viewer.entities.add({
+                    id: id,
+                    polygon: {
+                      hierarchy: polygonItem,
+                      material: new Cesium.Color.fromCssColorString(
+                        element.properties.fill
+                      ).withAlpha(1),
+                      height: that.gd + 3 + featuresindex * 0.1,
+                      outline: false,
+                      // outlineColor: Cesium.Color.BLACK,
+                      // outlineWidth: 2.0,
+                      // classificationType: Cesium.ClassificationType.TERRAIN,
+                    },
+                  });
+                });
+              } else {
+                // continue;
+                for (
+                  var index = 0;
+                  index < element.geometry.coordinates.length;
+                  index++
+                ) {
+                  var polygon = element.geometry.coordinates[index];
+                  let ps = polygon.flat();
+                  sssssd.push(ps);
+                  let id = uuidv4();
+                  that.eids.push(id);
+                  viewer.entities.add({
+                    id: id,
+                    polygon: {
+                      hierarchy: Cesium.Cartesian3.fromDegreesArray(ps),
+                      material: new Cesium.Color.fromCssColorString(
+                        element.properties.fill
+                      ).withAlpha(1),
+                      height: that.gd + 3 + featuresindex * 0.1,
+                      outline: false,
+                      // outlineColor: Cesium.Color.BLACK,
+                      // outlineWidth: 2.0,
+                      // classificationType: Cesium.ClassificationType.TERRAIN,
+                    },
+                  });
+                }
+              }
+            }
+            // var sdfsdfasf = sssssd;
+            debugger;
+            console.log(new Date().getSeconds());
+            setTimeout(function () {
+              if (shadowQuery) {
+                shadowQuery.clear();
+                shadowQuery.destroy();
+                shadowQuery = null;
+
+                // shadowQuery.qureyRegion({
+                //   position: [0, 0],
+                //   bottom: 0,
+                //   extend: 0,
+                // });
+              }
+            }, 1000);
+          });
+        }
+        let positions = that.positions;
+        let points = that.points;
+        // var polygons = result.object;
+        if (!polygons) {
+          return;
+        }
+
+        //保存当前范围,为导出准备
+        var geoposts=[];
+        polygons.positions.forEach((position) => {
+          let xy = cartesian3ToWGS84(position);
+          geoposts.push([xy.lng, xy.lat,xy.alt]);
+        });
+        geoposts.push(geoposts[0]);
+        that.geopolygon=polygon([geoposts]);
+
+        
+        // handlerPolygon.polyline.show = false;
+        positions = [].concat(polygons.positions);
+        positions = Cesium.arrayRemoveDuplicates(
+          positions,
+          Cesium.Cartesian3.equalsEpsilon
+        );
+        //遍历多边形,取出所有点
+        for (var i = 0, len = positions.length; i < len; i++) {
+          //转化为经纬度,并加入至临时数组
+          var cartographic = Cesium.Cartographic.fromCartesian(
+            polygons.positions[i]
+          );
+          var longitude = Cesium.Math.toDegrees(cartographic.longitude);
+          var latitude = Cesium.Math.toDegrees(cartographic.latitude);
+          if (i == 0) {
+            if (that.gd == 0) {
+              that.gd = Math.ceil(cartographic.height);
+            }
+          }
+          points.push(longitude);
+          points.push(latitude);
+        }
+        //设置分析对象的开始结束时间
+        var dateValue = that.form.selDate;
+        var st = new Date(dateValue);
+        st.setHours(Number(that.form.startTime));
+        shadowQuery.startTime = Cesium.JulianDate.fromDate(st);
+
+        var et = new Date(dateValue);
+        let endTime = 0;
+        if (that.form.startTime != that.form.endTime) {
+          endTime = that.form.endTime;
+        } else {
+          endTime = that.form.endTime;
+        }
+        et.setHours(Number(endTime));
+        shadowQuery.endTime = Cesium.JulianDate.fromDate(et);
+
+        //设置当前时间
+        that.setCurrentTime();
+
+        //设置根据面积计算间隔
+        var trufpolygons = [];
+        for (let pindex = 0; pindex < polygons.positions.length; pindex++) {
+          var pposition = polygons.positions[pindex];
+          var e_cartographic = Cesium.Cartographic.fromCartesian(pposition);
+          var e_longitude = Cesium.Math.toDegrees(e_cartographic.longitude);
+          var e_latitude = Cesium.Math.toDegrees(e_cartographic.latitude);
+          trufpolygons.push([e_longitude, e_latitude]);
+        }
+
+        if (trufpolygons[0] != trufpolygons[trufpolygons.length - 1]) {
+          trufpolygons.push(trufpolygons[0]);
+        }
+        var polygonPs = polygon([trufpolygons]);
+        let areaPs = area(polygonPs);
+        if (areaPs <= 20000) {
+          that.form.spacing = 10;
+        } else if (areaPs <= 60000) {
+          that.form.spacing = 10;
+        } else if (areaPs <= 100000) {
+          that.form.spacing = 10;
+        } else {
+          that.form.spacing = 10;
+        }
+
+        shadowQuery.spacing = that.form.spacing;
+        shadowQuery.timeInterval = that.form.timeInterval;
+
+        //设置分析区域、底部高程和拉伸高度
+        var bh = Number(that.gd + 1);
+        var eh = Number(2);
+        if (areaPs < 250000) {
+          shadowQuery.qureyRegion({
+            position: that.points,
+            bottom: bh,
+            extend: eh,
+          });
+          shadowQuery.build();
+          // that.resetForm();
+        } else {
+          that.loading = false;
+          this.$message({
+            dangerouslyUseHTMLString: true,
+            message:
+              "框选范围过大,为确保分析精度,建议以小区为单位<br />请选取小于250000平方米的区域!!!",
+            type: "warning",
+          });
+          if (shadowQuery) {
+            shadowQuery.clear();
+            shadowQuery.destroy();
+            shadowQuery = null;
+            // shadowQuery.qureyRegion({
+            //   position: [0, 0],
+            //   bottom: 0,
+            //   extend: 0,
+            // });
+          }
+        }
+    },
+    ExportResult() {
+      let that = this;
+      let entitys = [];
+      that.eids.forEach((id) => {
+        let entity = viewer.entities.getById(id);
+        if (entity) {
+          entitys.push(entity);
+        }
+      });
+
+      let box = that.squarePolygon(entitys);
+      viewer.camera.flyTo({
+        destination: Cesium.Rectangle.fromDegrees(
+          box[0][0] + 0.0002,
+          box[0][1] - 0.0002,
+          box[2][0] - 0.0002,
+          box[2][1] + 0.0002
+        ),
+      });
+
+      setTimeout(function () {
+        var promise = scene.outputSceneToFile();
+        Cesium.when(promise, function (base64data) {
+          that.download(base64data);
+        });
+      }, 4000);
+    },
+    /**
+     * 根据图片生成画布
+     */
+    convertImageToCanvas(image) {
+      var canvas = document.createElement("canvas");
+      canvas.width = image.width;
+      canvas.height = image.height;
+      var ctx = canvas.getContext("2d");
+      ctx.drawImage(image, 0, 0);
+      this.drawLegends(canvas, ctx);
+      return canvas;
+    },
+    // 绘制图例
+    drawLegends(canvas, ctx) {
+      var legends = this.sdh;
+      var padding = 10; // 图例与边缘的间距
+      var lineHeight = 30; // 每行图例的高度
+      var labW = 120;
+      var x = canvas.width - padding - labW; // 图例的起始X坐标
+      var y = canvas.height - legends.length * lineHeight - padding; // 图例的起始Y坐标
+      // 绘制颜色块
+      ctx.fillStyle = "#ffffff";
+      ctx.fillRect(
+        x - padding,
+        y - padding,
+        canvas.width - x + padding,
+        canvas.height - y + padding
+      );
+      legends.forEach(function (legend, index) {
+        // 绘制文本
+        ctx.fillStyle = "black";
+        ctx.fillText(
+          legend.scS + "小时",
+          x,
+          y + index * lineHeight + lineHeight / 2
+        );
+        // 绘制颜色块
+        ctx.fillStyle = legend.fill;
+        ctx.fillRect(
+          x + (labW / 3) * 2,
+          y + index * lineHeight,
+          30,
+          lineHeight
+        );
+      });
+    },
+    /**
+     * 下载图片
+     */
+    download(base64data) {
+      let that = this;
+      var image = new Image();
+      image.src = base64data;
+      image.onload = function () {
+        var canvas = that.convertImageToCanvas(image);
+        var url = canvas.toDataURL("image/jpeg");
+        var a = document.createElement("a");
+        var event = new MouseEvent("click");
+        a.download = new Date().getTime() + ".jpg"; // 指定下载图片的名称
+        a.href = url;
+        a.dispatchEvent(event); // 触发超链接的点击事件
+      };
+    },
+    clear() {
+      viewer.entities.removeById('polygon');
+      this.geopolygon=null;
+      // viewer.entities.removeAll();
+      // this.form.x = 0;
+      // this.form.y = 0;
+      this.tableData = [];
+      if (handlerPolygon) {
+        handlerPolygon.clear();
+        handlerPolygon.deactivate();
+        handlerPolygon = null;
+      }
+      this.tooltip.setVisible(false);
+      if (shadowQuery) {
+        shadowQuery.clear();
+        shadowQuery.destroy();
+        shadowQuery = null;
+        // shadowQuery.qureyRegion({
+        //   position: [0, 0],
+        //   bottom: 0,
+        //   extend: 0,
+        // });
+      }
+
+      this.positions = [];
+      this.points = [];
+      for (let i = 0; i < this.eids.length; i++) {
+        viewer.entities.removeById(this.eids[i]);
+      }
+      // this.sdh = [];
+      this.eids = [];
+    },
+    //结束时日照阴影
+    setCurrentTime() {
+      var et = this.form.selDate;
+      et.setHours(Number(this.form.endTime));
+      viewer.clock.currentTime = Cesium.JulianDate.fromDate(et);
+      viewer.clock.multiplier = 1;
+      viewer.clock.shouldAnimate = false;
+    },
+    /**
+     * 执行日照动画
+     */
+    statrSunlight() {
+      var dateVal = this.form.selDate;
+      var startTime = new Date(dateVal);
+      var shour = Number(this.form.startTime);
+      var ehour = Number(this.form.endTime);
+
+      if (shour > ehour) {
+        return;
+      }
+
+      var nTimer = 0.0;
+      if (this.nIntervId) {
+        clearInterval(this.nIntervId);
+      }
+      debugger;
+      this.nIntervId = setInterval(function () {
+        if (shour < ehour) {
+          startTime.setHours(shour);
+          startTime.setMinutes(nTimer);
+          viewer.clock.currentTime = Cesium.JulianDate.fromDate(startTime);
+          nTimer += 10.0;
+          if (nTimer > 60.0) {
+            shour += 1.0;
+            nTimer = 0.0;
+          }
+        } else {
+          clearInterval(this.nIntervId);
+        }
+      }, this.Intervalshijian * 10);
+    },
+    //当前日照效果
+    dqSunlight() {
+      viewer.clock.currentTime = Cesium.JulianDate.fromDate(new Date());
+      viewer.clock.multiplier = 1;
+      viewer.clock.shouldAnimate = true;
+    },
+    //日照列表行被点击
+    rowClick(row, column, event) {
+      this.clearmarkedPoints();
+      var markedPoint = viewer.entities.add(
+        new Cesium.Entity({
+          point: new Cesium.PointGraphics({
+            color: new Cesium.Color(1, 1, 0, 0.5),
+            pixelSize: 15,
+          }),
+          position: Cesium.Cartesian3.fromDegrees(
+            row.longitudeText,
+            row.latitudeText,
+            row.heightText
+          ),
+        })
+      );
+      markedPoints.push(markedPoint);
+    },
+    //清除点击的黄色圆圈
+    clearmarkedPoints() {
+      for (let i = 0; i < markedPoints.length; i++) {
+        viewer.entities.remove(markedPoints[i]);
+      }
+      markedPoints = [];
+    },
+    // x或y变化触发
+    XYChange() {
+      if (!shadowQuery) {
+        return;
+      }
+      this.loading = true;
+      let that = this;
+
+      var clickPoint = point([that.form.x, that.form.y]); //
+      var buffered = buffer(clickPoint, (that.form.spacing / 2 + 1) / 1000, {
+        units: "kilometers",
+      });
+      that.points = buffered.geometry.coordinates[0].flat();
+
+      //设置分析区域、底部高程和拉伸高度
+      var bh = Number(that.form.bottomHeight);
+      var eh = Number(that.form.extrudeHeight);
+      shadowQuery.qureyRegion({
+        position: that.points,
+        bottom: bh,
+        extend: eh,
+      });
+      shadowQuery.build();
+    },
+
+    // 时间范围变化触发
+    datavalueChange(val) {
+      if (val[0] == val[1]) {
+        this.form.timeInterval = 1;
+      } else {
+        this.form.timeInterval = 60;
+      }
+      this.form.startTime = val[0];
+      this.form.endTime = val[1];
+    },
+
+    setIsoline(turfPoints, polygons) {
+      //转换面
+      var trufpolygons = [];
+      for (var pindex = 0; pindex < polygons.positions.length; pindex++) {
+        var pposition = polygons.positions[pindex];
+        var e_cartographic = Cesium.Cartographic.fromCartesian(pposition);
+        var e_longitude = Cesium.Math.toDegrees(e_cartographic.longitude);
+        var e_latitude = Cesium.Math.toDegrees(e_cartographic.latitude);
+        trufpolygons.push([e_longitude, e_latitude]);
+      }
+
+      if (trufpolygons[0] != trufpolygons[trufpolygons.length - 1]) {
+        trufpolygons.push(trufpolygons[0]);
+      }
+      var polygonPs = polygon([trufpolygons]);
+
+      var sunriseDate = SunriseSunsetJS.getSunrise(
+        18.31723463241332,
+        109.5112252162011,
+        this.form.selDate
+      );
+      var sunsetdate = SunriseSunsetJS.getSunset(
+        18.31723463241332,
+        109.5112252162011,
+        this.form.selDate
+      );
+      //参与计算的日出日落时间
+      var jssunriseHours = 0;
+      var jssunsetHours = 0;
+      //日出时间
+      var sunriseHours = sunriseDate.getHours() + sunriseDate.getMinutes() / 60;
+      //日落时间
+      var sunsetHours = sunsetdate.getHours() + sunsetdate.getMinutes() / 60;
+
+      if (this.datavalue[0] > sunriseHours) jssunriseHours = this.datavalue[0];
+      else jssunriseHours = sunriseHours;
+
+      if (this.datavalue[1] > sunsetHours) jssunsetHours = sunsetHours;
+      else jssunsetHours = this.datavalue[1];
+
+      //赋值+计算小时数
+      for (var index = 0; index < turfPoints.length; index++) {
+        var element = turfPoints[index];
+        console.log(
+          jssunsetHours -
+            jssunriseHours +
+            "*" +
+            element.properties.value +
+            "==" +
+            (jssunsetHours - jssunriseHours) * element.properties.value
+        );
+
+        var time = (jssunsetHours - jssunriseHours) * element.properties.value;
+        // if (time > 5) {
+        //   element["value"] = 5;
+        //   element.properties.value = 5;
+        // } else {
+        element["value"] = time;
+        element.properties.value = time;
+        // }
+      }
+
+      // 使用turf.envelope计算包含所有点的最小矩形多边形
+      var envelopeP = envelope(featureCollection(turfPoints));
+      // var minX,max
+      // turfPoints.forEach()
+
+      // 从envelope多边形中提取bbox坐标
+      let dd1 = envelopeP.bbox;
+      // let dd1 = [107, 36, 180, 38];
+      // let dd1 = bbox(sdsd);
+      let points1 = {
+        type: "FeatureCollection",
+        features: turfPoints,
+      };
+
+      let levelv = [0, 1, 2, 3, 4, 5];
+      let colors = [
+        { fill: "#313695" },
+        { fill: "#1E90A8" },
+        { fill: "#00B457" },
+        { fill: "#B7FF01" },
+        { fill: "#F2A705" },
+        { fill: "#FF0000" },
+        { fill: "#FF0000" },
+      ];
+      // if (czsj.points1 == null) {
+      //   czsj.points1 = points1;
+      //   czsj.dd1 = dd1;
+      // } else {
+      //   points1 = czsj.points1;
+      //   dd1 = czsj.dd1;
+      // }
+
+      let kriging_contours = getVectorContour(
+        points1,
+        "value",
+        { model: "spherical", sigma2: 0, alpha: 50 },
+        levelv,
+        dd1
+      );
+
+      function hotcolor(d) {
+        let index = levelv.findIndex((item) => item >= d);
+        if (index > -1 && index < 6) {
+          return colors[index].fill;
+        } else {
+          return colors[colors.length - 1].fill;
+        }
+      }
+      function sortArea(a, b) {
+        return area(b) - area(a);
+      }
+      //按照面积对图层进行排序,规避turf的一个bug
+      kriging_contours.features.sort(sortArea);
+      //后面使用要求输入的参数为Feature<Polygon>,而turf.isobands的是 MultiPolygon,需
+      var boundaries = flatten(envelopeP); //行政边界
+
+      kriging_contours = flatten(kriging_contours); //等值面边界
+      //console.log('kriging_contours:'+JSON.stringify(kriging_contours));
+      //根据行政边界裁剪图形,
+      //现在放大一些区域边界还是没有充满  后面可以封装成一个插件,在源码里面进行canvas  clip 剪辑只显示的geojson区域,其余的栅格部分不显示
+      let features = []; //裁剪后的结果集
+      // kriging_contours.features.forEach(function (feature1) {
+      //   boundaries.features.forEach(function (feature2) {
+      //     let intersection = null;
+      //     try {
+      //       intersection = intersect(feature1, feature2);
+      //     } catch (e) {
+      //       try {
+      //         //色斑图绘制之后,可能会生成一些非法 Polygon
+      //         //解决的方法通常就是做一次 turf.buffer() 操作,这样可以把一些小的碎片 Polygon 清理掉。
+      //         feature1 = buffer(feature1, 0);
+      //         intersection = intersect(feature1, feature2);
+      //       } catch (e) {
+      //         intersection = feature1; //实在裁剪不了就不裁剪了,根据业务需求自行决定
+      //       }
+      //     }
+      //     if (intersection != null) {
+      //       intersection.properties = feature1.properties;
+      //       // intersection.properties.fill = hotcolor(feature1.properties.value);
+      //       intersection.id = (Math.random() * 100000).toFixed(0);
+      //       features.push(intersection);
+      //     }
+      //   });
+      // });
+      var polygonPs = polygon([trufpolygons]);
+      kriging_contours.features.forEach(function (feature1) {
+        // polygonPs.features.forEach(function (feature2) {
+        let inFeature = null;
+        try {
+          inFeature = intersect(feature1, polygonPs);
+        } catch (e) {
+          try {
+            //色斑图绘制之后,可能会生成一些非法 Polygon
+            //解决的方法通常就是做一次 turf.buffer() 操作,这样可以把一些小的碎片 Polygon 清理掉。
+            feature1 = buffer(feature1, 0);
+            inFeature = intersect(feature1, polygonPs);
+          } catch (e) {
+            inFeature = feature1; //实在裁剪不了就不裁剪了,根据业务需求自行决定
+          }
+        }
+        if (inFeature != null) {
+          inFeature.properties = feature1.properties;
+          // intersection.properties.fill = hotcolor(feature1.properties.value);
+          inFeature.id = (Math.random() * 100000).toFixed(0);
+          features.push(inFeature);
+        }
+        // });
+      });
+
+      let intersection = featureCollection(features);
+      intersection.features.forEach((element) => {
+        element.properties.fill = hotcolor(element.properties.contour_value);
+      });
+      // function zdx(a, b) {
+      //   return a.properties.contour_value - b.properties.contour_value;
+      // }
+      // intersection.features.sort(zdx);
+
+      // let features = []; //裁剪后的结果集
+
+      // intersection.features = features;
+      return intersection;
+    },
+
+    /**
+     * @property {Array} features  关键点集合
+     */
+    setIsoline1111(features) {
+      // 准备工作,创建 options
+      // const breaks = [0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1];
+      const breaks = [0];
+      for (
+        var index = 1;
+        index < this.datavalue[1] - this.datavalue[0] + 1;
+        index++
+      ) {
+        breaks.push(index * (1 / (this.datavalue[1] - this.datavalue[0])));
+      }
+      // breaks.push(2);
+      let breaksProperties = [];
+      for (var index = 0; index < breaks.length; index++) {
+        // let time1 = Math.ceil(
+        //   (this.datavalue[1] - this.datavalue[0]) * breaks[index]
+        // );
+
+        let time1 = (this.datavalue[1] - this.datavalue[0]) * breaks[index];
+        switch (time1) {
+          case 0:
+            breaksProperties.push(this.sdh[0]);
+            break;
+          case 1:
+            breaksProperties.push(this.sdh[1]);
+            break;
+          case 2:
+            breaksProperties.push(this.sdh[2]);
+            break;
+          case 3:
+            breaksProperties.push(this.sdh[3]);
+            break;
+          case 4:
+            breaksProperties.push(this.sdh[4]);
+            break;
+          default:
+            breaksProperties.push(this.sdh[5]);
+            break;
+        }
+      }
+
+      const interpolateOptions = {
+        gridType: "points",
+        property: "value",
+        units: "degrees",
+        weight: 50,
+      };
+      const isobandsOptions = {
+        zProperty: "value",
+        // commonProperties: {
+        //   "fill-opacity": 0.5,
+        // },
+        breaksProperties: breaksProperties,
+      };
+      // 准备工作结束
+
+      // 将散点合并成要素集
+      const points = featureCollection(features);
+      // 使用反向距离加权(IDW)方法进行运算
+      const grid = interpolate(
+        points,
+        this.form.spacing * 0.00001,
+        interpolateOptions
+      );
+      // 根据参与分级的属性和分级的数组计算出等值面
+      const isobandsData = isobands(grid, breaks, isobandsOptions);
+      const intersection = featureCollection(isobandsData.features);
+
+      return intersection;
+    },
+    /**
+     * 计算边界
+     */
+    squarePolygon(entitys) {
+      const polygons = [
+        /* ... 多边形数组 ... */
+      ];
+      entitys.forEach((entity) => {
+        let positions = entity.polygon.hierarchy.getValue().positions;
+        let posts = [];
+        positions.forEach((position) => {
+          let xy = cartesian3ToWGS84(position);
+          posts.push([xy.lng, xy.lat]);
+        });
+        let thispolygon = polygon([posts]);
+        polygons.push(thispolygon);
+      });
+
+      // 初始化边界框变量
+      let minX = Infinity,
+        minY = Infinity,
+        maxX = -Infinity,
+        maxY = -Infinity;
+
+      // 遍历每个多边形,计算其边界框,并更新最小/最大坐标
+      polygons.forEach((polygon) => {
+        const thisbbox = bbox(polygon);
+        minX = Math.min(minX, thisbbox[0]);
+        minY = Math.min(minY, thisbbox[1]);
+        maxX = Math.max(maxX, thisbbox[2]);
+        maxY = Math.max(maxY, thisbbox[3]);
+      });
+
+      // 计算正方形的边长
+      const sideLength = Math.max(maxX - minX, maxY - minY);
+
+      // 创建正方形的四个角点
+      const squareCoords = [
+        [minX, minY],
+        [minX + sideLength, minY],
+        [minX + sideLength, minY + sideLength],
+        [minX, minY + sideLength],
+        [minX, minY], // 闭合多边形
+      ];
+
+      // // 使用Turf.js创建正方形多边形
+      // const squarePolygon = polygon([squareCoords]);
+      return squareCoords;
+    },
+    geoJSONMultiPolygonToCesiumPolygons11(multiPolygon) {
+      let polygonsHierarchy = [];
+
+      multiPolygon.geometry.coordinates.forEach((polygon) => {
+        let rings = [];
+
+        polygon.forEach((ring) => {
+          let cartesianPoints = ring.map((coordinates) => {
+            return Cesium.Cartesian3.fromDegrees(
+              coordinates[0],
+              coordinates[1]
+            );
+          });
+
+          rings.push(cartesianPoints);
+        });
+
+        polygonsHierarchy.push(rings);
+      });
+
+      return polygonsHierarchy;
+    },
+    geoJSONMultiPolygonToCesiumPolygons(multiPolygon) {
+      // 假设multiPolygon是一个有效的多边形数组
+      let polygonsHierarchy = [];
+      // {
+      //             // Cesium.PolygonHierarchy
+      //             positions: point3ds[0],
+      //             holes: holes, // Cesium.PolygonHierarchy 数组
+      //           }
+      multiPolygon.geometry.coordinates.forEach((polygon) => {
+        var polygons = { positions: [] };
+        if (polygon.length > 1) {
+          polygons.holes = [];
+        }
+        polygon.forEach((element, i) => {
+          if (i == 0) {
+            polygons.positions = Cesium.Cartesian3.fromDegreesArray(
+              element.flat()
+            );
+          } else {
+            polygons.holes.push({
+              positions: Cesium.Cartesian3.fromDegreesArray(element.flat()),
+            });
+          }
+        });
+
+        // 创建PolygonHierarchy结构
+        polygonsHierarchy.push(polygons);
+      });
+
+      return polygonsHierarchy;
+    },
+  },
+  watch: {
+    "form.selDate": function (newValue) {
+      if (!shadowQuery) {
+        return;
+      }
+      this.loading = true;
+      let st = new Date(newValue);
+      st.setHours(this.form.startTime);
+      let et = new Date(newValue);
+      et.setHours(this.form.endTime);
+      shadowQuery.startTime = Cesium.JulianDate.fromDate(st);
+      shadowQuery.endTime = Cesium.JulianDate.fromDate(et);
+    },
+    "form.startTime": function (newValue) {
+      if (!shadowQuery) {
+        return;
+      }
+      this.loading = true;
+      let thisdate = new Date(this.form.selDate);
+      var st = thisdate;
+      st.setHours(Number(newValue));
+      shadowQuery.startTime = Cesium.JulianDate.fromDate(st);
+    },
+    "form.endTime": function (newValue) {
+      if (!shadowQuery) {
+        return;
+      }
+      this.loading = true;
+      let thisdate = new Date(this.form.selDate);
+      var et = thisdate;
+      et.setHours(Number(newValue));
+      shadowQuery.endTime = Cesium.JulianDate.fromDate(et);
+    },
+    "form.timeInterval": function (newValue) {
+      if (!shadowQuery) {
+        return;
+      }
+      this.loading = true;
+      shadowQuery.timeInterval = Number(newValue);
+
+      shadowQuery.build();
+    },
+    "form.spacing": function (newValue) {
+      if (!shadowQuery) {
+        return;
+      }
+      this.loading = true;
+      shadowQuery.spacing = Number(newValue);
+
+      shadowQuery.build();
+    },
+    "form.bottomHeight": function (newValue) {
+      if (!shadowQuery) {
+        return;
+      }
+      this.loading = true;
+      var bh = Number(newValue);
+      var eh = Number(this.form.extrudeHeight);
+      shadowQuery.qureyRegion({
+        position: this.points,
+        bottom: bh,
+        extend: eh,
+      });
+      shadowQuery.build();
+    },
+    "form.extrudeHeight": function (newValue) {
+      if (!shadowQuery) {
+        return;
+      }
+      this.loading = true;
+      var bh = Number(this.form.bottomHeight);
+      var eh = Number(newValue);
+      shadowQuery.qureyRegion({
+        position: this.points,
+        bottom: bh,
+        extend: eh,
+      });
+      shadowQuery.build();
+    },
+  },
+  beforeDestroy() {
+    document.oncontextmenu = null;
+    this.clear();
+    this.clearmarkedPoints();
+    if (shadowQuery) {
+      shadowQuery.clear();
+      shadowQuery.destroy();
+      shadowQuery = null;
+    }
+    if (handlerPolygon) {
+      handlerPolygon.deactivate();
+    }
+    handlerPolygon = undefined;
+    this.dqSunlight();
+
+    let scene = viewer.scene;
+    layers = scene.layers.layerQueue;
+    viewer.shadows = this.RecordInitializationScene.shadows;
+    //图层模型还原阴影
+    for (let i = 0; i < layers.length; i++) {
+      var shadowType = this.RecordInitializationScene.layersshadowType.find(
+        (c) => c.name == layers[i].name
+      );
+      if (shadowType) {
+        if (layers[i].shadowType != shadowType.shadowType) {
+          layers[i].shadowType = shadowType.shadowType;
+          layers[i].refresh();
+        }
+      }
+    }
+  },
+};
+</script>
+<style lang="scss">
+@import "@/../../zt.scss";
+</style>
+<style lang="scss" scoped>
+.el-card {
+  border: 0px solid #02a7f0;
+}
+.el-form-item {
+  margin-bottom: 0;
+}
+.slider_padding {
+  padding: 0rem 0.5rem;
+}
+</style>

+ 1401 - 0
src/views/ConstructionApplication3D/SunlightAnalysis/SunlightAnalysisSX.vue

@@ -0,0 +1,1401 @@
+<template>
+  <div
+    class="ZTGlobal"
+    style="width: 100%; padding: 1rem 1.1rem 0rem; color: white"
+    v-loading.fullscreen.lock="loading"
+    element-loading-text="正在分析中...."
+    element-loading-spinner="el-icon-loading"
+    element-loading-background="rgba(0, 0, 0, 0.8)"
+  >
+    <el-row :gutter="10">
+      <el-col :span="24">
+        <div class="titleHeader">
+          <h3>参数设置</h3>
+        </div>
+      </el-col>
+    </el-row>
+    <el-row :gutter="10">
+      <el-col :span="24">
+        <el-row :gutter="10" style="display: flex; align-items: center">
+          <el-col :span="24">
+            日 期:
+            <el-date-picker
+              size="mini"
+              v-model="form.selDate"
+              type="date"
+              placeholder="选择日期"
+            >
+            </el-date-picker>
+          </el-col>
+        </el-row>
+        <el-row :gutter="10" style="display: flex; align-items: center">
+          <el-col :span="6"> 日照时间范围: </el-col>
+          <el-col :span="18">
+            <el-slider
+              size="mini"
+              v-model="datavalue"
+              range
+              :marks="marks"
+              :max="24"
+              @change="datavalueChange"
+            >
+            </el-slider>
+          </el-col>
+        </el-row>
+        <el-row :gutter="10" style="display: flex; align-items: center">
+          <el-col :span="6"> 日照播放速度: </el-col>
+          <el-col :span="18">
+            <el-input-number
+              size="mini"
+              v-model="Intervalshijian"
+              :min="1"
+              :max="100"
+            ></el-input-number>
+          </el-col>
+        </el-row>
+        <el-row :gutter="10">
+          <el-col :span="24">
+            <div class="SaveCenter" style="padding: 0">
+              <el-button size="mini" type="primary" @click="statrSunlight"
+                >执行日照效果</el-button
+              >
+              <el-button size="mini" type="primary" @click="dqSunlight"
+                >当前日照</el-button
+              >
+            </div>
+          </el-col>
+        </el-row>
+        <el-divider></el-divider>
+        <!-- <el-row :gutter="10">
+          <el-col :span="12">
+            时间间隔:
+            <el-input-number
+              style="width: 50%"
+              size="mini"
+              v-model="form.timeInterval"
+            ></el-input-number>
+          </el-col>
+          <el-col :span="12">
+            间距(米):
+            <el-input-number
+              style="width: 50%"
+              size="mini"
+              v-model="form.spacing"
+            ></el-input-number>
+          </el-col>
+        </el-row> -->
+        <!-- <el-row :gutter="10">
+          <el-col :span="12" style="text-align: center">
+            X坐标(度):
+            <el-input-number
+              size="mini"
+              step="0.000001"
+              v-model="form.x"
+              @change="XYChange"
+            ></el-input-number>
+          </el-col>
+          <el-col :span="12" style="text-align: center">
+            Y坐标(度):
+            <el-input-number
+              size="mini"
+              step="0.000001"
+              v-model="form.y"
+              @change="XYChange"
+            ></el-input-number>
+          </el-col>
+        </el-row> -->
+
+        <!-- <el-row :gutter="10">
+          <el-col :span="12">
+            底部高程(米):
+            <el-input-number
+              style="width: 50%"
+              size="mini"
+              v-model="form.bottomHeight"
+            ></el-input-number>
+          </el-col>
+          <el-col :span="12">
+            拉伸高度(米):
+            <el-input-number
+              style="width: 50%"
+              size="mini"
+              v-model="form.extrudeHeight"
+            ></el-input-number>
+          </el-col>
+        </el-row> -->
+        <el-row :gutter="10">
+          <el-col :span="24">
+            阴影分析时日照时间案范围重合时为时刻阴影,不重合时计算为时间范围内阴影率
+          </el-col>
+        </el-row>
+      </el-col>
+    </el-row>
+    <!-- <el-row :gutter="10" v-if="multiViewportMode > 1">
+      <el-col :span="24">
+        选择分析视口:<el-radio-group
+          v-model="radio"
+          v-for="item in multiViewportMode"
+          :key="item"
+        >
+          <el-radio :label="item - 1">窗口{{ item }}</el-radio>
+        </el-radio-group>
+      </el-col>
+    </el-row> -->
+    <div class="SaveCenter">
+      <el-row :gutter="10">
+        <el-col :span="24">
+          <el-button size="mini" type="primary" @click="onSubmit"
+            >自定义日照分析</el-button
+          >
+          <el-button size="mini" type="primary" @click="onDHSubmit"
+            >大寒日</el-button
+          >
+
+          <el-button size="mini" type="primary" @click="onDZSubmit"
+            >冬至日</el-button
+          >
+        </el-col>
+      </el-row>
+      <el-row :gutter="10">
+        <el-col :span="24">
+          <el-tooltip
+            effect="dark"
+            content="日照时长结果生成后,调整地图到合适位置,然后导出"
+            placement="bottom"
+          >
+            <el-button
+              size="mini"
+              type="primary"
+              :disabled="sdh.length == 0 ? true : false"
+              @click="ExportResult"
+              >导出结果</el-button
+            >
+          </el-tooltip>
+
+          <el-button size="mini" @click="resetForm">清除</el-button>
+        </el-col>
+      </el-row>
+    </div>
+    <el-row :gutter="10">
+      <el-col :span="24">
+        <el-descriptions border size="mini" :column="2">
+          <el-descriptions-item
+            v-for="item in sdh"
+            :key="item"
+            :label="item.scS + ' 小时'"
+            ><div
+              style="width: 4.5rem; height: 100%"
+              :style="{ 'background-color': item.fill }"
+            >
+              &nbsp;
+            </div>
+          </el-descriptions-item>
+        </el-descriptions>
+      </el-col>
+    </el-row>
+    <!-- <el-row :gutter="10">
+      <el-col :span="24">
+        <el-table
+          size="mini"
+          :data="tableData"
+          style="width: 100%"
+          :highlight-current-row="true"
+          @row-click="rowClick"
+        >
+          <el-table-column prop="heightText" label="高程"> </el-table-column>
+          <el-table-column prop="sunDate" label="日照时间"> </el-table-column>
+          <el-table-column
+            prop="shadowRadioText"
+            label="日照率"
+          ></el-table-column> 
+        </el-table>
+      </el-col>
+    </el-row> -->
+  </div>
+</template>
+
+<script>
+var handlerPolygon = null,
+  layers = null,
+  shadowQuery = null,
+  markedPoints = [],
+  sightline;
+var sdfff = null;
+import {
+  intersect,
+  flatten,
+  envelope,
+  point,
+  buffer,
+  bboxPolygon,
+  bbox,
+  square,
+  destination,
+  polygon,
+  featureCollection,
+  interpolate,
+  isobands,
+  area,
+  isolines,
+  pointGrid,
+} from "@turf/turf";
+// # 引入kriging-contour
+import {
+  getVectorContour,
+  drawCanvasContour,
+} from "kriging-contour/dist/kriging-contour.js";
+// import { getSunrise, getSunset } from "sunrise-sunset-js";
+import {
+  cartesian3ToWGS84,
+  mapQuery,
+  mercator2lonLat,
+  undergroundMode,
+  getXYZPoint,
+} from "@/utils/MapHelper/MapHelper.js";
+import SunshineAnalysisBySXJS from "./SunshineAnalysisBySX.js";
+import { v4 as uuidv4 } from "uuid";
+import moment from "moment";
+export default {
+  data() {
+    return {
+      tooltip: createTooltip(document.body),
+      form: {
+        timeInterval: 60,
+        spacing: 8,
+        selDate: new Date(),
+        startTime: 10,
+        endTime: 14,
+        bottomHeight: 0,
+        extrudeHeight: 100,
+        x: 0,
+        y: 0,
+      },
+      sdh: [
+        { scS: "0-1", fill: "#313695" },
+        { scS: "1-2", fill: "#1E90A8" },
+        { scS: "2-3", fill: "#00B457" },
+        { scS: "3-4", fill: "#B7FF01" },
+        { scS: "4-5", fill: "#F2A705" },
+        { scS: ">=5", fill: "#FF0000" },
+      ],
+      loading: false,
+      datavalue: [10, 14],
+      positions: [],
+      points: [],
+      // layers: null,
+      // shadowQuery: null,
+      marks: {
+        8: "8点",
+        12: {
+          style: {
+            color: "#1989FA",
+          },
+          label: this.$createElement("strong", "12点"),
+        },
+        20: "20点",
+      },
+      tableData: [],
+      multiViewportMode: 0,
+      radio: 0,
+      eids: [],
+      //记录进入页面时的场景参数
+      RecordInitializationScene: {},
+      nIntervId: null,
+      Intervalshijian: 10,
+    };
+  },
+  props: {
+    info: {
+      type: Object,
+      default: () => {
+        return {};
+      },
+    },
+    layerid: {
+      type: String,
+      default: "",
+    },
+    lydata: {
+      type: Object,
+      default: () => {
+        return {};
+      },
+    },
+    lyoption: {
+      type: Object,
+      default: () => {
+        return {};
+      },
+    },
+  },
+  computed: {},
+  mounted() {
+    // sightline = new Cesium.Sightline(scene);
+    // sightline.build();
+    this.multiViewportMode = scene.multiViewportMode + 1;
+    document.oncontextmenu = function (e) {
+      e.preventDefault();
+    };
+    this.init();
+  },
+  methods: {
+    init() {
+      let scene = viewer.scene;
+      layers = scene.layers.layerQueue;
+
+      this.RecordInitializationScene.shadows = viewer.shadows;
+      this.RecordInitializationScene.layersshadowType = [];
+      for (let i = 0; i < layers.length; i++) {
+        this.RecordInitializationScene.layersshadowType.push({
+          name: layers[i].name,
+          shadowType: layers[i].shadowType,
+        });
+      }
+
+      if (viewer.shadows == false) {
+        viewer.shadows = true; //开启场景阴影
+      }
+
+      //图层模型设置阴影
+      for (let i = 0; i < layers.length; i++) {
+        // if (layers[i].shadowType !== 2) {
+        layers[i].shadowType = 2;
+        // layers[i].refresh();
+        // }
+      }
+
+      this.dqSunlight();
+    },
+
+    //自定义日照
+    onSubmit() {
+      this.analysis();
+    },
+    //大寒日
+    onDHSubmit() {
+      this.form.selDate = new Date(new Date().getFullYear() + "-01-20");
+      this.datavalue = [9, 15];
+      this.analysis();
+    },
+    //冬至日
+    onDZSubmit() {
+      //       冬至日期(东八区)的计算公式:(y×d+c)-l
+      //   公式解读:Y=年数后2位,D=0.2422,L=闰年数,21世纪C=21.94,20世纪=22.60。
+      //   举例说明:2088年冬至日期=[88×0.2422+21.94]-[88/4]=43-22=21,12月21日冬至。
+      //   例外:1918年和2021年的计算结果减1日。
+      let lastTwoDigitsOfYear = moment().format("YY");
+      let rns = lastTwoDigitsOfYear / 4;
+      let sjs = 21.94;
+      let dzr = Math.floor(lastTwoDigitsOfYear * 0.2422 + sjs - rns);
+      this.form.selDate = new Date(new Date().getFullYear() + "-12-" + dzr);
+
+      this.datavalue = [9, 15];
+      this.analysis();
+    },
+    //清空from
+    resetForm() {
+      this.clear();
+      // this.clearmarkedPoints();
+    },
+    /**
+     * 开始分析
+     */
+    analysis1() {
+      let that = this;
+      that.tableData = [];
+      if (!handlerPolygon) {
+        handlerPolygon = new Cesium.DrawHandler(
+          viewer,
+          Cesium.DrawMode.Point,
+          Cesium.ClampMode.Space
+        );
+      }
+
+      handlerPolygon.activate();
+      handlerPolygon.activeEvt.addEventListener(function (isActive) {
+        // if (isActive == true) {
+        //   viewer.enableCursorStyle = false;
+        //   viewer._element.style.cursor = "";
+        //   document.body.classList.add("drawCur");
+        // } else {
+        //   viewer.enableCursorStyle = true;
+        //   document.body.classList.remove("drawCur");
+        // }
+        that.tooltip.setVisible(false);
+      });
+      handlerPolygon.movingEvt.addEventListener((windowPosition) => {
+        that.tooltip.showAt(
+          windowPosition,
+          "<p>点击鼠标左键开始选择分析区域</p>"
+        );
+      });
+      handlerPolygon.drawEvt.addEventListener((result) => {
+        that.resetForm();
+        // that.clickSunDate();
+        that.loading = true;
+        let scene = viewer.scene;
+
+        //创建阴影查询对象
+        if (!shadowQuery) {
+          shadowQuery = new Cesium.ShadowQueryPoints(scene);
+          shadowQuery.setVisibleInViewport(that.radio);
+          shadowQuery.queryPointsEvent.addEventListener(function (e) {
+            that.tableData = [];
+            that.loading = false;
+            e.forEach(function (a) {
+              var e_cartographic = Cesium.Cartographic.fromCartesian(
+                a.position
+              );
+              var e_shadowRadio = shadowQuery.getShadowRadio(e_cartographic);
+              var e_longitude = Cesium.Math.toDegrees(e_cartographic.longitude);
+              var e_latitude = Cesium.Math.toDegrees(e_cartographic.latitude);
+              var e_height = e_cartographic.height;
+              let sunForm = {};
+              sunForm.shadowRadioText =
+                (Number(e_shadowRadio.toFixed(2)) * 100).toFixed(2) + "%";
+              sunForm.longitudeText = Number(e_longitude.toFixed(6));
+              sunForm.latitudeText = Number(e_latitude.toFixed(6));
+              sunForm.heightText = Number(e_height.toFixed(2));
+              sunForm.dateScope =
+                that.datavalue[0] + "时--" + that.datavalue[1] + "时";
+              if (that.datavalue[0] != that.datavalue[1]) {
+                sunForm.sunDate =
+                  (
+                    (that.datavalue[1] + 1 - that.datavalue[0]) *
+                    e_shadowRadio
+                  ).toFixed(2) + "小时";
+              } else {
+                sunForm.sunDate = "";
+              }
+              that.tableData.push(sunForm);
+            });
+          });
+        }
+        that.tooltip.setVisible(false);
+        var position = result.object.position;
+        var cartographic = Cesium.Cartographic.fromCartesian(position);
+        var longitude = Cesium.Math.toDegrees(cartographic.longitude);
+        var latitude = Cesium.Math.toDegrees(cartographic.latitude);
+        var clickPoint = point([longitude, latitude]); //
+        var buffered = buffer(clickPoint, (that.form.spacing / 2 + 1) / 1000, {
+          units: "kilometers",
+        });
+
+        that.form.x = longitude;
+        that.form.y = latitude;
+        that.points = buffered.geometry.coordinates[0].flat();
+        //设置分析对象的开始结束时间
+        var dateValue = that.form.selDate;
+        var st = new Date(dateValue);
+        st.setHours(Number(that.form.startTime));
+        shadowQuery.startTime = Cesium.JulianDate.fromDate(st);
+
+        var et = new Date(dateValue);
+        et.setHours(Number(that.form.endTime));
+        shadowQuery.endTime = Cesium.JulianDate.fromDate(et);
+
+        //设置当前时间
+        that.setCurrentTime();
+
+        shadowQuery.spacing = that.form.spacing;
+        shadowQuery.timeInterval = that.form.timeInterval;
+
+        //设置分析区域、底部高程和拉伸高度
+        var bh = Number(that.form.bottomHeight);
+        var eh = Number(that.form.extrudeHeight);
+        shadowQuery.qureyRegion({
+          position: that.points,
+          bottom: bh,
+          extend: eh,
+        });
+        shadowQuery.build();
+      });
+    },
+    analysis() {
+      let that = this;
+      that.clear();
+      that.tableData = [];
+      if (!handlerPolygon) {
+        handlerPolygon = new Cesium.DrawHandler(
+          viewer,
+          Cesium.DrawMode.Polygon,
+          0
+        );
+      }
+
+      handlerPolygon.activate();
+      handlerPolygon.activeEvt.addEventListener(function (isActive) {
+        // if (isActive == true) {
+        //   // viewer.enableCursorStyle = false;
+        //   // viewer._element.style.cursor = "";
+        //   document.body.classList.add("drawCur");
+        // } else {
+        //   // viewer.enableCursorStyle = true;
+        //   document.body.classList.remove("drawCur");
+        // }
+        that.tooltip.setVisible(false);
+      });
+      handlerPolygon.movingEvt.addEventListener((windowPosition) => {
+        that.tooltip.showAt(
+          windowPosition,
+          "<p>点击鼠标左键开始绘制分析区域</p>"
+        );
+      });
+      handlerPolygon.drawEvt.addEventListener(async (result) => {
+        debugger;
+        that.tooltip.setVisible(false);
+        that.resetForm();
+        // that.loading = true;
+
+        //根据范围随机生成点
+        var polygons = result.object.positions;
+        var cartographic = Cesium.Cartographic.fromCartesian(polygons[0]);
+
+        that.gd = Math.ceil(cartographic.height);
+
+        var sdsd = [];
+        for (var index = 0; index < polygons.length; index++) {
+          const a = polygons[index];
+          var e_cartographic = Cesium.Cartographic.fromCartesian(a);
+          var e_longitude = Cesium.Math.toDegrees(e_cartographic.longitude);
+          var e_latitude = Cesium.Math.toDegrees(e_cartographic.latitude);
+          // var e_height = e_cartographic.height;
+          let sd = point([e_longitude, e_latitude]);
+          sd.properties.value = 1;
+          sdsd.push(sd);
+        }
+        // 将散点合并成要素集
+        const points = featureCollection(sdsd);
+        var options = {
+          gridType: "points",
+          property: "value",
+          units: "degrees",
+        };
+        var grid = interpolate(points, that.form.spacing * 0.00001, options);
+
+        var Points = [];
+        for (var index = 0; index < grid.features.length; index++) {
+          var Point = grid.features[index];
+          var xy = Point.geometry.coordinates;
+          Points.push(xy);
+        }
+        var xyzs = await getXYZPoint(Points);
+
+        for (var index = 0; index < xyzs.length; index++) {
+          var xyz = xyzs[index];
+          if (xyz) {
+            xyz.z += 2;
+          } else {
+            xyz = { x: xyz[0], y: xyz[1], z: 2 };
+          }
+          xyz = new Cesium.Cartesian3.fromDegrees(xyz.x, xyz.y, xyz.z);
+          xyz.rzsc = 0;
+          xyzs[index] = xyz;
+        }
+
+        var ret = SunshineAnalysisBySXJS.PointSunshineAnalysis(
+          xyzs,
+          this.form.selDate,
+          this.datavalue[0],
+          this.datavalue[1]
+        );
+
+        debugger;
+        var trufPoints = [];
+        for (var index = 0; index < ret.length; index++) {
+          const a = ret[index];
+          var e_cartographic = Cesium.Cartographic.fromCartesian(a);
+          var e_longitude = Cesium.Math.toDegrees(e_cartographic.longitude);
+          var e_latitude = Cesium.Math.toDegrees(e_cartographic.latitude);
+
+          var trufPoint = point([e_longitude, e_latitude]);
+          trufPoint.properties.value = a.rzsc;
+          trufPoint.value = a.rzsc;
+          trufPoints.push(trufPoint);
+        }
+
+        let gsd = that.setIsoline(trufPoints, result.object);
+        for (
+          let featuresindex = 0;
+          featuresindex < gsd.features.length;
+          featuresindex++
+        ) {
+          var element = gsd.features[featuresindex];
+          if (element.geometry.type == "MultiPolygon") {
+            // continue;
+            var polygons = that.geoJSONMultiPolygonToCesiumPolygons(element);
+
+            polygons.forEach((polygonItem) => {
+              let id = uuidv4();
+              that.eids.push(id);
+              viewer.entities.add({
+                id: id,
+                polygon: {
+                  hierarchy: polygonItem,
+                  material: new Cesium.Color.fromCssColorString(
+                    element.properties.fill
+                  ).withAlpha(1),
+                  height: that.gd + 3 + featuresindex * 0.1,
+                  outline: false,
+                  // outlineColor: Cesium.Color.BLACK,
+                  // outlineWidth: 2.0,
+                  // classificationType: Cesium.ClassificationType.TERRAIN,
+                },
+              });
+            });
+          } else {
+            // continue;
+            for (
+              var index = 0;
+              index < element.geometry.coordinates.length;
+              index++
+            ) {
+              var polygon = element.geometry.coordinates[index];
+              let ps = polygon.flat();
+
+              let id = uuidv4();
+              that.eids.push(id);
+              viewer.entities.add({
+                id: id,
+                polygon: {
+                  hierarchy: Cesium.Cartesian3.fromDegreesArray(ps),
+                  material: new Cesium.Color.fromCssColorString(
+                    element.properties.fill
+                  ).withAlpha(1),
+                  height: that.gd + 3 + featuresindex * 0.1,
+                  outline: false,
+                  // outlineColor: Cesium.Color.BLACK,
+                  // outlineWidth: 2.0,
+                  // classificationType: Cesium.ClassificationType.TERRAIN,
+                },
+              });
+            }
+          }
+        }
+
+        that.loading = false;
+        return;
+      });
+    },
+
+    ExportResult() {
+      let that = this;
+      let entitys = [];
+      that.eids.forEach((id) => {
+        let entity = viewer.entities.getById(id);
+        if (entity) {
+          entitys.push(entity);
+        }
+      });
+
+      let box = that.squarePolygon(entitys);
+      viewer.camera.flyTo({
+        destination: Cesium.Rectangle.fromDegrees(
+          box[0][0] + 0.0002,
+          box[0][1] - 0.0002,
+          box[2][0] - 0.0002,
+          box[2][1] + 0.0002
+        ),
+      });
+
+      setTimeout(function () {
+        var promise = scene.outputSceneToFile();
+        Cesium.when(promise, function (base64data) {
+          that.download(base64data);
+        });
+      }, 4000);
+    },
+    /**
+     * 根据图片生成画布
+     */
+    convertImageToCanvas(image) {
+      var canvas = document.createElement("canvas");
+      canvas.width = image.width;
+      canvas.height = image.height;
+      var ctx = canvas.getContext("2d");
+      ctx.drawImage(image, 0, 0);
+      this.drawLegends(canvas, ctx);
+      return canvas;
+    },
+    // 绘制图例
+    drawLegends(canvas, ctx) {
+      var legends = this.sdh;
+      var padding = 10; // 图例与边缘的间距
+      var lineHeight = 30; // 每行图例的高度
+      var labW = 120;
+      var x = canvas.width - padding - labW; // 图例的起始X坐标
+      var y = canvas.height - legends.length * lineHeight - padding; // 图例的起始Y坐标
+      // 绘制颜色块
+      ctx.fillStyle = "#ffffff";
+      ctx.fillRect(
+        x - padding,
+        y - padding,
+        canvas.width - x + padding,
+        canvas.height - y + padding
+      );
+      legends.forEach(function (legend, index) {
+        // 绘制文本
+        ctx.fillStyle = "black";
+        ctx.fillText(
+          legend.scS + "小时",
+          x,
+          y + index * lineHeight + lineHeight / 2
+        );
+        // 绘制颜色块
+        ctx.fillStyle = legend.fill;
+        ctx.fillRect(
+          x + (labW / 3) * 2,
+          y + index * lineHeight,
+          30,
+          lineHeight
+        );
+      });
+    },
+    /**
+     * 下载图片
+     */
+    download(base64data) {
+      let that = this;
+      var image = new Image();
+      image.src = base64data;
+      image.onload = function () {
+        var canvas = that.convertImageToCanvas(image);
+        var url = canvas.toDataURL("image/jpeg");
+        var a = document.createElement("a");
+        var event = new MouseEvent("click");
+        a.download = new Date().getTime() + ".jpg"; // 指定下载图片的名称
+        a.href = url;
+        a.dispatchEvent(event); // 触发超链接的点击事件
+      };
+    },
+    clear() {
+      // viewer.entities.removeAll();
+      // this.form.x = 0;
+      // this.form.y = 0;
+      this.tableData = [];
+      if (handlerPolygon) {
+        handlerPolygon.clear();
+        handlerPolygon.deactivate();
+        handlerPolygon = null;
+      }
+      this.tooltip.setVisible(false);
+      if (shadowQuery) {
+        shadowQuery.clear();
+        shadowQuery.destroy();
+        shadowQuery = null;
+        // shadowQuery.qureyRegion({
+        //   position: [0, 0],
+        //   bottom: 0,
+        //   extend: 0,
+        // });
+      }
+
+      this.positions = [];
+      this.points = [];
+      for (let i = 0; i < this.eids.length; i++) {
+        viewer.entities.removeById(this.eids[i]);
+      }
+      // this.sdh = [];
+      this.eids = [];
+    },
+    //结束时日照阴影
+    setCurrentTime() {
+      var et = this.form.selDate;
+      et.setHours(Number(this.form.endTime));
+      viewer.clock.currentTime = Cesium.JulianDate.fromDate(et);
+      viewer.clock.multiplier = 1;
+      viewer.clock.shouldAnimate = false;
+    },
+    /**
+     * 执行日照动画
+     */
+    statrSunlight() {
+      var dateVal = this.form.selDate;
+      var startTime = new Date(dateVal);
+      var shour = Number(this.form.startTime);
+      var ehour = Number(this.form.endTime);
+
+      if (shour > ehour) {
+        return;
+      }
+
+      var nTimer = 0.0;
+      if (this.nIntervId) {
+        clearInterval(this.nIntervId);
+      }
+      debugger;
+      this.nIntervId = setInterval(function () {
+        if (shour < ehour) {
+          startTime.setHours(shour);
+          startTime.setMinutes(nTimer);
+          viewer.clock.currentTime = Cesium.JulianDate.fromDate(startTime);
+          nTimer += 10.0;
+          if (nTimer > 60.0) {
+            shour += 1.0;
+            nTimer = 0.0;
+          }
+        } else {
+          clearInterval(this.nIntervId);
+        }
+      }, this.Intervalshijian * 10);
+    },
+    //当前日照效果
+    dqSunlight() {
+      viewer.clock.currentTime = Cesium.JulianDate.fromDate(new Date());
+      viewer.clock.multiplier = 1;
+      viewer.clock.shouldAnimate = true;
+    },
+    //日照列表行被点击
+    rowClick(row, column, event) {
+      this.clearmarkedPoints();
+      var markedPoint = viewer.entities.add(
+        new Cesium.Entity({
+          point: new Cesium.PointGraphics({
+            color: new Cesium.Color(1, 1, 0, 0.5),
+            pixelSize: 15,
+          }),
+          position: Cesium.Cartesian3.fromDegrees(
+            row.longitudeText,
+            row.latitudeText,
+            row.heightText
+          ),
+        })
+      );
+      markedPoints.push(markedPoint);
+    },
+    //清除点击的黄色圆圈
+    clearmarkedPoints() {
+      for (let i = 0; i < markedPoints.length; i++) {
+        viewer.entities.remove(markedPoints[i]);
+      }
+      markedPoints = [];
+    },
+    // x或y变化触发
+    XYChange() {
+      if (!shadowQuery) {
+        return;
+      }
+      this.loading = true;
+      let that = this;
+
+      var clickPoint = point([that.form.x, that.form.y]); //
+      var buffered = buffer(clickPoint, (that.form.spacing / 2 + 1) / 1000, {
+        units: "kilometers",
+      });
+      that.points = buffered.geometry.coordinates[0].flat();
+
+      //设置分析区域、底部高程和拉伸高度
+      var bh = Number(that.form.bottomHeight);
+      var eh = Number(that.form.extrudeHeight);
+      shadowQuery.qureyRegion({
+        position: that.points,
+        bottom: bh,
+        extend: eh,
+      });
+      shadowQuery.build();
+    },
+
+    // 时间范围变化触发
+    datavalueChange(val) {
+      if (val[0] == val[1]) {
+        this.form.timeInterval = 1;
+      } else {
+        this.form.timeInterval = 60;
+      }
+      this.form.startTime = val[0];
+      this.form.endTime = val[1];
+    },
+
+    setIsoline(turfPoints, polygons) {
+      //转换面
+      var trufpolygons = [];
+      for (var pindex = 0; pindex < polygons.positions.length; pindex++) {
+        var pposition = polygons.positions[pindex];
+        var e_cartographic = Cesium.Cartographic.fromCartesian(pposition);
+        var e_longitude = Cesium.Math.toDegrees(e_cartographic.longitude);
+        var e_latitude = Cesium.Math.toDegrees(e_cartographic.latitude);
+        trufpolygons.push([e_longitude, e_latitude]);
+      }
+
+      if (trufpolygons[0] != trufpolygons[trufpolygons.length - 1]) {
+        trufpolygons.push(trufpolygons[0]);
+      }
+      var polygonPs = polygon([trufpolygons]);
+
+      // var sunriseDate = SunriseSunsetJS.getSunrise(
+      //   18.31723463241332,
+      //   109.5112252162011,
+      //   this.form.selDate
+      // );
+      // var sunsetdate = SunriseSunsetJS.getSunset(
+      //   18.31723463241332,
+      //   109.5112252162011,
+      //   this.form.selDate
+      // );
+      // //参与计算的日出日落时间
+      // var jssunriseHours = 0;
+      // var jssunsetHours = 0;
+      // //日出时间
+      // var sunriseHours = sunriseDate.getHours() + sunriseDate.getMinutes() / 60;
+      // //日落时间
+      // var sunsetHours = sunsetdate.getHours() + sunsetdate.getMinutes() / 60;
+
+      // if (this.datavalue[0] > sunriseHours) jssunriseHours = this.datavalue[0];
+      // else jssunriseHours = sunriseHours;
+
+      // if (this.datavalue[1] > sunsetHours) jssunsetHours = sunsetHours;
+      // else jssunsetHours = this.datavalue[1];
+
+      // //赋值+计算小时数
+      // for (var index = 0; index < turfPoints.length; index++) {
+      //   var element = turfPoints[index];
+      //   console.log(
+      //     jssunsetHours -
+      //       jssunriseHours +
+      //       "*" +
+      //       element.properties.value +
+      //       "==" +
+      //       (jssunsetHours - jssunriseHours) * element.properties.value
+      //   );
+
+      //   var time = (jssunsetHours - jssunriseHours) * element.properties.value;
+      //   // if (time > 5) {
+      //   //   element["value"] = 5;
+      //   //   element.properties.value = 5;
+      //   // } else {
+      //   element["value"] = time;
+      //   element.properties.value = time;
+      //   // }
+      // }
+
+      // 使用turf.envelope计算包含所有点的最小矩形多边形
+      var envelopeP = envelope(featureCollection(turfPoints));
+      // var minX,max
+      // turfPoints.forEach()
+
+      // 从envelope多边形中提取bbox坐标
+      let dd1 = envelopeP.bbox;
+      // let dd1 = [107, 36, 180, 38];
+      // let dd1 = bbox(sdsd);
+      let points1 = {
+        type: "FeatureCollection",
+        features: turfPoints,
+      };
+
+      let levelv = [0, 1, 2, 3, 4, 5];
+      let colors = [
+        { fill: "#313695" },
+        { fill: "#1E90A8" },
+        { fill: "#00B457" },
+        { fill: "#B7FF01" },
+        { fill: "#F2A705" },
+        { fill: "#FF0000" },
+        { fill: "#FF0000" },
+      ];
+
+      let kriging_contours = getVectorContour(
+        points1,
+        "value",
+        { model: "spherical", sigma2: 0, alpha: 10 },
+        levelv,
+        dd1
+      );
+
+      function hotcolor(d) {
+        let index = levelv.findIndex((item) => item >= d);
+        if (index > -1 && index < 6) {
+          return colors[index].fill;
+        } else {
+          return colors[colors.length - 1].fill;
+        }
+      }
+      function sortArea(a, b) {
+        return area(b) - area(a);
+      }
+      //按照面积对图层进行排序,规避turf的一个bug
+      kriging_contours.features.sort(sortArea);
+      //后面使用要求输入的参数为Feature<Polygon>,而turf.isobands的是 MultiPolygon,需
+      var boundaries = flatten(envelopeP); //行政边界
+
+      kriging_contours = flatten(kriging_contours); //等值面边界
+      //console.log('kriging_contours:'+JSON.stringify(kriging_contours));
+      //根据行政边界裁剪图形,
+      //现在放大一些区域边界还是没有充满  后面可以封装成一个插件,在源码里面进行canvas  clip 剪辑只显示的geojson区域,其余的栅格部分不显示
+      let features = []; //裁剪后的结果集
+      // kriging_contours.features.forEach(function (feature1) {
+      //   boundaries.features.forEach(function (feature2) {
+      //     let intersection = null;
+      //     try {
+      //       intersection = intersect(feature1, feature2);
+      //     } catch (e) {
+      //       try {
+      //         //色斑图绘制之后,可能会生成一些非法 Polygon
+      //         //解决的方法通常就是做一次 turf.buffer() 操作,这样可以把一些小的碎片 Polygon 清理掉。
+      //         feature1 = buffer(feature1, 0);
+      //         intersection = intersect(feature1, feature2);
+      //       } catch (e) {
+      //         intersection = feature1; //实在裁剪不了就不裁剪了,根据业务需求自行决定
+      //       }
+      //     }
+      //     if (intersection != null) {
+      //       intersection.properties = feature1.properties;
+      //       // intersection.properties.fill = hotcolor(feature1.properties.value);
+      //       intersection.id = (Math.random() * 100000).toFixed(0);
+      //       features.push(intersection);
+      //     }
+      //   });
+      // });
+      var polygonPs = polygon([trufpolygons]);
+      kriging_contours.features.forEach(function (feature1) {
+        // polygonPs.features.forEach(function (feature2) {
+        let inFeature = null;
+        try {
+          inFeature = intersect(feature1, polygonPs);
+        } catch (e) {
+          try {
+            //色斑图绘制之后,可能会生成一些非法 Polygon
+            //解决的方法通常就是做一次 turf.buffer() 操作,这样可以把一些小的碎片 Polygon 清理掉。
+            feature1 = buffer(feature1, 0);
+            inFeature = intersect(feature1, polygonPs);
+          } catch (e) {
+            inFeature = feature1; //实在裁剪不了就不裁剪了,根据业务需求自行决定
+          }
+        }
+        if (inFeature != null) {
+          inFeature.properties = feature1.properties;
+          // intersection.properties.fill = hotcolor(feature1.properties.value);
+          inFeature.id = (Math.random() * 100000).toFixed(0);
+          features.push(inFeature);
+        }
+        // });
+      });
+
+      let intersection = featureCollection(features);
+      intersection.features.forEach((element) => {
+        element.properties.fill = hotcolor(element.properties.contour_value);
+      });
+      // function zdx(a, b) {
+      //   return a.properties.contour_value - b.properties.contour_value;
+      // }
+      // intersection.features.sort(zdx);
+
+      // let features = []; //裁剪后的结果集
+
+      // intersection.features = features;
+      return intersection;
+    },
+
+    /**
+     * @property {Array} features  关键点集合
+     */
+    setIsoline1111(features) {
+      // 准备工作,创建 options
+      // const breaks = [0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1];
+      const breaks = [0];
+      for (
+        var index = 1;
+        index < this.datavalue[1] - this.datavalue[0] + 1;
+        index++
+      ) {
+        breaks.push(index * (1 / (this.datavalue[1] - this.datavalue[0])));
+      }
+      // breaks.push(2);
+      let breaksProperties = [];
+      for (var index = 0; index < breaks.length; index++) {
+        // let time1 = Math.ceil(
+        //   (this.datavalue[1] - this.datavalue[0]) * breaks[index]
+        // );
+
+        let time1 = (this.datavalue[1] - this.datavalue[0]) * breaks[index];
+        switch (time1) {
+          case 0:
+            breaksProperties.push(this.sdh[0]);
+            break;
+          case 1:
+            breaksProperties.push(this.sdh[1]);
+            break;
+          case 2:
+            breaksProperties.push(this.sdh[2]);
+            break;
+          case 3:
+            breaksProperties.push(this.sdh[3]);
+            break;
+          case 4:
+            breaksProperties.push(this.sdh[4]);
+            break;
+          default:
+            breaksProperties.push(this.sdh[5]);
+            break;
+        }
+      }
+
+      const interpolateOptions = {
+        gridType: "points",
+        property: "value",
+        units: "degrees",
+        weight: 50,
+      };
+      const isobandsOptions = {
+        zProperty: "value",
+        // commonProperties: {
+        //   "fill-opacity": 0.5,
+        // },
+        breaksProperties: breaksProperties,
+      };
+      // 准备工作结束
+
+      // 将散点合并成要素集
+      const points = featureCollection(features);
+      // 使用反向距离加权(IDW)方法进行运算
+      const grid = interpolate(
+        points,
+        this.form.spacing * 0.00001,
+        interpolateOptions
+      );
+      // 根据参与分级的属性和分级的数组计算出等值面
+      const isobandsData = isobands(grid, breaks, isobandsOptions);
+      const intersection = featureCollection(isobandsData.features);
+
+      return intersection;
+    },
+    /**
+     * 计算边界
+     */
+    squarePolygon(entitys) {
+      const polygons = [
+        /* ... 多边形数组 ... */
+      ];
+      entitys.forEach((entity) => {
+        let positions = entity.polygon.hierarchy.getValue().positions;
+        let posts = [];
+        positions.forEach((position) => {
+          let xy = cartesian3ToWGS84(position);
+          posts.push([xy.lng, xy.lat]);
+        });
+        let thispolygon = polygon([posts]);
+        polygons.push(thispolygon);
+      });
+
+      // 初始化边界框变量
+      let minX = Infinity,
+        minY = Infinity,
+        maxX = -Infinity,
+        maxY = -Infinity;
+
+      // 遍历每个多边形,计算其边界框,并更新最小/最大坐标
+      polygons.forEach((polygon) => {
+        const thisbbox = bbox(polygon);
+        minX = Math.min(minX, thisbbox[0]);
+        minY = Math.min(minY, thisbbox[1]);
+        maxX = Math.max(maxX, thisbbox[2]);
+        maxY = Math.max(maxY, thisbbox[3]);
+      });
+
+      // 计算正方形的边长
+      const sideLength = Math.max(maxX - minX, maxY - minY);
+
+      // 创建正方形的四个角点
+      const squareCoords = [
+        [minX, minY],
+        [minX + sideLength, minY],
+        [minX + sideLength, minY + sideLength],
+        [minX, minY + sideLength],
+        [minX, minY], // 闭合多边形
+      ];
+
+      // // 使用Turf.js创建正方形多边形
+      // const squarePolygon = polygon([squareCoords]);
+      return squareCoords;
+    },
+    geoJSONMultiPolygonToCesiumPolygons11(multiPolygon) {
+      let polygonsHierarchy = [];
+
+      multiPolygon.geometry.coordinates.forEach((polygon) => {
+        let rings = [];
+
+        polygon.forEach((ring) => {
+          let cartesianPoints = ring.map((coordinates) => {
+            return Cesium.Cartesian3.fromDegrees(
+              coordinates[0],
+              coordinates[1]
+            );
+          });
+
+          rings.push(cartesianPoints);
+        });
+
+        polygonsHierarchy.push(rings);
+      });
+
+      return polygonsHierarchy;
+    },
+    geoJSONMultiPolygonToCesiumPolygons(multiPolygon) {
+      // 假设multiPolygon是一个有效的多边形数组
+      let polygonsHierarchy = [];
+      // {
+      //             // Cesium.PolygonHierarchy
+      //             positions: point3ds[0],
+      //             holes: holes, // Cesium.PolygonHierarchy 数组
+      //           }
+      multiPolygon.geometry.coordinates.forEach((polygon) => {
+        var polygons = { positions: [] };
+        if (polygon.length > 1) {
+          polygons.holes = [];
+        }
+        polygon.forEach((element, i) => {
+          if (i == 0) {
+            polygons.positions = Cesium.Cartesian3.fromDegreesArray(
+              element.flat()
+            );
+          } else {
+            polygons.holes.push({
+              positions: Cesium.Cartesian3.fromDegreesArray(element.flat()),
+            });
+          }
+        });
+
+        // 创建PolygonHierarchy结构
+        polygonsHierarchy.push(polygons);
+      });
+
+      return polygonsHierarchy;
+    },
+    /**
+     *  //笛卡尔转换为经纬度
+     * @param {*} position
+     */
+    Cartesian2toDegrees(position) {
+      var cartographic = Cesium.Cartographic.fromCartesian(position);
+      var longitude = Cesium.Math.toDegrees(cartographic.longitude);
+      var latitude = Cesium.Math.toDegrees(cartographic.latitude);
+      var height = cartographic.height;
+      return [longitude, latitude, height];
+    },
+  },
+  watch: {
+    "form.selDate": function (newValue) {
+      if (!shadowQuery) {
+        return;
+      }
+      this.loading = true;
+      let st = new Date(newValue);
+      st.setHours(this.form.startTime);
+      let et = new Date(newValue);
+      et.setHours(this.form.endTime);
+      shadowQuery.startTime = Cesium.JulianDate.fromDate(st);
+      shadowQuery.endTime = Cesium.JulianDate.fromDate(et);
+    },
+    "form.startTime": function (newValue) {
+      if (!shadowQuery) {
+        return;
+      }
+      this.loading = true;
+      let thisdate = new Date(this.form.selDate);
+      var st = thisdate;
+      st.setHours(Number(newValue));
+      shadowQuery.startTime = Cesium.JulianDate.fromDate(st);
+    },
+    "form.endTime": function (newValue) {
+      if (!shadowQuery) {
+        return;
+      }
+      this.loading = true;
+      let thisdate = new Date(this.form.selDate);
+      var et = thisdate;
+      et.setHours(Number(newValue));
+      shadowQuery.endTime = Cesium.JulianDate.fromDate(et);
+    },
+    "form.timeInterval": function (newValue) {
+      if (!shadowQuery) {
+        return;
+      }
+      this.loading = true;
+      shadowQuery.timeInterval = Number(newValue);
+
+      shadowQuery.build();
+    },
+    "form.spacing": function (newValue) {
+      if (!shadowQuery) {
+        return;
+      }
+      this.loading = true;
+      shadowQuery.spacing = Number(newValue);
+
+      shadowQuery.build();
+    },
+    "form.bottomHeight": function (newValue) {
+      if (!shadowQuery) {
+        return;
+      }
+      this.loading = true;
+      var bh = Number(newValue);
+      var eh = Number(this.form.extrudeHeight);
+      shadowQuery.qureyRegion({
+        position: this.points,
+        bottom: bh,
+        extend: eh,
+      });
+      shadowQuery.build();
+    },
+    "form.extrudeHeight": function (newValue) {
+      if (!shadowQuery) {
+        return;
+      }
+      this.loading = true;
+      var bh = Number(this.form.bottomHeight);
+      var eh = Number(newValue);
+      shadowQuery.qureyRegion({
+        position: this.points,
+        bottom: bh,
+        extend: eh,
+      });
+      shadowQuery.build();
+    },
+  },
+  beforeDestroy() {
+    document.oncontextmenu = null;
+    this.clear();
+    this.clearmarkedPoints();
+    if (shadowQuery) {
+      shadowQuery.clear();
+      shadowQuery.destroy();
+      shadowQuery = null;
+    }
+    if (handlerPolygon) {
+      handlerPolygon.deactivate();
+    }
+    handlerPolygon = undefined;
+    this.dqSunlight();
+
+    let scene = viewer.scene;
+    layers = scene.layers.layerQueue;
+    viewer.shadows = this.RecordInitializationScene.shadows;
+    //图层模型还原阴影
+    for (let i = 0; i < layers.length; i++) {
+      var shadowType = this.RecordInitializationScene.layersshadowType.find(
+        (c) => c.name == layers[i].name
+      );
+      if (shadowType) {
+        if (layers[i].shadowType != shadowType.shadowType) {
+          layers[i].shadowType = shadowType.shadowType;
+          layers[i].refresh();
+        }
+      }
+    }
+  },
+};
+</script>
+<style lang="scss">
+@import "@/../../zt.scss";
+</style>
+<style lang="scss" scoped>
+.el-card {
+  border: 0px solid #02a7f0;
+}
+.el-form-item {
+  margin-bottom: 0;
+}
+.slider_padding {
+  padding: 0rem 0.5rem;
+}
+</style>

+ 158 - 0
src/views/ConstructionApplication3D/SunlightAnalysis/SunshineAnalysisBySX.js

@@ -0,0 +1,158 @@
+const SunshineAnalysisBySXJS = {
+  //第一个是要分析的点的位置(是世界坐标)
+  /**
+   *
+   * @param {*} postions 经纬度
+   * @param {*} selDate 日期
+   * @param {*} startTime 开始时间
+   * @param {*} endTime 结束时间
+   * @returns
+   */
+  PointSunshineAnalysis(postions, selDate, startTime, endTime) {
+    var rcrlTime = SunshineAnalysisBySXJS.calculateTime(
+      selDate,
+      startTime,
+      endTime
+    );
+    for (
+      var Timenumber = rcrlTime.jssunriseHours;
+      Timenumber <= rcrlTime.jssunsetHours;
+      Timenumber++
+    ) {
+      var date = new Date(new Date(selDate).setHours(Timenumber));
+      //获取太阳的世界坐标,
+      let transforMatrix = Cesium.Transforms.computeTemeToPseudoFixedMatrix(
+        Cesium.JulianDate.fromDate(date)
+      );
+      let sunposition2 =
+        Cesium.Simon1994PlanetaryPositions.computeSunPositionInEarthInertialFrame(
+          Cesium.JulianDate.fromDate(date)
+        );
+      Cesium.Matrix3.multiplyByVector(
+        transforMatrix,
+        sunposition2,
+        sunposition2
+      );
+
+      // var e_cartographic2 = Cesium.Cartographic.fromCartesian(sunposition2);
+      // var e_longitude2 = Cesium.Math.toDegrees(e_cartographic2.longitude);
+      // var e_latitude2 = Cesium.Math.toDegrees(e_cartographic2.latitude);
+      // var e_height2 = e_cartographic2.height;
+      // console.log(
+      //   "起点2:" + e_longitude2 + "  " + e_latitude2 + "  " + e_height2
+      // );
+
+      for (let index = 0; index < postions.length; index++) {
+        const postion = postions[index];
+        var fx = new Cesium.Cartesian3(
+          sunposition2.x - postion.x,
+          sunposition2.y - postion.y,
+          sunposition2.z - postion.z
+        );
+        var dec = Math.sqrt(fx.x * fx.x + fx.y * fx.y + fx.z * fx.z);
+        var fxxl = new Cesium.Cartesian3(fx.x / dec, fx.y / dec, fx.z / dec); //方向向量
+        var changdu = 200;
+        var zd = new Cesium.Cartesian3(
+          postion.x + changdu * fxxl.x,
+          postion.y + changdu * fxxl.y,
+          postion.z + changdu * fxxl.z
+        );
+
+        // var e_cartographic = Cesium.Cartographic.fromCartesian(postion);
+        // var e_longitude = Cesium.Math.toDegrees(e_cartographic.longitude);
+        // var e_latitude = Cesium.Math.toDegrees(e_cartographic.latitude);
+        // var e_height = e_cartographic.height;
+        // console.log(
+        //   "起点:" + e_longitude + "  " + e_latitude + "  " + e_height
+        // );
+
+        // var e_cartographiczd = Cesium.Cartographic.fromCartesian(zd);
+        // var e_longitudezd = Cesium.Math.toDegrees(e_cartographiczd.longitude);
+        // var e_latitudezd = Cesium.Math.toDegrees(e_cartographiczd.latitude);
+        // var e_heightzd = e_cartographiczd.height;
+        // console.log(
+        //   "终点:" + e_longitudezd + "  " + e_latitudezd + "  " + e_heightzd
+        // );
+
+        //如果线之间被隔断,就认为该点被阻挡了
+        var isLineOfSightClear = SunshineAnalysisBySXJS.jiance(postion, zd);
+        // true 不在阴影中   false 在阴影中
+        if (isLineOfSightClear) {
+          postion.rzsc += 1;
+          if (postion.rzsc > 5) {
+            postion.rzsc = 5;
+          }
+        }
+        //做射线,
+        // var arrowPositions = [postion, zd];
+        // var arrow = viewer.entities.add({
+        //   polyline: {
+        //     positions: arrowPositions,
+        //     width: 10,
+        //     followSurface: false,
+        //     material: new Cesium.PolylineArrowMaterialProperty(
+        //       Cesium.Color.WHITE
+        //     ),
+        //   },
+        // });
+        // viewer.entities.add({
+        //   polyline: {
+        //     positions: [postion, zd],
+        //     width: 5,
+        //     material: isLineOfSightClear
+        //       ? Cesium.Color.GREEN
+        //       : Cesium.Color.RED,
+        //   },
+        // });
+
+        //pickFromRay(postion,sunposition2);
+      }
+    }
+
+    return postions;
+  },
+  jiance(startPoint, endPoint) {
+    var scene = viewer.scene;
+    var ray = new Cesium.Ray(
+      startPoint,
+      Cesium.Cartesian3.subtract(endPoint, startPoint, new Cesium.Cartesian3())
+    );
+
+    var result = scene.pickFromRay(ray);
+    if (result) {
+      // console.log("在阴影中", result);
+      return false;
+    } else {
+      // console.log("不在阴影中");
+      return true;
+    }
+  },
+  //计算日照时间范围
+  calculateTime(selDate, startTime, endTime) {
+    var sunriseDate = SunriseSunsetJS.getSunrise(
+      18.31723463241332,
+      109.5112252162011,
+      selDate
+    );
+    var sunsetdate = SunriseSunsetJS.getSunset(
+      18.31723463241332,
+      109.5112252162011,
+      selDate
+    );
+    //参与计算的日出日落时间
+    var jssunriseHours = 0;
+    var jssunsetHours = 0;
+    //日出时间
+    var sunriseHours = sunriseDate.getHours() + sunriseDate.getMinutes() / 60;
+    //日落时间
+    var sunsetHours = sunsetdate.getHours() + sunsetdate.getMinutes() / 60;
+
+    if (startTime > sunriseHours) jssunriseHours = startTime;
+    else jssunriseHours = sunriseHours;
+
+    if (endTime > sunsetHours) jssunsetHours = sunsetHours;
+    else jssunsetHours = endTime;
+    return { jssunriseHours: jssunriseHours, jssunsetHours: jssunsetHours };
+  },
+};
+export default SunshineAnalysisBySXJS;

+ 323 - 0
src/views/ConstructionApplication3D/SunlightAnalysis/SunshineAnalysisSDT.js

@@ -0,0 +1,323 @@
+const SunshineAnalysisByJS = {
+  //第一个是要分析的点的位置(是世界坐标)
+  //date(日期),经纬度,startTime是开始时间,endTime是结束时间,这里经纬度不传值的话默认是前面的要日照分析的点。,date,startTime,endTime
+  PointSunshineAnalysis(postion) {
+    viewer.scene.globe.depthTestAgainstTerrain = true;
+    viewer.entities.remove(viewer.entities.getById("1"));
+    viewer.entities.remove(viewer.entities.getById("point"));
+
+    //第二步,获取太阳的世界坐标,这里获取太阳的坐标的做法是很傻的,现在做一个函数,根据日期,时间,来推算出太阳高度角和太阳俯视角
+    console.log(postion.x + "  " + postion.y);
+    if (!viewer.scene.sun.show) {
+      SunshineAnalysis.OpenSun();
+    }
+    //1、获取太阳位置的方法
+    //var sunPostion = Cesium.Simon1994PlanetaryPositions.computeSunPositionInEarthInertialFrame(date);地球为中心的坐标系下的太阳位置
+
+    var sunposition2 = viewer.scene.context.uniformState.sunPositionWC; //这个应该是贴图的位置,
+    console.log(sunposition2.x + "  " + sunposition2.y);
+    var fx = new Cesium.Cartesian3(
+      sunposition2.x - postion.x,
+      sunposition2.y - postion.y,
+      sunposition2.z - postion.z
+    );
+    var dec = Math.sqrt(fx.x * fx.x + fx.y * fx.y + fx.z * fx.z);
+    var fxxl = new Cesium.Cartesian3(fx.x / dec, fx.y / dec, fx.z / dec); //方向向量
+    var changdu = 200;
+    var zd = new Cesium.Cartesian3(
+      postion.x + changdu * fxxl.x,
+      postion.y + changdu * fxxl.y,
+      postion.z + changdu * fxxl.z
+    );
+    //第三步,做射线,
+    var arrowPositions = [postion, zd];
+    var arrow = viewer.entities.add({
+      id: "1",
+      polyline: {
+        positions: arrowPositions,
+        width: 10,
+        followSurface: false,
+        material: new Cesium.PolylineArrowMaterialProperty(Cesium.Color.WHITE),
+      },
+    });
+    //第四步,一天进行日照分析,如果线之间被隔断,就认为该点被阻挡了
+
+    SunshineAnalysisByJS.jiance(postion, zd);
+    //pickFromRay(postion,sunposition2);
+  },
+  jiance(start, end) {
+    var num = 100;
+    var isshowders = false;
+    var rad1 = Cesium.Cartographic.fromCartesian(start);
+    var rad2 = Cesium.Cartographic.fromCartesian(end); //开始节点和结束节点转换为以弧度计算的经纬度
+    var points = [];
+    //这里表示插值函数,start和end是起始点,然后进行插值,检测高程,如果获取的地面点比差值点的高程高的话就代表有焦点
+    //坐标转经纬度
+    let startpoint = {};
+    startpoint.longitude = (rad1.longitude / Math.PI) * 180;
+    startpoint.latitude = (rad1.latitude / Math.PI) * 180;
+    startpoint.czheight = rad1.height; //将开始节点转换为角度的点
+    let endpoint = {};
+    endpoint.longitude = (rad2.longitude / Math.PI) * 180;
+    endpoint.latitude = (rad2.latitude / Math.PI) * 180;
+    endpoint.czheight = rad2.height; //将结束节点节点转换为角度的点
+    for (var i = 0; i < num; i++) {
+      let point = {};
+      point.longitude = Cesium.Math.lerp(
+        startpoint.longitude,
+        endpoint.longitude,
+        0.01 * (i + 1)
+      );
+      point.latitude = Cesium.Math.lerp(
+        startpoint.latitude,
+        endpoint.latitude,
+        0.01 * (i + 1)
+      );
+      point.czheight =
+        startpoint.czheight -
+        (startpoint.czheight - endpoint.czheight) * 0.01 * (i + 1);
+      var terCartographic = new Cesium.Cartographic(
+        Cesium.Math.toRadians(point.longitude),
+        Cesium.Math.toRadians(point.latitude),
+        0
+      ); //转经纬度对像
+      var cartographichight = viewer.scene.sampleHeight(terCartographic); //坐标点获取建筑物高程
+
+      var cartographic = Cesium.Cartesian3.fromDegrees(
+        point.longitude,
+        point.latitude,
+        cartographichight
+      ); //经纬度转世界坐标
+      viewer.entities.add({
+        position: cartographic,
+        point: {
+          pixelSize: 4,
+          color: Cesium.Color.RED,
+          outlineColor: Cesium.Color.BLACK,
+          outlineWidth: 2,
+        },
+      });
+      point.zsheight = cartographichight; //真实点的高程
+      if (point.zsheight > point.czheight) {
+        isshowders = true;
+      }
+      points.push(point);
+    }
+    if (isshowders) console.log("在阴影中");
+    else console.log("不在阴影中");
+    console.log(points);
+  },
+  Pointxyz(positions) {
+    positions = Cesium.Cartesian3.fromDegreesArrayHeights(
+      [].concat.apply([], positions)
+    );
+    let offscreenCamera = SunshineAnalysisByJS.createOffscreenCamera(positions);
+    const depthTextureSize = 100;
+    let picking = SunshineAnalysisByJS.creatPicking(offscreenCamera);
+
+    // var sdsdsd = SunshineAnalysisByJS.offscreenRender(offscreenCamera, picking);
+    var ray = new Cesium.Ray(
+      offscreenCamera.position,
+      offscreenCamera.direction
+    );
+    var sdfsdf = SunshineAnalysisByJS.pickPositions(
+      ray,
+      picking,
+      viewer.scene,
+      100,
+      100,
+      depthTextureSize,
+      offscreenCamera,
+      positions
+    );
+    var sfsdf = sdfsdf;
+  },
+  createOffscreenCamera(positions) {
+    //创建相机 (正交投影)
+    const offscreenCamera = new Cesium.Camera(viewer.scene);
+    //设置相机的位置
+    let center = new Cesium.Cartesian3();
+    let n = positions.length;
+    let centerPosition = new Cesium.Cartesian3();
+    positions.forEach((p) => {
+      centerPosition = Cesium.Cartesian3.add(centerPosition, p, centerPosition);
+    });
+    centerPosition = Cesium.Cartesian3.multiplyByScalar(
+      centerPosition,
+      1 / n,
+      centerPosition
+    ); //中心点
+
+    //获取中心点的法线
+    let normal = Cesium.Ellipsoid.WGS84.geodeticSurfaceNormal(centerPosition);
+    //中心点向上平移5000米
+    centerPosition = Cesium.Cartesian3.add(
+      centerPosition,
+      Cesium.Cartesian3.multiplyByScalar(normal, 5000, new Cesium.Cartesian3()),
+      centerPosition
+    );
+    offscreenCamera.position = centerPosition;
+    //相机方向 从上往下看
+    offscreenCamera.direction = Cesium.Cartesian3.negate(normal, normal);
+
+    //设置相机上方向 (这里使用类似正北的方向)
+    let d = Cesium.Cartographic.fromCartesian(centerPosition);
+    let up = Cesium.Cartesian3.subtract(
+      Cesium.Cartesian3.fromRadians(d.longitude, d.latitude + 0.005, d.height),
+      centerPosition,
+      new Cesium.Cartesian3()
+    );
+    up = Cesium.Cartesian3.normalize(up, up);
+    offscreenCamera.up = up;
+    // offscreenCamera.frustum.aspectRatio = 1;
+    // offscreenCamera.frustum.near = 0.1;
+    // offscreenCamera.frustum.far = 10000;
+    // offscreenCamera.frustum = new Cesium.OrthographicFrustum({
+    //   width: 1000,
+    //   aspectRatio: 1,
+    //   near: 0.1,
+    //   far: 10000,
+    // });
+
+    //可视化相机
+    viewer.scene.primitives.add(
+      new Cesium.DebugCameraPrimitive({
+        camera: offscreenCamera,
+        color: Cesium.Color.BLUE,
+        updateOnChange: false, //不更新
+        show: true,
+      })
+    );
+
+    return offscreenCamera;
+  },
+  creatPicking(offscreenCamera) {
+    const picking = new Cesium.Picking(viewer.scene);
+    const view = picking._pickOffscreenView;
+
+    view.camera = offscreenCamera;
+    return picking;
+  },
+  offscreenRender(camera, picking) {
+    const { scene } = viewer;
+    const { context, frameState } = scene;
+    const view = picking._pickOffscreenView;
+    let sceneView = scene.view;
+    scene.view = view;
+    var scratchRectangle = new Cesium.BoundingRectangle(); // 创建一个新的空矩形
+
+    Cesium.BoundingRectangle.clone(view.viewport, scratchRectangle);
+    const passState = view.pickFramebuffer.begin(
+      scratchRectangle,
+      view.viewport
+    );
+    scene.jobScheduler.disableThisFrame();
+    scene.updateFrameState();
+    frameState.invertClassification = false;
+    frameState.passes.pick = true;
+    frameState.passes.offscreen = true;
+    var pickTilesetPassState = new Cesium.Cesium3DTilePassState({
+      pass: Cesium.Cesium3DTilePass.RENDER,
+    });
+
+    frameState.tilesetPassState = pickTilesetPassState;
+    context.uniformState.update(frameState);
+    scene.updateEnvironment();
+    scene.updateAndExecuteCommands(passState, Cesium.Color.TRANSPARENT);
+    scene.resolveFramebuffers(passState);
+
+    var ray = new Cesium.Ray(camera.position, camera.direction);
+
+    scene.view = sceneView;
+    context.endFrame();
+
+    return positions;
+  },
+  pickPositions(
+    ray,
+    picking,
+    scene,
+    width,
+    height,
+    depthTextureSize,
+    offscreenCamera,
+    positions
+  ) {
+    const res = [];
+    const { context } = scene;
+    if (!context.depthTexture) {
+      return res;
+    }
+    const view = picking._pickOffscreenView;
+    const { camera } = view;
+    const numFrustums = view.frustumCommandsList.length;
+    const offset = new Cesium.Cartesian3();
+    for (let i = 0; i < numFrustums; ++i) {
+      // 获取每个视锥体的深度缓存
+      const pickDepth = picking.getPickDepth(scene, i);
+      const depths = SunshineAnalysisByJS.getDepths(
+        context,
+        0,
+        0,
+        depthTextureSize,
+        depthTextureSize,
+        pickDepth.framebuffer
+      );
+
+      for (let j = 0, len = depths.length; j < len; j++) {
+        const depth = depths[j];
+        if (Cesium.defined(depth) && depth > 0.0 && depth < 1.0) {
+          // 根据视锥体远近截面计算出相机到物体表面的距离
+          const renderedFrustum = view.frustumCommandsList[i];
+          const near =
+            renderedFrustum.near *
+            (j !== 0 ? scene.opaqueFrustumNearOffset : 1.0);
+
+          // const point = new Cesium.Cartesian3();
+          // Cesium.Cartesian3.multiplyByScalar(camera.up, rowScalar, offset);
+          // Cesium.Cartesian3.add(offset, camera.position, point);
+          // Cesium.Cartesian3.multiplyByScalar(
+          //   camera.right,
+          //   columnScalar,
+          //   offset
+          // );
+          // Cesium.Cartesian3.add(offset, point, point);
+
+          // // 利用射线获取坐标高程
+          // const clonedRay = Cesium.Ray.clone(ray);
+          // clonedRay.origin = point;
+          // const position = Cesium.Ray.getPoint(clonedRay, distance);
+
+          // if (!res[j]) {
+          //   res[j] = position;
+          // }
+        }
+      }
+    }
+    return res;
+  },
+
+  getDepths(context, x, y, width, height, framebuffer) {
+    const packedDepthScale = new Cesium.Cartesian4(
+      1.0,
+      1.0 / 255.0,
+      1.0 / 65025.0,
+      1.0 / 16581375.0
+    ); // 1, 1 / 255, 1 / (255^2), 1 / (255^3)
+    // 获取颜深度缓存中的所有像素值
+    const pixels = context.readPixels({
+      x,
+      y,
+      width,
+      height,
+      framebuffer,
+    });
+    const packedDepthArray = Cesium.Cartesian4.unpackArray(pixels);
+    //像素值转深度值
+    return packedDepthArray.map((t) => {
+      Cesium.Cartesian4.divideByScalar(t, 255.0, t);
+      return Cesium.Cartesian4.dot(t, packedDepthScale);
+    });
+  },
+};
+export default SunshineAnalysisByJS;

+ 710 - 0
src/views/ConstructionApplication3D/SunlightAnalysis/SunshineAnalysisSDTSD.js

@@ -0,0 +1,710 @@
+//深度图中心坐标SunshineAnalysisSDTSD
+import {
+  intersect,
+  flatten,
+  envelope,
+  point,
+  buffer,
+  bboxPolygon,
+  bbox,
+  square,
+  destination,
+  polygon,
+  featureCollection,
+  interpolate,
+  isobands,
+  area,
+  isolines,
+  pointGrid,
+} from "@turf/turf";
+import {
+  cartesian3ToWGS84,
+  mapQuery,
+  mercator2lonLat,
+  undergroundMode,
+  getXYZPoint,
+} from "@/utils/MapHelper/MapHelper.js";
+const SunshineAnalysisByJS = {
+  /**
+   * 计算边界
+   */
+  squarePolygon(entitys) {
+    if (entitys[0] != entitys[entitys.length]) {
+      entitys.push(entitys[0]);
+    }
+    let thispolygon = polygon([entitys]);
+    // 初始化边界框变量
+    let minX = Infinity,
+      minY = Infinity,
+      maxX = -Infinity,
+      maxY = -Infinity;
+
+    // 遍历每个多边形,计算其边界框,并更新最小/最大坐标
+
+    const thisbbox = bbox(thispolygon);
+    minX = Math.min(minX, thisbbox[0]);
+    minY = Math.min(minY, thisbbox[1]);
+    maxX = Math.max(maxX, thisbbox[2]);
+    maxY = Math.max(maxY, thisbbox[3]);
+
+    return { minX, minY, maxX, maxY };
+  },
+  Pointxyz(positions) {
+    var sfsd = SunshineAnalysisByJS.squarePolygon(positions);
+    positions = Cesium.Cartesian3.fromDegreesArrayHeights(
+      [].concat.apply([], positions)
+    );
+    //设置相机的位置
+    let n = positions.length;
+    let centerCartesian = new Cesium.Cartesian3();
+    positions.forEach((p) => {
+      centerCartesian = Cesium.Cartesian3.add(
+        centerCartesian,
+        p,
+        centerCartesian
+      );
+    });
+    centerCartesian = Cesium.Cartesian3.multiplyByScalar(
+      centerCartesian,
+      1 / n,
+      centerCartesian
+    ); //中心点
+
+    const southwest = Cesium.Cartographic.fromDegrees(
+      sfsd.minX,
+      sfsd.minY,
+      0 // 经度, 纬度, 高程
+    );
+    const northeast = Cesium.Cartographic.fromDegrees(sfsd.maxX, sfsd.maxY, 0);
+    const ellipsoid = Cesium.Ellipsoid.WGS84;
+    // 计算西南角和东北角的笛卡尔坐标
+    const minCartesian = ellipsoid.cartographicToCartesian(southwest);
+    const maxCartesian = ellipsoid.cartographicToCartesian(northeast);
+
+    var widthMeters = Cesium.Cartesian3.distance(
+      minCartesian,
+      new Cesium.Cartesian3(minCartesian.x, maxCartesian.y, minCartesian.z)
+    );
+    var heightMeters = widthMeters;
+    // 3. 创建正交相机
+    const cameraHeight = Math.max(widthMeters, heightMeters) * 2;
+    const offscreenCamera = new Cesium.Camera(viewer.scene);
+    offscreenCamera.position = Cesium.Cartesian3.add(
+      centerCartesian,
+      Cesium.Cartesian3.multiplyByScalar(
+        Cesium.Cartesian3.normalize(centerCartesian, new Cesium.Cartesian3()),
+        ellipsoid.maximumRadius + cameraHeight,
+        new Cesium.Cartesian3()
+      ),
+      new Cesium.Cartesian3()
+    );
+    const upDirection = ellipsoid.geodeticSurfaceNormal(centerCartesian);
+    offscreenCamera.lookAt(centerCartesian, upDirection);
+    offscreenCamera.frustum = new Cesium.OrthographicFrustum({
+      width: widthMeters,
+      aspectRatio: widthMeters / heightMeters,
+      near: 0.1,
+      far: cameraHeight * 2,
+    });
+
+    viewer.scene.primitives.add(
+      new Cesium.DebugCameraPrimitive({
+        camera: offscreenCamera,
+        color: Cesium.Color.BLUE,
+        updateOnChange: false, //不更新
+        show: true,
+      })
+    );
+
+    // 4. 渲染深度图
+    const context = viewer.scene.context;
+    const depthTexture = new Cesium.Texture({
+      context,
+      width: 1024,
+      height: 1024,
+      pixelFormat: Cesium.PixelFormat.DEPTH_COMPONENT,
+      pixelDatatype: Cesium.PixelDatatype.UNSIGNED_SHORT,
+    });
+    const framebuffer = new Cesium.Framebuffer({ context, depthTexture });
+    // viewer.scene.renderForSpecs(offscreenCamera, framebuffer);
+
+    // 5. 读取深度数据并转换
+    const pixels = new Uint16Array(1024 * 1024);
+    context.readPixels({
+      framebuffer,
+      x: 0,
+      y: 0,
+      width: 1024,
+      height: 1024,
+      pixelFormat: Cesium.PixelFormat.DEPTH_COMPONENT,
+      pixelDatatype: Cesium.PixelDatatype.UNSIGNED_SHORT,
+      data: pixels,
+    });
+
+    const viewMatrix = offscreenCamera.viewMatrix;
+    const projectionMatrix = offscreenCamera.frustum.projectionMatrix;
+    const inverseViewProj = Cesium.Matrix4.multiply(
+      projectionMatrix,
+      viewMatrix,
+      new Cesium.Matrix4()
+    );
+    Cesium.Matrix4.inverse(inverseViewProj, inverseViewProj);
+
+    // 转换中心像素
+    const x = 512,
+      y = 512;
+    const depth = pixels[y * 1024 + x];
+    const depthNormalized = depth / 65535.0;
+    const zNDC = depthNormalized * 2.0 - 1.0;
+    const xNDC = (x / 1024) * 2.0 - 1.0;
+    const yNDC = ((1024 - y) / 1024) * 2.0 - 1.0;
+
+    const positionNDC = new Cesium.Cartesian4(xNDC, yNDC, zNDC, 1.0);
+    const positionWorld = Cesium.Matrix4.multiplyByVector(
+      inverseViewProj,
+      positionNDC,
+      new Cesium.Cartesian4()
+    );
+    const worldCartesian = new Cesium.Cartesian3(
+      positionWorld.x / positionWorld.w,
+      positionWorld.y / positionWorld.w,
+      positionWorld.z / positionWorld.w
+    );
+
+    var labelentity = new Cesium.Entity({
+      position: worldCartesian,
+      point: {
+        // 点的大小(像素)
+        pixelSize: 10,
+        // 点位颜色,fromCssColorString 可以直接使用CSS颜色
+        color: Cesium.Color.RED,
+        // 边框颜色
+        outlineColor: Cesium.Color.fromCssColorString("#fff"),
+        // 边框宽度(像素)
+        outlineWidth: 2,
+        // 显示在距相机的距离处的属性,多少区间内是可以显示的
+        distanceDisplayCondition: new Cesium.DistanceDisplayCondition(0, 1500),
+        // 是否显示
+        show: true,
+      },
+      label: {
+        show: true,
+        text: "观察点",
+        font: "15px sans-serif",
+        pixelOffset: new Cesium.Cartesian2(0, -20), //文字偏移
+        fillColor: Cesium.Color.RED,
+        // backgroundColor:new Cesium.Color(0, 0, 0, 1),
+
+        disableDepthTestDistance: Number.POSITIVE_INFINITY,
+      },
+    });
+    viewer.entities.add(labelentity);
+    viewer.flyTo(labelentity);
+    const cartographic = ellipsoid.cartesianToCartographic(worldCartesian);
+    console.log(
+      `World Coordinate: ${Cesium.Math.toDegrees(cartographic.longitude)}, 
+   ${Cesium.Math.toDegrees(cartographic.latitude)}, 
+   ${cartographic.height}`
+    );
+  },
+
+  scratchRight: new Cesium.Cartesian3(),
+  scratchUp: new Cesium.Cartesian3(),
+  offscreenDefaultWidth: 0.1,
+  scratchRectangle: new Cesium.BoundingRectangle(0.0, 0.0, 3.0, 3.0),
+  scratchPosition: new Cesium.Cartesian2(),
+  scratchColorZero: new Cesium.Color(0.0, 0.0, 0.0, 0.0),
+
+  pickTilesetPassState: new Cesium.Cesium3DTilePassState({
+    pass: Cesium.Cesium3DTilePass.PICK,
+  }),
+  Pointxyz1() {
+    viewer.entities.removeAll();
+    //首先创建一个Picking对象
+    let picking = new Cesium.Picking(viewer.scene);
+    //然后创建一条射线 这里使用相机方向作为射线
+    let ray = new Cesium.Ray(viewer.camera.position, viewer.camera.direction);
+    let result = SunshineAnalysisByJS.getRayIntersection(
+      picking,
+      viewer.scene,
+      ray,
+      [],
+      0.1,
+      true
+    );
+    if (!result.position) return;
+
+    //显示结果
+    viewer.entities.add({
+      position: result.position,
+      point: {
+        pixelSize: 10,
+        color: Cesium.Color.RED,
+      },
+    });
+
+    //显示射线
+    viewer.entities.add({
+      polyline: {
+        positions: [viewer.camera.position, result.position],
+        width: 10,
+        material: new Cesium.PolylineArrowMaterialProperty(Cesium.Color.YELLOW),
+      },
+    });
+  },
+  Picking(scene) {
+    this._mostDetailedRayPicks = [];
+    this.pickRenderStateCache = {};
+    this._pickPositionCache = {};
+    this._pickPositionCacheDirty = false;
+
+    const pickOffscreenViewport = new BoundingRectangle(0, 0, 1, 1);
+    const pickOffscreenCamera = new Camera(scene);
+    pickOffscreenCamera.frustum = new OrthographicFrustum({
+      width: SunshineAnalysisByJS.offscreenDefaultWidth,
+      aspectRatio: 1.0,
+      near: 0.1,
+    });
+
+    this._pickOffscreenView = new View(
+      scene,
+      pickOffscreenCamera,
+      pickOffscreenViewport
+    );
+  },
+  getRayIntersection(
+    picking,
+    scene,
+    ray,
+    objectsToExclude,
+    width,
+    requirePosition,
+    mostDetailed
+  ) {
+    const { context, frameState } = scene;
+    const uniformState = context.uniformState;
+
+    const view = picking._pickOffscreenView;
+    scene.view = view;
+
+    SunshineAnalysisByJS.updateOffscreenCameraFromRay(
+      picking,
+      ray,
+      width,
+      view.camera
+    );
+
+    const drawingBufferRectangle = Cesium.BoundingRectangle.clone(
+      view.viewport,
+      SunshineAnalysisByJS.scratchRectangle
+    );
+
+    const passState = view.pickFramebuffer.begin(
+      drawingBufferRectangle,
+      view.viewport
+    );
+
+    scene.jobScheduler.disableThisFrame();
+
+    scene.updateFrameState();
+    frameState.invertClassification = false;
+    frameState.passes.pick = true;
+    frameState.passes.offscreen = true;
+
+    if (mostDetailed) {
+      frameState.tilesetPassState = mostDetailedPickTilesetPassState;
+    } else {
+      frameState.tilesetPassState = SunshineAnalysisByJS.pickTilesetPassState;
+    }
+
+    uniformState.update(frameState);
+
+    scene.updateEnvironment();
+    scene.updateAndExecuteCommands(
+      passState,
+      SunshineAnalysisByJS.scratchColorZero
+    );
+    scene.resolveFramebuffers(passState);
+
+    let position;
+    const object = view.pickFramebuffer.end(drawingBufferRectangle);
+
+    if (scene.context.depthTexture) {
+      const { frustumCommandsList } = view;
+      const numFrustums = frustumCommandsList.length;
+      for (let i = 0; i < numFrustums; ++i) {
+        const pickDepth = picking.getPickDepth(scene, i);
+        const depth = pickDepth.getDepth(context, 0, 0);
+        if (!depth) {
+          continue;
+        }
+        if (depth > 0.0 && depth < 1.0) {
+          const renderedFrustum = frustumCommandsList[i];
+          const near =
+            renderedFrustum.near *
+            (i !== 0 ? scene.opaqueFrustumNearOffset : 1.0);
+          const far = renderedFrustum.far;
+          const distance = near + depth * (far - near);
+          position = new Cesium.Ray.getPoint(ray, distance);
+          break;
+        }
+      }
+    }
+
+    scene.view = scene.defaultView;
+    context.endFrame();
+
+    if (object || position) {
+      return {
+        object: object,
+        position: position,
+        exclude: !position && requirePosition, //|| isExcluded(object, objectsToExclude),
+      };
+    }
+  },
+  updateOffscreenCameraFromRay(picking, ray, width, camera) {
+    const direction = ray.direction;
+    const orthogonalAxis = new Cesium.Cartesian3.mostOrthogonalAxis(
+      direction,
+      SunshineAnalysisByJS.scratchRight
+    );
+    const right = new Cesium.Cartesian3.cross(
+      direction,
+      orthogonalAxis,
+      SunshineAnalysisByJS.scratchRight
+    );
+    const up = new Cesium.Cartesian3.cross(
+      direction,
+      right,
+      SunshineAnalysisByJS.scratchUp
+    );
+
+    camera.position = ray.origin;
+    camera.direction = direction;
+    camera.up = up;
+    camera.right = right;
+
+    // camera.frustum.width = defaultValue(
+    //   width,
+    //   SunshineAnalysisByJS.offscreenDefaultWidth
+    // );
+    return camera.frustum.computeCullingVolume(
+      camera.positionWC,
+      camera.directionWC,
+      camera.upWC
+    );
+  },
+
+  positions: [],
+  offscreenCamera: null,
+  picking: null,
+  Pointxyz12(positions) {
+    SunshineAnalysisByJS.positions = Cesium.Cartesian3.fromDegreesArrayHeights(
+      [].concat.apply([], positions)
+    );
+    SunshineAnalysisByJS.offscreenCamera =
+      SunshineAnalysisByJS.createOffscreenCamera();
+    // SunshineAnalysisByJS.picking = SunshineAnalysisByJS.creatPicking();
+    // let result = SunshineAnalysisByJS.offscreenRender(
+    //   SunshineAnalysisByJS.picking._pickOffscreenView.camera,
+    //   SunshineAnalysisByJS.picking
+    // );
+
+    // if (!result.position) return;
+
+    // //显示结果
+    // viewer.entities.add({
+    //   position: result.position,
+    //   point: {
+    //     pixelSize: 10,
+    //     color: Cesium.Color.RED,
+    //   },
+    // });
+
+    // //显示射线
+    // viewer.entities.add({
+    //   polyline: {
+    //     positions: [viewer.camera.position, result.position],
+    //     width: 10,
+    //     material: new Cesium.PolylineArrowMaterialProperty(Cesium.Color.YELLOW),
+    //   },
+    // });
+  },
+  /**
+   * 首先需要设置离屏相机,一般将离屏相机设置在感兴趣的研究区域,从上往下看
+   * @returns
+   */
+  createOffscreenCamera() {
+    var sfsd = SunshineAnalysisByJS.squarePolygon(
+      SunshineAnalysisByJS.positions
+    );
+    const southwest = Cesium.Cartographic.fromDegrees(
+      sfsd.minX,
+      sfsd.minY,
+      0 // 经度, 纬度, 高程
+    );
+    const northeast = Cesium.Cartographic.fromDegrees(sfsd.maxX, sfsd.maxY, 0);
+    const ellipsoid = Cesium.Ellipsoid.WGS84;
+    // 计算西南角和东北角的笛卡尔坐标
+    const minCartesian = ellipsoid.cartographicToCartesian(southwest);
+    const maxCartesian = ellipsoid.cartographicToCartesian(northeast);
+
+    var widthMeters = Cesium.Cartesian3.distance(
+      minCartesian,
+      new Cesium.Cartesian3(minCartesian.x, maxCartesian.y, minCartesian.z)
+    );
+    var heightMeters = widthMeters;
+
+    //创建相机 (正交投影)
+    const offscreenCamera = new Cesium.Camera(viewer.scene);
+    //设置相机的位置
+    let n = SunshineAnalysisByJS.positions.length;
+    let centerPosition = new Cesium.Cartesian3();
+    SunshineAnalysisByJS.positions.forEach((p) => {
+      centerPosition = Cesium.Cartesian3.add(centerPosition, p, centerPosition);
+    });
+    centerPosition = Cesium.Cartesian3.multiplyByScalar(
+      centerPosition,
+      1 / n,
+      centerPosition
+    ); //中心点
+
+    //获取中心点的法线
+    let normal = Cesium.Ellipsoid.WGS84.geodeticSurfaceNormal(centerPosition);
+    //中心点向上平移5000米
+    centerPosition = Cesium.Cartesian3.add(
+      centerPosition,
+      Cesium.Cartesian3.multiplyByScalar(normal, 5000, new Cesium.Cartesian3()),
+      centerPosition
+    );
+    offscreenCamera.position = centerPosition;
+    //相机方向 从上往下看
+    offscreenCamera.direction = Cesium.Cartesian3.negate(normal, normal);
+
+    //设置相机上方向 (这里使用类似正北的方向)
+    let d = Cesium.Cartographic.fromCartesian(centerPosition);
+    let up = Cesium.Cartesian3.subtract(
+      Cesium.Cartesian3.fromRadians(d.longitude, d.latitude + 0.005, d.height),
+      centerPosition,
+      new Cesium.Cartesian3()
+    );
+    up = Cesium.Cartesian3.normalize(up, up);
+    offscreenCamera.up = up;
+
+    // offscreenCamera.frustum = new Cesium.OrthographicFrustum({
+    //   width: 100000,
+    //   aspectRatio: 1,
+    //   near: 1,
+    //   far: 10000,
+    // });
+
+    offscreenCamera.frustum = new Cesium.OrthographicFrustum({
+      width: widthMeters,
+      aspectRatio: widthMeters / heightMeters,
+      near: 0.1,
+      far: cameraHeight * 2,
+    });
+
+    // var frustum = new Cesium.OrthographicFrustum(
+    //   -100 / 2, // left
+    //   100 / 2, // right
+    //   -100 / (2 * 1), // bottom
+    //   100 / (2 * 1), // top
+    //   0.1, // near
+    //   10000 // far
+    // );
+    // offscreenCamera.frustum = frustum;
+
+    //可视化相机
+    viewer.scene.primitives.add(
+      new Cesium.DebugCameraPrimitive({
+        camera: offscreenCamera,
+        color: Cesium.Color.BLUE,
+        updateOnChange: false, //不更新
+        show: true,
+      })
+    );
+
+    return offscreenCamera;
+  },
+  /**
+   * 设置纹理大小
+     需要修改默认的纹理大小,使其能够存储多个值,在创建 Picking对象时设置其视口大小即可。
+   */
+  depthTextureSize: 100,
+  creatPicking() {
+    const picking = new Cesium.Picking(viewer.scene);
+    const view = picking._pickOffscreenView;
+    //...
+    view.camera = SunshineAnalysisByJS.offscreenCamera;
+    return picking;
+  },
+  /**
+   * 离屏渲染
+参考getRayIntersection方法,将离屏渲染的代码封装成一个方法,离屏渲染中使用自定义的相机。
+   * @param {*} camera 
+   * @param {*} picking 
+   * @returns 
+   */
+  offscreenRender(camera, picking) {
+    const { scene } = viewer;
+    const { context, frameState } = scene;
+    const view = picking._pickOffscreenView;
+    let sceneView = scene.view;
+    scene.view = view;
+    const drawingBufferRectangle = Cesium.BoundingRectangle.clone(
+      view.viewport,
+      SunshineAnalysisByJS.scratchRectangle
+    );
+    const passState = view.pickFramebuffer.begin(
+      SunshineAnalysisByJS.scratchRectangle,
+      view.viewport
+    );
+    scene.jobScheduler.disableThisFrame();
+    scene.updateFrameState();
+    frameState.invertClassification = false;
+    frameState.passes.pick = true;
+    frameState.passes.offscreen = true;
+    frameState.tilesetPassState = SunshineAnalysisByJS.pickTilesetPassState;
+    context.uniformState.update(frameState);
+    scene.updateEnvironment();
+    scene.updateAndExecuteCommands(passState, Cesium.Color.TRANSPARENT);
+    scene.resolveFramebuffers(passState);
+
+    const ray = new Cesium.Ray(camera.position, camera.direction);
+
+    let position;
+    const object = view.pickFramebuffer.end(drawingBufferRectangle);
+
+    if (scene.context.depthTexture) {
+      const { frustumCommandsList } = view;
+      const numFrustums = frustumCommandsList.length;
+      for (let i = 0; i < numFrustums; ++i) {
+        const pickDepth = picking.getPickDepth(scene, i);
+        const depth = pickDepth.getDepth(context, 0, 0);
+        if (!depth) {
+          continue;
+        }
+        if (depth > 0.0 && depth < 1.0) {
+          const renderedFrustum = frustumCommandsList[i];
+          const near =
+            renderedFrustum.near *
+            (i !== 0 ? scene.opaqueFrustumNearOffset : 1.0);
+          const far = renderedFrustum.far;
+          const distance = near + depth * (far - near);
+          position = new Cesium.Ray.getPoint(ray, distance);
+          break;
+        }
+      }
+    }
+
+    scene.view = sceneView;
+    context.endFrame();
+    if (object || position) {
+      return {
+        object: object,
+        position: position,
+        exclude: !position && requirePosition, //|| isExcluded(object, objectsToExclude),
+      };
+    }
+    // return positions;
+  },
+  /**
+ * 解析坐标值
+在渲染完成后就可以对坐标进行解析了,这里也将其封装成一个方法。
+ * @param {*} ray 
+ * @param {*} picking 
+ * @param {*} scene 
+ * @param {*} width 
+ * @param {*} height 
+ * @param {*} depthTextureSize 
+ * @returns 
+ */
+  pickPositions(ray, picking, scene, width, height, depthTextureSize) {
+    const res = [];
+    const { context } = scene;
+    if (!context.depthTexture) {
+      return res;
+    }
+    const view = picking._pickOffscreenView;
+    const { camera } = view;
+    const numFrustums = view.frustumCommandsList.length;
+    const offset = new Cesium.Cartesian3();
+    for (let i = 0; i < numFrustums; ++i) {
+      // 获取每个视锥体的深度缓存
+      const pickDepth = picking.getPickDepth(scene, i);
+      const depths = getDepths(
+        context,
+        0,
+        0,
+        depthTextureSize,
+        depthTextureSize,
+        pickDepth.framebuffer
+      );
+
+      for (let j = 0, len = depths.length; j < len; j++) {
+        const depth = depths[j];
+        if (Cesium.defined(depth) && depth > 0.0 && depth < 1.0) {
+          // 根据视锥体远近截面计算出相机到物体表面的距离
+          const renderedFrustum = view.frustumCommandsList[i];
+          const near =
+            renderedFrustum.near *
+            (j !== 0 ? scene.opaqueFrustumNearOffset : 1.0);
+          // ...
+          const point = new Cesium.Cartesian3();
+          Cesium.Cartesian3.multiplyByScalar(camera.up, rowScalar, offset);
+          Cesium.Cartesian3.add(offset, camera.position, point);
+          Cesium.Cartesian3.multiplyByScalar(
+            camera.right,
+            columnScalar,
+            offset
+          );
+          Cesium.Cartesian3.add(offset, point, point);
+
+          // 利用射线获取坐标高程
+          const clonedRay = Cesium.Ray.clone(ray);
+          clonedRay.origin = point;
+          const position = Cesium.Ray.getPoint(clonedRay, distance);
+
+          if (!res[j]) {
+            res[j] = position;
+          }
+        }
+      }
+    }
+    return res;
+  },
+  packedDepthScale: new Cesium.Cartesian4(
+    1.0,
+    1.0 / 255.0,
+    1.0 / 65025.0,
+    1.0 / 16581375.0
+  ), // 1, 1 / 255, 1 / (255^2), 1 / (255^3)
+  /**
+   * 方法中调用了一个getDepths方法,用于从深度图中获取深度数组,可以参考PickDepth.prototype.getDepth方法。
+   * @param {*} context
+   * @param {*} x
+   * @param {*} y
+   * @param {*} width
+   * @param {*} height
+   * @param {*} framebuffer
+   * @returns
+   */
+  getDepths(context, x, y, width, height, framebuffer) {
+    // 获取颜深度缓存中的所有像素值
+    const pixels = context.readPixels({
+      x,
+      y,
+      width,
+      height,
+      framebuffer,
+    });
+    const packedDepthArray = Cesium.Cartesian4.unpackArray(pixels);
+    //像素值转深度值
+    return packedDepthArray.map((t) => {
+      Cesium.Cartesian4.divideByScalar(t, 255.0, t);
+      return Cesium.Cartesian4.dot(t, packedDepthScale);
+    });
+  },
+};
+export default SunshineAnalysisByJS;

+ 322 - 0
src/views/ConstructionApplication3D/SunlightAnalysis/SunshineAnalysisdb.js

@@ -0,0 +1,322 @@
+import {
+  intersect,
+  flatten,
+  envelope,
+  point,
+  buffer,
+  bboxPolygon,
+  bbox,
+  square,
+  destination,
+  polygon,
+  featureCollection,
+  interpolate,
+  isobands,
+  area,
+  isolines,
+  pointGrid,
+} from "@turf/turf";
+import {
+  cartesian3ToWGS84,
+  mapQuery,
+  mercator2lonLat,
+  undergroundMode,
+  getXYZPoint,
+} from "@/utils/MapHelper/MapHelper.js";
+const SunshineAnalysisByJS = {
+  constructor(options = {}) {
+    viewer.scene.shadowMap.cascadesEnabled = false;
+    viewer.scene.debugShowShadowMap = true; // 显示阴影贴图
+    viewer.scene.debugShowShadowCameraFrustums = true; // 显示光源视锥体
+    this._scene = viewer.scene;
+    this._shadowMap = this._scene.shadowMap;
+
+    // 配置参数
+    this._textureSize = options.textureSize || 2048; // 阴影图分辨率
+    this._bias = options.bias || 0.1; // 阴影偏移量
+    this._depthData = null;
+    this._isCapturing = false;
+
+    // 初始化阴影设置
+    this._shadowMap.enabled = true;
+    this._shadowMap.size = this._textureSize;
+  },
+  /**
+   * 计算边界
+   */
+  squarePolygon(entitys) {
+    if (entitys[0] != entitys[entitys.length]) {
+      entitys.push(entitys[0]);
+    }
+    let thispolygon = polygon([entitys]);
+    // 初始化边界框变量
+    let minX = Infinity,
+      minY = Infinity,
+      maxX = -Infinity,
+      maxY = -Infinity;
+
+    // 遍历每个多边形,计算其边界框,并更新最小/最大坐标
+
+    const thisbbox = bbox(thispolygon);
+    minX = Math.min(minX, thisbbox[0]);
+    minY = Math.min(minY, thisbbox[1]);
+    maxX = Math.max(maxX, thisbbox[2]);
+    maxY = Math.max(maxY, thisbbox[3]);
+
+    return { minX, minY, maxX, maxY };
+  },
+  Pointxyz(positions, xyzs) {
+    positions = Cesium.Cartesian3.fromDegreesArrayHeights(
+      [].concat.apply([], positions)
+    );
+
+    SunshineAnalysisByJS.constructor({
+      textureSize: 2048, // 阴影图分辨率 (256/512/1024/2048/4096)
+      bias: 0.15, // 阴影偏移量,用于消除自阴影伪影
+    });
+
+    viewer.scene.primitives.add(
+      new Cesium.DebugCameraPrimitive({
+        camera: this._shadowMap._lightCamera,
+        color: Cesium.Color.BLUE,
+        updateOnChange: false, //不更新
+        show: true,
+      })
+    );
+
+    return;
+    SunshineAnalysisByJS.checkShadows(positions, xyzs);
+  },
+  // 捕获深度图并判断坐标
+  async checkShadows(position, xyzs) {
+    // 捕获单帧深度图
+    const success = await SunshineAnalysisByJS.captureDepthFrame();
+    if (!success) return;
+
+    // 定义测试坐标
+    // const positions = [
+    //   // Cesium.Cartesian3.fromDegrees(-75.59777, 40.03883, 1000),
+    //   // Cesium.Cartesian3.fromDegrees(-75.598, 40.039, 500),
+    //   // 更多坐标...
+    // ];
+    const positions = xyzs;
+
+    // 批量判断阴影状态
+    positions.forEach((pos) => {
+      console.log(`Position (${pos.x.toFixed(2)}, ${pos.y.toFixed(2)})`);
+      var sdf = SunshineAnalysisByJS.isPositionInShadow(pos)
+        ? "In Shadow"
+        : "Not in Shadow";
+
+      console.log(sdf);
+    });
+  },
+  /**
+   * 捕获当前帧的阴影深度图(单次)
+   * @returns {Promise<boolean>} 是否捕获成功
+   */
+  captureDepthFrame() {
+    return new Promise((resolve) => {
+      if (this._isCapturing) {
+        resolve(false);
+        return;
+      }
+
+      this._isCapturing = true;
+      this._depthData = null;
+
+      // 临时监听渲染事件
+      this.handler = this._scene.postRender.addEventListener(() => {
+        const texture = this._shadowMap._shadowMapTexture;
+        if (!texture) {
+          SunshineAnalysisByJS._cleanup(resolve, false);
+          return;
+        }
+
+        const context = this._scene.context;
+        const gl = context._gl;
+        const fb = this._shadowMap._framebuffer;
+
+        try {
+          gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
+          const pixels = new Uint16Array(texture.width * texture.height);
+          gl.readPixels(
+            0,
+            0,
+            texture.width,
+            texture.height,
+            gl.DEPTH_COMPONENT,
+            gl.UNSIGNED_SHORT,
+            pixels
+          );
+          this._depthData = pixels;
+          SunshineAnalysisByJS._cleanup(resolve, true);
+        } catch (error) {
+          console.error("Failed to read depth texture:", error);
+          SunshineAnalysisByJS._cleanup(resolve, false);
+        }
+      });
+    });
+  },
+
+  /**
+   * 判断指定坐标是否在阴影中
+   * @param {Cesium.Cartesian3} positionWC 世界坐标系下的位置
+   * @returns {boolean} 是否在阴影中
+   */
+  isPositionInShadow(positionWC) {
+    if (!this._depthData) {
+      console.warn("Depth data not captured. Call captureDepthFrame() first.");
+      return false;
+    }
+
+    const lightCamera = this._shadowMap._lightCamera;
+    const texture = this._shadowMap._shadowMapTexture;
+
+    const uvDepth = SunshineAnalysisByJS._worldToLightUV(
+      positionWC,
+      lightCamera
+    );
+
+    if (!uvDepth) return false;
+
+    // 计算纹理坐标
+    const pixelX = Math.floor(uvDepth.u * texture.width);
+    const pixelY = Math.floor(uvDepth.v * texture.height);
+    const index = pixelY * texture.width + pixelX;
+
+    if (index < 0 || index >= this._depthData.length) return false;
+
+    // 深度值处理
+    const textureDepth = this._depthData[index] / 65535; // 归一化
+    const near = lightCamera.frustum.near;
+    const far = lightCamera.frustum.far;
+    const linearDepth = textureDepth * (far - near) + near;
+
+    // 当前坐标深度
+    const currentDepth = uvDepth.depth * (far - near) + near;
+
+    return currentDepth > linearDepth + this._bias;
+  },
+
+  // 私有方法:清理捕获状态
+  _cleanup(resolve, success) {
+    this._scene.postRender.removeEventListener(this.handler);
+    this._isCapturing = false;
+    const context = this._scene.context;
+    const gl = context._gl;
+    gl.bindFramebuffer(gl.FRAMEBUFFER, null);
+    resolve(success);
+  },
+
+  // _worldToLightUV(positionWC, lightCamera) {
+  //   // 组合视图矩阵和投影矩阵
+  //   const viewMatrix = lightCamera.viewMatrix;
+  //   const projectionMatrix = lightCamera.frustum.projectionMatrix;
+  //   const viewProjectionMatrix = Cesium.Matrix4.multiply(
+  //     projectionMatrix,
+  //     viewMatrix,
+  //     new Cesium.Matrix4()
+  //   );
+
+  //   // 将世界坐标转换到光源裁剪空间
+  //   const positionH = Cesium.Matrix4.multiplyByVector(
+  //     viewProjectionMatrix,
+  //     Cesium.Cartesian4.fromElements(
+  //       positionWC.x,
+  //       positionWC.y,
+  //       positionWC.z,
+  //       1
+  //     ),
+  //     new Cesium.Cartesian4()
+  //   );
+
+  //   // 透视除法
+  //   const w = positionH.w;
+  //   if (w === 0) return null;
+  //   const ndc = new Cesium.Cartesian3(
+  //     positionH.x / w,
+  //     positionH.y / w,
+  //     positionH.z / w
+  //   );
+
+  //   // 视锥体裁剪检查
+  //   if (
+  //     ndc.x < -1 ||
+  //     ndc.x > 1 ||
+  //     ndc.y < -1 ||
+  //     ndc.y > 1 ||
+  //     ndc.z < 0 ||
+  //     ndc.z > 1
+  //   ) {
+  //     return null;
+  //   }
+
+  //   // 转换为UV坐标
+  //   return {
+  //     u: (ndc.x + 1) / 2,
+  //     v: 1 - (ndc.y + 1) / 2, // 翻转V轴
+  //     depth: ndc.z,
+  //   };
+  // },
+  _worldToLightUV(positionWC, lightCamera) {
+    // 1. 组合视图投影矩阵(注意顺序!)
+    const viewProjectionMatrix = Cesium.Matrix4.multiply(
+      lightCamera.frustum.projectionMatrix,
+      lightCamera.viewMatrix,
+      new Cesium.Matrix4()
+    );
+
+    // 2. 转换为齐次坐标(w=1)
+    const positionH = Cesium.Matrix4.multiplyByVector(
+      viewProjectionMatrix,
+      Cesium.Cartesian4.fromElements(
+        positionWC.x,
+        positionWC.y,
+        positionWC.z,
+        1
+      ),
+      new Cesium.Cartesian4()
+    );
+
+    // 3. 检查w分量
+    if (positionH.w === 0) {
+      console.error("坐标位于无限远或视锥体平面外");
+      return null;
+    }
+
+    // 4. 透视除法
+    const ndc = new Cesium.Cartesian3(
+      positionH.x / positionH.w,
+      positionH.y / positionH.w,
+      positionH.z / positionH.w
+    );
+
+    // 5. 视锥体裁剪检查
+    if (
+      ndc.x < -1 ||
+      ndc.x > 1 ||
+      ndc.y < -1 ||
+      ndc.y > 1 ||
+      ndc.z < 0 ||
+      ndc.z > 1
+    ) {
+      console.warn("坐标在光源视锥体外");
+      return null;
+    }
+
+    // 6. 转换为纹理UV
+    return {
+      u: (ndc.x + 1) / 2,
+      v: 1 - (ndc.y + 1) / 2,
+      depth: ndc.z,
+    };
+  },
+
+  // 销毁方法
+  destroy() {
+    this._depthData = null;
+    this._isCapturing = false;
+  },
+};
+export default SunshineAnalysisByJS;

+ 273 - 0
src/views/ConstructionApplication3D/SunlightAnalysis/ViewShed.js

@@ -0,0 +1,273 @@
+// ViewShed.js
+import glsl from "./glsl2";
+/**
+ * 可视域分析。
+ *
+ * @author Helsing
+ * @date 2020/08/28
+ * @alias ViewShedStage
+ * @class
+ * @param {Cesium.Viewer} viewer Cesium三维视窗。
+ * @param {Object} options 选项。
+ * @param {Cesium.Cartesian3} options.viewPosition 观测点位置。
+ * @param {Cesium.Cartesian3} options.viewPositionEnd 最远观测点位置(如果设置了观测距离,这个属性可以不设置)。
+ * @param {Number} options.viewDistance 观测距离(单位`米`,默认值100)。
+ * @param {Number} options.viewHeading 航向角(单位`度`,默认值0)。
+ * @param {Number} options.viewPitch 俯仰角(单位`度`,默认值0)。
+ * @param {Number} options.horizontalViewAngle 可视域水平夹角(单位`度`,默认值90)。
+ * @param {Number} options.verticalViewAngle 可视域垂直夹角(单位`度`,默认值60)。
+ * @param {Cesium.Color} options.visibleAreaColor 可视区域颜色(默认值`绿色`)。
+ * @param {Cesium.Color} options.invisibleAreaColor 不可视区域颜色(默认值`红色`)。
+ * @param {Boolean} options.enabled 阴影贴图是否可用。
+ * @param {Boolean} options.softShadows 是否启用柔和阴影。
+ * @param {Boolean} options.size 每个阴影贴图的大小。
+ */
+class ViewShed {
+  constructor(viewer, options) {
+    this.viewer = viewer;
+    this.viewPosition = options.viewPosition;
+    this.viewPositionEnd = options.viewPositionEnd;
+    this.viewDistance = this.viewPositionEnd
+      ? Cesium.Cartesian3.distance(this.viewPosition, this.viewPositionEnd)
+      : options.viewDistance || 100.0;
+    this.viewHeading = this.viewPositionEnd
+      ? this.getHeading(this.viewPosition, this.viewPositionEnd)
+      : options.viewHeading || 0.0;
+    this.viewPitch = this.viewPositionEnd
+      ? this.getPitch(this.viewPosition, this.viewPositionEnd)
+      : options.viewPitch || 0.0;
+    this.horizontalViewAngle = options.horizontalViewAngle || 90.0;
+    this.verticalViewAngle = options.verticalViewAngle || 60.0;
+    this.visibleAreaColor = options.visibleAreaColor || Cesium.Color.GREEN;
+    this.invisibleAreaColor = options.invisibleAreaColor || Cesium.Color.RED;
+    this.enabled =
+      typeof options.enabled === "boolean" ? options.enabled : true;
+    this.softShadows =
+      typeof options.softShadows === "boolean" ? options.softShadows : true;
+    this.size = options.size || 2048;
+
+    this.update();
+  }
+
+  add() {
+    this.createLightCamera();
+    this.createShadowMap();
+    this.createPostStage();
+    // this.drawFrustumOutine();
+    this.drawSketch();
+  }
+
+  update() {
+    this.clear();
+    this.add();
+  }
+
+  clear() {
+    if (this.sketch) {
+      this.viewer.entities.removeById(this.sketch.id);
+      this.sketch = null;
+    }
+    if (this.frustumOutline) {
+      this.frustumOutline.destroy();
+      this.frustumOutline = null;
+    }
+    if (this.postStage) {
+      this.viewer.scene.postProcessStages.remove(this.postStage);
+      this.postStage = null;
+    }
+  }
+
+  createLightCamera() {
+    this.lightCamera = new Cesium.Camera(this.viewer.scene);
+    this.lightCamera.position = this.viewPosition;
+    // if (this.viewPositionEnd) {
+    //     let direction = Cesium.Cartesian3.normalize(Cesium.Cartesian3.subtract(this.viewPositionEnd, this.viewPosition, new Cesium.Cartesian3()), new Cesium.Cartesian3());
+    //     this.lightCamera.direction = direction; // direction是相机面向的方向
+    // }
+    this.lightCamera.frustum.near = this.viewDistance * 0.001;
+    this.lightCamera.frustum.far = this.viewDistance;
+    const hr = Cesium.Math.toRadians(this.horizontalViewAngle);
+    const vr = Cesium.Math.toRadians(this.verticalViewAngle);
+    const aspectRatio =
+      (this.viewDistance * Math.tan(hr / 2) * 2) /
+      (this.viewDistance * Math.tan(vr / 2) * 2);
+    this.lightCamera.frustum.aspectRatio = aspectRatio;
+    if (hr > vr) {
+      this.lightCamera.frustum.fov = hr;
+    } else {
+      this.lightCamera.frustum.fov = vr;
+    }
+    this.lightCamera.setView({
+      destination: this.viewPosition,
+      orientation: {
+        heading: Cesium.Math.toRadians(this.viewHeading || 0),
+        pitch: Cesium.Math.toRadians(this.viewPitch || 0),
+        roll: 0,
+      },
+    });
+  }
+  createShadowMap() {
+    this.shadowMap = new Cesium.ShadowMap({
+      context: this.viewer.scene.context,
+      lightCamera: this.lightCamera,
+      enabled: this.enabled,
+      isPointLight: true,
+      pointLightRadius: this.viewDistance,
+      cascadesEnabled: false,
+      size: this.size,
+      softShadows: this.softShadows,
+      normalOffset: false,
+      fromLightSource: false,
+    });
+    this.viewer.scene.shadowMap = this.shadowMap;
+  }
+  createPostStage() {
+    const fs = glsl;
+    const postStage = new Cesium.PostProcessStage({
+      fragmentShader: fs,
+      uniforms: {
+        shadowMap_textureCube: () => {
+          this.shadowMap.update(Reflect.get(this.viewer.scene, "_frameState"));
+          return Reflect.get(this.shadowMap, "_shadowMapTexture");
+        },
+        shadowMap_matrix: () => {
+          this.shadowMap.update(Reflect.get(this.viewer.scene, "_frameState"));
+          return Reflect.get(this.shadowMap, "_shadowMapMatrix");
+        },
+        shadowMap_lightPositionEC: () => {
+          this.shadowMap.update(Reflect.get(this.viewer.scene, "_frameState"));
+          return Reflect.get(this.shadowMap, "_lightPositionEC");
+        },
+        shadowMap_normalOffsetScaleDistanceMaxDistanceAndDarkness: () => {
+          this.shadowMap.update(Reflect.get(this.viewer.scene, "_frameState"));
+          const bias = this.shadowMap._pointBias;
+          return Cesium.Cartesian4.fromElements(
+            bias.normalOffsetScale,
+            this.shadowMap._distance,
+            this.shadowMap.maximumDistance,
+            0.0,
+            new Cesium.Cartesian4()
+          );
+        },
+        shadowMap_texelSizeDepthBiasAndNormalShadingSmooth: () => {
+          this.shadowMap.update(Reflect.get(this.viewer.scene, "_frameState"));
+          const bias = this.shadowMap._pointBias;
+          const scratchTexelStepSize = new Cesium.Cartesian2();
+          const texelStepSize = scratchTexelStepSize;
+          texelStepSize.x = 1.0 / this.shadowMap._textureSize.x;
+          texelStepSize.y = 1.0 / this.shadowMap._textureSize.y;
+
+          return Cesium.Cartesian4.fromElements(
+            texelStepSize.x,
+            texelStepSize.y,
+            bias.depthBias,
+            bias.normalShadingSmooth,
+            new Cesium.Cartesian4()
+          );
+        },
+        camera_projection_matrix: this.lightCamera.frustum.projectionMatrix,
+        camera_view_matrix: this.lightCamera.viewMatrix,
+        helsing_viewDistance: () => {
+          return this.viewDistance;
+        },
+        helsing_visibleAreaColor: this.visibleAreaColor,
+        helsing_invisibleAreaColor: this.invisibleAreaColor,
+      },
+    });
+    this.postStage = this.viewer.scene.postProcessStages.add(postStage);
+  }
+  drawFrustumOutline() {
+    const scratchRight = new Cesium.Cartesian3();
+    const scratchRotation = new Cesium.Matrix3();
+    const scratchOrientation = new Cesium.Quaternion();
+    const position = this.lightCamera.positionWC;
+    const direction = this.lightCamera.directionWC;
+    const up = this.lightCamera.upWC;
+    let right = this.lightCamera.rightWC;
+    right = Cesium.Cartesian3.negate(right, scratchRight);
+    let rotation = scratchRotation;
+    Cesium.Matrix3.setColumn(rotation, 0, right, rotation);
+    Cesium.Matrix3.setColumn(rotation, 1, up, rotation);
+    Cesium.Matrix3.setColumn(rotation, 2, direction, rotation);
+    let orientation = Cesium.Quaternion.fromRotationMatrix(
+      rotation,
+      scratchOrientation
+    );
+
+    let instance = new Cesium.GeometryInstance({
+      geometry: new Cesium.FrustumOutlineGeometry({
+        frustum: this.lightCamera.frustum,
+        origin: this.viewPosition,
+        orientation: orientation,
+      }),
+      id: Math.random().toString(36).substr(2),
+      attributes: {
+        color: Cesium.ColorGeometryInstanceAttribute.fromColor(
+          Cesium.Color.YELLOWGREEN //new Cesium.Color(0.0, 1.0, 0.0, 1.0)
+        ),
+        show: new Cesium.ShowGeometryInstanceAttribute(true),
+      },
+    });
+
+    this.frustumOutline = this.viewer.scene.primitives.add(
+      new Cesium.Primitive({
+        geometryInstances: [instance],
+        appearance: new Cesium.PerInstanceColorAppearance({
+          flat: true,
+          translucent: false,
+        }),
+      })
+    );
+  }
+  drawSketch() {
+    this.sketch = this.viewer.entities.add({
+      name: "sketch",
+      position: this.viewPosition,
+      orientation: Cesium.Transforms.headingPitchRollQuaternion(
+        this.viewPosition,
+        Cesium.HeadingPitchRoll.fromDegrees(
+          this.viewHeading - this.horizontalViewAngle,
+          this.viewPitch,
+          0.0
+        )
+      ),
+      ellipsoid: {
+        radii: new Cesium.Cartesian3(
+          this.viewDistance,
+          this.viewDistance,
+          this.viewDistance
+        ),
+        // innerRadii: new Cesium.Cartesian3(2.0, 2.0, 2.0),
+        minimumClock: Cesium.Math.toRadians(-this.horizontalViewAngle / 2),
+        maximumClock: Cesium.Math.toRadians(this.horizontalViewAngle / 2),
+        minimumCone: Cesium.Math.toRadians(this.verticalViewAngle + 7.75),
+        maximumCone: Cesium.Math.toRadians(180 - this.verticalViewAngle - 7.75),
+        fill: false,
+        outline: true,
+        subdivisions: 256,
+        stackPartitions: 64,
+        slicePartitions: 64,
+        outlineColor: Cesium.Color.YELLOWGREEN,
+      },
+    });
+  }
+  getHeading(fromPosition, toPosition) {
+    let finalPosition = new Cesium.Cartesian3();
+    let matrix4 = Cesium.Transforms.eastNorthUpToFixedFrame(fromPosition);
+    Cesium.Matrix4.inverse(matrix4, matrix4);
+    Cesium.Matrix4.multiplyByPoint(matrix4, toPosition, finalPosition);
+    Cesium.Cartesian3.normalize(finalPosition, finalPosition);
+    return Cesium.Math.toDegrees(Math.atan2(finalPosition.x, finalPosition.y));
+  }
+
+  getPitch(fromPosition, toPosition) {
+    let finalPosition = new Cesium.Cartesian3();
+    let matrix4 = Cesium.Transforms.eastNorthUpToFixedFrame(fromPosition);
+    Cesium.Matrix4.inverse(matrix4, matrix4);
+    Cesium.Matrix4.multiplyByPoint(matrix4, toPosition, finalPosition);
+    Cesium.Cartesian3.normalize(finalPosition, finalPosition);
+    return Cesium.Math.toDegrees(Math.asin(finalPosition.z));
+  }
+}
+
+export default ViewShed;

+ 117 - 0
src/views/ConstructionApplication3D/SunlightAnalysis/glsl.js

@@ -0,0 +1,117 @@
+export default `
+varying vec2 v_textureCoordinates;
+uniform sampler2D colorTexture;
+uniform sampler2D depthTexture;
+uniform sampler2D shadowMap_texture;
+uniform mat4 shadowMap_matrix;
+uniform vec4 shadowMap_lightPositionEC;
+uniform vec4 shadowMap_normalOffsetScaleDistanceMaxDistanceAndDarkness;
+uniform vec4 shadowMap_texelSizeDepthBiasAndNormalShadingSmooth;
+uniform int helsing_textureType;
+uniform sampler2D helsing_texture;
+uniform float helsing_alpha;
+uniform vec4 helsing_visibleAreaColor;
+uniform vec4 helsing_invisibleAreaColor;
+vec4 toEye(in vec2 uv, in float depth){
+    vec2 xy = vec2((uv.x * 2.0 - 1.0),(uv.y * 2.0 - 1.0));
+    vec4 posInCamera =czm_inverseProjection * vec4(xy, depth, 1.0);
+    posInCamera =posInCamera / posInCamera.w;
+    return posInCamera;
+}
+float getDepth(in vec4 depth){
+    float z_window = czm_unpackDepth(depth);
+    z_window = czm_reverseLogDepth(z_window);
+    float n_range = czm_depthRange.near;
+    float f_range = czm_depthRange.far;
+    return (2.0 * z_window - n_range - f_range) / (f_range - n_range);
+}
+float _czm_sampleShadowMap(sampler2D shadowMap, vec2 uv){
+    return texture2D(shadowMap, uv).r;
+}
+float _czm_shadowDepthCompare(sampler2D shadowMap, vec2 uv, float depth){
+    return step(depth, _czm_sampleShadowMap(shadowMap, uv));
+}
+float _czm_shadowVisibility(sampler2D shadowMap, czm_shadowParameters shadowParameters){
+    float depthBias = shadowParameters.depthBias;
+    float depth = shadowParameters.depth;
+    float nDotL = shadowParameters.nDotL;
+    float normalShadingSmooth = shadowParameters.normalShadingSmooth;
+    float darkness = shadowParameters.darkness;
+    vec2 uv = shadowParameters.texCoords;
+    depth -= depthBias;
+    vec2 texelStepSize = shadowParameters.texelStepSize;
+    float radius = 1.0;
+    float dx0 = -texelStepSize.x * radius;
+    float dy0 = -texelStepSize.y * radius;
+    float dx1 = texelStepSize.x * radius;
+    float dy1 = texelStepSize.y * radius;
+    float visibility = (_czm_shadowDepthCompare(shadowMap, uv, depth)
+        + _czm_shadowDepthCompare(shadowMap, uv + vec2(dx0, dy0), depth)
+        + _czm_shadowDepthCompare(shadowMap, uv + vec2(0.0, dy0), depth)
+        + _czm_shadowDepthCompare(shadowMap, uv + vec2(dx1, dy0), depth)
+        + _czm_shadowDepthCompare(shadowMap, uv + vec2(dx0, 0.0), depth)
+        + _czm_shadowDepthCompare(shadowMap, uv + vec2(dx1, 0.0), depth)
+        + _czm_shadowDepthCompare(shadowMap, uv + vec2(dx0, dy1), depth)
+        + _czm_shadowDepthCompare(shadowMap, uv + vec2(0.0, dy1), depth)
+        + _czm_shadowDepthCompare(shadowMap, uv + vec2(dx1, dy1), depth)
+    ) * (1.0 / 9.0);
+    return visibility;
+}
+vec3 pointProjectOnPlane(in vec3 planeNormal, in vec3 planeOrigin, in vec3 point){
+    vec3 v01 = point -planeOrigin;
+    float d = dot(planeNormal, v01) ;
+    return (point - planeNormal * d);
+}
+void main(){
+    const float PI = 3.141592653589793;
+    vec4 color = texture2D(colorTexture, v_textureCoordinates);
+    vec4 currentDepth = texture2D(depthTexture, v_textureCoordinates);
+    if(currentDepth.r >= 1.0){
+        gl_FragColor = color;
+        return;
+    }
+    float depth = getDepth(currentDepth);
+    vec4 positionEC = toEye(v_textureCoordinates, depth);
+    vec3 normalEC = vec3(1.0);
+    czm_shadowParameters shadowParameters;
+    shadowParameters.texelStepSize = shadowMap_texelSizeDepthBiasAndNormalShadingSmooth.xy;
+    shadowParameters.depthBias = shadowMap_texelSizeDepthBiasAndNormalShadingSmooth.z;
+    shadowParameters.normalShadingSmooth = shadowMap_texelSizeDepthBiasAndNormalShadingSmooth.w;
+    shadowParameters.darkness = shadowMap_normalOffsetScaleDistanceMaxDistanceAndDarkness.w;
+    shadowParameters.depthBias *= max(depth * 0.01, 1.0);
+    vec3 directionEC = normalize(positionEC.xyz - shadowMap_lightPositionEC.xyz);
+    float nDotL = clamp(dot(normalEC, -directionEC), 0.0, 1.0);
+    vec4 shadowPosition = shadowMap_matrix * positionEC;
+    shadowPosition /= shadowPosition.w;
+    if (any(lessThan(shadowPosition.xyz, vec3(0.0))) || any(greaterThan(shadowPosition.xyz, vec3(1.0)))){
+        gl_FragColor = color;
+        return;
+    }
+    shadowParameters.texCoords = shadowPosition.xy;
+    shadowParameters.depth = shadowPosition.z;
+    shadowParameters.nDotL = nDotL;
+    float visibility = _czm_shadowVisibility(shadowMap_texture, shadowParameters);
+    if (helsing_textureType >1){ // 视频或图片模式
+        vec4 videoColor = texture2D(helsing_texture, shadowPosition.xy);
+        if (visibility == 1.0){
+            gl_FragColor =  mix(color, vec4(videoColor.xyz, 1.0), helsing_alpha * videoColor.a);
+        }
+        else{
+            if(abs(shadowPosition.z - 0.0) < 0.01){
+                return;
+            }
+            gl_FragColor = color;
+        }
+    }
+    else{ // 可视域模式
+        if (visibility == 1.0){
+            gl_FragColor = mix(color, vec4(0.,1.,0.,.5), helsing_alpha);
+        }
+        else{
+            if(abs(shadowPosition.z - 0.0) < 0.01){
+                return;
+            }
+            gl_FragColor = mix(color, vec4(0.,1.,0.,.5), helsing_alpha);
+        }
+    }
+}`;

+ 121 - 0
src/views/ConstructionApplication3D/SunlightAnalysis/glsl2.js

@@ -0,0 +1,121 @@
+export default `
+ #define USE_CUBE_MAP_SHADOW true
+ uniform sampler2D colorTexture;
+ uniform sampler2D depthTexture;
+ varying vec2 v_textureCoordinates;
+ uniform mat4 camera_projection_matrix;
+ uniform mat4 camera_view_matrix;
+ uniform samplerCube shadowMap_textureCube;
+ uniform mat4 shadowMap_matrix;
+ uniform vec4 shadowMap_lightPositionEC;
+ uniform vec4 shadowMap_normalOffsetScaleDistanceMaxDistanceAndDarkness;
+ uniform vec4 shadowMap_texelSizeDepthBiasAndNormalShadingSmooth;
+ uniform float helsing_viewDistance; 
+ uniform vec4 helsing_visibleAreaColor;
+ uniform vec4 helsing_invisibleAreaColor;
+ struct zx_shadowParameters
+ {
+     vec3 texCoords;
+     float depthBias;
+     float depth;
+     float nDotL;
+     vec2 texelStepSize;
+     float normalShadingSmooth;
+     float darkness;
+ };
+ float czm_shadowVisibility(samplerCube shadowMap, zx_shadowParameters shadowParameters)
+ {
+     float depthBias = shadowParameters.depthBias;
+     float depth = shadowParameters.depth;
+     float nDotL = shadowParameters.nDotL;
+     float normalShadingSmooth = shadowParameters.normalShadingSmooth;
+     float darkness = shadowParameters.darkness;
+     vec3 uvw = shadowParameters.texCoords;
+     depth -= depthBias;
+     float visibility = czm_shadowDepthCompare(shadowMap, uvw, depth);
+     return czm_private_shadowVisibility(visibility, nDotL, normalShadingSmooth, darkness);
+ }
+ vec4 getPositionEC(){
+     return czm_windowToEyeCoordinates(gl_FragCoord);
+ }
+ vec3 getNormalEC(){
+     return vec3(1.);
+ }
+ vec4 toEye(in vec2 uv,in float depth){
+     vec2 xy=vec2((uv.x*2.-1.),(uv.y*2.-1.));
+     vec4 posInCamera=czm_inverseProjection*vec4(xy,depth,1.);
+     posInCamera=posInCamera/posInCamera.w;
+     return posInCamera;
+ }
+ vec3 pointProjectOnPlane(in vec3 planeNormal,in vec3 planeOrigin,in vec3 point){
+     vec3 v01=point-planeOrigin;
+     float d=dot(planeNormal,v01);
+     return(point-planeNormal*d);
+ }
+ float getDepth(in vec4 depth){
+     float z_window=czm_unpackDepth(depth);
+     z_window=czm_reverseLogDepth(z_window);
+     float n_range=czm_depthRange.near;
+     float f_range=czm_depthRange.far;
+     return(2.*z_window-n_range-f_range)/(f_range-n_range);
+ }
+ float shadow(in vec4 positionEC){
+     vec3 normalEC=getNormalEC();
+     zx_shadowParameters shadowParameters;
+     shadowParameters.texelStepSize=shadowMap_texelSizeDepthBiasAndNormalShadingSmooth.xy;
+     shadowParameters.depthBias=shadowMap_texelSizeDepthBiasAndNormalShadingSmooth.z;
+     shadowParameters.normalShadingSmooth=shadowMap_texelSizeDepthBiasAndNormalShadingSmooth.w;
+     shadowParameters.darkness=shadowMap_normalOffsetScaleDistanceMaxDistanceAndDarkness.w;
+     vec3 directionEC=positionEC.xyz-shadowMap_lightPositionEC.xyz;
+     float distance=length(directionEC);
+     directionEC=normalize(directionEC);
+     float radius=shadowMap_lightPositionEC.w;
+     if(distance>radius)
+     {
+         return 2.0;
+     }
+     vec3 directionWC=czm_inverseViewRotation*directionEC;
+     shadowParameters.depth=distance/radius-0.0003;
+     shadowParameters.nDotL=clamp(dot(normalEC,-directionEC),0.,1.);
+     shadowParameters.texCoords=directionWC;
+     float visibility=czm_shadowVisibility(shadowMap_textureCube,shadowParameters);
+     return visibility;
+ }
+ bool visible(in vec4 result)
+ {
+     result.x/=result.w;
+     result.y/=result.w;
+     result.z/=result.w;
+     return result.x>=-1.&&result.x<=1.
+     &&result.y>=-1.&&result.y<=1.
+     &&result.z>=-1.&&result.z<=1.;
+ }
+ void main(){
+     // 釉色 = 结构二维(颜色纹理, 纹理坐标)
+     gl_FragColor = texture2D(colorTexture, v_textureCoordinates);
+     // 深度 = 获取深度(结构二维(深度纹理, 纹理坐标))
+     float depth = getDepth(texture2D(depthTexture, v_textureCoordinates));
+     // 视角 = (纹理坐标, 深度)
+     vec4 viewPos = toEye(v_textureCoordinates, depth);
+     // 世界坐标
+     vec4 wordPos = czm_inverseView * viewPos;
+     // 虚拟相机中坐标
+     vec4 vcPos = camera_view_matrix * wordPos;
+     float near = .001 * helsing_viewDistance;
+     float dis = length(vcPos.xyz);
+     if(dis > near && dis < helsing_viewDistance){
+         // 透视投影
+         vec4 posInEye = camera_projection_matrix * vcPos;
+         // 可视区颜色
+         // vec4 helsing_visibleAreaColor=vec4(0.,1.,0.,.5);
+         // vec4 helsing_invisibleAreaColor=vec4(1.,0.,0.,.5);
+         if(visible(posInEye)){
+             float vis = shadow(viewPos);
+             if(vis > 0.3){
+                 gl_FragColor = mix(gl_FragColor,helsing_visibleAreaColor,.5);
+             } else{
+                 gl_FragColor = mix(gl_FragColor,helsing_invisibleAreaColor,.5);
+             }
+         }
+     }
+ }`;

+ 176 - 0
src/views/ConstructionApplication3D/SunlightAnalysis/yytt.js

@@ -0,0 +1,176 @@
+import glsl from "./glsl";
+/**
+ * 阴影贴图
+ *
+ * @author Helsing
+ * @date 2020/08/28
+ * @alias ViewShedStage
+ * @class
+ * @param {Cesium.Viewer} viewer Cesium三维视窗。
+
+ */
+class yytt {
+  // 定义变量
+  /** 纹理类型:VIDEO、IMAGE、COLOR */
+  textureType;
+  /** 纹理 */
+  texture;
+  /** 观测点位置 */
+  viewPosition;
+  /** 最远观测点位置(如果设置了观测距离,这个属性可以不设置) */
+  viewPositionEnd;
+  // ...
+
+  // 构造函数
+  constructor(viewer, options) {
+    // super(viewer);
+    this.viewer = viewer;
+    // 纹理类型
+    this.textureType = options.textureType;
+    // 纹理地址(纹理为视频或图片的时候需要设置此项)
+    this.textureUrl = options.textureUrl;
+    // 观测点位置
+    this.viewPosition = options.viewPosition;
+    // 最远观测点位置(如果设置了观测距离,这个属性可以不设置)
+    this.viewPositionEnd = options.viewPositionEnd;
+
+    switch (this.textureType) {
+      default:
+      case VideoShed.TEXTURE_TYPE.VIDEO:
+        this.activeVideo();
+        break;
+      case VideoShed.TEXTURE_TYPE.IMAGE:
+        this.activePicture();
+        break;
+    }
+    this.refresh();
+    this.viewer.scene.primitives.add(this);
+  }
+
+  /**
+   * 投放视频。
+   *
+   * @author Helsing
+   * @date 2020/09/19
+   * @param {String} textureUrl 视频地址。
+   */
+  activeVideo(textureUrl = undefined) {
+    if (!textureUrl) {
+      textureUrl = this.textureUrl;
+    } else {
+      this.textureUrl = textureUrl;
+    }
+    const video = this.createVideoElement(textureUrl);
+    const that = this;
+    if (video /*&& !video.paused*/) {
+      this.activeVideoListener ||
+        (this.activeVideoListener = function () {
+          that.texture && that.texture.destroy();
+          that.texture = new Texture({
+            context: that.viewer.scene.context,
+            source: video,
+            width: 1,
+            height: 1,
+            pixelFormat: PixelFormat.RGBA,
+            pixelDatatype: PixelDatatype.UNSIGNED_BYTE,
+          });
+        });
+      that.viewer.clock.onTick.addEventListener(this.activeVideoListener);
+    }
+  }
+
+  /**
+   * 投放图片。
+   *
+   * @author Helsing
+   * @date 2020/09/19
+   * @param {String} textureUrl 图片地址。
+   */
+  activePicture(textureUrl = undefined) {
+    this.deActiveVideo();
+    if (!textureUrl) {
+      textureUrl = this.textureUrl;
+    } else {
+      this.textureUrl = textureUrl;
+    }
+    const that = this;
+    const img = new Image();
+    img.onload = function () {
+      that.textureType = VideoShed.TEXTURE_TYPE.IMAGE;
+      that.texture = new Texture({
+        context: that.viewer.scene.context,
+        source: img,
+      });
+    };
+    img.onerror = function () {
+      console.log("图片加载失败:" + textureUrl);
+    };
+    img.src = textureUrl;
+  }
+  /**
+   * 创建后期程序。
+   *
+   * @author Helsing
+   * @date 2020/09/19
+   * @ignore
+   */
+  addPostProcessStage() {
+    const that = this;
+    const bias = that.shadowMap._isPointLight
+      ? that.shadowMap._pointBias
+      : that.shadowMap._primitiveBias;
+    const postStage = new PostProcessStage({
+      fragmentShader: glsl,
+      uniforms: {
+        helsing_textureType: function () {
+          return that.textureType;
+        },
+        helsing_texture: function () {
+          return that.texture;
+        },
+        helsing_alpha: function () {
+          return that.alpha;
+        },
+        helsing_visibleAreaColor: function () {
+          return that.visibleAreaColor;
+        },
+        helsing_invisibleAreaColor: function () {
+          return that.invisibleAreaColor;
+        },
+        shadowMap_texture: function () {
+          return that.shadowMap._shadowMapTexture;
+        },
+        shadowMap_matrix: function () {
+          return that.shadowMap._shadowMapMatrix;
+        },
+        shadowMap_lightPositionEC: function () {
+          return that.shadowMap._lightPositionEC;
+        },
+        shadowMap_texelSizeDepthBiasAndNormalShadingSmooth: function () {
+          const t = new Cartesian2();
+          t.x = 1 / that.shadowMap._textureSize.x;
+          t.y = 1 / that.shadowMap._textureSize.y;
+          return Cartesian4.fromElements(
+            t.x,
+            t.y,
+            bias.depthBias,
+            bias.normalShadingSmooth,
+            that.combinedUniforms1
+          );
+        },
+        shadowMap_normalOffsetScaleDistanceMaxDistanceAndDarkness: function () {
+          return Cartesian4.fromElements(
+            bias.normalOffsetScale,
+            that.shadowMap._distance,
+            that.shadowMap.maximumDistance,
+            that.shadowMap._darkness,
+            that.combinedUniforms2
+          );
+        },
+      },
+    });
+    this.postProcessStage = this.viewer.scene.postProcessStages.add(postStage);
+  }
+}
+
+export default yytt;

+ 1 - 1
src/views/ConstructionApplication3D/ZBFXAnalysisinfo/ZBFXAnalysisinfo.vue

@@ -473,7 +473,7 @@ export default {
 
           TableData.push(LDLrow);
 
-          if (!rgzbData.id) {
+          if (!rgzbData.id && DKZBData.infoData) {
             rgzbData.id = rgzbid;
             rgzbData.zbcs = JSON.stringify(rgzb);
             //这里替换为后台添加表,现在纯前台,自动更新更新

+ 1 - 1
src/views/ConstructionApplication3D/backLineAnalysis/backLineAnalysisinfo.vue

@@ -13,7 +13,7 @@
         </div>
       </el-col>
     </el-row>
-    <el-row :gutter="10">
+    <el-row :gutter="10" v-if="TableData.length > 0">
       <el-col :span="24">
         <el-table
           ref="table"

+ 44 - 27
src/views/ConstructionApplication3D/billboard/billboardDesign.vue

@@ -371,25 +371,11 @@ export default {
     deleteBillard(model) {
       debugger;
       var that = this;
-      //  that.$layer.confirm("确定要删除当前广告吗?", {
-      //     btn: ['确定', '取消']     //按钮
-      //   }, function (layerid) {
-      //     that.$layer.close(layerid);
-      //     that.$layer.msg('已删除');
-      //   },
-      //     function (layerid) {
-      //       that.$layer.close(layerid);
-      //       that.$layer.msg('已取消');
-      //     });
-      // options,yes和cancel可以省略, 如果您不愿意写options,则可以直接写确定按钮的函数,即yes,或者覆盖默认的cancel方法。PS:yes和cancel方法不能互换
-      //content 可以为html
-      //yes,cancel如果是个function,这会自动添加参数layerid,
-      this.$confirm("确定要删除当前广告吗?, 是否继续?", "提示", {
-        confirmButtonText: "确定",
-        cancelButtonText: "取消",
-        type: "warning",
-      })
-        .then(async () => {
+      var confirmid = that.$layer.confirm(
+        "确定要删除当前广告吗?, 是否继续?",
+        {},
+        async function () {
+          that.$layer.close(confirmid);
           debugger;
           let result = await delZtBillboardInfoList(model.id);
           debugger;
@@ -402,15 +388,46 @@ export default {
               message: "删除成功",
               type: "success",
             });
+          } else {
+            that.getZtBillboardInfoList();
+            viewer.entities.removeAll();
+            that.$message({
+              message: "删除失败",
+              type: "error",
+            });
           }
-        })
-        .catch(() => {
-          debugger;
-          this.$message({
-            type: "info",
-            message: "已取消删除",
-          });
-        });
+        },
+        function () {
+          return;
+        }
+      );
+      // this.$confirm("确定要删除当前广告吗?, 是否继续?", "提示", {
+      //   confirmButtonText: "确定",
+      //   cancelButtonText: "取消",
+      //   type: "warning",
+      // })
+      //   .then(async () => {
+      //     debugger;
+      //     let result = await delZtBillboardInfoList(model.id);
+      //     debugger;
+      //     if (result.code == 200) {
+      //       that.getZtBillboardInfoList();
+      //       viewer.entities.removeAll();
+      //       // that.lyoption.cancel();
+      //       // that.$layer.close(that.layerid);
+      //       that.$message({
+      //         message: "删除成功",
+      //         type: "success",
+      //       });
+      //     }
+      //   })
+      //   .catch(() => {
+      //     debugger;
+      //     this.$message({
+      //       type: "info",
+      //       message: "已取消删除",
+      //     });
+      //   });
     },
     /**
      * 导入模型(添加广告牌模型)

+ 43 - 14
src/views/ConstructionApplication3D/billboard/billboardJTList.vue

@@ -216,13 +216,13 @@ export default {
      */
     deleteBillardJT(model) {
       debugger;
+
       var that = this;
-      this.$confirm("确定要删除当前截图, 是否继续?", "提示", {
-        confirmButtonText: "确定",
-        cancelButtonText: "取消",
-        type: "warning",
-      })
-        .then(async () => {
+      var confirmid = that.$layer.confirm(
+        "确定要删除当前截图, 是否继续?",
+        {},
+        async function () {
+          that.$layer.close(confirmid);
           debugger;
           let result = await delZtBillboardJt(model.id);
           debugger;
@@ -232,15 +232,44 @@ export default {
               message: "删除成功",
               type: "success",
             });
+          } else {
+            that.getZtBillboardJtList(that.info.id);
+            that.$message({
+              message: "删除失败",
+              type: "error",
+            });
           }
-        })
-        .catch(() => {
-          debugger;
-          this.$message({
-            type: "info",
-            message: "已取消删除",
-          });
-        });
+        },
+        function () {
+          return;
+        }
+      );
+
+      // var that = this;
+      // this.$confirm("确定要删除当前截图, 是否继续?", "提示", {
+      //   confirmButtonText: "确定",
+      //   cancelButtonText: "取消",
+      //   type: "warning",
+      // })
+      //   .then(async () => {
+      //     debugger;
+      //     let result = await delZtBillboardJt(model.id);
+      //     debugger;
+      //     if (result.code == 200) {
+      //       that.getZtBillboardJtList(that.info.id);
+      //       that.$message({
+      //         message: "删除成功",
+      //         type: "success",
+      //       });
+      //     }
+      //   })
+      //   .catch(() => {
+      //     debugger;
+      //     this.$message({
+      //       type: "info",
+      //       message: "已取消删除",
+      //     });
+      //   });
     },
 
     /**

+ 26 - 29
src/views/ConstructionApplication3D/projectManagement/projectManagement.vue

@@ -947,7 +947,6 @@ export default {
 
     //分析列表显隐
     async openAnalyzeList(itemModel) {
-      debugger;
       if (itemModel.isggp == null) {
         let BenchmarkLandPrices = await listZtBillboardInfoList({
           bjmxid: itemModel.id,
@@ -982,7 +981,6 @@ export default {
 
     //切换项目
     handleChangeXM(val) {
-      debugger;
       // closAndChangeXM(val);
       // 清除待选模型
       this.WaitingSelectionModel = null;
@@ -1021,12 +1019,10 @@ export default {
 
     //选中报建模型
     SelectConstructionModelHendle(Minfo) {
-      debugger;
       if (this.WaitingSelectionModel != Minfo) {
         this.removeModel();
         this.WaitingSelectionModel = null;
         this.removeAll();
-        debugger;
 
         var wshData = this.wsh.find((c) => c.id == Minfo.projectinformationid);
         if (wshData && wshData.meetingprogress != "1") {
@@ -1077,7 +1073,7 @@ export default {
         shadeClose: false, //点击遮罩是否关闭
         cancel: async () => {
           //关闭事件
-          debugger;
+
           // this.wsh = await this.getshProjectinformations("0");
           this.wshinit();
         },
@@ -1102,7 +1098,7 @@ export default {
         shadeClose: false, //点击遮罩是否关闭
         cancel: async () => {
           //关闭事件
-          debugger;
+
           // this.wsh = await this.getshProjectinformations("0");
           this.wshinit();
         },
@@ -1288,6 +1284,7 @@ export default {
       that.layerDataList = [];
       Cesium.when(modelLayer, async function (layers) {
         layers.forEach((layer) => {
+          layer.visible = true;
           viewer.flyTo(layer);
           layer.shadowType = 2;
           that.layerList.push(layer.name);
@@ -1421,14 +1418,22 @@ export default {
       });
     },
     //添加多个模型
-    async addModels(Minfos, completed) {
+    async addModels(Minfos, completed, isflyTo) {
       let that = this;
       await this.yp(Minfos);
-      debugger;
+
       let models = [];
       try {
         Minfos.forEach((element) => {
-          var modelLayer = scene.open(element.url);
+          var modelLayer = null;
+          if (isflyTo == false) {
+            modelLayer = scene.open(element.url, undefined, {
+              autoSetView: false,
+            });
+          } else {
+            modelLayer = scene.open(element.url);
+          }
+
           models.push(modelLayer);
         });
         // // 为每个 Promise 添加 .catch() 处理程序
@@ -1441,7 +1446,6 @@ export default {
         //   });
         // });
         Cesium.when.all(models, async function (modelLayers) {
-          debugger;
           for (let index = 0; index < modelLayers.length; index++) {
             let modelData = {
               id: uuidv4(),
@@ -1558,7 +1562,6 @@ export default {
 
       //清除多模型图层,数据
       this.modelsload.forEach((model) => {
-        debugger;
         model.layers.forEach((element) => {
           scene.layers.remove(element);
         });
@@ -1591,7 +1594,6 @@ export default {
 
     //模型对比按钮
     ModelComparison(info) {
-      debugger;
       let that = this;
       if (this.modelsload.length > 0) {
         scene.multiViewportMode = Cesium.MultiViewportMode.NONE;
@@ -1628,7 +1630,7 @@ export default {
         this.removeModel();
         //加载模型
         this.addModels(checkedModeinfos, function () {
-          that.openMXDBInfo();
+          that.openMXDBInfo(info);
           that.loading = false;
         });
       } else if (checkedModeinfos.length > 2) {
@@ -1778,7 +1780,7 @@ export default {
       let that = this;
       if (!info.plotnumber) {
         that.$message({
-          message: "请在项目信息中补全项目地块编码",
+          message: "请在项目信息中补全项目地块编码",
           type: "warning",
         });
         return;
@@ -1890,7 +1892,6 @@ export default {
               clampToGround: true,
             },
           });
-          debugger;
 
           let dom = document.createElement("div");
           dom.id = "JZXGD-A";
@@ -1953,7 +1954,7 @@ export default {
           //   },
           // });
           // that.layerList.forEach((layer) => {
-          //   debugger;
+          //
           //   var hyp = new Cesium.HypsometricSetting();
 
           //   //创建分层设色对象   设置最大/最小可见高度   颜色表  显示模式   透明度及线宽
@@ -1998,7 +1999,6 @@ export default {
               // if (viewer.entities.getById("JZXG-" + SMID)) {
               //   viewer.entities.removeById("JZXG-" + SMID);
               // }
-              debugger;
 
               var BoxIndex = popupBoxs.findIndex(
                 (c) => c.element.id == "JZXG-" + SMID
@@ -2010,8 +2010,6 @@ export default {
 
               let cg = this.calculateHighLimit(Height, JZXGD);
               if (cg > 0) {
-                debugger;
-
                 let dom = document.createElement("div");
                 dom.id = "JZXG-" + SMID;
                 dom.style.position = "absolute";
@@ -2506,7 +2504,6 @@ export default {
                   ps.push(element.y);
                   ps.push(0);
                 }
-                debugger;
 
                 //限高高度
                 let xg = 87.4;
@@ -2544,7 +2541,7 @@ export default {
       let that = this;
       if (!info.plotnumber) {
         that.$message({
-          message: "请在项目信息中补全项目地块编码",
+          message: "请在项目信息中补全项目地块编码",
           type: "warning",
         });
         return;
@@ -2709,7 +2706,7 @@ export default {
       let that = this;
       if (!info.plotnumber) {
         that.$message({
-          message: "请在项目信息中补全项目地块编码",
+          message: "请在项目信息中补全项目地块编码",
           type: "warning",
         });
         return;
@@ -2741,7 +2738,6 @@ export default {
      * @param Minfo
      */
     async getnorm(Minfo) {
-      debugger;
       //组装指标对象
       let tableDataList = [];
       for (let index = 0; index < this.LandPlanningList.length; index++) {
@@ -2970,7 +2966,7 @@ export default {
           if (land == null) continue;
           tableDataList[i].FA_Data.JZMJ = land.mj;
           tableDataList[i].FA_Data.JRJZMJ = land.jrmj;
-          debugger;
+
           //20240814改为使用建筑面积计算容积率
           // tableDataList[i].FA_Data.RJL = (land.jrmj / item.FA_Data.YDMJ).toFixed(2);
           tableDataList[i].FA_Data.RJL = (
@@ -2978,7 +2974,7 @@ export default {
             item.FA_Data.YDMJ
           ).toFixed(2);
           //开发商提交的方案文档指标
-          debugger;
+
           tableDataList[i].TJFA_Data.JZMJ = land.famj;
           tableDataList[i].TJFA_Data.JRJZMJ = land.fajrmj;
           tableDataList[i].infoData = land;
@@ -3147,7 +3143,6 @@ export default {
     },
     //取消左键事件
     removeEventHandler() {
-      debugger;
       if (this.handler) {
         this.tooltip.setVisible(false);
         this.handler.removeInputAction(Cesium.ScreenSpaceEventType.MOUSE_MOVE);
@@ -3418,16 +3413,17 @@ export default {
     /**
      * //打开模型对比弹窗
      */
-    openMXDBInfo() {
-      debugger;
+    openMXDBInfo(info) {
       let that = this;
       let modelsloadData = that.modelsload.map((item) => {
         return {
           id: item.id,
           Minfo: item.Minfo,
+          layers: item.layers,
           layerDataList: item.layerDataList,
         };
       });
+      debugger;
       //弹窗最小化
       this.$layer.min(this.layerid);
       if (this.MXDBInfolayerid) {
@@ -3444,6 +3440,7 @@ export default {
           content: MXDBinfo, //传递的组件对象
           parent: this, //当前的vue对象
           data: {
+            pinfo: info,
             info: { modelsloadData },
           }, //props
         },
@@ -3599,7 +3596,7 @@ export default {
       this.removeJZTXlayerDatas();
       this.removeDLTBlayerDatas();
       ghqk.removeAll();
-      debugger;
+
       if (iscloseBJTC != false) {
         this.$layer.close("BJTC");
       }

+ 242 - 36
static/Config/config.js

@@ -1,7 +1,7 @@
 //后台地址配置
 window.axiosURI = "http://192.168.60.2:8080";
 // window.axiosURI = "http://192.168.60.88:8080";//小谷
-window.ZTaxiosURI = "http://localhost:9300";
+window.supermapIServerUrl = "http://192.168.60.2:8090";
 window.aiURI = "http://192.168.60.2:4000";
 //倾斜模型高度配置
 window.modelBottomAltitude = 0;
@@ -972,7 +972,7 @@ window.layerTree = [
         date_server: {
           nvfid: "4526wsd78",
           server_name: "地类图斑",
-          url: "http://192.168.60.2:8090/iserver/services/data-sanyamap1/rest/data",
+          url: "http://192.168.2.130:8091/iserver/services/data-sanyamap1/rest/data",
           datasourcename: "sanya",
           datasetname: "地类图斑",
         },
@@ -1114,7 +1114,7 @@ window.layerTree = [
         date_server: {
           nvfid: "4526wsd78",
           server_name: "规划地块",
-          url: "http://192.168.60.2:8090/iserver/services/data-sanyamap1/rest/data",
+          url: "http://192.168.2.130:8091/iserver/services/data-sanyamap1/rest/data",
           datasourcename: "sanya",
           datasetname: "规划地块",
         },
@@ -1156,7 +1156,7 @@ window.layerTree = [
         date_server: {
           nvfid: "456sd78",
           server_name: "城镇开发边界",
-          url: "http://192.168.60.2:8090/iserver/services/data-sanyamap1/rest/data",
+          url: "http://192.168.2.130:8091/iserver/services/data-sanyamap1/rest/data",
           datasourcename: "sanya",
           datasetname: "城镇开发边界",
         },
@@ -1176,7 +1176,7 @@ window.layerTree = [
         date_server: {
           nvfid: "4526wsd78",
           server_name: "生态保护红线",
-          url: "http://192.168.60.2:8090/iserver/services/data-sanyamap1/rest/data",
+          url: "http://192.168.2.130:8091/iserver/services/data-sanyamap1/rest/data",
           datasourcename: "sanya",
           datasetname: "生态保护红线",
         },
@@ -1196,7 +1196,7 @@ window.layerTree = [
         date_server: {
           nvfid: "4526wsd78",
           server_name: "永久基本农田",
-          url: "http://192.168.60.2:8090/iserver/services/data-sanyamap1/rest/data",
+          url: "http://192.168.2.130:8091/iserver/services/data-sanyamap1/rest/data",
           datasourcename: "sanya",
           datasetname: "永久基本农田",
         },
@@ -1216,7 +1216,7 @@ window.layerTree = [
         date_server: {
           nvfid: "4526wsd78",
           server_name: "建筑退线",
-          url: "http://192.168.60.2:8090/iserver/services/data-sanyamap1/rest/data",
+          url: "http://192.168.2.130:8091/iserver/services/data-sanyamap1/rest/data",
           datasourcename: "sanya",
           datasetname: "建筑退线",
         },
@@ -1318,7 +1318,7 @@ window.layerTree = [
         date_server: {
           nvfid: "4526wsd78",
           server_name: "道路中线",
-          url: "http://192.168.60.2:8090/iserver/services/data-sanyamap1/rest/data",
+          url: "http://192.168.2.130:8091/iserver/services/data-sanyamap1/rest/data",
           datasourcename: "sanya",
           datasetname: "道路中线",
         },
@@ -1338,7 +1338,7 @@ window.layerTree = [
         date_server: {
           nvfid: "4526wsd78",
           server_name: "禁止开口线",
-          url: "http://192.168.60.2:8090/iserver/services/data-sanyamap1/rest/data",
+          url: "http://192.168.2.130:8091/iserver/services/data-sanyamap1/rest/data",
           datasourcename: "sanya",
           datasetname: "禁止开口线",
         },
@@ -1358,7 +1358,7 @@ window.layerTree = [
         date_server: {
           nvfid: "4526wsd78",
           server_name: "道路红线",
-          url: "http://192.168.60.2:8090/iserver/services/data-sanyamap1/rest/data",
+          url: "http://192.168.2.130:8091/iserver/services/data-sanyamap1/rest/data",
           datasourcename: "sanya",
           datasetname: "道路红线",
         },
@@ -1400,7 +1400,7 @@ window.layerTree = [
         date_server: {
           nvfid: "456sd78",
           server_name: "c1_2_商服级别",
-          url: "http://192.168.60.2:8090/iserver/services/data-sanyamap1/rest/data",
+          url: "http://192.168.2.130:8091/iserver/services/data-sanyamap1/rest/data",
           datasourcename: "sanya",
           datasetname: "c1_2_商服级别",
         },
@@ -1420,7 +1420,7 @@ window.layerTree = [
         date_server: {
           nvfid: "4526wsd78",
           server_name: "c2_2_0_住宅级别",
-          url: "http://192.168.60.2:8090/iserver/services/data-sanyamap1/rest/data",
+          url: "http://192.168.2.130:8091/iserver/services/data-sanyamap1/rest/data",
           datasourcename: "sanya",
           datasetname: "c2_2_0_住宅级别",
         },
@@ -1440,7 +1440,7 @@ window.layerTree = [
         date_server: {
           nvfid: "4526wsd78",
           server_name: "c3_2_工业级别",
-          url: "http://192.168.60.2:8090/iserver/services/data-sanyamap1/rest/data",
+          url: "http://192.168.2.130:8091/iserver/services/data-sanyamap1/rest/data",
           datasourcename: "sanya",
           datasetname: "c3_2_工业级别",
         },
@@ -1460,7 +1460,7 @@ window.layerTree = [
         date_server: {
           nvfid: "4526wsd78",
           server_name: "c4_1_公服级别",
-          url: "http://192.168.60.2:8090/iserver/services/data-sanyamap1/rest/data",
+          url: "http://192.168.2.130:8091/iserver/services/data-sanyamap1/rest/data",
           datasourcename: "sanya",
           datasetname: "c4_1_公服级别",
         },
@@ -1480,7 +1480,7 @@ window.layerTree = [
         date_server: {
           nvfid: "4526wsd78",
           server_name: "c2_3_0_工业级别",
-          url: "http://192.168.60.2:8090/iserver/services/data-sanyamap1/rest/data",
+          url: "http://192.168.2.130:8091/iserver/services/data-sanyamap1/rest/data",
           datasourcename: "sanya",
           datasetname: "c2_3_0_工业级别",
         },
@@ -1500,7 +1500,7 @@ window.layerTree = [
         date_server: {
           nvfid: "4526wsd78",
           server_name: "c2_1_0_商服级别",
-          url: "http://192.168.60.2:8090/iserver/services/data-sanyamap1/rest/data",
+          url: "http://192.168.2.130:8091/iserver/services/data-sanyamap1/rest/data",
           datasourcename: "sanya",
           datasetname: "c2_1_0_商服级别",
         },
@@ -1520,7 +1520,7 @@ window.layerTree = [
         date_server: {
           nvfid: "4526wsd78",
           server_name: "c4_路线价",
-          url: "http://192.168.60.2:8090/iserver/services/data-sanyamap1/rest/data",
+          url: "http://192.168.2.130:8091/iserver/services/data-sanyamap1/rest/data",
           datasourcename: "sanya",
           datasetname: "c4_路线价",
         },
@@ -1540,7 +1540,7 @@ window.layerTree = [
         date_server: {
           nvfid: "4526sawsd78",
           server_name: "c2_2_住宅级别",
-          url: "http://192.168.60.2:8090/iserver/services/data-sanyamap1/rest/data",
+          url: "http://192.168.2.130:8091/iserver/services/data-sanyamap1/rest/data",
           datasourcename: "sanya",
           datasetname: "c2_2_住宅级别",
         },
@@ -1560,7 +1560,7 @@ window.layerTree = [
         date_server: {
           nvfid: "4526sawsd78",
           server_name: "c2_4_0_公服级别",
-          url: "http://192.168.60.2:8090/iserver/services/data-sanyamap1/rest/data",
+          url: "http://192.168.2.130:8091/iserver/services/data-sanyamap1/rest/data",
           datasourcename: "sanya",
           datasetname: "c2_4_0_公服级别",
         },
@@ -1602,7 +1602,7 @@ window.layerTree = [
         date_server: {
           nvfid: "456sd78",
           server_name: "国有使用权",
-          url: "http://192.168.60.2:8090/iserver/services/data-sanyamap1/rest/data",
+          url: "http://192.168.2.130:8091/iserver/services/data-sanyamap1/rest/data",
           datasourcename: "sanya",
           datasetname: "国有使用权",
         },
@@ -1622,7 +1622,7 @@ window.layerTree = [
         date_server: {
           nvfid: "456sd78",
           server_name: "集体使用权",
-          url: "http://192.168.60.2:8090/iserver/services/data-sanyamap1/rest/data",
+          url: "http://192.168.2.130:8091/iserver/services/data-sanyamap1/rest/data",
           datasourcename: "sanya",
           datasetname: "集体使用权",
         },
@@ -1642,7 +1642,7 @@ window.layerTree = [
         date_server: {
           nvfid: "456sd78",
           server_name: "集体所有权",
-          url: "http://192.168.60.2:8090/iserver/services/data-sanyamap1/rest/data",
+          url: "http://192.168.2.130:8091/iserver/services/data-sanyamap1/rest/data",
           datasourcename: "sanya",
           datasetname: "集体所有权",
         },
@@ -1689,8 +1689,6 @@ window.dict = {
 };
 //白膜可通过这里添加自发光纹理
 window.NightViewLayerName = [
-  // "抱坡规划区域建筑基底@building",
-  // "规划区基底高度@sanyaLAT",
 ];
 //广告模型审查规则
 window.billboardReviewList = [
@@ -1829,6 +1827,12 @@ window.billboardReviewList = [
                     ReviewContent:
                       "一层建筑层高≤4.5m并且广告高度≤1.5m或者一层建筑层高>4.5m并且广告高度小于等于2m",
                   },
+                  // {
+                  //   id: "453sd45xcv53",
+                  //   code: "00102020103",
+                  //   ReviewMethod: "自动审查",
+                  //   ReviewContent: "一层建筑层高>4.5m并且广告高度小于等于2m",
+                  // },
                   {
                     id: "453sd45xcv53",
                     code: "00102020104",
@@ -2754,6 +2758,205 @@ window.billboardReviewList = [
         code: "00502",
         billboardType: "小型LED广告牌",
         children: [
+          // {
+          //   id: "wew232",
+          //   code: "0050201",
+          //   billboardType: "依附于建(构)筑物主体墙面的小型LED广告牌",
+          //   isAddModel: true,
+          //   ModelType: "rectangleBillboard",
+          //   ReviewItems: [
+          //     {
+          //       id: "45cv5sdfcx3",
+          //       code: "001234",
+          //       ReviewMethod: "自动审查",
+          //       ReviewContent:
+          //         "筑高度不超过24米的多层建筑墙面和高层建筑裙楼的主体墙面",
+          //     },
+          //     {
+          //       id: "453bdf4553",
+          //       code: "0010101",
+          //       ReviewMethod: "手动审查",
+          //       ReviewContent:
+          //         "户外广告上沿不得突出墙面(包括女儿墙)的外轮廓线",
+          //     },
+          //     {
+          //       id: "453szxcvd4553",
+          //       code: "0010102",
+          //       ReviewMethod: "手动审查",
+          //       ReviewContent: "不得遮挡建筑窗户",
+          //     },
+          //     {
+          //       id: "453shtd45xcv53",
+          //       code: "0010103",
+          //       ReviewMethod: "手动审查",
+          //       ReviewContent:
+          //         "一层与二层之间,二层与三层之间可设广告,其他楼层不得设广告, 不得在门的两侧和立柱上设置户外广告",
+          //     },
+          //     {
+          //       id: "453sd4wntye553",
+          //       code: "0010104",
+          //       ReviewMethod: "手动审查",
+          //       ReviewContent:
+          //         "广告设施宽度应与墙面相协调,周围不应超出墙面外轮廓线,垂直方向突出墙面距离不宜大于0.5米",
+          //     },
+          //     {
+          //       id: "4d4we5vcb53",
+          //       code: "0010105",
+          //       ReviewMethod: "自动审查",
+          //       ReviewContent:
+          //         "户外广告下端距地面净高不得低于3米,且不得防碍行人安全;",
+          //     },
+          //     {
+          //       id: "4d4w6kdsaesd553",
+          //       code: "0010106",
+          //       ReviewMethod: "手动审查",
+          //       ReviewContent:
+          //         "依附于多层建筑、裙房或附楼主体墙面的广告建筑同一立面成组广告设置须规格、形式一致,集中布置",
+          //     },
+          //   ],
+          // },
+          // {
+          //   id: "we443wxcvb232",
+          //   code: "0050202",
+          //   billboardType: "依附于门楣的小型LED广告牌",
+          //   children: [
+          //     {
+          //       id: "wmbnfd32",
+          //       code: "005020201",
+          //       billboardType: "底层以上没有出挑结构的建筑",
+          //       isAddModel: true,
+          //       ModelType: "rectangleBillboard",
+          //       ReviewItems: [
+          //         {
+          //           id: "455uy3",
+          //           code: "001234",
+          //           ReviewMethod: "自动审查",
+          //           ReviewContent:
+          //             "筑高度不超过24米的多层建筑墙面和高层建筑裙楼的主体墙面",
+          //         },
+          //         {
+          //           id: "4534553",
+          //           code: "001020101",
+          //           ReviewMethod: "手动审查",
+          //           ReviewContent:
+          //             "附设于建筑一层门楣的广告,下沿不得低于门楣上沿,上沿不得高于二层窗户下沿",
+          //         },
+          //         {
+          //           id: "453sd4553",
+          //           code: "001020102",
+          //           ReviewMethod: "自动审查",
+          //           ReviewContent:
+          //             "宽度应以建筑开间为单元,且广告高度不得大于3米",
+          //         },
+          //         {
+          //           id: "453sd45xcv53",
+          //           code: "001020103",
+          //           ReviewMethod: "手动审查",
+          //           ReviewContent:
+          //             "户外广告外表面距离墙面不得超过0.3米(霓虹灯户外广告则外表面距离墙面不得超过0.5米)",
+          //         },
+          //       ],
+          //     },
+          //     {
+          //       id: "dfxjntdg",
+          //       code: "005020202",
+          //       billboardType: "底层以上有出挑结构的建筑",
+          //       children: [
+          //         {
+          //           id: "gfho3w232",
+          //           code: "00502020201",
+          //           billboardType: "附设于建筑一层门楣的广告",
+          //           isAddModel: true,
+          //           ModelType: "rectangleBillboard",
+          //           ReviewItems: [
+          //             {
+          //               id: "45fgv53",
+          //               code: "001234",
+          //               ReviewMethod: "自动审查",
+          //               ReviewContent:
+          //                 "筑高度不超过24米的多层建筑墙面和高层建筑裙楼的主体墙面",
+          //             },
+          //             {
+          //               id: "4534tbgh553",
+          //               code: "00102020101",
+          //               ReviewMethod: "手动审查",
+          //               ReviewContent:
+          //                 "下沿不得低于门楣上沿,宽度应以建筑开间为单元",
+          //             },
+          //             {
+          //               id: "453bd4553",
+          //               code: "00102020102",
+          //               ReviewMethod: "自动审查",
+          //               ReviewContent:
+          //                 "一层建筑层高≤4.5m并且广告高度≤1.5m或者一层建筑层高>4.5m并且广告高度小于等于2m",
+          //             },
+          //             // {
+          //             //   id: "453sd45xcv53",
+          //             //   code: "00102020103",
+          //             //   ReviewMethod: "自动审查",
+          //             //   ReviewContent: "一层建筑层高>4.5m并且广告高度小于等于2m",
+          //             // },
+          //             {
+          //               id: "453sddbv53",
+          //               code: "00102020104",
+          //               ReviewMethod: "手动审查",
+          //               ReviewContent:
+          //                 "户外广告外表面距离墙面不得超过0.3米(霓虹灯户外广告则外表面距离墙面不得超过0.5米)",
+          //             },
+          //           ],
+          //         },
+          //         {
+          //           id: "wed3w232",
+          //           code: "00502020202",
+          //           billboardType: "设于建筑出挑部分的墙面上",
+          //           isAddModel: true,
+          //           ModelType: "rectangleBillboard",
+          //           ReviewItems: [
+          //             {
+          //               id: "455vsdf3",
+          //               code: "001234",
+          //               ReviewMethod: "自动审查",
+          //               ReviewContent:
+          //                 "筑高度不超过24米的多层建筑墙面和高层建筑裙楼的主体墙面",
+          //             },
+          //             {
+          //               id: "4534fyj553",
+          //               code: "00102020201",
+          //               ReviewMethod: "自动审查",
+          //               ReviewContent: "出挑部分的底部距离地面小于3米",
+          //             },
+          //             {
+          //               id: "453b53",
+          //               code: "00102020202",
+          //               ReviewMethod: "手动审查",
+          //               ReviewContent:
+          //                 "户外广告的下沿不得低于建筑出挑部分的楼板,上沿不得高于二层窗户下沿",
+          //             },
+          //             {
+          //               id: "445xcv53",
+          //               code: "00102020203",
+          //               ReviewMethod: "手动审查",
+          //               ReviewContent: "允许将户外广告设于建筑出挑部分的墙面上",
+          //             },
+          //             {
+          //               id: "453sd453",
+          //               code: "00102020204",
+          //               ReviewMethod: "自动审查",
+          //               ReviewContent: "广告高度不得大于3米",
+          //             },
+          //             {
+          //               id: "45dfgbvfv53",
+          //               code: "00102020205",
+          //               ReviewMethod: "手动审查",
+          //               ReviewContent:
+          //                 "户外广告外表面距离墙面不得超过0.3米(霓虹灯户外广告外表面距离墙面不得超过0.5米)",
+          //             },
+          //           ],
+          //         },
+          //       ],
+          //     },
+          //   ],
+          // },
           {
             id: "wewsdf232",
             code: "0050203",
@@ -3127,7 +3330,7 @@ window.ZSBC = {
    * 征地补偿数据服务
    */
   dataServiceUrl:
-    'http://192.168.60.2:8090/iserver/services/data-sanyamap1/rest/data/featureResults.rjson?returnContent=true&hasGeometry=true"',
+    'http://192.168.2.130:8091/iserver/services/data-sanyamap1/rest/data/featureResults.rjson?returnContent=true&hasGeometry=true"',
 
   /**征地补偿标准 */
   ZDBCList: [
@@ -3300,23 +3503,24 @@ window.ZSBC = {
     StateUsed: {
       layerName: "国有使用权",
       layerDataSource: "sanya:国有使用权", //[数据集:图层名]
-      ownerfld: "RIGHT_OWNE",
+      // ownerfld: "RIGHT_OWNE",
+      ownerfld: "RIGHTOWNE",
     },
     /**
-     * 集体使用
+     * 集体所有
      */
     CollectiveUsed: {
-      layerName: "集体使用权",
-      layerDataSource: "sanya:集体使用权", //[数据集:图层名]
-      ownerfld: "QLR",
+      layerName: "集体所有权",
+      layerDataSource: "sanya:集体所有权", //[数据集:图层名]
+      ownerfld: "SYQR",
     },
     /**
-     * 集体所有
+     * 集体使用
      */
     CollectiveOwner: {
-      layerName: "集体所有权",
-      layerDataSource: "sanya:集体所有权", //[数据集:图层名]
-      ownerfld: "SYQR",
+      layerName: "集体使用权",
+      layerDataSource: "sanya:集体使用权", //[数据集:图层名]
+      ownerfld: "QLR",
     },
     /**
      * 地类图斑
@@ -3385,11 +3589,11 @@ window.ZSBC = {
       /**
        *不动产图层
        */
-      layerName: "建筑矢量",
+      layerName: "不动产",
       /**
        * 不动产数据集
        */
-      layerDataSource: "sanya:建筑矢量", //[数据集:图层名]
+      layerDataSource: "sanya:不动产", //[数据集:图层名]
       /**
        * 产权人
        */
@@ -3850,3 +4054,5 @@ window.QXLayerNames = [
 ];
 window.Layeralpha = 0.4;
 window.isUseDB = true;
+// window.epsgcode = "4490";
+// window.unit = "METER";