第三章:Cesium 矢量数据可视化(点、线、面)

发布于:2025-08-29 ⋅ 阅读:(11) ⋅ 点赞:(0)

在地理信息系统中,矢量数据(点、线、面)是表达地理要素的基础。本章将详细介绍如何在 Cesium 中创建、样式化和管理矢量数据,包括点标记、线要素和面要素的可视化方法,并并提供可直接运行的 Vue2 组件示例。

3.1 矢量数据基础概念

矢量数据通过几何图形描述地理要素,主要包括三种类型:

  • 点要素:表示离散的地理位置(如 POI、传感器位置)
  • 线要素:表示线性特征(如道路、河流、航线)
  • 面要素:表示区域特征(如行政区、湖泊、建筑轮廓)

Cesium 中处理矢量数据的核心类是 Entity(实体),它可以关联几何形状、样式、描述信息等,是组织矢量数据的最佳实践。

3.2 创建点要素(Point)

点要素通常用于标记特定位置,Cesium 支持普通点、billboard(广告牌)和标签等多种点展示形式。

3.2.1 基础点要素示例


 

<!-- 点 -->
<template>
  <div class="cesium-container">
    <div id="cesiumContainer" class="cesium-viewer"></div>
    <div class="control-panel">
      <button @click="addPoints">添加点要素</button>
      <button @click="clearAll">清除所有要素</button>
    </div>
  </div>
</template>

<script>
// 导入地图初始化函数
import initMap from '@/config/initMap.js';
// 导入地图配置项(包含高德地图服务地址等)
import { mapConfig } from '@/config/mapConfig';
// 图片
import iconMaker from '@/assets/images/edit-point.png';

export default {
  name: 'CesiumPoints',
  data() {
    return {
      viewer: null,
      entities: [], // 存储创建的实体,便于后续管理
    };
  },
  mounted() {
    // 初始化Cesium地图,使用高德地图服务
    const options = {
      infoBox: true, // 显示信息框
    };

    this.viewer = initMap(mapConfig.gaode.url3, true, options);
  },
  methods: {
    addPoints() {
      // 清除已有点(避免重复添加)
      this.clearAll();

      // 1. 基础点要素(圆形点)
      const beijingPoint = this.viewer.entities.add({
        name: '北京市', // 要素名称(会显示在信息框中)
        position: Cesium.Cartesian3.fromDegrees(116.404, 39.915), // 经纬度
        point: {
          pixelSize: 10, // 像素大小
          color: Cesium.Color.RED, // 颜色
          outlineColor: Cesium.Color.WHITE, // 轮廓颜色
          outlineWidth: 2, // 轮廓宽度
          heightReference: Cesium.HeightReference.CLAMP_TO_GROUND, // 贴地 此属性必须开启3D属性
        },
        // 信息框内容(点击要素时显示)
        description: `
          <div style="padding: 10px;">
            <h3>北京市</h3>
            <p>坐标:116.404°E, 39.915°N</p>
            <p>类型:基础点要素</p>
          </div>
        `,
      });

      // 2. 图片标记点(Billboard)
      const shanghaiPoint = this.viewer.entities.add({
        name: '上海市',
        position: Cesium.Cartesian3.fromDegrees(121.4737, 31.2304),
        billboard: {
          image: iconMaker, // 图片URL
          width: 40, // 宽度
          height: 40, // 高度
          scale: 1.0, // 缩放比例
          // 偏移量(使图片底部中心点对准坐标)
          verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
          horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
        },
        description: `<div><h3>上海市</h3><p>图片标记点示例</p></div>`,
      });

      // 3. 带标签的点
      const guangzhouPoint = this.viewer.entities.add({
        name: '广州市',
        position: Cesium.Cartesian3.fromDegrees(113.2644, 23.1291),
        point: {
          pixelSize: 8,
          color: Cesium.Color.BLUE,
        },
        label: {
          text: '广州', // 标签文本
          font: '16px 微软雅黑', // 字体样式
          fillColor: Cesium.Color.YELLOW, // 文本颜色
          outlineColor: Cesium.Color.BLACK, // 轮廓颜色
          outlineWidth: 2,
          // 标签位置(点的上方)
          verticalOrigin: Cesium.VerticalOrigin.TOP,
          pixelOffset: new Cesium.Cartesian2(0, -10), // 像素偏移
        },
      });

      // 存储实体引用
      this.entities.push(beijingPoint, shanghaiPoint, guangzhouPoint);

      // 定位到所有点的范围
      this.viewer.flyTo(this.entities, {
        duration: 3,
      });
    },
    clearAll() {
      // 移除所有实体
      this.entities.forEach((entity) => {
        this.viewer.entities.remove(entity);
      });
      this.entities = [];
    },
  },
  beforeDestroy() {
    if (this.viewer) {
      this.viewer.destroy();
    }
  },
};
</script>

<style scoped>
.cesium-container {
  width: 100vw;
  height: 100vh;
  position: relative;
}

.cesium-viewer {
  width: 100%;
  height: 100%;
}

.control-panel {
  position: absolute;
  top: 20px;
  left: 20px;
  display: flex;
  gap: 10px;
  z-index: 10;
}

button {
  padding: 8px 12px;
  background: #42b983;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  transition: background 0.3s;
}

button:hover {
  background: #359e75;
}
</style>

3.2.2 关键参数解析

  1. 点样式(point)

    • pixelSize:点的大小(像素)
    • color:点的填充色(支持 RGBA、命名颜色)
    • outlineWidth/outlineColor:点的轮廓样式
    • heightReference:高度参考模式(CLAMP_TO_GROUND 贴地,RELATIVE_TO_GROUND 相对地面,ABSOLUTE 绝对高度)
  2. 图片标记(billboard)

    • image:支持 URL、DataURL 或 Canvas
    • verticalOrigin/horizontalOrigin:锚点位置(控制图片与坐标点的对齐方式)
    • scale:缩放比例(负值会翻转图片)
  3. 标签(label)

    • text:显示文本(支持 HTML 片段)
    • font:字体样式(如 "bold 14px sans-serif"
    • pixelOffset:相对于点的像素偏移量

3.3 创建线要素(Polyline)

线要素用于表示路径、边界等线性特征,Cesium 支持多种线样式和动态效果。

3.3.1 线要素示例(基础线,虚线,箭头线,动态线)

<!-- 线 -->
<template>
  <div class="cesium-container">
    <div id="cesiumContainer" class="cesium-viewer"></div>
    <div class="control-panel">
      <button @click="addPolylines">添加线要素</button>
      <button @click="clearAll">清除所有要素</button>
    </div>
  </div>
</template>

<script>
// 导入地图初始化函数
import initMap from '@/config/initMap.js';
// 导入地图配置项(包含高德地图服务地址等)
import { mapConfig } from '@/config/mapConfig';

export default {
  name: 'CesiumPoints',
  data() {
    return {
      viewer: null,
      entities: [], // 存储创建的实体,便于后续管理
    };
  },
  mounted() {
    // 初始化Cesium地图,使用高德地图服务
    this.viewer = initMap(mapConfig.gaode.url3, true);
  },
  methods: {
    addPolylines() {
      this.clearAll();

      // 1. 基础线要素
      const basicLine = this.viewer.entities.add({
        name: '基础线路',
        polyline: {
          // 线路经纬度点数组
          positions: Cesium.Cartesian3.fromDegreesArray([
            116.404,
            39.915, // 北京
            117.2,
            39.13, // 天津
            118.05,
            39.31, // 唐山
          ]),
          width: 5, // 线宽
          material: Cesium.Color.GREEN, // 线颜色
          clampToGround: true, // 贴地(考虑地形起伏)
        },
      });

      // 2. 虚线样式
      const dashedLine = this.viewer.entities.add({
        name: '虚线线路',
        polyline: {
          positions: Cesium.Cartesian3.fromDegreesArray([
            121.4737,
            31.2304, // 上海
            120.1551,
            30.2741, // 杭州
            118.7969,
            32.0603, // 南京
          ]),
          width: 4,
          material: new Cesium.PolylineDashMaterialProperty({
            color: Cesium.Color.PURPLE,
            dashLength: 20, // 虚线长度
          }),
          clampToGround: true,
        },
      });

      // 3. 带箭头的线
      const arrowLine = this.viewer.entities.add({
        name: '带箭头的线',
        polyline: {
          positions: Cesium.Cartesian3.fromDegreesArray([
            113.2644,
            23.1291, // 广州
            114.0665,
            22.5488, // 深圳
            113.5494,
            22.1987, // 珠海
          ]),
          width: 6,
          material: new Cesium.PolylineArrowMaterialProperty(Cesium.Color.RED),
          clampToGround: true,
        },
      });


      this.entities.push(basicLine, dashedLine, arrowLine);
      this.viewer.flyTo(this.entities, { duration: 3 });
    },
    clearAll() {
      // 移除所有实体
      this.entities.forEach((entity) => {
        this.viewer.entities.remove(entity);
      });
      this.entities = [];
    },
  },
  beforeDestroy() {
    if (this.viewer) {
      this.viewer.destroy();
    }
  },
};
</script>

<style scoped>
.cesium-container {
  width: 100vw;
  height: 100vh;
  position: relative;
}

.cesium-viewer {
  width: 100%;
  height: 100%;
}

.control-panel {
  position: absolute;
  top: 20px;
  left: 20px;
  display: flex;
  gap: 10px;
  z-index: 10;
}

button {
  padding: 8px 12px;
  background: #42b983;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  transition: background 0.3s;
}

button:hover {
  background: #359e75;
}
</style>

3.3.2 线要素关键技术

  1. 坐标定义

    • fromDegreesArray([lon1, lat1, lon2, lat2, ...]):适用于 2D 贴地线
    • fromDegreesArrayHeights([lon1, lat1, h1, lon2, lat2, h2, ...]):支持高度参数
  2. 材质(material)

    • 基础颜色:Cesium.Color.XXX
    • 虚线:PolylineDashMaterialProperty(可配置虚线长度、间隔)
    • 箭头:PolylineArrowMaterialProperty(自动在终点显示箭头)
    • 发光效果:PolylineGlowMaterialProperty(适合动态效果)
  3. 地形贴合

    • clampToGround: true:线会贴合地形起伏(适合道路、河流)
    • clampToGround: false:线会保持直线(适合航线、管道)

3.4 创建面要素(Polygon)

面要素用于表示区域,如行政区、湖泊等,支持填充色、轮廓线等样式配置。

3.4.1 面要素示例

<!-- 面 -->
<!-- 线 -->
<template>
  <div class="cesium-container">
    <div id="cesiumContainer" class="cesium-viewer"></div>
    <div class="control-panel">
      <button @click="addPolygons">添加面要素</button>
      <button @click="clearAll">清除所有要素</button>
    </div>
  </div>
</template>

<script>
// 导入地图初始化函数
import initMap from '@/config/initMap.js';
// 导入地图配置项(包含高德地图服务地址等)
import { mapConfig } from '@/config/mapConfig';

export default {
  name: 'CesiumPoints',
  data() {
    return {
      viewer: null,
      entities: [], // 存储创建的实体,便于后续管理
    };
  },
  mounted() {
    // 初始化Cesium地图,使用高德地图服务
    this.viewer = initMap(mapConfig.gaode.url3, true);
  },
  methods: {
    addPolygons() {
      this.clearAll();

      // 1. 基础多边形
      const basicPolygon = this.viewer.entities.add({
        name: '基础多边形',
        polygon: {
          // 多边形顶点(闭合区域,最后一点可与第一点重合)
          hierarchy: new Cesium.PolygonHierarchy(
            Cesium.Cartesian3.fromDegreesArray([
              116.1, 39.9, 116.5, 39.9, 116.5, 39.5, 116.1, 39.5,
            ])
          ),
          material: Cesium.Color.RED.withAlpha(0.3), // 填充色(带透明度)
          outline: true, // 显示轮廓
          outlineColor: Cesium.Color.RED, // 轮廓颜色
          outlineWidth: 2,
          height: 0, // 高度(0表示贴地)
          extrudedHeight: 50000, // 拉伸高度(为0时不拉伸)
        },
      });

      // 2. 带孔的多边形
      const holePolygon = this.viewer.entities.add({
        name: '带孔多边形',
        polygon: {
          hierarchy: new Cesium.PolygonHierarchy(
            // 外环
            Cesium.Cartesian3.fromDegreesArray([
              121.0, 31.0, 121.8, 31.0, 121.8, 30.5, 121.0, 30.5,
            ]),
            // 内环(孔)
            [
              Cesium.Cartesian3.fromDegreesArray([
                121.2, 30.8, 121.6, 30.8, 121.6, 30.6, 121.2, 30.6,
              ]),
            ]
          ),
          material: new Cesium.ColorMaterialProperty(
            Cesium.Color.BLUE.withAlpha(0.3)
          ),
          outline: true,
          outlineColor: Cesium.Color.BLUE,
        },
      });

      // 3. 动态颜色面
      const dynamicPolygon = this.viewer.entities.add({
        name: '动态面',
        polygon: {
          hierarchy: new Cesium.PolygonHierarchy(
            Cesium.Cartesian3.fromDegreesArray([
              113.0, 22.5, 114.0, 22.5, 114.0, 22.0, 113.0, 22.0,
            ])
          ),
          material: Cesium.Color.GREEN.withAlpha(0.3),
          outline: true,
        },
      });

      // 添加颜色动画
      this.viewer.clock.onTick.addEventListener((clock) => {
        const time = clock.currentTime.secondsOfDay;
        const hue = (time % 10) / 10; // 每10秒循环一次色相
        dynamicPolygon.polygon.material = Cesium.Color.fromHsl(
          hue,
          0.7,
          0.5,
          0.3
        );
      });

      this.entities.push(basicPolygon, holePolygon, dynamicPolygon);
      this.viewer.flyTo(this.entities[2], { duration: 3 });
    },
    clearAll() {
      // 移除所有实体
      this.entities.forEach((entity) => {
        this.viewer.entities.remove(entity);
      });
      this.entities = [];
    },
  },
  beforeDestroy() {
    if (this.viewer) {
      this.viewer.destroy();
    }
  },
};
</script>

<style scoped>
.cesium-container {
  width: 100vw;
  height: 100vh;
  position: relative;
}

.cesium-viewer {
  width: 100%;
  height: 100%;
}

.control-panel {
  position: absolute;
  top: 20px;
  left: 20px;
  display: flex;
  gap: 10px;
  z-index: 10;
}

button {
  padding: 8px 12px;
  background: #42b983;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  transition: background 0.3s;
}

button:hover {
  background: #359e75;
}
</style>

3.4.2 面要素核心参数

  1. 层级结构(hierarchy)

    • 外环:定义多边形的外边界
    • 内环:定义多边形中的 "孔"(支持多个孔)
  2. 高度参数

    • height:多边形底部高度
    • extrudedHeight:多边形顶部高度(当 extrudedHeight > height 时形成 3D 立体效果)
  3. 样式控制

    • material:填充材质(支持颜色、纹理、动态材质)
    • outline:是否显示轮廓线
    • perPositionHeight:是否使用每个顶点的高度(默认使用统一高度)

3.5 实体管理最佳实践

  1. 批量操作

    • 使用 viewer.entities.addAll(entitiesArray) 批量添加
    • 使用 viewer.entities.removeAll() 清空所有实体
  2. 属性查询

    // 根据名称查询实体
    const beijing = this.viewer.entities.getById('beijing-point');
    // 遍历所有实体
    this.viewer.entities.values.forEach(entity => {
      console.log(entity.name);
    });
    
  3. 性能优化

    • 对于大量点数据(>1000),考虑使用 PointPrimitiveCollection 替代 Entity
    • 复杂面要素可简化顶点数量
    • 关闭不可见区域的要素渲染

小结

本章系统介绍了 Cesium 矢量数据可视化的核心方法:

  • 点要素:包括基础点、图片标记和标签的创建与样式设置
  • 线要素:掌握普通线、虚线、箭头线和动态线的实现
  • 面要素:学习基础多边形、带孔多边形和 3D 拉伸效果的配置
  • 实体管理:了解实体的添加、删除、查询和性能优化技巧

这些技能是构建地理信息应用的基础,下一章节内容将学习如何加载和展示 GIS 矢量数据(如 GeoJSON、KML 等格式)。


网站公告

今日签到

点亮在社区的每一天
去签到