前面介绍了Cesium如何加载影像数据、地形数据、以及矢量数据,但是作为一个完整的三维系统,仅仅包括这些数据还是远远不够的。当然,还需要一些其他数据,比如空间可视化数据、三维数据数据等,今天我们先从空间数据的可视化说起,后面会有专门的章节介绍三维数据方面的加载。

Cesium在空间数据可视化方面提供了两种类型的API,一种是面向图形开发人员的低级(原始)API,通过Primitive类实现,对于那些对计算机图形学知识很了解的同学可以采用Primitive API,后面章节会有详细介绍;另一种是用于数据驱动的高级(实体)API,通过Entity类实现,相对于Primitive API,Entity API实现起来更简单一些,特别建议初学者使用。Entity API 实际上是对Primitive API的二次封装,底层调用的仍然是Primitive API,目的就是为我们提供灵活的、易学、易用的高性能可视化界面。本章节内容主要介绍后者Entity API,Primitive API放在后面的高级篇里讲解。

Entity支持的图形类型

通过在Cesium API文档中查看Entity类的构造函数,我们发现Entity支持的图形类型都是以Graphics结尾的,一共有17种类型。如下图所示,列出了Entity支持的图形类型以及对应的js类。

空间数据分析与可视化 空间数据的可视化_三维GIS

空间数据分析与可视化 空间数据的可视化_Cesium_02

下面,简单介绍一下每一种类型的Graphic添加方式。
1)billboard 广告牌

var entity = viewer.entities.add({
      name: "billboard",
      position: Cesium.Cartesian3.fromDegrees(-75.59777, 40.03883),
      billboard: {
        show: true, 
        image: "./images/Cesium_Logo_overlay.png", 
        scale: 2.0, 
        pixelOffset: new Cesium.Cartesian2(0, -50),
        eyeOffset: new Cesium.Cartesian3(0.0, 0.0, 0.0),
        horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
        verticalOrigin: Cesium.VerticalOrigin.BOTTOM, 
        heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
        color: Cesium.Color.LIME,
        rotation: Cesium.Math.PI_OVER_FOUR, 
        alignedAxis: Cesium.Cartesian3.ZERO,
        width: 100, 
        height: 25, 

        
        scaleByDistance: new Cesium.NearFarScalar(1.0e3, 2.0, 2.0e3, 1.0),
        
        translucencyByDistance: new Cesium.NearFarScalar(
          1.0e3,
          1.0,
          1.5e6,
          0.5
        ),
        
        pixelOffsetScaleByDistance: new Cesium.NearFarScalar(
          1.0e3,
          1.0,
          1.5e6,
          0.0
        ),
        disableDepthTestDistance: Number.POSITIVE_INFINITY,
      },
    });

2)box 盒子

var entity = viewer.entities.add({
      name: "box",
      position: Cesium.Cartesian3.fromDegrees(-107.0, 40.0, 300000.0),
      box: {
        show: true,
        dimensions: new Cesium.Cartesian3(400000.0, 300000.0, 500000.0), 
        heightReference: Cesium.HeightReference.NONE,
        fill: true,
        material: Cesium.Color.RED.withAlpha(0.5),
        outline: true,
        outlineColor: Cesium.Color.BLACK,
        outlineWidth: 1.0,
        shadows: Cesium.ShadowMode.DISABLED,
      },
    });

3)corridor 走廊

var entity = viewer.entities.add({
      name: "corridor",
      corridor: {
        positions: Cesium.Cartesian3.fromDegreesArray([
          -80.0,
          40.0,
          -85.0,
          40.0,
          -85.0,
          35.0,
        ]),
        width: 200000.0,
        height: 200000.0,
        heightReference: Cesium.HeightReference.NONE,
        extrudedHeight: 100000.0,
        extrudedHeightReference: Cesium.HeightReference.NONE,
        cornerType: Cesium.CornerType.ROUNDED,
        granularity: Cesium.Math.RADIANS_PER_DEGREE, 
        fill: true,
        material: Cesium.Color.BLUE.withAlpha(0.5),
        outline: true, 
        outlineColor: Cesium.Color.WHITE,
        outlineWidth: 1.0,
        shadows: Cesium.ShadowMode.DISABLED, 
        classificationType: Cesium.ClassificationType.BOTH,
      },
    });

4)cylinder 圆柱、圆锥

var entity = viewer.entities.add({
      name: "cylinder",
      position: Cesium.Cartesian3.fromDegrees(-105.0, 40.0, 200000.0),
      cylinder: {
        length: 400000.0, 
        topRadius: 200000.0, 
        bottomRadius: 200000.0, 
        heightReference: Cesium.HeightReference.NONE,
        fill: true,
        material: Cesium.Color.GREEN.withAlpha(0.5),
        outline: true,
        outlineColor: Cesium.Color.DARK_GREEN,
        outlineWidth: 1.0,
        numberOfVerticalLines: 16, 
        shadows: Cesium.ShadowMode.DISABLED,
        slices: 128, 
      },
    });

5)ellipse 椭圆或拉伸的椭圆

var entity = viewer.entities.add({
      name: "Circles and Ellipses",
      position: Cesium.Cartesian3.fromDegrees(-95.0, 40.0, 100000.0),
      ellipse: {
        show: true,
        semiMajorAxis: 300000.0, 
        semiMinorAxis: 150000.0, 
        height: 20000.0,
        heightReference: Cesium.HeightReference.NONE,
        extrudedHeight: 20000.0,
        extrudedHeightReference: Cesium.HeightReference.NONE,
        stRotation: 0.0, 
        granularity: Cesium.Math.RADIANS_PER_DEGREE, 
        material: Cesium.Color.BLUE.withAlpha(0.5),
        fill: true,
        outline: true,
        outlineColor: Cesium.Color.DARK_GREEN,
        outlineWidth: 1.0,
        numberOfVerticalLines: 16, 
        shadows: Cesium.ShadowMode.DISABLED,
        classificationType: Cesium.ClassificationType.BOTH,
      },
    });

6)ellipsoid 椭球体

var entity = viewer.entities.add({
      name: "Spheres and Ellipsoids",
      position: Cesium.Cartesian3.fromDegrees(-100.0, 40.0, 300000.0),
      ellipsoid: {
        show: true,
        radii: new Cesium.Cartesian3(200000.0, 200000.0, 300000.0), 
        minimumClock: 0.0, 
        maximumClock: 2 * Math.PI, 
        minimumCone: 0.0, 
        maximumCone: Math.PI, 
        heightReference: Cesium.HeightReference.NONE,
        fill: true,
        material: Cesium.Color.BLUE.withAlpha(0.5),
        outline: true,
        outlineColor: Cesium.Color.YELLOW,
        outlineWidth: 1.0,
        stackPartitions: 64, 
        slicePartitions: 64, 
        subdivisions: 128, 
        shadows: Cesium.ShadowMode.DISABLED,
      },
    });

7)label 标签

var entity = viewer.entities.add({
      name: "label",
      position: Cesium.Cartesian3.fromDegrees(
        -75.1641667,
        39.9522222,
        300000.0
      ),
      label: {
        show: true,
        text: "label标签",
        font: "24px Helvetica",
        style: Cesium.LabelStyle.FILL_AND_OUTLINE,
        scale: 1.0,
        showBackground: true,
        backgroundColor: Cesium.Color.BLUE,
        backgroundPadding: new Cartesian2(7, 5),
        pixelOffset: Cartesian2.ZERO,
        eyeOffset: Cartesian3.ZERO,
        horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
        verticalOrigin: Cesium.VerticalOrigin.CENTER,
        heightReference: Cesium.HeightReference.NONE,
        fillColor: Cesium.Color.SKYBLUE,
        outlineColor: Cesium.Color.BLACK,
        outlineWidth: 2,
        translucencyByDistance: new Cesium.NearFarScalar(
          1.0e3,
          1.0,
          1.5e6,
          0.5
        ),
        pixelOffsetScaleByDistance: new Cesium.NearFarScalar(
          1.0e3,
          1.0,
          1.5e6,
          0.0
        ),
        scaleByDistance: new Cesium.NearFarScalar(1.0e3, 2.0, 2.0e3, 1.0),
        disableDepthTestDistance: Number.POSITIVE_INFINITY,
      },
    });

8)model 模型

var position = Cesium.Cartesian3.fromDegrees(
      -123.0744619,
      44.0503706,
      5000.0
    );
    var heading = Cesium.Math.toRadians(135);
    var pitch = 0;
    var roll = 0;
    var hpr = new Cesium.HeadingPitchRoll(heading, pitch, roll);
    var orientation = Cesium.Transforms.headingPitchRollQuaternion(
      position,
      hpr
    );

    var url = "./data/models/CesiumAir/Cesium_Air.glb";
    var entity = viewer.entities.add({
      name: "model",
      position: position,
      orientation: orientation,
      model: {
        show: true,
        uri: url,
        scale: 1.0,
        minimumPixelSize: 128, 
        maximumScale: 20000, 
        incrementallyLoadTextures: true, 
        runAnimations: true, 
        clampAnimations: true, 
        shadows: Cesium.ShadowMode.DISABLED,
        heightReference: Cesium.HeightReference.NONE,
        silhouetteColor: Cesium.Color.RED, 
        silhouetteSize: 0.0, 
        color: Cesium.Color.WHITE, 
        colorBlendMode: Cesium.ColorBlendMode.HIGHLIGHT,
        colorBlendAmount: 0.5,
        imageBasedLightingFactor: new Cesium.Cartesian2(1.0, 1.0), 
        lightColor: undefined, 
      },
    });

9)tileset 3D Tiles瓦片集

var tileset = viewer.entities.add({
      name: "3D Tiles",
      position: Cesium.Cartesian3.fromDegrees(-114.0, 40.0, 300000.0),
      tileset: {
        show: true,
        uri: new Cesium.Plane(Cesium.Cartesian3.UNIT_X, 0.0),
      },
    });

10)path 路径

var entityPath = viewer.entities.add({
      position: pathPosition,
      name: "path",
      path: {
        show: true,
        leadTime: 0,
        trailTime: 60,
        width: 10,
        resolution: 1,
        material: new Cesium.PolylineGlowMaterialProperty({
          glowPower: 0.3,
          taperPower: 0.3,
          color: Cesium.Color.PALEGOLDENROD,
        }),
      },
    });

11)plane 平面

var bluePlane = viewer.entities.add({
      name: "Blue plane",
      position: Cesium.Cartesian3.fromDegrees(-114.0, 40.0, 300000.0),
      plane: {
        show: true,
        
        plane: new Cesium.Plane(Cesium.Cartesian3.UNIT_X, 0.0),
        dimensions: new Cesium.Cartesian2(400000.0, 300000.0), 
        fill: true,
        material: Cesium.Color.BLUE,
        outline: false,
        outlineColor: Cesium.Color.BLACK,
        outlineWidth: 1.0,
        shadows: Cesium.ShadowMode.DISABLED,
      },
    });

12)point 点

viewer.entities.add({
      position: Cesium.Cartesian3.fromDegrees(-75.59777, 40.03883),
      point: {
        show: true,
        pixelSize: 10, // 像素大小
        heightReference: Cesium.HeightReference.NONE,
        color: Cesium.Color.YELLOW,
        outlineColor: Cesium.Color.BLACK,
        outlineWidth: 0,
        scaleByDistance: new Cesium.NearFarScalar(1.0e3, 10.0, 2.0e3, 1.0),
        translucencyByDistance: new Cesium.NearFarScalar(
          1.0e3,
          1.0,
          1.5e6,
          0.5
        ),
        // distanceDisplayCondition: new Cesium.DistanceDisplayCondition(
        //   1.0e3,
        //   2.0e3
        // ),
        // 获取或设置与相机的距离,在深度处禁用深度测试,例如,以防止剪切地形。
        // 设置为零时,将始终应用深度测试。设置为Number.POSITIVE_INFINITY时,永远不会应用深度测试。
        disableDepthTestDistance: Number.POSITIVE_INFINITY,
      },
    });

13)polygon 多边形

var redPolygon = viewer.entities.add({
      name: "Red polygon on surface",
      polygon: {
        show: true,
        
        hierarchy: Cesium.Cartesian3.fromDegreesArray([
          -115.0,
          37.0,
          -115.0,
          32.0,
          -107.0,
          33.0,
          -102.0,
          31.0,
          -102.0,
          35.0,
        ]),
        height: 0, 
        heightReference: Cesium.HeightReference.NONE,
        
        
        stRotation: 0.0, 
        granularity: Cesium.Math.RADIANS_PER_DEGREE, 
        fill: true,
        material: Cesium.Color.RED,
        outline: false,
        outlineColor: Cesium.Color.BLACK,
        outlineWidth: 1.0,
        perPositionHeight: false, 
        closeTop: true, 
        closeBottom: true, 
        arcType: Cesium.ArcType.GEODESIC,
        shadows: Cesium.ShadowMode.DISABLED,
        classificationType: Cesium.ClassificationType.BOTH,
        zIndex: 0,
      },
    });

14)polyline 多线段

var redLine = viewer.entities.add({
      name: "Red line on terrain",
      polyline: {
        show: true,
        positions: Cesium.Cartesian3.fromDegreesArray([-75, 35, -125, 35]),
        width: 5,
        material: Cesium.Color.RED,
        clampToGround: true, 
        shadows: Cesium.ShadowMode.DISABLED, 
        classificationType: Cesium.ClassificationType.BOTH,
      },
    });

15)polylineVolume 多线段柱体

function computeCircle(radius) {
      var positions = [];
      for (var i = 0; i < 360; i++) {
        var radians = Cesium.Math.toRadians(i);
        positions.push(
          new Cesium.Cartesian2(
            radius * Math.cos(radians),
            radius * Math.sin(radians)
          )
        );
      }
      return positions;
    }

    var redTube = viewer.entities.add({
      name: "Red tube with rounded corners",
      polylineVolume: {
        show: true,

        
        positions: Cesium.Cartesian3.fromDegreesArray([
          -85.0,
          32.0,
          -85.0,
          36.0,
          -89.0,
          36.0,
        ]),
        shape: computeCircle(60000.0),
        cornerType: Cesium.CornerType.ROUNDED,
        fill: true,
        material: Cesium.Color.RED,
        outline: false,
        outlineColor: Cesium.Color.BLACK,
        outlineWidth: 1.0,
        shadows: Cesium.ShadowMode.DISABLED,   
      },
    });

16)rectangle 矩形

var redRectangle = viewer.entities.add({
      name: "Red translucent rectangle",
      rectangle: {
        show: true,
        coordinates: Cesium.Rectangle.fromDegrees(-110.0, 20.0, -80.0, 25.0),
        rotation: 0.0, 
        stRotation: 0.0, 
        granularity: Cesium.Math.RADIANS_PER_DEGREE, 
        fill: true,
        material: Cesium.Color.RED.withAlpha(0.5),
        outline: false,
        outlineColor: Cesium.Color.BLACK,
        outlineWidth: 1.0,
        shadows: Cesium.ShadowMode.DISABLED,     
        classificationType: Cesium.ClassificationType.BOTH,       
        zIndex: 0,
      },
    });

17)wall 墙

var redWall = viewer.entities.add({
      name: "Red wall at height",
      wall: {
        show: true,
        positions: Cesium.Cartesian3.fromDegreesArrayHeights([
          -115.0,
          44.0,
          200000.0,
          -90.0,
          44.0,
          200000.0,
        ]),     
        minimumHeights: [100000.0, 100000.0],
        granularity: Cesium.Math.RADIANS_PER_DEGREE, 
        fill: true,
        material: Cesium.Color.RED,
        outline: false,
        outlineColor: Cesium.Color.BLACK,
        outlineWidth: 1.0,
        shadows: Cesium.ShadowMode.DISABLED,    
      },
    });

Entity 聚合

同时,针对Billboard、Label、Point,Cesium 提供了 EntityCluster 类用于实现聚合效果,但必须结合 PinBuilder 类实现。下面为实现聚合效果的核心代码:

var options = {
      camera: viewer.scene.camera,
      canvas: viewer.scene.canvas,
    };
    var dataSourcePromise = viewer.dataSources.add(
      Cesium.KmlDataSource.load("./data/kml/facilities/facilities.kml", options)
    );
    dataSourcePromise.then(function (dataSource) {
      var pixelRange = 15;
      var minimumClusterSize = 3;
      var enabled = true;
      dataSource.clustering.enabled = enabled;
      dataSource.clustering.pixelRange = pixelRange; 
      dataSource.clustering.minimumClusterSize = minimumClusterSize; 
      var removeListener;
      var pinBuilder = new Cesium.PinBuilder();
      var pin50 = pinBuilder.fromText("50+", Cesium.Color.RED, 48).toDataURL();
      var pin40 = pinBuilder
        .fromText("40+", Cesium.Color.ORANGE, 48)
        .toDataURL();
      var pin30 = pinBuilder
        .fromText("30+", Cesium.Color.YELLOW, 48)
        .toDataURL();
      var pin20 = pinBuilder
        .fromText("20+", Cesium.Color.GREEN, 48)
        .toDataURL();
      var pin10 = pinBuilder.fromText("10+", Cesium.Color.BLUE, 48).toDataURL();
      var singleDigitPins = new Array(8);
      for (var i = 0; i < singleDigitPins.length; ++i) {
        singleDigitPins[i] = pinBuilder
          .fromText("" + (i + 2), Cesium.Color.VIOLET, 48)
          .toDataURL();
      }

      function customStyle() {
        if (Cesium.defined(removeListener)) {
          removeListener();
          removeListener = undefined;
        } else {
          removeListener = dataSource.clustering.clusterEvent.addEventListener(
            function (clusteredEntities, cluster) {
              cluster.label.show = false;
              cluster.billboard.show = true;
              cluster.billboard.id = cluster.label.id;
              cluster.billboard.verticalOrigin = Cesium.VerticalOrigin.BOTTOM;

              if (clusteredEntities.length >= 50) {
                cluster.billboard.image = pin50;
              } else if (clusteredEntities.length >= 40) {
                cluster.billboard.image = pin40;
              } else if (clusteredEntities.length >= 30) {
                cluster.billboard.image = pin30;
              } else if (clusteredEntities.length >= 20) {
                cluster.billboard.image = pin20;
              } else if (clusteredEntities.length >= 10) {
                cluster.billboard.image = pin10;
              } else {
                cluster.billboard.image =
                  singleDigitPins[clusteredEntities.length - 2];
              }
            }
          );
        }        
        var pixelRange = dataSource.clustering.pixelRange;
        dataSource.clustering.pixelRange = 0;
        dataSource.clustering.pixelRange = pixelRange;
      }      
      customStyle();
      var handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
      handler.setInputAction(function (movement) {
        var pickedLabel = viewer.scene.pick(movement.position);
        if (Cesium.defined(pickedLabel)) {
          var ids = pickedLabel.id;
          if (Array.isArray(ids)) {
            for (var i = 0; i < ids.length; ++i) {
              ids[i].billboard.color = Cesium.Color.RED;
            }
          }
        }
      }, Cesium.ScreenSpaceEventType.LEFT_CLICK);
    });

Entity 管理

上面介绍了Entity的图形类型,有这么多类型的实体,Cesium是如何管理这些实体对象的呢,这就需要我们从初始化Viewer对象开始说起了。当我们初始化Viewer类之后,会得到一个实例化对象viewer,这个viewer会包含一个属性 entities ,它的类型是 EntityCollection ,也就是 Entity 的集合,它包括了 EntityCollection 类里面的所有属性和方法。所以 Cesium 管理 Entity 本质上是通过 EntityCollection 类进行管理的,比如add(添加Entity)、contains(是否存在某个Entity)、getById(通过ID获取Entity)、remove(移除某个Entity)、removeAll(移除所有的Entity)、removeById(通过ID移除Entity)方法等。

var point = viewer.entities.add({
      position: Cesium.Cartesian3.fromDegrees(-105.0, 41, 50010),
      point: {
        show: true,
        pixelSize: 10, 
      },
    });
    var entity = viewer.entities.getById("entity_1");
    viewer.entities.remove(entity);

Entity 拾取

在三维场景种,很常见的一种交互方式,就是鼠标点击三维场景种某一个几何图形,查看该图形的包含的属性信息,并显示在对应的信息窗体中。单击事件通过 ScreenSpaceEventHandler 类注册,拾取到的信息可通过以下两种方式获取。

  • scene.pick:获取窗体坐标处最顶部的实体;
  • scene.drillPick:窗体坐标处的实体列表。
var handler = new Cesium.ScreenSpaceEventHandler(viewer.canvas);
    handler.setInputAction(function (movement) {
      var pickedEntity = pickEntity(viewer, movement.position);
      console.log(pickedEntity);

      var pickedEntities = drillPickEntities(viewer, movement.position);
      console.log(pickedEntities);
    }, Cesium.ScreenSpaceEventType.LEFT_CLICK);

    function pickEntity(viewer, windowPosition) {
      var picked = viewer.scene.pick(windowPosition);
      if (Cesium.defined(picked)) {
        var id = Cesium.defaultValue(picked.id, picked.primitive.id);
        if (id instanceof Cesium.Entity) {
          return id;
        }
      }
      return undefined;
    }
    function drillPickEntities(viewer, windowPosition) {
      var i;
      var entity;
      var picked;
      var pickedPrimitives = viewer.scene.drillPick(windowPosition);
      var length = pickedPrimitives.length;
      var result = [];
      var hash = {};

      for (i = 0; i < length; i++) {
        picked = pickedPrimitives[i];
        entity = Cesium.defaultValue(picked.id, picked.primitive.id);
        if (
          entity instanceof Cesium.Entity &&
          !Cesium.defined(hash[entity.id])
        ) {
          result.push(entity);
          hash[entity.id] = true;
        }
      }
      return result;
    }

Entity 固定

在实际的应用系统中,会有这样的需求,要求画的实体附着在地形表面、或三维建筑表面(比如视频融合),这时候就需要设置xxGraphics的相关属性了,可通过 heightReference 或 classificationType 这两个属性去控制。属性值描述如下:

  • heightReference属性值:
    NONE:位置绝对(默认值);
    CLAMP_TO_GROUND:位置固定在地形上;
    RELATIVE_TO_GROUND:位置高度是指地形上方的高度
  • classificationType属性值:
    TERRAIN:将仅对地形进行分类;
    CESIUM_3D_TILE:将仅对3D Tiles进行分类;
    BOTH :将同时对Terrain和3D Tiles进行分类。

其中corridor 、 ellipse 、 polygon 、 polyline 、 rectangle 可通过设置 classificationType 属性值显示仅贴地、仅贴建筑或者两者都贴的效果,billboard 、 box 、 corridor 、 cylinder 、 ellipse 、 ellipsoid 、 label 、 model 、 point 、 polygon 、 tectangle通过设置 heightReference 属性值为 CLAMP_TO_GROUND 显示贴地效果。这里需要注意的是,如果是polyline必须设置 clampToGround 属性为 true 。

viewer.entities.add({
      position: Cesium.Cartesian3.fromDegrees(-122.1958, 46.1915),
      billboard: {
        image: "./images/facility.gif",
        heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
      },
      point: {
        color: Cesium.Color.SKYBLUE,
        pixelSize: 10,
        heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
      },
      label: {
        text: "Clamped to ground",
        font: "14pt sans-serif",
        heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
        horizontalOrigin: Cesium.HorizontalOrigin.LEFT,
        verticalOrigin: Cesium.VerticalOrigin.BASELINE,
        fillColor: Cesium.Color.BLACK,
        showBackground: true,
        backgroundColor: new Cesium.Color(1, 1, 1, 0.7),
        backgroundPadding: new Cesium.Cartesian2(8, 4),
        disableDepthTestDistance: Number.POSITIVE_INFINITY, 
      },
    });
    viewer.entities.add({
      position: Cesium.Cartesian3.fromDegrees(-122.1958, 46.1915),
      model: {
        uri: "./data/models/CesiumMan/Cesium_Man.glb",
        heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
        minimumPixelSize: 128,
        maximumScale: 100,
      },
    });


    viewer.entities.add({
      position: Cesium.Cartesian3.fromDegrees(-122.195, 46.1915),
      corridor: {
        positions: Cesium.Cartesian3.fromDegreesArray([
          -122.19,
          46.1914,
          -122.2,
          46.1924,
          -122.21,
          46.193,
        ]),
        width: 500.0,
        material: Cesium.Color.GREEN.withAlpha(0.5),
      },
      ellipse: {
        semiMajorAxis: 300.0, 
        semiMinorAxis: 150.0,        
        material: Cesium.Color.BLUE.withAlpha(0.5),   
      },
      polygon: {
        hierarchy: {
          positions: [
            new Cesium.Cartesian3(
              -2358138.847340281,
              -3744072.459541374,
              4581158.5714175375
            ),
            new Cesium.Cartesian3(
              -2357231.4925370603,
              -3745103.7886602185,
              4580702.9757762635
            ),
            new Cesium.Cartesian3(
              -2355912.902205431,
              -3744249.029778454,
              4582402.154378103
            ),
            new Cesium.Cartesian3(
              -2357208.0209552636,
              -3743553.4420488174,
              4581961.863286629
            ),
          ],
        },      
        material: "./images/Cesium_Logo_Color.jpg",
      },
      rectangle: {
        coordinates: Cesium.Rectangle.fromDegrees(-122.2, 46.2, -122.1, 46.3),
        material: Cesium.Color.RED.withAlpha(0.5),
      },
    });
   
    viewer.entities.add({
      polyline: {
        positions: Cesium.Cartesian3.fromDegreesArray([
          -122.1968,
          46.1915,
          -122.1968,
          46.2015,
          -122.1968,
          46.2015,
        ]),
        clampToGround: true,
        width: 5,
        material: Cesium.Color.ORANGE,
        depthFailMaterial: Cesium.Color.RED,
      },
    });
var polygon = viewer.entities.add({
      polygon: {
        hierarchy: new Cesium.PolygonHierarchy(
          Cesium.Cartesian3.fromRadiansArray([
            -1.3194369277314022,
            0.6988062530900625,
            -1.3193955980204217,
            0.6988091578771254,
            -1.3193931220959367,
            0.698743632490865,
            -1.3194358224045408,
            0.6987471965556998,
          ])
        ),
        material: "./images/Cesium_Logo_Color.jpg",
        classificationType: Cesium.ClassificationType.CESIUM_3D_TILE,
      },
    });

    var polyline = viewer.entities.add({
      polyline: {
        positions: Cesium.Cartesian3.fromDegreesArray([
          -75.60217330403601,
          40.04102882709425,
          -75.59968252414251,
          40.04093615560871,
          -75.598020153828,
          40.04079437042357,
          -75.59674934074435,
          40.040816173283304,
          -75.59630042791713,
          40.03986900370842,
          -75.59563636849978,
          40.03930996506271,
          -75.59492397899098,
          40.03873932846581,
          -75.59457991226778,
          40.038392701955786,
          -75.59424838652453,
          40.03775403572295,
          -75.59387104290336,
          40.03677022167725,
          -75.59355000490342,
          40.03588760913535,
        ]),
        width: 8,
        material: new Cesium.PolylineOutlineMaterialProperty({
          color: Cesium.Color.YELLOW,
          outlineWidth: 2,
          outlineColor: Cesium.Color.BLACK,
        }),
        clampToGround: true,
        
        classificationType: Cesium.ClassificationType.TERRAIN,
      },
    });