空间数据可视化之Entity

发布时间 2023-11-09 10:59:56作者: 紅葉

Cesium在空间数据可视化方面提供了两种类型的API,一种是面向图形开发人员的低级(原始)API,通过Primitive类实现,对于那些对计算机图形学知识很了解的同学可以采用Primitive API;另一种是用于数据驱动的高级(实体)API,通过Entity类实现,相对于Primitive API,Entity API实现起来更简单一些,特别建议初学者使用。Entity API 实际上是对Primitive API的二次封装,底层调用的仍然是Primitive API,目的就是为我们提供灵活的、易学、易用的高性能可视化界面。使用Cesium的Entity API我们可以去绘制空间数据,如点,图标,文字标注,折线,模型,图形和立体图形。

Entity支持的图形类型

通过在Cesium API文档中查看Entity类的构造函数,我们发现Entity支持的图形类型都是以Graphics结尾的,一共有17种类型:

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,
      },
    });
viewer.zoomTo(entity);
    var billboard = entity.billboard;
    billboard.scale = 3.0;
    billboard.color = Cesium.Color.WHITE.withAlpha(0.25);
View Code

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,
      },
    });
viewer.zoomTo(entity);
View Code

corridor 走廊

var entity = viewer.entities.add({
      name: "corridor",
      corridor: {
// 指定定义走廊中心线的 Cartesian3 位置的数组  type: Cartesian3
        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,
// 拐角的样式  type:CornerType  default:CornerType.ROUNDED
        // ROUNDED    角有光滑的边缘;MITERED    拐角点是相邻边的交点;BEVELED    角被修剪
        cornerType: Cesium.CornerType.ROUNDED,
// 每个纬度和经度之间的距离
        granularity: Cesium.Math.RADIANS_PER_DEGREE, 
        fill: true,
// 材质  type:MaterialProperty|Color  default:Color.WHITE
        material: Cesium.Color.BLUE.withAlpha(0.5),
        outline: true, 
        outlineColor: Cesium.Color.WHITE,
        outlineWidth: 1.0,
        shadows: Cesium.ShadowMode.DISABLED, 
// 走廊在地面上时将对地形,3D tiles还是对两者进行分类  type:ClassificationType  default:ClassificationType.BOTH
        // TERRAIN 将仅对地形进行分类;CESIUM_3D_TILE 将仅对3D Tiles进行分类;BOTH    将同时对Terrain和3D Tiles进行分类。
        classificationType: Cesium.ClassificationType.BOTH,
      },
    });
View Code

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, 
      },
    });
View Code

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,
      },
    });
View Code

label 标签

var citizensBankPark = viewer.entities.add({
    name : 'Citizens Bank Park',
    position : Cesium.Cartesian3.fromDegrees(-75.166493, 39.9060534),
    label : {
        text : 'Citizens Bank Park',
        font : '14pt monospace',
        style: Cesium.LabelStyle.FILL_AND_OUTLINE,
        outlineWidth : 2,
        verticalOrigin : Cesium.VerticalOrigin.BOTTOM,
        pixelOffset : new Cesium.Cartesian2(0, -9)
    }
});
View Code

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, 
      },
    });
View Code

tileset 3D Tiles瓦片集

var entity = viewer.entities.add({
      name: "3D Tiles",
      position: Cesium.Cartesian3.fromDegrees(-114.0, 40.0, 300000.0),
      tileset: {
        show: true,
        uri: "./data/Cesium3DTiles/Tilesets/Tileset/tileset.json",
      },
    });
    
View Code

plane 平面

  var entity= 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,
      },
    });
View Code

point 点

 var entity = 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,
      },
    });
View Code

polygon 多边形

var entity = 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,
      },
    });
View Code

polyline 多线段

var entity= 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,
      },
    });
View Code

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 entity= 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,   
      },
    });
View Code

rectangle 矩形

 var entity= 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,
      },
    });
View Code

wall 墙

 var entity= 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,    
      },
    });
View Code

材质和边线

无论各种几何体有什么不同,所有形状和体都有一系列相同的属性来控制它们的外观。fill 为boolean类型,控制表面是否填充。 outline 属性控制是否有外边界。当 fill=truematerial属性决定了用什么材质填充表面。

当设置颜色或者url之后Cesium会自动创建 ColorMaterialProperty 或者ImageMaterialProperty对象。 对于更复杂的材质, 需要手动创建 MaterialProperty对象。 当前, Entity 面和体支持 颜色(colors),纹理图片( images),棋盘 (checkerboard), 条纹(stripe), 网格(grid)等材质

半透明

var entity = viewer.entities.add({
  position: Cesium.Cartesian3.fromDegrees(-103.0, 40.0),
  ellipse : {
    semiMinorAxis : 250000.0,
    semiMajorAxis : 400000.0,
    material : Cesium.Color.BLUE.withAlpha(0.5)
  }
});
viewer.zoomTo(entity);
View Code

图片

var entity = viewer.entities.add({
  position: Cesium.Cartesian3.fromDegrees(-103.0, 40.0),
  ellipse : {
    semiMinorAxis : 250000.0,
    semiMajorAxis : 400000.0,
    material : './images/Cesium_Logo_overlay.png'
  }
});
viewer.zoomTo(entity);
View Code

网格

var entity = viewer.entities.add({
      position: Cesium.Cartesian3.fromDegrees(-103.0, 40.0),
      ellipse: {
        semiMinorAxis: 250000.0,
        semiMajorAxis: 400000.0,
        material: new Cesium.CheckerboardMaterialProperty({
          evenColor: Cesium.Color.WHITE,
          oddColor: Cesium.Color.BLACK,
          repeat: new Cesium.Cartesian2(4, 4),
        }),
   },
    });
    viewer.zoomTo(entity);
View Code

条纹

var entity = viewer.entities.add({
      position: Cesium.Cartesian3.fromDegrees(-103.0, 40.0),
      ellipse: {
        semiMinorAxis: 250000.0,
        semiMajorAxis: 400000.0,
       material: new Cesium.StripeMaterialProperty({
          evenColor: Cesium.Color.WHITE,
          oddColor: Cesium.Color.BLACK,
          repeat: 32,
        }),
},
    });
    viewer.zoomTo(entity);
View Code

网格

var entity = viewer.entities.add({
      position: Cesium.Cartesian3.fromDegrees(-103.0, 40.0),
      ellipse: {
        semiMinorAxis: 250000.0,
        semiMajorAxis: 400000.0,
material: new Cesium.GridMaterialProperty({
          color: Cesium.Color.YELLOW,
          cellAlpha: 0.2,
          lineCount: new Cesium.Cartesian2(8, 8),
          lineThickness: new Cesium.Cartesian2(2.0, 2.0),
        }),
      },
    });
    viewer.zoomTo(entity);
View Code

边线

fill属性不太一样,outline没有对应的材质配置,而是用两个独立的属性outlineColoroutlineWidth
注意outlineWidth属性仅仅在非windows系统上有效,比如Android, iOS, Linux, 和OS X。Windows系统上边线宽度永远为1
var entity = viewer.entities.add({
      position: Cesium.Cartesian3.fromDegrees(-103.0, 40.0),
      ellipse: {
        semiMinorAxis: 250000.0,
        semiMajorAxis: 400000.0,
        fill:false,
        outlineColor:Cesium.Color.RED,
        outlineWidth:2.0,
        outline:true,
      },
    });
    viewer.zoomTo(entity);
View Code

折线

ar entity = viewer.entities.add({
      polyline: {
        positions: Cesium.Cartesian3.fromDegreesArray([77, 35, 75, 34, 60, 30]),
        width: 5,
        material: new Cesium.PolylineOutlineMaterialProperty({
          color: Cesium.Color.ORANGE,
          outlineWidth: 3,
          outlineColor: Cesium.Color.BLUE,
        }),
      },
    });
    viewer.
View Code

高度和垂直挤压

所有的面形状都是平铺在地球上,当前 圆(circles)、椭圆(ellipses)、多边形(polygons)、矩形(rectangles)可以有一个高程属性 或者 垂直挤压变成体。这两种情况种,这些面或者体仍然会贴合地球曲率。
上面我们列出的所有图形,都是只需要在图形对象(graphics )上设置一个高度属性即可。这里顺便说明下,除非在函数上明确说明,否则Cesium总是使用米、弧度、秒做为标准单位。如Cartesian3.fromDegrees.
把图形挤压为体,也非常简单。仅仅需要设置 extrudedHeight 属性。将会创建一个在heightextrudedHeight之间的体块。如果 height 没有定义, 体块从 0高程开始。下面代码创建一个从200,000米到 250,000米的体 。也就是说这个体的高度是50000米。
var entity = viewer.entities.add({
      polygon: {
        hierarchy: Cesium.Cartesian3.fromDegreesArray([
-109.080842, 45.002073, -105.91517, 45.002073, -111.047063, 42.000709,
          -111.047063, 44.476286, -111.05254, 45.002073,
        ]),
        height: 200000,
extrudedHeight: 250000,
        material: Cesium.Color.RED.withAlpha(0.5),
        outline: true,
        outlineColor: Cesium.Color.BLACK,
      },
    });
    viewer.zoomTo(viewer.entities);
View Code

管理Entity集合

EntityCollection类是一个Entity数组集合,用来它管理和控制一组entity非常方便。我们已经见过它的一个实例 viewer.entities 属性。EntityCollection 提供了基本的数组方法 add, remove, 和 removeAll;同时还有下面我们要讨论的一些特有方法或者属性。
很多项目的数据实际都是存在服务端的,只有客户端需要的时候才会加载。有时候需要更改一个我们已经创建的entity。所有entity对象都有一个独一无二的 id 属性,这种情况情况下就非常有用。前面的示例里,我们并没有指定这个id,Cesium会自动生成一个 GUID 类似182bdba4-2b3e-47ae-bf0b-83f6fde285fd 填充到id属性里。服务端的数据一般都有自己主键id属性,所以可以在enity创建的时候指定这个id。

随后,可以通过 getById来获取Entity对象。如果没有找到对应的id,那么该方法返回 undefined

另一个常见的应用,是如果id不存在就新建,如果id存在就更新。 getOrCreateEntity 总会返回以传入的参数为id的对象实例, 如果id不存在,那么会新建一个,并且增加到entity集合里,然后返回。

 最后,简单的通过 add就可以新建一个Entity实例。这种情况下,add函数会检测如果传入了一个已经存在的id,那么会报异常。

EntityCollection 最强大的功能其实是collectionChanged Event,我们用它来接收集合里entity被添加、删除甚至更新的通知。当项目里的用户界面或者某个功能需要监控集合里的对象改变的时候,这个功能非常有用。
var viewer = new Cesium.Viewer("cesiumContainer");
    function onChanged(collection, added, removed, changed) {
      var msg = "Added ids";
for (var i = 0; i < added.length; i++) {
        msg += "\n" + added[i].id;
      }
      console.log(msg);
    }
    viewer.entities.collectionChanged.addEventListener(onChanged);
 var entity = viewer.entities.add({
      id: "test",
      polygon: {
        hierarchy: Cesium.Cartesian3.fromDegreesArray([
 -109.080842, 45.002073, -105.91517, 45.002073, -111.047063, 42.000709,
          -111.047063, 44.476286, -111.05254, 45.002073,
        ]),
        height: 200000,
extrudedHeight: 250000,
        material: Cesium.Color.RED.withAlpha(0.5),
        outline: true,
        outlineColor: Cesium.Color.BLACK,
      },
});

    viewer.zoomTo(viewer.entities);
View Code

拾取