第08章 - 影像图层与地图服务

第08章:影像图层与地图服务

8.1 影像图层概述

8.1.1 ImageryLayer 架构

CesiumJS 支持多种影像数据源,通过 ImageryLayer 和 ImageryProvider 进行管理:

┌─────────────────────────────────────────────────────────────────┐
│                    影像图层架构                                   │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  ImageryLayerCollection (影像图层集合)                           │
│  └── ImageryLayer (影像图层)                                    │
│      ├── ImageryProvider (影像提供者)                           │
│      │   ├── 请求瓦片                                           │
│      │   ├── 解码图片                                           │
│      │   └── 提供元数据                                         │
│      │                                                          │
│      └── 图层属性                                               │
│          ├── alpha (透明度)                                     │
│          ├── brightness (亮度)                                  │
│          ├── contrast (对比度)                                  │
│          ├── hue (色调)                                         │
│          └── saturation (饱和度)                                │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

8.1.2 支持的影像服务类型

类型 Provider 类 描述
Cesium Ion IonImageryProvider Cesium 官方云服务
OpenStreetMap OpenStreetMapImageryProvider 开放街图
Bing Maps BingMapsImageryProvider 微软地图
ArcGIS ArcGisMapServerImageryProvider Esri 地图服务
WMS WebMapServiceImageryProvider OGC WMS 服务
WMTS WebMapTileServiceImageryProvider OGC WMTS 服务
TMS TileMapServiceImageryProvider 瓦片地图服务
URL Template UrlTemplateImageryProvider 自定义 URL 模板
Single Tile SingleTileImageryProvider 单张图片
Google Earth GoogleEarthEnterpriseImageryProvider Google 企业版
Mapbox MapboxImageryProvider Mapbox 地图

8.2 内置影像提供者

8.2.1 Cesium Ion 影像

// Cesium World Imagery(默认卫星影像)
const worldImagery = await Cesium.createWorldImageryAsync();
viewer.imageryLayers.addImageryProvider(worldImagery);

// 指定样式
const aerialImagery = await Cesium.createWorldImageryAsync({
    style: Cesium.IonWorldImageryStyle.AERIAL  // 航空影像
});

const aerialWithLabels = await Cesium.createWorldImageryAsync({
    style: Cesium.IonWorldImageryStyle.AERIAL_WITH_LABELS  // 带标签
});

const road = await Cesium.createWorldImageryAsync({
    style: Cesium.IonWorldImageryStyle.ROAD  // 道路图
});

// 自定义 Ion 资源
const customIonImagery = await Cesium.IonImageryProvider.fromAssetId(3954);
viewer.imageryLayers.addImageryProvider(customIonImagery);

8.2.2 OpenStreetMap

// 基本 OpenStreetMap
const osmImagery = new Cesium.OpenStreetMapImageryProvider({
    url: 'https://tile.openstreetmap.org/'
});
viewer.imageryLayers.addImageryProvider(osmImagery);

// 自定义 OSM 服务器
const customOsm = new Cesium.OpenStreetMapImageryProvider({
    url: 'https://a.tile.openstreetmap.org/',
    maximumLevel: 19,
    credit: 'OpenStreetMap contributors'
});

8.2.3 Bing Maps

// Bing Maps 航空影像
const bingAerial = await Cesium.BingMapsImageryProvider.fromUrl(
    'https://dev.virtualearth.net',
    {
        key: 'YOUR_BING_MAPS_KEY',
        mapStyle: Cesium.BingMapsStyle.AERIAL
    }
);
viewer.imageryLayers.addImageryProvider(bingAerial);

// 其他样式
const bingStyles = {
    AERIAL: Cesium.BingMapsStyle.AERIAL,                    // 航空
    AERIAL_WITH_LABELS: Cesium.BingMapsStyle.AERIAL_WITH_LABELS,  // 航空带标签
    AERIAL_WITH_LABELS_ON_DEMAND: Cesium.BingMapsStyle.AERIAL_WITH_LABELS_ON_DEMAND,
    ROAD: Cesium.BingMapsStyle.ROAD,                        // 道路
    ROAD_ON_DEMAND: Cesium.BingMapsStyle.ROAD_ON_DEMAND,
    CANVAS_DARK: Cesium.BingMapsStyle.CANVAS_DARK,          // 深色
    CANVAS_LIGHT: Cesium.BingMapsStyle.CANVAS_LIGHT,        // 浅色
    CANVAS_GRAY: Cesium.BingMapsStyle.CANVAS_GRAY,          // 灰色
    ORDNANCE_SURVEY: Cesium.BingMapsStyle.ORDNANCE_SURVEY,  // 英国测绘
    COLLINS_BART: Cesium.BingMapsStyle.COLLINS_BART         // 柯林斯
};

8.2.4 ArcGIS MapServer

// ArcGIS World Imagery
const arcgisImagery = await Cesium.ArcGisMapServerImageryProvider.fromUrl(
    'https://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer'
);
viewer.imageryLayers.addImageryProvider(arcgisImagery);

// ArcGIS World Street Map
const arcgisStreet = await Cesium.ArcGisMapServerImageryProvider.fromUrl(
    'https://services.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer'
);

// ArcGIS World Topo Map
const arcgisTopo = await Cesium.ArcGisMapServerImageryProvider.fromUrl(
    'https://services.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer'
);

// 自定义 ArcGIS 服务
const customArcgis = await Cesium.ArcGisMapServerImageryProvider.fromUrl(
    'https://your-arcgis-server/arcgis/rest/services/YourService/MapServer',
    {
        token: 'YOUR_ARCGIS_TOKEN',  // 如果需要认证
        layers: '0,1,2',              // 指定图层
        enablePickFeatures: true      // 启用要素拾取
    }
);

8.3 OGC 标准服务

8.3.1 WMS(Web Map Service)

// 基本 WMS
const wmsImagery = new Cesium.WebMapServiceImageryProvider({
    url: 'https://your-wms-server/wms',
    layers: 'layer_name',
    parameters: {
        service: 'WMS',
        format: 'image/png',
        transparent: true
    }
});
viewer.imageryLayers.addImageryProvider(wmsImagery);

// 完整配置
const advancedWms = new Cesium.WebMapServiceImageryProvider({
    url: 'https://your-wms-server/wms',
    layers: 'layer1,layer2',          // 多图层
    
    // WMS 参数
    parameters: {
        service: 'WMS',
        version: '1.1.1',             // 或 1.3.0
        request: 'GetMap',
        format: 'image/png',
        transparent: true,
        styles: '',                    // 样式
        srs: 'EPSG:4326',             // 坐标系(1.1.1用srs)
        // crs: 'EPSG:4326',           // 坐标系(1.3.0用crs)
        bgcolor: '0xFFFFFF',           // 背景色
        exceptions: 'application/vnd.ogc.se_xml'
    },
    
    // Cesium 配置
    minimumLevel: 0,
    maximumLevel: 18,
    
    // 瓦片配置
    tileWidth: 256,
    tileHeight: 256,
    
    // 时间维度(如果支持)
    times: undefined,
    
    // 子域(负载均衡)
    subdomains: ['a', 'b', 'c'],
    
    // 信用信息
    credit: 'Data from WMS Server',
    
    // 拾取功能
    enablePickFeatures: true,
    getFeatureInfoFormats: [
        new Cesium.GetFeatureInfoFormat('json', 'application/json'),
        new Cesium.GetFeatureInfoFormat('xml', 'application/vnd.ogc.gml')
    ]
});

// 带时间维度的 WMS
const timeWms = new Cesium.WebMapServiceImageryProvider({
    url: 'https://your-wms-server/wms',
    layers: 'time_layer',
    parameters: {
        format: 'image/png',
        transparent: true,
        time: '2024-01-01T00:00:00Z'  // 时间参数
    }
});

// 动态更新时间
viewer.clock.onTick.addEventListener(function(clock) {
    const isoTime = Cesium.JulianDate.toIso8601(clock.currentTime);
    // 需要重新创建 provider 或使用其他方式更新
});

8.3.2 WMTS(Web Map Tile Service)

// 基本 WMTS
const wmtsImagery = new Cesium.WebMapTileServiceImageryProvider({
    url: 'https://your-wmts-server/wmts',
    layer: 'layer_name',
    style: 'default',
    tileMatrixSetID: 'EPSG:4326',
    format: 'image/png'
});
viewer.imageryLayers.addImageryProvider(wmtsImagery);

// 完整配置
const advancedWmts = new Cesium.WebMapTileServiceImageryProvider({
    url: 'https://your-wmts-server/wmts',
    layer: 'layer_name',
    style: 'default',
    tileMatrixSetID: 'GoogleMapsCompatible',  // 或 EPSG:3857, EPSG:4326
    format: 'image/png',
    
    // 瓦片矩阵配置
    tileMatrixLabels: undefined,  // 自定义级别标签
    
    // 范围限制
    rectangle: Cesium.Rectangle.fromDegrees(73, 3, 135, 54),  // 中国范围
    
    // 级别限制
    minimumLevel: 0,
    maximumLevel: 18,
    
    // 时间维度
    times: undefined,
    
    // 子域
    subdomains: ['a', 'b', 'c'],
    
    // 信用
    credit: 'WMTS Data'
});

// 天地图 WMTS 示例
const tiandituImagery = new Cesium.WebMapTileServiceImageryProvider({
    url: 'http://t{s}.tianditu.gov.cn/img_w/wmts?tk=YOUR_TIANDITU_KEY',
    layer: 'img',
    style: 'default',
    tileMatrixSetID: 'w',
    format: 'tiles',
    subdomains: ['0', '1', '2', '3', '4', '5', '6', '7'],
    maximumLevel: 18
});

// 天地图注记图层
const tiandituLabel = new Cesium.WebMapTileServiceImageryProvider({
    url: 'http://t{s}.tianditu.gov.cn/cia_w/wmts?tk=YOUR_TIANDITU_KEY',
    layer: 'cia',
    style: 'default',
    tileMatrixSetID: 'w',
    format: 'tiles',
    subdomains: ['0', '1', '2', '3', '4', '5', '6', '7'],
    maximumLevel: 18
});

8.3.3 TMS(Tile Map Service)

// 基本 TMS
const tmsImagery = await Cesium.TileMapServiceImageryProvider.fromUrl(
    'https://your-tms-server/tiles/',
    {
        fileExtension: 'png'
    }
);
viewer.imageryLayers.addImageryProvider(tmsImagery);

// 完整配置
const advancedTms = await Cesium.TileMapServiceImageryProvider.fromUrl(
    'https://your-tms-server/tiles/',
    {
        fileExtension: 'png',
        
        // 级别范围
        minimumLevel: 0,
        maximumLevel: 18,
        
        // 地理范围
        rectangle: Cesium.Rectangle.fromDegrees(-180, -90, 180, 90),
        
        // 瓦片大小
        tileWidth: 256,
        tileHeight: 256,
        
        // 翻转 Y 轴(某些 TMS 需要)
        flipXY: false,
        
        // 信用
        credit: 'TMS Data'
    }
);

8.4 自定义影像源

8.4.1 UrlTemplateImageryProvider

// 使用 URL 模板
const urlTemplateImagery = new Cesium.UrlTemplateImageryProvider({
    url: 'https://your-server/{z}/{x}/{y}.png',
    
    // 或使用函数
    // url: function(x, y, level) {
    //     return `https://your-server/${level}/${x}/${y}.png`;
    // },
    
    minimumLevel: 0,
    maximumLevel: 18,
    
    // 子域
    subdomains: ['a', 'b', 'c'],
    
    // 范围
    rectangle: Cesium.Rectangle.fromDegrees(-180, -90, 180, 90),
    
    // 瓦片大小
    tileWidth: 256,
    tileHeight: 256,
    
    // 是否有 Alpha 通道
    hasAlphaChannel: true,
    
    // 信用
    credit: 'Custom Tiles'
});

// 高德地图示例
const amapImagery = new Cesium.UrlTemplateImageryProvider({
    url: 'https://webst0{s}.is.autonavi.com/appmaptile?style=6&x={x}&y={y}&z={z}',
    subdomains: ['1', '2', '3', '4'],
    maximumLevel: 18
});

// 高德路网图层
const amapRoad = new Cesium.UrlTemplateImageryProvider({
    url: 'https://webst0{s}.is.autonavi.com/appmaptile?style=8&x={x}&y={y}&z={z}',
    subdomains: ['1', '2', '3', '4'],
    maximumLevel: 18
});

// 腾讯地图示例
function getTencentUrl(x, y, level) {
    const y_t = Math.pow(2, level) - 1 - y;
    const m = Math.floor(x / 16);
    const n = Math.floor(y_t / 16);
    return `https://p2.map.gtimg.com/sateTiles/${level}/${m}/${n}/${x}_${y_t}.jpg`;
}

const tencentImagery = new Cesium.UrlTemplateImageryProvider({
    url: getTencentUrl,
    minimumLevel: 0,
    maximumLevel: 18
});

8.4.2 SingleTileImageryProvider

// 单张图片
const singleTileImagery = new Cesium.SingleTileImageryProvider({
    url: 'https://example.com/map.png',
    rectangle: Cesium.Rectangle.fromDegrees(116, 39, 117, 40)
});
viewer.imageryLayers.addImageryProvider(singleTileImagery);

// 带透明通道的图片
const overlayImage = new Cesium.SingleTileImageryProvider({
    url: 'overlay.png',
    rectangle: Cesium.Rectangle.fromDegrees(115.5, 38.5, 116.5, 39.5)
});
const overlayLayer = viewer.imageryLayers.addImageryProvider(overlayImage);
overlayLayer.alpha = 0.7;

8.4.3 自定义 ImageryProvider

// 自定义影像提供者
class CustomImageryProvider {
    constructor(options) {
        this._tilingScheme = new Cesium.GeographicTilingScheme();
        this._tileWidth = 256;
        this._tileHeight = 256;
        this._minimumLevel = options.minimumLevel || 0;
        this._maximumLevel = options.maximumLevel || 18;
        this._rectangle = Cesium.Rectangle.MAX_VALUE;
        this._credit = new Cesium.Credit(options.credit || 'Custom Provider');
        this._hasAlphaChannel = true;
        this._ready = true;
        
        this._baseUrl = options.url;
    }
    
    get tilingScheme() { return this._tilingScheme; }
    get tileWidth() { return this._tileWidth; }
    get tileHeight() { return this._tileHeight; }
    get minimumLevel() { return this._minimumLevel; }
    get maximumLevel() { return this._maximumLevel; }
    get rectangle() { return this._rectangle; }
    get credit() { return this._credit; }
    get hasAlphaChannel() { return this._hasAlphaChannel; }
    get ready() { return this._ready; }
    
    getTileCredits(x, y, level) {
        return undefined;
    }
    
    requestImage(x, y, level, request) {
        const url = `${this._baseUrl}/${level}/${x}/${y}.png`;
        return Cesium.ImageryProvider.loadImage(this, url);
    }
    
    pickFeatures(x, y, level, longitude, latitude) {
        return undefined;
    }
}

// 使用自定义提供者
const customProvider = new CustomImageryProvider({
    url: 'https://your-server/tiles',
    minimumLevel: 0,
    maximumLevel: 18,
    credit: 'My Custom Tiles'
});
viewer.imageryLayers.addImageryProvider(customProvider);

8.5 图层管理

8.5.1 ImageryLayerCollection 操作

const imageryLayers = viewer.imageryLayers;

// ===== 添加图层 =====
const layer = imageryLayers.addImageryProvider(provider);
const layerAtIndex = imageryLayers.addImageryProvider(provider, 0);

// ===== 移除图层 =====
imageryLayers.remove(layer);
imageryLayers.remove(layer, true);  // 移除并销毁
imageryLayers.removeAll();
imageryLayers.removeAll(true);      // 移除并销毁所有

// ===== 获取图层 =====
const length = imageryLayers.length;
const layerAt = imageryLayers.get(0);
const indexOf = imageryLayers.indexOf(layer);
const contains = imageryLayers.contains(layer);

// ===== 调整顺序 =====
imageryLayers.raise(layer);          // 上移一层
imageryLayers.lower(layer);          // 下移一层
imageryLayers.raiseToTop(layer);     // 移到顶层
imageryLayers.lowerToBottom(layer);  // 移到底层

// ===== 事件监听 =====
imageryLayers.layerAdded.addEventListener(function(layer, index) {
    console.log('图层添加:', index);
});

imageryLayers.layerRemoved.addEventListener(function(layer, index) {
    console.log('图层移除:', index);
});

imageryLayers.layerMoved.addEventListener(function(layer, newIndex, oldIndex) {
    console.log('图层移动:', oldIndex, '->', newIndex);
});

imageryLayers.layerShownOrHidden.addEventListener(function(layer, index, show) {
    console.log('图层显示/隐藏:', index, show);
});

8.5.2 ImageryLayer 属性

const layer = viewer.imageryLayers.addImageryProvider(provider);

// ===== 显示控制 =====
layer.show = true;                  // 显示/隐藏

// ===== 透明度 =====
layer.alpha = 1.0;                  // 透明度 (0-1)

// ===== 颜色调整 =====
layer.brightness = 1.0;             // 亮度 (0-2, 默认1)
layer.contrast = 1.0;               // 对比度 (0-2, 默认1)
layer.hue = 0.0;                    // 色调 (-1 到 1, 默认0)
layer.saturation = 1.0;             // 饱和度 (0-2, 默认1)
layer.gamma = 1.0;                  // 伽马 (0.1-4, 默认1)

// ===== 滤镜 =====
layer.minificationFilter = Cesium.TextureMinificationFilter.LINEAR;
layer.magnificationFilter = Cesium.TextureMagnificationFilter.LINEAR;

// ===== 分割线显示 =====
layer.splitDirection = Cesium.SplitDirection.NONE;
// Cesium.SplitDirection.LEFT   // 左侧显示
// Cesium.SplitDirection.RIGHT  // 右侧显示

// ===== 夜间图层 =====
layer.nightAlpha = 1.0;             // 夜间透明度
layer.dayAlpha = 1.0;               // 白天透明度

// ===== 裁剪 =====
layer.cutoutRectangle = Cesium.Rectangle.fromDegrees(116, 39, 117, 40);

// ===== 颜色转换 =====
layer.colorToAlpha = new Cesium.Color(0, 0, 0, 1);  // 将指定颜色转为透明
layer.colorToAlphaThreshold = 0.004;

8.5.3 图层管理器

// 影像图层管理器
class ImageryLayerManager {
    constructor(viewer) {
        this.viewer = viewer;
        this.layers = new Map();
    }
    
    // 添加图层
    async addLayer(name, provider, options = {}) {
        const layer = this.viewer.imageryLayers.addImageryProvider(provider, options.index);
        
        if (options.alpha !== undefined) layer.alpha = options.alpha;
        if (options.brightness !== undefined) layer.brightness = options.brightness;
        if (options.contrast !== undefined) layer.contrast = options.contrast;
        if (options.show !== undefined) layer.show = options.show;
        
        this.layers.set(name, { layer, provider, options });
        return layer;
    }
    
    // 获取图层
    getLayer(name) {
        const info = this.layers.get(name);
        return info ? info.layer : null;
    }
    
    // 设置可见性
    setVisible(name, visible) {
        const layer = this.getLayer(name);
        if (layer) layer.show = visible;
    }
    
    // 设置透明度
    setAlpha(name, alpha) {
        const layer = this.getLayer(name);
        if (layer) layer.alpha = alpha;
    }
    
    // 移除图层
    removeLayer(name) {
        const info = this.layers.get(name);
        if (info) {
            this.viewer.imageryLayers.remove(info.layer, true);
            this.layers.delete(name);
            return true;
        }
        return false;
    }
    
    // 切换底图
    switchBaseLayer(name) {
        // 隐藏所有底图
        this.layers.forEach((info, layerName) => {
            if (info.options.isBaseLayer) {
                info.layer.show = (layerName === name);
            }
        });
    }
    
    // 获取所有图层名称
    getLayerNames() {
        return Array.from(this.layers.keys());
    }
    
    // 清除所有图层
    clear() {
        this.layers.forEach(info => {
            this.viewer.imageryLayers.remove(info.layer, true);
        });
        this.layers.clear();
    }
}

// 使用示例
const layerManager = new ImageryLayerManager(viewer);

// 添加底图
await layerManager.addLayer('osm', new Cesium.OpenStreetMapImageryProvider({
    url: 'https://tile.openstreetmap.org/'
}), { isBaseLayer: true });

await layerManager.addLayer('satellite', await Cesium.createWorldImageryAsync(), 
    { isBaseLayer: true, show: false });

// 添加叠加图层
await layerManager.addLayer('overlay', overlayProvider, 
    { alpha: 0.7, isBaseLayer: false });

// 切换底图
layerManager.switchBaseLayer('satellite');

8.6 要素拾取

8.6.1 WMS GetFeatureInfo

// 启用 WMS 要素拾取
const wmsWithPick = new Cesium.WebMapServiceImageryProvider({
    url: 'https://your-wms-server/wms',
    layers: 'layer_name',
    parameters: {
        format: 'image/png',
        transparent: true
    },
    enablePickFeatures: true,
    getFeatureInfoFormats: [
        new Cesium.GetFeatureInfoFormat('json', 'application/json'),
        new Cesium.GetFeatureInfoFormat('xml', 'text/xml')
    ]
});

// 监听点击事件并获取要素信息
const handler = new Cesium.ScreenSpaceEventHandler(viewer.canvas);
handler.setInputAction(async function(click) {
    const pickedPosition = viewer.scene.pickPosition(click.position);
    
    if (Cesium.defined(pickedPosition)) {
        const cartographic = Cesium.Cartographic.fromCartesian(pickedPosition);
        const longitude = Cesium.Math.toDegrees(cartographic.longitude);
        const latitude = Cesium.Math.toDegrees(cartographic.latitude);
        
        // 获取可见图层
        const imageryLayers = viewer.imageryLayers;
        for (let i = 0; i < imageryLayers.length; i++) {
            const layer = imageryLayers.get(i);
            if (layer.show && layer.imageryProvider.enablePickFeatures) {
                const features = await layer.imageryProvider.pickFeatures(
                    click.position.x, 
                    click.position.y,
                    viewer.scene.globe.ellipsoid,
                    cartographic
                );
                
                if (features && features.length > 0) {
                    console.log('拾取的要素:', features);
                    // 显示要素信息
                    displayFeatureInfo(features);
                }
            }
        }
    }
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);

function displayFeatureInfo(features) {
    features.forEach(feature => {
        console.log('要素名称:', feature.name);
        console.log('要素描述:', feature.description);
        console.log('要素属性:', feature.properties);
    });
}

8.7 本章小结

本章详细介绍了影像图层与地图服务:

  1. 影像架构:ImageryLayer、ImageryProvider 结构
  2. 内置提供者:Cesium Ion、OSM、Bing、ArcGIS
  3. OGC 服务:WMS、WMTS、TMS 配置
  4. 自定义影像:URL 模板、单张图片、自定义 Provider
  5. 图层管理:添加、移除、排序、属性调整
  6. 要素拾取:GetFeatureInfo 功能

在下一章中,我们将详细介绍地形数据处理。

8.8 思考与练习

  1. 实现一个底图切换控件,支持多种地图源。
  2. 添加天地图影像和注记图层。
  3. 实现图层透明度和亮度的动态调整。
  4. 开发 WMS 要素查询功能。
  5. 创建自定义影像提供者,加载本地瓦片。
posted @ 2026-01-08 11:13  我才是银古  阅读(20)  评论(0)    收藏  举报