第11章 - 数据格式与数据源

第11章:数据格式与数据源

11.1 数据源概述

CesiumJS 支持多种数据格式,通过 DataSource 统一管理:

┌─────────────────────────────────────────────────────────────────┐
│                     DataSource 架构                              │
├─────────────────────────────────────────────────────────────────┤
│  DataSourceCollection                                            │
│  └── DataSource                                                  │
│      ├── entities (EntityCollection)                            │
│      ├── clock (时钟配置)                                        │
│      └── changedEvent / errorEvent / loadingEvent               │
│                                                                  │
│  内置数据源:                                                    │
│  ├── GeoJsonDataSource   - GeoJSON/TopoJSON                     │
│  ├── KmlDataSource       - KML/KMZ                              │
│  ├── CzmlDataSource      - CZML                                 │
│  └── GpxDataSource       - GPX                                  │
└─────────────────────────────────────────────────────────────────┘

11.2 GeoJSON 数据

11.2.1 加载 GeoJSON

// 基本加载
const dataSource = await Cesium.GeoJsonDataSource.load('data.geojson');
viewer.dataSources.add(dataSource);
viewer.zoomTo(dataSource);

// 带样式加载
const styledDataSource = await Cesium.GeoJsonDataSource.load('data.geojson', {
    stroke: Cesium.Color.RED,
    fill: Cesium.Color.RED.withAlpha(0.5),
    strokeWidth: 3,
    markerSymbol: '?',
    markerColor: Cesium.Color.BLUE,
    markerSize: 48,
    clampToGround: true
});
viewer.dataSources.add(styledDataSource);

// 加载 GeoJSON 对象
const geojson = {
    type: 'FeatureCollection',
    features: [{
        type: 'Feature',
        geometry: {
            type: 'Point',
            coordinates: [116.4, 39.9]
        },
        properties: { name: '北京' }
    }, {
        type: 'Feature',
        geometry: {
            type: 'Polygon',
            coordinates: [[[116, 39], [117, 39], [117, 40], [116, 40], [116, 39]]]
        },
        properties: { name: '区域' }
    }]
};

const objectDataSource = await Cesium.GeoJsonDataSource.load(geojson);
viewer.dataSources.add(objectDataSource);

11.2.2 自定义 GeoJSON 样式

// 加载后自定义样式
const dataSource = await Cesium.GeoJsonDataSource.load('data.geojson');
viewer.dataSources.add(dataSource);

// 遍历实体设置样式
const entities = dataSource.entities.values;
entities.forEach(entity => {
    // 点样式
    if (entity.point) {
        entity.point.pixelSize = 12;
        entity.point.color = Cesium.Color.RED;
    }
    
    // 多边形样式
    if (entity.polygon) {
        const height = entity.properties.height?.getValue() || 0;
        
        if (height > 100) {
            entity.polygon.material = Cesium.Color.RED.withAlpha(0.6);
        } else if (height > 50) {
            entity.polygon.material = Cesium.Color.ORANGE.withAlpha(0.6);
        } else {
            entity.polygon.material = Cesium.Color.YELLOW.withAlpha(0.6);
        }
        
        entity.polygon.outline = true;
        entity.polygon.outlineColor = Cesium.Color.BLACK;
    }
    
    // 折线样式
    if (entity.polyline) {
        entity.polyline.material = Cesium.Color.BLUE;
        entity.polyline.width = 3;
    }
});

11.3 CZML 数据

11.3.1 CZML 基本结构

// CZML 文档结构
const czml = [
    // 文档声明(必须是第一个元素)
    {
        id: 'document',
        name: 'CZML 示例',
        version: '1.0',
        clock: {
            interval: '2024-01-01T00:00:00Z/2024-01-02T00:00:00Z',
            currentTime: '2024-01-01T00:00:00Z',
            multiplier: 60
        }
    },
    // 实体定义
    {
        id: 'point1',
        name: '点对象',
        position: {
            cartographicDegrees: [116.4, 39.9, 100]
        },
        point: {
            pixelSize: 10,
            color: { rgba: [255, 0, 0, 255] }
        }
    }
];

// 加载 CZML
const dataSource = await Cesium.CzmlDataSource.load(czml);
viewer.dataSources.add(dataSource);

11.3.2 CZML 动态轨迹

// 动态轨迹 CZML
const trajectoryDoc = [
    {
        id: 'document',
        name: '飞行轨迹',
        version: '1.0',
        clock: {
            interval: '2024-01-01T00:00:00Z/2024-01-01T01:00:00Z',
            currentTime: '2024-01-01T00:00:00Z',
            multiplier: 60,
            range: 'LOOP_STOP',
            step: 'SYSTEM_CLOCK_MULTIPLIER'
        }
    },
    {
        id: 'aircraft',
        name: '飞机',
        availability: '2024-01-01T00:00:00Z/2024-01-01T01:00:00Z',
        position: {
            epoch: '2024-01-01T00:00:00Z',
            cartographicDegrees: [
                0, 116.0, 39.0, 10000,
                1800, 117.0, 39.5, 12000,
                3600, 118.0, 40.0, 10000
            ],
            interpolationAlgorithm: 'LAGRANGE',
            interpolationDegree: 5
        },
        orientation: {
            velocityReference: '#position'
        },
        model: {
            gltf: 'aircraft.glb',
            scale: 100,
            minimumPixelSize: 64
        },
        path: {
            material: {
                solidColor: { color: { rgba: [255, 255, 0, 255] } }
            },
            width: 2,
            leadTime: 600,
            trailTime: 3600,
            resolution: 120
        }
    }
];

const trajectoryDataSource = await Cesium.CzmlDataSource.load(trajectoryDoc);
viewer.dataSources.add(trajectoryDataSource);
viewer.trackedEntity = trajectoryDataSource.entities.getById('aircraft');

11.4 KML 数据

11.4.1 加载 KML/KMZ

// 加载 KML
const kmlDataSource = await Cesium.KmlDataSource.load('data.kml', {
    camera: viewer.camera,
    canvas: viewer.canvas,
    clampToGround: true
});
viewer.dataSources.add(kmlDataSource);
viewer.zoomTo(kmlDataSource);

// 加载 KMZ
const kmzDataSource = await Cesium.KmlDataSource.load('data.kmz', {
    camera: viewer.camera,
    canvas: viewer.canvas
});
viewer.dataSources.add(kmzDataSource);

11.5 glTF 模型

11.5.1 加载 glTF/GLB

// 使用 Entity API
const modelEntity = viewer.entities.add({
    name: '3D模型',
    position: Cesium.Cartesian3.fromDegrees(116.4, 39.9, 0),
    orientation: Cesium.Transforms.headingPitchRollQuaternion(
        Cesium.Cartesian3.fromDegrees(116.4, 39.9, 0),
        new Cesium.HeadingPitchRoll(Cesium.Math.toRadians(90), 0, 0)
    ),
    model: {
        uri: 'model.glb',
        scale: 1.0,
        minimumPixelSize: 64,
        maximumScale: 20000,
        silhouetteColor: Cesium.Color.RED,
        silhouetteSize: 2.0
    }
});

// 使用 Primitive API(更高性能)
const modelPrimitive = await Cesium.Model.fromGltfAsync({
    url: 'model.glb',
    modelMatrix: Cesium.Transforms.eastNorthUpToFixedFrame(
        Cesium.Cartesian3.fromDegrees(116.4, 39.9, 0)
    ),
    scale: 1.0,
    minimumPixelSize: 64
});
viewer.scene.primitives.add(modelPrimitive);

11.6 DataSource 管理

11.6.1 DataSourceCollection 操作

const dataSources = viewer.dataSources;

// 添加
const ds = await Cesium.GeoJsonDataSource.load('data.geojson');
dataSources.add(ds);

// 获取
const count = dataSources.length;
const dsAt = dataSources.get(0);
const contains = dataSources.contains(ds);
const indexOf = dataSources.indexOf(ds);
const byName = dataSources.getByName('数据源名称');

// 移除
dataSources.remove(ds);
dataSources.remove(ds, true);  // 移除并销毁
dataSources.removeAll();

// 调整顺序
dataSources.raise(ds);
dataSources.lower(ds);
dataSources.raiseToTop(ds);
dataSources.lowerToBottom(ds);

// 事件
dataSources.dataSourceAdded.addEventListener((collection, dataSource) => {
    console.log('数据源添加:', dataSource.name);
});

dataSources.dataSourceRemoved.addEventListener((collection, dataSource) => {
    console.log('数据源移除:', dataSource.name);
});

11.6.2 数据源管理器

class DataSourceManager {
    constructor(viewer) {
        this.viewer = viewer;
        this.sources = new Map();
    }
    
    async addGeoJson(name, url, options = {}) {
        const ds = await Cesium.GeoJsonDataSource.load(url, options);
        ds.name = name;
        this.viewer.dataSources.add(ds);
        this.sources.set(name, { type: 'geojson', dataSource: ds });
        return ds;
    }
    
    async addCzml(name, url) {
        const ds = await Cesium.CzmlDataSource.load(url);
        ds.name = name;
        this.viewer.dataSources.add(ds);
        this.sources.set(name, { type: 'czml', dataSource: ds });
        return ds;
    }
    
    async addKml(name, url) {
        const ds = await Cesium.KmlDataSource.load(url, {
            camera: this.viewer.camera,
            canvas: this.viewer.canvas
        });
        ds.name = name;
        this.viewer.dataSources.add(ds);
        this.sources.set(name, { type: 'kml', dataSource: ds });
        return ds;
    }
    
    get(name) {
        const info = this.sources.get(name);
        return info ? info.dataSource : null;
    }
    
    show(name, visible) {
        const ds = this.get(name);
        if (ds) ds.show = visible;
    }
    
    remove(name) {
        const info = this.sources.get(name);
        if (info) {
            this.viewer.dataSources.remove(info.dataSource, true);
            this.sources.delete(name);
            return true;
        }
        return false;
    }
    
    zoomTo(name) {
        const ds = this.get(name);
        if (ds) this.viewer.zoomTo(ds);
    }
    
    clear() {
        this.sources.forEach((info, name) => {
            this.viewer.dataSources.remove(info.dataSource, true);
        });
        this.sources.clear();
    }
}

// 使用
const dsManager = new DataSourceManager(viewer);
await dsManager.addGeoJson('cities', 'cities.geojson');
await dsManager.addCzml('flights', 'flights.czml');
dsManager.zoomTo('cities');
dsManager.show('flights', false);

11.7 本章小结

本章介绍了数据格式与数据源:

  1. GeoJSON:加载、样式自定义
  2. CZML:动态轨迹、时间序列
  3. KML:Google Earth 格式支持
  4. glTF:3D 模型加载
  5. DataSource 管理:添加、移除、排序

在下一章中,我们将详细介绍空间分析与测量。

11.8 思考与练习

  1. 加载并展示 GeoJSON 行政区划数据。
  2. 创建 CZML 动态飞行轨迹。
  3. 实现数据源的动态切换功能。
  4. 开发 GeoJSON 数据导入工具。
  5. 实现基于属性的 GeoJSON 专题图。
posted @ 2026-01-08 11:13  我才是银古  阅读(3)  评论(0)    收藏  举报