第18章 - 实战案例与项目应用

第18章:实战案例与项目应用

18.1 智慧城市可视化

18.1.1 项目架构

// 智慧城市应用框架
class SmartCityApp {
    constructor(containerId) {
        this.viewer = null;
        this.layerManager = null;
        this.toolManager = null;
        this.init(containerId);
    }
    
    async init(containerId) {
        // 初始化 Viewer
        Cesium.Ion.defaultAccessToken = 'your_token';
        
        this.viewer = new Cesium.Viewer(containerId, {
            terrainProvider: Cesium.createWorldTerrain(),
            animation: false,
            timeline: false,
            baseLayerPicker: false,
            geocoder: false,
            homeButton: false,
            sceneModePicker: false,
            navigationHelpButton: false,
            infoBox: true,
            selectionIndicator: true
        });
        
        // 初始化管理器
        this.layerManager = new LayerManager(this.viewer);
        this.toolManager = new ToolManager(this.viewer);
        
        // 加载城市数据
        await this.loadCityData();
        
        // 初始化交互
        this.initInteraction();
    }
    
    async loadCityData() {
        // 加载建筑 3D Tiles
        const buildings = await this.layerManager.add3DTiles('buildings',
            'https://city-server/buildings/tileset.json',
            {
                style: new Cesium.Cesium3DTileStyle({
                    color: {
                        conditions: [
                            ['${height} > 100', 'color("#FF4444")'],
                            ['${height} > 50', 'color("#FF8844")'],
                            ['true', 'color("#AAAAAA")']
                        ]
                    }
                })
            }
        );
        
        // 加载道路数据
        await this.layerManager.addGeoJson('roads', 'data/roads.geojson', {
            stroke: Cesium.Color.WHITE,
            strokeWidth: 2,
            clampToGround: true
        });
        
        // 加载 POI 数据
        await this.layerManager.addGeoJson('poi', 'data/poi.geojson');
    }
    
    initInteraction() {
        // 点击建筑显示信息
        const handler = new Cesium.ScreenSpaceEventHandler(this.viewer.canvas);
        
        handler.setInputAction((click) => {
            const picked = this.viewer.scene.pick(click.position);
            if (Cesium.defined(picked) && picked.primitive instanceof Cesium.Cesium3DTileset) {
                this.showBuildingInfo(picked);
            }
        }, Cesium.ScreenSpaceEventType.LEFT_CLICK);
    }
    
    showBuildingInfo(picked) {
        if (picked.getPropertyIds) {
            const info = {};
            picked.getPropertyIds().forEach(id => {
                info[id] = picked.getProperty(id);
            });
            console.log('建筑信息:', info);
            
            // 显示信息面板
            this.showInfoPanel(info);
        }
    }
    
    showInfoPanel(info) {
        let panel = document.getElementById('info-panel');
        if (!panel) {
            panel = document.createElement('div');
            panel.id = 'info-panel';
            panel.style.cssText = `
                position: absolute;
                top: 10px;
                right: 10px;
                background: rgba(0,0,0,0.8);
                color: white;
                padding: 15px;
                border-radius: 5px;
                z-index: 1000;
            `;
            this.viewer.container.appendChild(panel);
        }
        
        panel.innerHTML = `
            <h3>建筑信息</h3>
            ${Object.entries(info).map(([k, v]) => `<p>${k}: ${v}</p>`).join('')}
        `;
    }
    
    flyTo(lon, lat, height = 1000) {
        this.viewer.camera.flyTo({
            destination: Cesium.Cartesian3.fromDegrees(lon, lat, height),
            orientation: {
                heading: 0,
                pitch: Cesium.Math.toRadians(-45),
                roll: 0
            }
        });
    }
}

// 使用
const app = new SmartCityApp('cesiumContainer');
app.flyTo(116.4, 39.9, 5000);

18.2 飞行轨迹追踪

18.2.1 航班追踪系统

class FlightTracker {
    constructor(viewer) {
        this.viewer = viewer;
        this.flights = new Map();
        this.dataSource = new Cesium.CustomDataSource('flights');
        viewer.dataSources.add(this.dataSource);
    }
    
    addFlight(flightData) {
        const { id, positions, model } = flightData;
        
        // 创建位置属性
        const positionProperty = new Cesium.SampledPositionProperty();
        positions.forEach(p => {
            positionProperty.addSample(
                Cesium.JulianDate.fromIso8601(p.time),
                Cesium.Cartesian3.fromDegrees(p.lon, p.lat, p.altitude)
            );
        });
        
        positionProperty.setInterpolationOptions({
            interpolationDegree: 5,
            interpolationAlgorithm: Cesium.LagrangePolynomialApproximation
        });
        
        // 创建实体
        const entity = this.dataSource.entities.add({
            id: id,
            name: flightData.name || id,
            availability: new Cesium.TimeIntervalCollection([
                new Cesium.TimeInterval({
                    start: Cesium.JulianDate.fromIso8601(positions[0].time),
                    stop: Cesium.JulianDate.fromIso8601(positions[positions.length - 1].time)
                })
            ]),
            position: positionProperty,
            orientation: new Cesium.VelocityOrientationProperty(positionProperty),
            model: {
                uri: model || 'models/aircraft.glb',
                scale: 1.0,
                minimumPixelSize: 64
            },
            path: {
                material: Cesium.Color.YELLOW,
                width: 2,
                leadTime: 0,
                trailTime: 3600
            },
            label: {
                text: flightData.name || id,
                font: '14px sans-serif',
                fillColor: Cesium.Color.WHITE,
                showBackground: true,
                verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
                pixelOffset: new Cesium.Cartesian2(0, -40)
            }
        });
        
        this.flights.set(id, entity);
        return entity;
    }
    
    trackFlight(id) {
        const entity = this.flights.get(id);
        if (entity) {
            this.viewer.trackedEntity = entity;
        }
    }
    
    removeFlight(id) {
        const entity = this.flights.get(id);
        if (entity) {
            this.dataSource.entities.remove(entity);
            this.flights.delete(id);
        }
    }
    
    updateFlightPosition(id, position) {
        const entity = this.flights.get(id);
        if (entity && entity.position) {
            entity.position.addSample(
                Cesium.JulianDate.now(),
                Cesium.Cartesian3.fromDegrees(position.lon, position.lat, position.altitude)
            );
        }
    }
}

// 使用示例
const tracker = new FlightTracker(viewer);

tracker.addFlight({
    id: 'CA123',
    name: '国航 CA123',
    positions: [
        { time: '2024-01-01T00:00:00Z', lon: 116.4, lat: 39.9, altitude: 10000 },
        { time: '2024-01-01T01:00:00Z', lon: 118.0, lat: 38.0, altitude: 11000 },
        { time: '2024-01-01T02:00:00Z', lon: 121.5, lat: 31.2, altitude: 10000 }
    ]
});

tracker.trackFlight('CA123');

18.3 地质灾害预警

18.3.1 灾害监测系统

class DisasterMonitoringSystem {
    constructor(viewer) {
        this.viewer = viewer;
        this.monitorPoints = [];
        this.warningAreas = [];
    }
    
    // 添加监测点
    addMonitorPoint(data) {
        const entity = this.viewer.entities.add({
            name: data.name,
            position: Cesium.Cartesian3.fromDegrees(data.lon, data.lat, data.height || 0),
            point: {
                pixelSize: 12,
                color: this.getStatusColor(data.status),
                outlineColor: Cesium.Color.WHITE,
                outlineWidth: 2,
                heightReference: Cesium.HeightReference.CLAMP_TO_GROUND
            },
            label: {
                text: data.name,
                font: '12px sans-serif',
                fillColor: Cesium.Color.WHITE,
                showBackground: true,
                verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
                pixelOffset: new Cesium.Cartesian2(0, -15)
            },
            properties: data
        });
        
        this.monitorPoints.push(entity);
        return entity;
    }
    
    getStatusColor(status) {
        switch (status) {
            case 'danger': return Cesium.Color.RED;
            case 'warning': return Cesium.Color.ORANGE;
            case 'attention': return Cesium.Color.YELLOW;
            default: return Cesium.Color.GREEN;
        }
    }
    
    // 添加预警区域
    addWarningArea(data) {
        const entity = this.viewer.entities.add({
            name: data.name,
            polygon: {
                hierarchy: Cesium.Cartesian3.fromDegreesArray(data.coordinates.flat()),
                material: this.getWarningMaterial(data.level),
                outline: true,
                outlineColor: Cesium.Color.RED,
                outlineWidth: 2,
                classificationType: Cesium.ClassificationType.TERRAIN
            },
            properties: data
        });
        
        this.warningAreas.push(entity);
        return entity;
    }
    
    getWarningMaterial(level) {
        switch (level) {
            case 4: return Cesium.Color.RED.withAlpha(0.5);    // 一级
            case 3: return Cesium.Color.ORANGE.withAlpha(0.5); // 二级
            case 2: return Cesium.Color.YELLOW.withAlpha(0.5); // 三级
            default: return Cesium.Color.BLUE.withAlpha(0.3);  // 四级
        }
    }
    
    // 更新监测点状态
    updatePointStatus(name, newStatus) {
        const entity = this.monitorPoints.find(e => e.name === name);
        if (entity) {
            entity.point.color = this.getStatusColor(newStatus);
            entity.properties.status = newStatus;
            
            // 触发预警
            if (newStatus === 'danger') {
                this.triggerWarning(entity);
            }
        }
    }
    
    // 触发预警
    triggerWarning(entity) {
        // 闪烁效果
        let visible = true;
        const interval = setInterval(() => {
            entity.show = visible;
            visible = !visible;
        }, 500);
        
        // 5秒后停止闪烁
        setTimeout(() => {
            clearInterval(interval);
            entity.show = true;
        }, 5000);
        
        // 飞到预警点
        this.viewer.flyTo(entity);
    }
}

// 使用
const disasterSystem = new DisasterMonitoringSystem(viewer);

// 添加监测点
disasterSystem.addMonitorPoint({
    name: '滑坡监测点1',
    lon: 104.5,
    lat: 31.2,
    status: 'normal'
});

// 添加预警区域
disasterSystem.addWarningArea({
    name: '高风险区域A',
    level: 4,
    coordinates: [
        104.4, 31.1, 104.6, 31.1, 104.6, 31.3, 104.4, 31.3
    ]
});

// 模拟状态更新
setTimeout(() => {
    disasterSystem.updatePointStatus('滑坡监测点1', 'danger');
}, 3000);

18.4 项目部署

18.4.1 构建优化

// vite.config.js
import { defineConfig } from 'vite';
import cesium from 'vite-plugin-cesium';

export default defineConfig({
    plugins: [cesium()],
    build: {
        rollupOptions: {
            output: {
                manualChunks: {
                    cesium: ['cesium']
                }
            }
        },
        chunkSizeWarningLimit: 2000
    },
    server: {
        host: true,
        port: 3000
    }
});

18.4.2 部署配置

# nginx 配置示例
server {
    listen 80;
    server_name your-domain.com;
    root /var/www/cesium-app;
    
    # 静态资源缓存
    location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2)$ {
        expires 30d;
        add_header Cache-Control "public, no-transform";
    }
    
    # 3D Tiles 缓存
    location /tiles/ {
        expires 7d;
        add_header Cache-Control "public";
    }
    
    # SPA 路由
    location / {
        try_files $uri $uri/ /index.html;
    }
    
    # Gzip 压缩
    gzip on;
    gzip_types application/javascript text/css application/json;
}

18.5 本章小结

本章通过实战案例展示了 CesiumJS 的综合应用:

  1. 智慧城市:建筑可视化、信息展示
  2. 飞行追踪:轨迹动画、实时更新
  3. 灾害预警:监测点、预警区域
  4. 项目部署:构建优化、服务器配置

18.6 教程总结

通过本教程的学习,您已经掌握了:

  • CesiumJS 核心概念和架构
  • Viewer、Camera、Entity、Primitive
  • 影像、地形、3D Tiles 数据处理
  • 交互事件与绘图工具
  • 动画与时间系统
  • 样式效果与粒子系统
  • 性能优化与最佳实践
  • 实际项目应用

继续深入学习建议:

  1. 阅读 CesiumJS 源码
  2. 参与社区讨论
  3. 尝试更复杂的项目
  4. 关注官方更新

祝您在三维地理信息可视化领域取得更大成就!

posted @ 2026-01-08 11:13  我才是银古  阅读(9)  评论(0)    收藏  举报