Cesium-基础入门

Cesium 数据

影像数据:Bing、天地图、ArcGIS、OSM、WMTS、WMS等

地形数据:ArcGIS、谷歌、STK等

矢量数据:KML、KMZ、GeoJSON、TopoJSON、CZML

三维模型:GLTF、GLB(二进制glTF文件)

三维瓦片:3D Tiles(倾斜摄影、人工模型、 三维建筑物、CAD、BIM,点云数据等)

Cesium 坐标系统

  • WGS84弧度坐标系(Cartographic)
    弧度= π/180×经纬度角度

  • 笛卡尔空间直角坐标系(Cartesian3)

    平面坐标系(Cartesian2)

    4D笛卡尔坐标系(Cartesian4)

项目初始化

  1. vite一个项目

  2. npm i cesium@1.99 vite-plugin-cesium

  3. 配置插件

    import cesium from 'vite-plugin-cesium'
    export default defineConfig({
      plugins: [
        vue(),
        vueDevTools(),
        cesium(),
      ],
    
  4. app.vue中引入Cesium

    import * as Cesium from 'cesium'
    console.log(Cesium)
    
  5. 一个页面

    <template>
      <div id="cesiumContainer"></div>
    </template>
     
    <script setup>
    import { onMounted } from 'vue'
    import * as Cesium from 'cesium'
     
    onMounted(() => {
      // 使用Cesium的Ion服务进行认证
      Cesium.Ion.defaultAccessToken = '';
     
      // 创建一个Viewer实例
      const viewer = new Cesium.Viewer('cesiumContainer', {
        // 使用默认的影像图层和地形图层
        terrainProvider: Cesium.createWorldTerrain({ requestWaterMask: true })
      })
    })
    </script>
     
    <style scoped>
    #cesiumContainer {
     width: 100vw;
     height: 100vh;
     overflow: hidden;
    }
    </style>
    

Viewer基础操作

  • 地图加载与初始化
    通过创建一个Viewer对象来完成。这个对象包含了场景(scene)、相机(camera)和其他一些默认的控件。

    const viewer = new Cesium.Viewer('cesiumContainer', {
        terrainProvider: Cesium.createWorldTerrain({
            requestWaterMask: true,
            requestVertexNormals: true,
        }),
    })
    
  • 相机控制
    实现动态地图查看的关键部分

    1. setView方法

      立即将相机定位到指定的位置,没有动画过渡

      const position = Cesium.Cartesian3.fromDegrees(116.40, 39.90, 1000);
      viewer.camera.setView({
          destination: position,
          orientation: {
              heading: Cesium.Math.toRadians(0),
              pitch: Cesium.Math.toRadians(-90),
              roll: Cesium.Math.toRadians(0),
          },
      });
      
    2. flyTo方法
      让相机平滑地飞向指定位置,提供了动画效果

      viewer.camera.flyTo({
          destination: Cesium.Cartesian3.fromDegrees(120.0, 30.0, 2000000),
          duration: 3.0,
          orientation: {
              heading: Cesium.Math.toRadians(20),
              pitch: Cesium.Math.toRadians(-15),
              roll: 0.0,
          },
      });
      
    3. lookAt方法
      将相机指向一个特定的目标点,而不会改变当前的相机位置

      const target = Cesium.Cartesian3.fromDegrees(120.0, 30.0);
      viewer.camera.lookAt(target, new Cesium.HeadingPitchRange(0, -
      Cesium.Math.PI_OVER_TWO, 5000000));
      
  • 坐标转换

    1. 经纬度转笛卡尔

      const cartesian3 = Cesium.Cartesian3.fromDegrees(114.0, 30.0, 500000);
      
    2. 笛卡尔转经纬度

      const cartographic = Cesium.Cartographic.fromCartesian(cartesian3);
      const longitude = Cesium.Math.toDegrees(cartographic.longitude);
      const latitude = Cesium.Math.toDegrees(cartographic.latitude);
      

实体与数据源

  1. 实体(Entity)
    描述具有几何形状和属性的对象的基类

    • 添加实体

      const pointEntity = viewer.entities.add({
          position: Cesium.Cartesian3.fromDegrees(103.1, 25.0),
          point: {
              color: Cesium.Color.YELLOW,
              pixelSize: 10,
          },
          name: 'Sample Point',
          description: 'This is a description for the sample point.'
      });
      
    • 删除实体

      viewer.entities.remove(pointEntity);
      
    • 创建动态效果
      定义一个回调函数,这个函数可以在每个帧中被CallbackProperty调用,以动态地更新实体的属性

      // 定义一个回调函数,该函数将根据当前时间返回实体的位置
      function positionCallback(time, result) {
          // 获取当前时间,并转换为JulianDate
          var timestamp = Cesium.JulianDate.toDate(time);
          // 根据时间计算经度,这里假设每秒移动10度
          var longitude = Cesium.Math.toRadians(10 * timestamp.getSeconds());
          // 固定纬度值
          var latitude = Cesium.Math.toRadians(20);
          // 固定高度值
          var height = 100000.0;
          // 返回Cartesian3位置
          if (!Cesium.defined(result)) {
              result = new Cesium.Cartesian3();
          }
          result = Cesium.Cartesian3.fromRadians(longitude, latitude, height);
          return result;
      }
      
      // 创建一个CallbackProperty,该属性将在每一帧调用positionCallback函数
      var positionProperty = new Cesium.CallbackProperty(positionCallback, false);
      
      // 添加一个点状实体到Viewer
      var pointEntity = viewer.entities.add({
          name: 'Dynamic point',
          position: positionProperty,
          point: {
              pixelSize: 10,
              color: Cesium.Color.YELLOW
          }
      });
      
      // 定位到实体
      viewer.zoomTo(viewer.entities);
      
  2. 数据源(DataSources)
    加载和管理地理数据的组件, 可以处理多种格式的数据

    • 加载GeoJSON数据

      const geoJsonData = {
          "type": "FeatureCollection",
          "features": [
              {
                  "type": "Feature",
                  "geometry": {
                      "type": "Point",
                      "coordinates": [-122.39, 47.5]
                  }
              }
          ]
      };
       
      const geoJsonPromise = Cesium.GeoJsonDataSource.load(geoJsonData);
      geoJsonPromise.then(function(dataSource) {
          viewer.dataSources.add(dataSource);
          viewer.zoomTo(dataSource);
      });
      
    • 加载TopoJSON数据

      const topoJsonPromise = Cesium.GeoJsonDataSource.load('path/to/topojson.data');
      topoJsonPromise.then(function(dataSource) {
          viewer.dataSources.add(dataSource);
          viewer.zoomTo(dataSource);
      });
      
    • 加载KML数据 (Google Earth)

      const kmlPromise = Cesium.KmlDataSource.load('path/to/placemark.kml');
      kmlPromise.then(function(dataSource) {
          viewer.dataSources.add(dataSource);
          viewer.zoomTo(dataSource);
      });
      
    • 加载CZML数据
      专为Cesium设计的动态数据格式, 使用JSON数组来描述随时间变化的图形属性

      const czmlPromise = Cesium.CzmlDataSource.load('path/to/document.czml');
      czmlPromise.then(function(dataSource) {
          viewer.dataSources.add(dataSource);
          viewer.trackedEntity = dataSource.entities.getById('ID_of_Entity');
          // 允许相机自动跟踪数据源中的特定实体
      });
      

图元(Primitive)

一种用于创建和操作三维几何形状的底层API, 面向三维图形开发者, 允许开发者直接控制几何体(Geometry)的创建和外观(Appearance)表现;
Entity API是数据驱动更高级一些

创建基本图元:

  1. 创建一个基本几何体对象(Primitive):
    使用Cesium.Primitive构造函数创建一个新的几何体对象。

  2. 定义几何实例:
    geometryInstances属性接受一个Cesium.GeometryInstance对象,这个对象包含几何体的具体信息。

  3. 创建椭圆形几何体(EllipseGeometry):
    geometry属性是一个Cesium.EllipseGeometry对象,它定义了一个椭圆的几何形状。
    rotation属性定义了椭圆的旋转角度,这里使用了Cesium.Math.PI_OVER_FOUR,表示旋转了45度。
    vertexFormat定义了顶点格式,表示顶点包含位置和纹理坐标。

  4. 定义外观(EllipsoidSurfaceAppearance):
    appearance属性接受一个Cesium.EllipsoidSurfaceAppearance对象,它定义了几何体的外观。
    material属性定义了材质,这里使用了Cesium.Material.fromType方法,并传入了Stripe类型,表示使用条纹材质。

  5. 添加几何体到场景(Viewer):
    使用viewer.scene.primitives.add(primitive)将创建的几何体添加到Cesium Viewer的场景中。

const primitive = new Cesium.Primitive({
  geometryInstances: new Cesium.GeometryInstance({
    geometry: new Cesium.EllipseGeometry({
      center: Cesium.Cartesian3.fromDegrees(-100.0, 20.0),
      semiMinorAxis: 500000.0,
      semiMajorAxis: 1000000.0,
      rotation: Cesium.Math.PI_OVER_FOUR,
      vertexFormat: Cesium.VertexFormat.POSITION_AND_ST
    }),
  }),
  appearance: new Cesium.EllipsoidSurfaceAppearance({
    material: Cesium.Material.fromType('Stripe'),
  }),
})
viewer.scene.primitives.add(primitive);

交互事件

ScreenSpaceEventHandler

  • 点击事件

      let viewer = new Cesium.Viewer('cesiumContainer', {
        terrainProvider: Cesium.createWorldTerrain()
      })
      let handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas)
      handler.setInputAction((event) => {
        // 返回一个笛卡尔坐标
        let position = viewer.scene.pickPosition(event.position)
        // 如果有这个坐标
        if (Cesium.defined(position)) {
          console.log(position)
          viewer.entities.add({
            position: position,
            point: {
              color: Cesium.Color.BLUE,
              pixelSize: 20,
            },
        })
        }
        console.log(viewer.entities)
      }, Cesium.ScreenSpaceEventType.LEFT_CLICK)
    
  • 移动事件

      let pickModel
      let viewer = new Cesium.Viewer('cesiumContainer', {
        terrainProvider: Cesium.createWorldTerrain()
      })
      // 添加建筑物
      const city = viewer.scene.primitives.add(
        new Cesium.Cesium3DTileset({
          url: Cesium.IonResource.fromAssetId(75343),
        })
      )
      viewer.flyTo(city)
      let handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
      handler.setInputAction((event) => {
        // 拾取模型
        const pick = viewer.scene.pick(event.endPosition);
        if (pick) {
          if (pickModel) {
            pickModel.color = Cesium.Color.WHITE;
          }
          pick.color = Cesium.Color.ORANGERED;
          pickModel = pick;
        }
    }, Cesium.ScreenSpaceEventType.MOUSE_MOVE)
    
  • 事件注销

    handler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK);  //移除左键点击事件
    

综合应用

  1. 初始化Cesium Viewer
const viewer = new Cesium.Viewer('cesiumContainer', {
  terrainProvider: Cesium.createWorldTerrain(),
  baseLayerPicker: false,  // 隐藏基础图层选择器
  shouldAnimate: true
})
  1. 3D Tiles格式加载三维模型
const cityModel = viewer.scene.primitives.add(new Cesium.Cesium3DTileset({
  url: Cesium.IonResource.fromAssetId(123456),  // 替换为实际的模型ID
  maximumScreenSpaceError: 16
}))
  1. 点击显示建筑物详细信息
viewer.screenSpaceEventHandler.setInputAction((event) => {
  const clickPosition = event.position
  const pickedObject = viewer.scene.pick(clickPosition)
  if (pickedObject && pickedObject instanceof Cesium.Cesium3DTileFeature) {
    const buildingInfo = pickedObject.getProperty('name')
    showBuildingInfo(buildingInfo)  // 显示建筑物信息的自定义函数
  }
}, Cesium.ScreenSpaceEventType.LEFT_CLICK)
  1. 创建粒子系统来模拟城市中夜晚的灯光
const particleSystem = new Cesium.ParticleSystem({
  image: 'path/to/particle-image.png',
  emitter: new Cesium.CircleEmitter({
    radius: 10
  }),
  emissionRate: 1,
  lifetime: 60,
  loop: true,
  modelMatrix: Cesium.Matrix4.multiplyByTranslation({
    Cesium.Transforms.eastNorthUpToFixedFrame(
      Cesium.Cartesian3.fromDegrees(103.1, 25.0, 1000)
    ),
    new Cesium.Cartesian3(0, 0, 0),
    new Cesium.Matrix4()
  })
})
viewer.scene.primitives.add(particleSystem)
posted @ 2025-01-15 16:33  Khru  阅读(312)  评论(0)    收藏  举报