智慧園區(qū)簡單功能Demo

一徽职、前言

智慧園區(qū)業(yè)內(nèi)有較多成熟解決方案,這里僅個人純原生Cesium開發(fā)、使用各開源免費數(shù)據(jù)做出其中部分功能解愤。

二、獲得數(shù)據(jù)

地理信息數(shù)據(jù)來源

地理空間數(shù)據(jù)云
數(shù)據(jù)資源更新比較穩(wěn)定乎莉,免費數(shù)據(jù)包括Landsat系列送讲、中巴資源衛(wèi)星、MODIS數(shù)據(jù)的各種產(chǎn)品梦鉴、DEM數(shù)字高程數(shù)據(jù)李茫、EO-1數(shù)據(jù)、NOAAA VHRR數(shù)據(jù)產(chǎn)品肥橙、Sentinel數(shù)據(jù)等魄宏。賬號注冊,通過審核直接下載即可存筏。

中國遙感數(shù)據(jù)共享網(wǎng)
國內(nèi)存檔周期最長的數(shù)據(jù)網(wǎng)站宠互,對Landsat數(shù)據(jù)免費共享,也可訂購國外商業(yè)衛(wèi)星數(shù)據(jù)椭坚。注冊賬號予跌,通過審核就可直接下載。

OpenStreetMap
一個開源的世界地圖善茎,可依據(jù)開放許可協(xié)議自由使用券册,并且可以由人們自由的進行編輯。

自行繪制geoJson矢量數(shù)據(jù)

模型數(shù)據(jù)來源

1垂涯、通過revit烁焙、bentley、3dmax耕赘、maya等模型制作軟件制作建筑模型骄蝇。通過obj2gltf等格式轉(zhuǎn)換工具轉(zhuǎn)換成Cesium可展示格式。

2操骡、調(diào)用Cesium Ion的OSMBuilding服務九火,展示全球建筑模型數(shù)據(jù)。

傾斜攝影數(shù)據(jù)來源

無人機航拍照片經(jīng)過空三演算獲得osgb數(shù)據(jù)册招。

三岔激、功能

全景展示

需要對應園區(qū)模型數(shù)據(jù),用Cesium對應的加載方法加載是掰。

const tileset = new Cesium.Cesium3DTileset({
      url: './NewYork/tileset.json',
    })
    tileset.readyPromise.then((tile) => {
      tileset.style = new Cesium.Cesium3DTileStyle({
        color: {
          conditions: [
            /* 根據(jù)模型屬性分層設色 */
            ['true', "color('white')"],
            //eg: ['${Height} >=50', "color('red')"],
          ],
        },
      })
      viewer.scene.primitives.add(tileset)
image.png

多元數(shù)據(jù)疊加

路網(wǎng)信息

async addGeoJson() {
      /**
       * @description: 添加路網(wǎng)信息
       *
       * @param {*}
       * @author: citrusrlia@foxmail.com
       */
      const that = this
      let res = await Cesium.GeoJsonDataSource.load('NYC_roads_draw.json', {
        stroke: Cesium.Color.WHITE,
        fill: Cesium.Color.BLUE.withAlpha(0.3),
        strokeWidth: 2,
      })
      res.show = false
      viewer.dataSources.add(res)
      let entities = res.entities.values
      for (let i = 0, l = entities.length; i < l; i++) {
        let thisLine = entities[i]
        // thisLine.nameID = 'line' + i
        thisLine.polyline.width = 20
        thisLine.polyline.material = new Cesium.PolylineGlowMaterialProperty({
          glowPower: 0.1,
          color: Cesium.Color.BLUE.withAlpha(0.7),
        })
      }
    }
image.png

管線信息

地下管線缺少數(shù)據(jù)虑鼎,本來用glb礦道數(shù)據(jù)模擬,效果不佳冀惭,采用手繪動態(tài)線模擬震叙。動態(tài)線PolylineTrailLinkMaterialProperty類在Cesium1.7版本后無法拓展至Cesium類掀鹅。


管網(wǎng).gif
async addPipe() {
      /**
       * @description: 添加管線(geojson)
       * @param {*}
       * @author: citrusrlia@foxmail.com
       */
      const that = this
      let res = await Cesium.GeoJsonDataSource.load('NYC_pipes_draw.json', {
        stroke: Cesium.Color.WHITE,
        fill: Cesium.Color.BLUE.withAlpha(0.3),
        strokeWidth: 2,
      })
      res.show = false
      viewer.dataSources.add(res)
      let entities = res.entities.values
      for (let i = 0, l = entities.length; i < l; i++) {
        let thisLine = entities[i]
        thisLine.polyline.width = 5
        thisLine.polyline.material = new that.PolylineTrailLinkMaterialProperty(
          Cesium.Color.GREEN,
          3000
        )
      }
      /* ??若使用gltf模型 */
      // const pipes = addGltf(
      //   [-74.01263164288234, 40.710022989658896, -250],
      //   'pipe',
      //   'ParcLeadMine.glb'
      // )
      // viewer.scene.primitives.add(pipes)
      // pipes.show = false
      // function addGltf(degrees, id, model_url, scale = 1) {
      //   /**
      //    * @author: citrusrlia@foxmail.com
      //    * @description: 添加gltf模型
      //    * @param {degrees:array id:string model_url:string scale:number}
      //    * @return {*}
      //    */
      //   let position = Cesium.Cartesian3.fromDegrees(
      //     degrees[0],
      //     degrees[1],
      //     degrees[2]
      //   )
      //   let heading = 90
      //   let pitch = 0
      //   let roll = 0
      //   let modelMatrix = Cesium.Transforms.headingPitchRollToFixedFrame(
      //     position,
      //     new Cesium.HeadingPitchRoll(heading, pitch, roll)
      //   )
      //   let model = Cesium.Model.fromGltf({
      //     url: model_url,
      //     modelMatrix: modelMatrix,
      //     scale: scale,
      //     id: id + '_model',
      //     maximumScreenSpaceError: 16,
      //     show: true,
      //     allowPicking: true,
      //   })
      //   return model
      // }
    }

流動線PolylineTrailLinkMaterialProperty

initFlow() {
      /**
       * @description:流動線類,1.70后版本Cesium不可拓展材質(zhì)類,將材質(zhì)類添加至vue
       * @param {color:Cesium.color duation:ms}
       * @author: citrusrlia@foxmail.com
       */
      function PolylineTrailLinkMaterialProperty(color, duration) {
        this._definitionChanged = new Cesium.Event()
        this._color = undefined
        this._colorSubscription = undefined
        this.color = color
        this.duration = duration
        this._time = new Date().getTime()
      }

      Object.defineProperties(PolylineTrailLinkMaterialProperty.prototype, {
        isConstant: {
          get: function () {
            return false
          },
        },
        definitionChanged: {
          get: function () {
            return this._definitionChanged
          },
        },
        color: Cesium.createPropertyDescriptor('color'),
      })
      PolylineTrailLinkMaterialProperty.prototype.getType = function (time) {
        return 'PolylineTrailLink'
      }
      PolylineTrailLinkMaterialProperty.prototype.getValue = function (
        time,
        result
      ) {
        if (!Cesium.defined(result)) {
          result = {}
        }
        result.color = Cesium.Property.getValueOrClonedDefault(
          this._color,
          time,
          Cesium.Color.WHITE,
          result.color
        )
        result.image = Cesium.Material.PolylineTrailLinkImage
        result.time =
          ((new Date().getTime() - this._time) % this.duration) / this.duration
        return result
      }
      PolylineTrailLinkMaterialProperty.prototype.equals = function (other) {
        return (
          this === other ||
          (other instanceof PolylineTrailLinkMaterialProperty &&
            Cesium.Property.equals(this._color, other._color))
        )
      }
      this.PolylineTrailLinkMaterialProperty = PolylineTrailLinkMaterialProperty
      Cesium.Material.PolylineTrailLinkType = 'PolylineTrailLink'
      Cesium.Material.PolylineTrailLinkImage = 'fade_blue.jpeg'
      Cesium.Material.PolylineTrailLinkSource =
        'czm_material czm_getMaterial(czm_materialInput materialInput)\n\
                                                      {\n\
                                                           czm_material material = czm_getDefaultMaterial(materialInput);\n\
                                                           vec2 st = materialInput.st;\n\
                                                           vec4 colorImage = texture2D(image, vec2(fract(st.s - time), st.t));\n\
                                                           material.alpha = colorImage.a * color.a;\n\
                                                           material.diffuse = (colorImage.rgb+color.rgb)/2.0;\n\
                                                           return material;\n\
                                                       }'
      Cesium.Material._materialCache.addMaterial(
        Cesium.Material.PolylineTrailLinkType,
        {
          fabric: {
            type: Cesium.Material.PolylineTrailLinkType,
            uniforms: {
              color: new Cesium.Color(1.0, 0.0, 0.0, 0.5),
              image: Cesium.Material.PolylineTrailLinkImage,
              time: 0,
            },
            source: Cesium.Material.PolylineTrailLinkSource,
          },
          translucent: function (material) {
            return true
          },
        }
      )
    },
  }

動態(tài)邊界

添加動態(tài)墻顯示園區(qū)邊界


光墻_ss.gif
addBorder() {
      /**
       * @description: 添加園區(qū)動態(tài)光效墻
       * @param {*}
       * @author: citrusrlia@foxmail.com
       */
      let alp = 1,
        num = 0
      const border = viewer.entities.add({
        name: 'my-border',
        wall: {
          show: true,
          positions: new Cesium.Cartesian3.fromDegreesArrayHeights([
            -74.0134334564209, 40.71439496334888, 100, -74.01660919189453,
            40.70500981124441, 100, -74.01418447494507, 40.70463567898069, 100,
            -74.00809049606323, 40.71203660068803, 100, -74.0134334564209,
            40.71439496334888, 100,
          ]),
          material: new Cesium.ImageMaterialProperty({
            image: 'fade_blue.jpeg',
            transparent: true,
            color: new Cesium.CallbackProperty(function () {
              if (num % 2 === 0) {
                alp -= 0.005
              } else {
                alp += 0.005
              }

              if (alp <= 0.3) {
                num++
              } else if (alp >= 1) {
                num++
              }
              return Cesium.Color.WHITE.withAlpha(alp)
            }, false),
          }),
        },
      })
    }

地標信息

添加地標label媒楼,設置對應可視距離乐尊。

addLabel() {
      /**
       * @description: 添加Label 設置label可見距離
       * @param {*}
       * @author: citrusrlia@foxmail.com
       */
      const that = this
      for (let i = 0, l = Object.keys(this.places).length; i < l; i++) {
        viewer.entities.add({
          name: Object.keys(this.places)[i],
          position: Cesium.Cartesian3.fromDegrees(
            this.places[Object.keys(this.places)[i]][0],
            this.places[Object.keys(this.places)[i]][1],
            this.places[Object.keys(this.places)[i]][2]
          ),
          label: {
            text: Object.keys(this.places)[i],
            scale: 0.6,
            fillColor: Cesium.Color.fromCssColorString('#ffffff'), //字體顏色
            backgroundColor: Cesium.Color.fromCssColorString('#666666'), //背景顏色
            showBackground: true, //是否顯示背景顏色
            // style: 2, //label樣式
            // show: false,
            outlineWidth: 1,
            verticalOrigin: Cesium.VerticalOrigin.CENTER, //垂直位置
            horizontalOrigin: Cesium.HorizontalOrigin.LEFT, //水平位置
            pixelOffset: new Cesium.Cartesian2(-50, 0), //偏移
            eyeOffset: new Cesium.Cartesian3(0, 0, -10), // 負值則在更上層
          },
          scaleByDistance: new Cesium.NearFarScalar(100, 2, 500, 0.0),
        })
      }
      let labelArray = [
        [-74.01319334175476, 40.708918331339284, '格林威治街給水管'],
        [-74.01117454037451, 40.708399481792796, '華爾街中央給水管'],
        [-74.0130122995653, 40.707738996075705, '尤特爾街給水管'],
        [-74.01235941779147, 40.70907308085917, '泰晤士街給水管'],
        [-74.01118964381898, 40.7063315127262, '拿索街給水管'],
      ]
      for (let i = 0, l = labelArray.length; i < l; i++) {
        viewer.entities.add({
          name: 'underground_pip_' + i,
          position: Cesium.Cartesian3.fromDegrees(
            labelArray[i][0],
            labelArray[i][1],
            10
          ),
          show: false,
          label: {
            text: labelArray[i][2],
            scale: 0.6,
            fillColor: Cesium.Color.fromCssColorString('#ffffff'), //字體顏色
            backgroundColor: Cesium.Color.fromCssColorString('#666666'), //背景顏色
            showBackground: true, //是否顯示背景顏色
            // style: 2, //label樣式
            // show: false,
            outlineWidth: 1,
            // clampToGround:true,
            verticalOrigin: Cesium.VerticalOrigin.CENTER, //垂直位置
            horizontalOrigin: Cesium.HorizontalOrigin.LEFT, //水平位置
            pixelOffset: new Cesium.Cartesian2(-50, 0), //偏移
            eyeOffset: new Cesium.Cartesian3(0, 0, -1000), // 負值則在更上層
          },
        })
      }
    }

園區(qū)漫游

自由漫游

使用wasd控制行動,鼠標左鍵控制方向划址。


自由漫游s.gif
startRoaming() {
    this.roamingSettings(false);
    /* 自由漫游初始點位 */
    this.cameraFlyTo(
      new Cesium.Cartesian3(
        1333262.809154561,
        -4654847.86027459,
        4137655.768559768
      ),
      0.4234449223726292,
      0,
      6.283167794440473
    );
    let that = this;
    const ellipsoid = that.viewer.scene.globe.ellipsoid;
    let startMousePosition;
    let mousePosition;
    let flags = this.roamingFlags;
    flags.available = true;
    this.handler = new Cesium.ScreenSpaceEventHandler(that.viewer.scene.canvas);
    let handler = this.handler;
    handler.setInputAction(function (movement) {
      flags.looking = true;
      mousePosition = startMousePosition = Cesium.Cartesian3.clone(
        movement.position
      );
    }, Cesium.ScreenSpaceEventType.LEFT_DOWN);

    handler.setInputAction(function (movement) {
      mousePosition = movement.endPosition;
    }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);

    handler.setInputAction(function (position) {
      flags.looking = false;
    }, Cesium.ScreenSpaceEventType.LEFT_UP);

    function getFlagForKeyCode(keyCode) {
      switch (keyCode) {
        case "W".charCodeAt(0):
          return "moveForward";
        case "S".charCodeAt(0):
          return "moveBackward";
        case "Q".charCodeAt(0):
          return "moveUp";
        case "E".charCodeAt(0):
          return "moveDown";
        case "D".charCodeAt(0):
          return "moveRight";
        case "A".charCodeAt(0):
          return "moveLeft";
        default:
          return undefined;
      }
    }

    document.addEventListener(
      "keydown",
      function (e) {
        let flagName = getFlagForKeyCode(e.keyCode);
        if (typeof flagName !== "undefined") {
          flags[flagName] = true;
        }
      },
      false
    );

    document.addEventListener(
      "keyup",
      function (e) {
        let flagName = getFlagForKeyCode(e.keyCode);
        if (typeof flagName !== "undefined") {
          flags[flagName] = false;
        }
      },
      false
    );

    that.viewer.clock.onTick.addEventListener(function (clock) {
      let camera = that.viewer.camera;
      if (!flags.available) {
        return;
      }
      if (flags.looking) {
        let width = that.viewer.scene.canvas.clientWidth;
        let height = that.viewer.scene.canvas.clientHeight;
        /* 保證MousePositon存在 */
        if (mousePosition) {
          // Coordinate (0.0, 0.0) will be where the mouse was clicked.
          let x = (mousePosition.x - startMousePosition.x) / width;
          let y = -(mousePosition.y - startMousePosition.y) / height;
          /* 轉(zhuǎn)向系數(shù) */
          let lookFactor = 0.05;
          camera.lookRight(x * lookFactor);
          camera.lookUp(y * lookFactor);
        }
      }

      // 移動系數(shù)
      let cameraHeight = ellipsoid.cartesianToCartographic(camera.position)
        .height;
      let moveRate = cameraHeight / 20.0;

      if (flags.moveForward) {
        camera.moveForward(moveRate);
      }
      if (flags.moveBackward) {
        camera.moveBackward(moveRate);
      }
      if (flags.moveUp) {
        camera.moveUp(moveRate);
      }
      if (flags.moveDown) {
        camera.moveDown(moveRate);
      }
      if (flags.moveLeft) {
        camera.moveLeft(moveRate);
      }
      if (flags.moveRight) {
        camera.moveRight(moveRate);
      }
    });
  }

給定線路漫游

通過畫線繪制漫游路線扔嵌,通過漫游點列表編輯或刪除漫游點,點擊開始漫游后跟隨所畫線路漫游


漫游點編輯s.gif

漫游點漫游s.gif
addPlace(position) {
      /**
       * @description:添加漫游點
       * @param {*}position:Cartisian3
       * @author: citrusrlia@foxmail.com
       */
      let Stop = {}
      //參數(shù)傳入站點變量
      Stop.position = position
      Stop.time = 5
      Stop.name = '漫游點'
      if (this.allStops.length < 1) {
        Stop.heading = 0
        Stop.pitch = 0
        Stop.roll = 0
      } else {
        Stop.heading = this.getHeading(
          this.allStops.slice(-1)[0].position,
          position
        )
        Stop.pitch = this.getPitch(
          this.allStops.slice(-1)[0].position,
          position
        )
        Stop.roll = 0
      }

      //傳入飛行站點數(shù)組
      this.allStops.push(Stop)
      this.$notify({
        title: '成功',
        message: '添加漫游點成功',
        type: 'success',
      })

      let length = this.allStops.length

      if (this.allStops.length > 1) {
        // 實體路線
        viewer.entities.add({
          id: 'fly_line_' + (this.allStops.length + 1),

          polyline: {
            positions: [
              this.allStops[length - 2].position,

              this.allStops[length - 1].position,
            ],
            width: 5,
            material: Cesium.Color.BLUE,
          },
          show: this.line_bool,
        })
      }
      /* 動態(tài)點參數(shù) */
      let x = 0
      let size = 10
      let isAdd = true
      let isZoom = true

      viewer.entities.add({
        position: this.allStops[length - 1].position,
        point: {
          color: new Cesium.CallbackProperty(function () {
            if (isAdd) {
              x = x + 0.05
              if (x > 1) {
                isAdd = false
              }
            } else {
              x = x - 0.05
              if (x < 0) {
                isAdd = true
              }
            }
            return Cesium.Color.fromCssColorString('#ffffff')
          }, false),
          pixelSize: new Cesium.CallbackProperty(function () {
            if (isZoom) {
              size = size + 0.5
              if (size > 10) {
                isZoom = false
              }
            } else {
              size = size - 0.5
              if (size < 3) {
                isZoom = true
              }
            }
            return size
          }, false),
          outlineWidth: 1,
          outlineColor: new Cesium.CallbackProperty(function () {
            return Cesium.Color.fromCssColorString('#ffffff').withAlpha(0.2)
          }, false),
          disableDepthTestDistance: Number.POSITIVE_INFINITY,
        },
        id: 'fly_nail_' + (this.allStops.length + 1),
      })
    },
    cleanPlace() {
      /**
       * @description: 清除所有漫游路線
       * @param {*}
       * @author: citrusrlia@foxmail.com
       */
      /* 清除所有線路夺颤,統(tǒng)一重繪 */
      for (let i = 0, l = viewer.entities._entities._array.length; i < l; i++) {
        if (viewer.entities._entities._array[i].id?.indexOf('fly') > -1) {
          viewer.entities.remove(viewer.entities._entities._array[i])
          i--
          l--
        }
      }
    },
    startFly() {
      /**
       * @description: 開始飛行
       * @param {*} this
       * @author: citrusrlia@foxmail.com
       */
      if (this.allStops.length < 1) {
        this.$notify.error({
          title: '錯誤',
          message: '請?zhí)砑又辽賰蓚€漫游點',
        })
        return
      }
      const that = this
      const scene = viewer.scene
      this.reCalStops()
      if (this.tempFlyPoint) {
        /* 暫停漫游 繼續(xù) */
        this.flyIndex = this.tempFlyPoint
        this.tempFlyPoint = undefined
        if (this.flyIndex < this.allStops.length) {
          /* 關閉鏡頭控制 */
          scene.screenSpaceCameraController.enableRotate = false
          scene.screenSpaceCameraController.enableTranslate = false
          scene.screenSpaceCameraController.enableZoom = false
          scene.screenSpaceCameraController.enableTilt = false
          scene.screenSpaceCameraController.enableLook = false

          viewer.camera.setView({
            destination: this.allStops[this.flyIndex - 1].position,
            orientation: {
              heading: this.allStops[this.flyIndex - 1].heading,
              pitch: this.allStops[this.flyIndex - 1].pitch,
              roll: this.allStops[this.flyIndex - 1].roll,
            },
          })
          fly()
        }
      } else {
        this.flyIndex = 1
        if (this.flyIndex < this.allStops.length) {
          scene.screenSpaceCameraController.enableRotate = false
          scene.screenSpaceCameraController.enableTranslate = false
          scene.screenSpaceCameraController.enableZoom = false
          scene.screenSpaceCameraController.enableTilt = false
          scene.screenSpaceCameraController.enableLook = false
          /* 使用setView定位第一個漫游點 */
          viewer.camera.setView({
            destination: this.allStops[0].position,
            orientation: {
              heading: this.allStops[0].heading,
              pitch: this.allStops[0].pitch,
              roll: this.allStops[0].roll,
            },
          })
          fly()
        }
      }
      function changeCameraHeading(stopIndex, duration = 5) {
        /**
         * @description: 轉(zhuǎn)向
         * @param {*}
         * @author: citrusrlia@foxmail.com
         */
        viewer.camera.setView({
          orientation: {
            heading: that.allStops[stopIndex + 1].heading, // 方向
            pitch: that.allStops[stopIndex + 1].pitch, // 傾斜角度
          },
        })
        let count = 1
        let thisHeadingDegree = Cesium.Math.toDegrees(viewer.camera.heading)
        let nextHeadingDegree = Cesium.Math.toDegrees(
          that.allStops[stopIndex + 1].heading
        )
        let angle = nextHeadingDegree - thisHeadingDegree
        let perTurn = Cesium.Math.toRadians(angle / duration)
        let turningCallback = (time, result) => {
          if (count == duration) {
            viewer.scene.postRender.removeEventListener(turningCallback)
            return
          }
          viewer.camera.flyTo({
            destination: that.allStops[stopIndex + 1].position,
            orientation: {
              heading: perTurn + viewer.camera.heading,
              pitch: that.allStops[stopIndex + 1].pitch,
            },
            duration: 5,
          })
          count += 1
        }
        // viewer.scene.postRender.addEventListener(turningCallback)
      }
      function fly() {
        /**
         * @description: 飛行主函數(shù)
         * @param {*} that
         * @author: citrusrlia@foxmail.com
         */
        if (that.flyIndex >= that.allStops.length) {
          /* 飛行結(jié)束 */
          scene.screenSpaceCameraController.enableRotate = true
          scene.screenSpaceCameraController.enableTranslate = true
          scene.screenSpaceCameraController.enableZoom = true
          scene.screenSpaceCameraController.enableTilt = true
          scene.screenSpaceCameraController.enableLook = true
          MyCamera.resetCamera()
        } else {
          let l = that.flyIndex
          if (l >= 1) {
            viewer.camera.flyTo({
              destination: that.allStops[l].position, // 設置位置
              orientation: {
                heading: that.allStops[l - 1].heading, // 方向
                pitch: that.allStops[l - 1].pitch, // 傾斜角度
                roll: that.allStops[l - 1].roll,
              },
              // easingFunction: Cesium.EasingFunction.CUBIC_IN_OUT,
              duration: 5, // 設置飛行持續(xù)時間痢缎,默認會根據(jù)距離來計算
              complete: function () {
                /* 飛完后執(zhí)行下一站,調(diào)整鏡頭角度指向下一站 */
                if (l + 1 < that.allStops.length) {
                  changeCameraHeading(l)
                }
                fly()
              },
            })
          }
          that.flyIndex++
        }
      }
    },
    // 飛行暫停
    pauseFly() {
      this.tempFlyPoint = this.flyIndex
      this.flyIndex = this.allStops.length + 1
    },
    // 飛行停止
    stopFly() {
      this.flyIndex = this.allStops.length + 1
      this.tempFlyPoint = undefined
      viewer.scene.screenSpaceCameraController.enableRotate = true
      viewer.scene.screenSpaceCameraController.enableTranslate = true
      viewer.scene.screenSpaceCameraController.enableZoom = true
      viewer.scene.screenSpaceCameraController.enableTilt = true
      viewer.scene.screenSpaceCameraController.enableLook = true
      MyCamera.resetCamera()
    },
    changeLine() {
      viewer.entities._entities._array.forEach((res) => {
        if (res.id.indexOf('fly') > -1) {
          res.show = !res.show
        }
      })
      this.tempFlyPoint = undefined
    }

視頻影像融合

通過video標簽構建dom實體,將其設為entity的材質(zhì)對象.


視頻融合s.gif
// video標簽世澜,設置autoplay和display:none
<video ref="video" autoplay loop crossorigin controls style="display: none">
    <source
      src="https://cesium.com/public/SandcastleSampleData/big-buck-bunny_trailer.mp4"
      type="video/mp4"
    />
  </video>

addVideo() {
      /**
       * @description: 添加視頻
       * @param {*}
       * @author: citrusrlia@foxmail.com
       */
      const videoElement = this.$refs.video
      viewer.showRenderLoopErrors = false
      viewer.shouldAnimate = true

      viewer.entities.add({
        name: 'video-screen',
        id: 'video_screen',
        wall: {
          positions: Cesium.Cartesian3.fromDegreesArrayHeights([
            -74.01595609453216, 40.706172490663725, 120, -74.0162584955552,
            40.70537146061003, 120,
          ]),
          material: videoElement,
          // clampToGround: true,
        },
        show: false,
      })
    }

應急事件

在地圖上顯示應急事件(應是傳感器實時信息)独旷,并可以定位,設置影響范圍寥裂。


定位火源_s.gif

改變火源位置_s.gif
addParticleSystem() {
      /**
       * @description:添加粒子效果與波紋效果
       * @param {*}
       * @author: citrusrlia@foxmail.com
       */
      const that = this
      const viewModel = {
        emissionRate: 200.0,
        gravity: 0,
        minimumParticleLife: 1.5,
        maximumParticleLife: 1.8,
        minimumSpeed: 7,
        maximumSpeed: 9,
        startScale: 3.0,
        endScale: 1.5,
        particleSize: 2,
      }
      let emitterModelMatrix = new Cesium.Matrix4()
      let translation = new Cesium.Cartesian3()
      let rotation = new Cesium.Quaternion()
      let hpr = new Cesium.HeadingPitchRoll()
      let trs = new Cesium.TranslationRotationScale()

      that.entity = viewer.entities.add({
        position: this.particlePoint,
      })
      let gravityScratch = new Cesium.Cartesian3()
      function computeEmitterModelMatrix() {
        //調(diào)節(jié)粒子的發(fā)射方向
        hpr = Cesium.HeadingPitchRoll.fromDegrees(0.0, 0.0, 0.0, hpr)
        //噴泉位置
        trs.translation = Cesium.Cartesian3.fromElements(0, 0, 5.4, translation)
        trs.rotation = Cesium.Quaternion.fromHeadingPitchRoll(hpr, rotation)

        return Cesium.Matrix4.fromTranslationRotationScale(
          trs,
          emitterModelMatrix
        )
      }
      /* 重力,火焰特效時關閉,漏水特效時開啟 */
      function applyGravity(p, dt) {
        // We need to compute a local up vector for each particle in geocentric space.
        var position = p.position

        Cesium.Cartesian3.normalize(position, gravityScratch)
        Cesium.Cartesian3.multiplyByScalar(
          gravityScratch,
          viewModel.gravity * dt,
          gravityScratch
        )

        p.velocity = Cesium.Cartesian3.add(
          p.velocity,
          gravityScratch,
          p.velocity
        )
      }
      function computeModelMatrix(entity, time) {
        return entity.computeModelMatrix(time, new Cesium.Matrix4())
      }
      const particleSystem = viewer.scene.primitives.add(
        new Cesium.ParticleSystem({
          show: false,
          image: 'fire4.png',
          startColor: new Cesium.Color(1, 1, 1, 1),
          endColor: new Cesium.Color(0.5, 0, 0, 0),
          startScale: viewModel.startScale,
          endScale: viewModel.endScale,
          minimumParticleLife: viewModel.minimumParticleLife,
          maximumParticleLife: viewModel.maximumParticleLife,
          minimumSpeed: viewModel.minimumSpeed,
          maximumSpeed: viewModel.maximumSpeed,
          imageSize: new Cesium.Cartesian2(
            viewModel.particleSize,
            viewModel.particleSize
          ),
          emissionRate: viewModel.emissionRate,
          lifetime: 6.0,
          //粒子發(fā)射器
          emitter: new Cesium.SphereEmitter(2.5),
          emitterModelMatrix: computeEmitterModelMatrix(),
          // updateCallback: applyGravity,
          sizeInMeters: true,
          performance: false,
        })
      )
      viewer.scene.preUpdate.addEventListener(function (scene, time) {
        particleSystem.modelMatrix = computeModelMatrix(that.entity, time)
        // Account for any changes to the emitter model matrix.
        particleSystem.emitterModelMatrix = computeEmitterModelMatrix()
      })
      /**
       * @description: 添加應急點波紋特效
       * @param {*}
       * @author: citrusrlia@foxmail.com
       */
      let myAxis = 0,
        myAxis2 = 0
      const waveCallback = new Cesium.CallbackProperty((time, result) => {
        myAxis += 1
        if (myAxis >= that.maxendAxis) {
          myAxis = 1
          return 1
        }
        return myAxis
      }, false)
      const waveCallback2 = new Cesium.CallbackProperty((time, result) => {
        myAxis2 += 1
        if (myAxis2 >= that.maxendAxis) {
          myAxis2 = 1
          return 1
        }
        return myAxis2
      }, false)
      viewer.entities.add({
        id: 'waveEffect',
        show: false,
        ellipse: {
          clampToGround: true, // 與outline無法一起啟用
          semiMinorAxis: waveCallback,
          semiMajorAxis: waveCallback2,
          // outline: true,
          // outlineColor: Cesium.Color.RED,
          // outlineWidth: 20,
          material: Cesium.Color.RED.withAlpha(0.3),
        },
        position: this.particlePoint,
      })
    }
changeParticlePoint() {
      /**
       * @description: 改變粒子效果位置
       * @param {*}
       * @author: citrusrlia@foxmail.com
       */
      const that = this
      that.$notify({
        title: '變更應急點',
        message: '移動鼠標改變位置嵌洼,點擊鼠標右鍵確認。',
        duration: 0,
      })
      let em_handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas)
      em_handler.setInputAction((e) => {
        let ray = viewer.scene.camera.getPickRay(e.endPosition)
        let cartesian3 = viewer.scene.globe.pick(ray, viewer.scene)
        that.particlePoint = cartesian3
        let waveEntity = viewer.entities.getById('waveEffect')
        waveEntity.position._value = cartesian3
        that.entity.position._value = cartesian3
      }, Cesium.ScreenSpaceEventType.MOUSE_MOVE)
      em_handler.setInputAction((e) => {
        let ray = viewer.scene.camera.getPickRay(e.position)
        let cartesian3 = viewer.scene.globe.pick(ray, viewer.scene)
        that.particlePoint = cartesian3
        let waveEntity = viewer.entities.getById('waveEffect')
        waveEntity.position._value = cartesian3
        that.entity.position._value = cartesian3
        em_handler.removeInputAction(Cesium.ScreenSpaceEventType.MOUSE_MOVE)
        em_handler.removeInputAction(Cesium.ScreenSpaceEventType.RIGHT_CLICK)
      }, Cesium.ScreenSpaceEventType.RIGHT_CLICK)
    }

信息彈窗與邊框拾取

點擊模型封恰、標簽等彈出信息窗口麻养,鼠標滑過模型有邊框拾取。


handler_s.gif
 init(viewer) {
    /**
     * @description: handler初始化
     * @param {*}
     * @author: citrusrlia@foxmail.com
     */
    const that = this
    this.viewer = viewer
    this.handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas)
    this.handler.setInputAction((e) => {
      let pickedObject = that.viewer.scene.pick(e.position)
      let pickPosition = that.viewer.scene.camera.pickEllipsoid(e.position)
      let cartographic = Cesium.Cartographic.fromCartesian(
        pickPosition,
        that.viewer.scene.globe.ellipsoid,
        new Cesium.Cartographic()
      )
      let lat = Cesium.Math.toDegrees(cartographic.latitude)
      let lng = Cesium.Math.toDegrees(cartographic.longitude)
      let height = cartographic.height
      console.log('[Lng=>' + lng + ',Lat=>' + lat + ',H=>' + height + ']')
      /* 選擇模型 */
      if (pickedObject && pickedObject.content) {
        that.lastPickedObject &&
          (that.lastPickedObject.color = that.lastPickedColor)
        that.lastPickedObject = pickedObject
        that.lastPickedColor = pickedObject.color
        pickedObject.color = Cesium.Color.RED
      } else {
        that.lastPickedObject &&
          (that.lastPickedObject.color = that.lastPickedColor)
        that.lastPickedObject = null
        that.lastPickedColor = null
      }
      if (
        that.viewer.scene.pickPositionSupported &&
        Cesium.defined(pickedObject) &&
        pickedObject.id
      ) {
        /* todo 判斷是否點擊primitive */
        if (pickedObject.id.constructor == String) {
        }
      }
    }, Cesium.ScreenSpaceEventType.LEFT_CLICK)
    /* 3Dtile藍色邊框 */
    const silhouetteBlue =
      Cesium.PostProcessStageLibrary.createEdgeDetectionStage()
    silhouetteBlue.uniforms.color = Cesium.Color.BLUE
    silhouetteBlue.uniforms.length = 0.01
    silhouetteBlue.selected = []
    const silhouetteGreen =
      Cesium.PostProcessStageLibrary.createEdgeDetectionStage()
    silhouetteGreen.uniforms.color = Cesium.Color.LIME
    silhouetteGreen.uniforms.length = 0.01
    silhouetteGreen.selected = []

    viewer.scene.postProcessStages.add(
      Cesium.PostProcessStageLibrary.createSilhouetteStage([
        silhouetteBlue,
        silhouetteGreen,
      ])
    )
    // Information about the currently selected feature
    const selected = {
      feature: undefined,
      originalColor: new Cesium.Color(),
    }

    // An entity object which will hold info about the currently selected feature for infobox display
    const selectedEntity = new Cesium.Entity()
    this.handler.setInputAction((e) => {
      silhouetteBlue.selected = []
      var pickedFeature = viewer.scene.pick(e.endPosition)
      if (pickedFeature !== selected.feature) {
        silhouetteBlue.selected = [pickedFeature]
      }
    }, Cesium.ScreenSpaceEventType.MOUSE_MOVE)

    // this.initMeasure()
    return this
  }

四诺舔、 結(jié)語

git地址:https://gitee.com/han_wu_xian/cesium-demo.git
本例使用數(shù)據(jù)均開源合法鳖昌,如果這篇文章對你有一些幫助,那我會很開心??

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末低飒,一起剝皮案震驚了整個濱河市许昨,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌逸嘀,老刑警劉巖车要,帶你破解...
    沈念sama閱讀 216,651評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件允粤,死亡現(xiàn)場離奇詭異崭倘,居然都是意外死亡,警方通過查閱死者的電腦和手機类垫,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,468評論 3 392
  • 文/潘曉璐 我一進店門司光,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人悉患,你說我怎么就攤上這事残家。” “怎么了售躁?”我有些...
    開封第一講書人閱讀 162,931評論 0 353
  • 文/不壞的土叔 我叫張陵坞淮,是天一觀的道長茴晋。 經(jīng)常有香客問我,道長回窘,這世上最難降的妖魔是什么诺擅? 我笑而不...
    開封第一講書人閱讀 58,218評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮啡直,結(jié)果婚禮上烁涌,老公的妹妹穿的比我還像新娘。我一直安慰自己酒觅,他們只是感情好撮执,可當我...
    茶點故事閱讀 67,234評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著舷丹,像睡著了一般抒钱。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上颜凯,一...
    開封第一講書人閱讀 51,198評論 1 299
  • 那天继效,我揣著相機與錄音,去河邊找鬼装获。 笑死瑞信,一個胖子當著我的面吹牛胁附,可吹牛的內(nèi)容都是我干的欢顷。 我是一名探鬼主播,決...
    沈念sama閱讀 40,084評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼呀闻,長吁一口氣:“原來是場噩夢啊……” “哼精肃!你這毒婦竟也來了秤涩?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,926評論 0 274
  • 序言:老撾萬榮一對情侶失蹤司抱,失蹤者是張志新(化名)和其女友劉穎筐眷,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體习柠,經(jīng)...
    沈念sama閱讀 45,341評論 1 311
  • 正文 獨居荒郊野嶺守林人離奇死亡匀谣,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,563評論 2 333
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了资溃。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片武翎。...
    茶點故事閱讀 39,731評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖溶锭,靈堂內(nèi)的尸體忽然破棺而出宝恶,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 35,430評論 5 343
  • 正文 年R本政府宣布垫毙,位于F島的核電站霹疫,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏综芥。R本人自食惡果不足惜更米,卻給世界環(huán)境...
    茶點故事閱讀 41,036評論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望毫痕。 院中可真熱鬧征峦,春花似錦、人聲如沸消请。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,676評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽臊泰。三九已至蛉加,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間缸逃,已是汗流浹背针饥。 一陣腳步聲響...
    開封第一講書人閱讀 32,829評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留需频,地道東北人丁眼。 一個月前我還...
    沈念sama閱讀 47,743評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像昭殉,于是被迫代替她去往敵國和親苞七。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,629評論 2 354

推薦閱讀更多精彩內(nèi)容