vue3.2+ts+cesium制作3DGIS效果的大屏(上)

大屏主场景是3d的一个gis,用的是cesium,在线服务的arcGis,离线服务的瓦片是百度图

在cesium中实现 地球自转,昼夜光照,定位追踪平滑视角转移,定位追踪直接视角转移,开启地形服务实现瓦片模型偏移贴地加载+glb贴地加载,告警异常变红呼吸提示效果,点击特效,点击挂载dom节点入cesium,3d嵌套2d内再嵌套3d,左键点击标记效果,左键点击定位追踪效果,左键点击区分效果,右键查询笛卡尔坐标系,右键落点贴地生成站房效果并进行打点

先贴一点效果,图3瓦片是太原市的 我demo场景是阳泉市 

图一 

vue3.2+ts+cesium制作3DGIS效果的大屏(上)_第1张图片

图二 

图三 

vue3.2+ts+cesium制作3DGIS效果的大屏(上)_第2张图片

图四 

图五 

初始化的配置项贴一个我常用的在线图 arcGis的非常的好用,离线服务后续我再开一篇文章讲述离线gis的搭建

/*
vue版本 3.2
echatrs版本 5.3.2
echarts-gl版本 2.0.9
cesium基础底图 ArcGIS在线底图
cesium地形叠加​ ArcGIS地形
*/
let viewerLoad:Function = (data:number,Cesium:any):Object =>{
    return [{
        geocoder:false,    
        homeButton:false,
        sceneModePicker:true,
        baseLayerPicker:false,
        navigationHelpButton:false,
        animation:false,
        timeline:false,
        fullscreenButton:false,
        vrButton:false,
        // terrainProvider:Cesium.createWorldTerrain(),
        // terrainProvider:Cesium.createWorldTerrain({
        //     url : 'https://elevation3d.arcgis.com/arcgis/rest/services/WorldElevation3D/Terrain3D/ImageServer',
        //     requestVertexNormals: true,requestWaterMask: true
        // }),
        terrainExaggeration: 2,
        imageryProvider:new Cesium.ArcGisMapServerImageryProvider({
            url : 'https://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer'
        })
    }][data]
}

export default viewerLoad;

 然后我们写一个地球的初始界面 完成图一的效果,写一段html

 当dom挂载完成之后我们生成我们的地球


import { reactive,provide,inject,onMounted,ref} from 'vue';
import viewerLoad from './home.ts'
let viewer:any=null
onMounted(()=>{
  viewer = new Cesium.Viewer("cesiumContainer",  viewerLoad(0,Cesium));
  viewer.scene.globe.enableLighting = true;
})

只要简短的代码我们就能获得初始的地球了ok了  那么我们来实现自转的效果,那么再加上地球自转的效果,代码已经完成了,只需要new一个GlobeRotate 对象传入viewer参数,之后使用对象调用stop或者start来控制地球自转的效果

class GlobeRotate {
  constructor(V) {this._viewer = V; }
  _icrf() {
    if (this._viewer.scene.mode !== Cesium.SceneMode.SCENE3D) {
      return ture;
    }
    let icrfToFixed = Cesium.Transforms.computeIcrfToFixedMatrix(this._viewer.clock.currentTime);
    if (icrfToFixed) {
      let camera = this._viewer.camera;
      let offset = Cesium.Cartesian3.clone(camera.position);
      let transform = Cesium.Matrix4.fromRotationTranslation(icrfToFixed);
      camera.lookAtTransform(transform, offset);
    }
  }
  _bindEvent() {
    this._viewer.clock.multiplier = 15 * 300;
    this._viewer.camera.lookAtTransform(Cesium.Matrix4.IDENTITY);
    this._viewer.scene.postUpdate.addEventListener(this._icrf, this);
  }
  _unbindEvent() {
    this._viewer.clock.multiplier = 1;
    this._viewer.camera.lookAtTransform(Cesium.Matrix4.IDENTITY);
    this._viewer.scene.postUpdate.removeEventListener(this._icrf, this);
  }
  start() {
    this._viewer.clock.shouldAnimate = true;
    this._unbindEvent();
    this._bindEvent();
    return this;
  }
  stop() {
    this._unbindEvent();
    return this;
  }
}

然后我们选择一个地址  我的项目用的是山西的经纬度  相机视角直接定位过去

  viewer.camera.setView({
    destination: Cesium.Cartesian3.fromDegrees(65.562942,43.86264,22206333),//山西阳泉
    orientation: {
      heading: Cesium.Math.toRadians(45), pitch: Cesium.Math.toRadians(-90),
      roll: Cesium.Math.toRadians(0 ), range:10000
    }})
  viewer.zoomTo(viewer);

 我们开始加载模型了,我们分别加载obj的瓦片(后缀是json的url)和glb的模型(后缀是glb的url),瓦片加载之后只需要稍微调整一下经纬度高度偏移度缩放以及透明度,glb我测试加载了很多,然后然后选择一个标记红色告警呼吸的动画效果并且加上独特的tip点击提示效果

  let tileset=viewer.scene.primitives.add( new Cesium.Cesium3DTileset({ url: "3DTiles/bm/tileset.json", }) )
  tileset.readyPromise.then((currentModel:any)=> {
    let mx = Cesium.Matrix3.fromRotationX(Cesium.Math.toRadians(38));
    let my = Cesium.Matrix3.fromRotationY(Cesium.Math.toRadians(4));
    let mz = Cesium.Matrix3.fromRotationZ(Cesium.Math.toRadians(40));
    let rotationX = Cesium.Matrix4.fromRotationTranslation(mx);
    let rotationY = Cesium.Matrix4.fromRotationTranslation(my);
    let rotationZ = Cesium.Matrix4.fromRotationTranslation(mz);
    let position = Cesium.Cartesian3.fromDegrees( 113.53,37.93,-7464 );
    let m = Cesium.Transforms.eastNorthUpToFixedFrame(position);
    Cesium.Matrix4.multiply(m, rotationX, m);
    Cesium.Matrix4.multiply(m, rotationY, m);
    Cesium.Matrix4.multiply(m, rotationZ, m);
    let scale = Cesium.Matrix4.fromUniformScale(0.005);
    Cesium.Matrix4.multiply(m, scale, m);
    currentModel._root.transform = m;
    // viewer.scene.globe.translucency.frontFaceAlphaByDistance.nearValue = Cesium.Math.clamp( 0.5, 0.0, 1.0 );
  });


  let tempArr: number[][]=[[1,2,3,4,5,6,7],[1,2,3,4,5,6,7,8]],tempNumber=1;
  for (let index0=0;index0<30;index0++){
    for (let index1=0;index1<40;index1++){
      let modelMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(
       Cesium.Cartesian3.fromDegrees(113.557942+index1/1800,37.86464+index0/1800,660.0));
      let model = scene.primitives.add(Cesium.Model.fromGltf({
        url : 'Models/hcity/model38.glb',
        modelMatrix : modelMatrix,scale : 20.0,
      }));
      if(index0 === 6 && index1 === 26){
        model.color.green=model.color.blue=0
        model.Mid='001'
        twinkles.push(model)
      }
    }
  }

给Mid为001的加上点击tip的效果 并且更正视角 重新定位,对于其他的模型只做选择效果 切换rgb中的re来实现,

 let handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
        let leftclick = Cesium.ScreenSpaceEventType.LEFT_CLICK;
        viewer.screenSpaceEventHandler.removeInputAction(leftclick);
        handler.setInputAction((clickEvent:any) => {
          let ray1 = viewer.camera.getPickRay(clickEvent.position);
          let cartesian = viewer.scene.globe.pick(ray1, viewer.scene);
          let pick = viewer.scene.pickPosition(clickEvent.position);
          let pickModel = viewer.scene.pick(clickEvent.position);
          if(pickModel ) {
            if(pickModel.primitive.Mid === "001"){
              ttc.value=true
              pickModel.primitive.readyPromise.then(function(model:any) {
                let camera = viewer.camera;
                let scene = viewer.scene;
                let center = Cesium.Matrix4.multiplyByPoint(model.modelMatrix,model.boundingSphere.center, new Cesium.Cartesian3());
                let hpr = new Cesium.HeadingPitchRange(Cesium.Math.toRadians(90), Cesium.Math.toRadians(-50) , 1500);
                camera.lookAt(center,hpr );
              })
            }else{
              if(pickModel.primitive.color.red !==0){
                pickModel.primitive.color.red=0
              }else{
                pickModel.primitive.color.red=1
              }
            }
          }
        }, leftclick)

然后就实现的图二跟图三的加载之后排版效果了

本文共分两个阶段,点我主页看下面效果的实现步骤以及代码,需要源码或者效果指导请找我描述

你可能感兴趣的:(GIS,typescript,javascript,前端)