cesium 直接加载 tif格式文件

1.先安装依赖读取tif文件插件

yarn add geotiff

npm install geotiff

import GeoTIFF, { fromBlob, fromUrl, fromArrayBuffer } from 'geotiff';

import GeoTIFFImage from 'geotiff/dist-node/geotiffimage';

2.安装proj4坐标转换

yarn add proj4

npm install proj4

import proj4 from 'proj4'

proj4js 坐标转换,git代码库地址:https://github.com/proj4js/proj4js 

另一个坐标系在线查询和坐标转换地址:EPSG.io: Coordinate Systems Worldwide

在PostGIS中有一个表 spatial_ref_sys ,可以查询所有的坐标系信息。

在Geoserver中也有所有坐标系的信息。在ArcGIS中也有。

以下介绍在node中使用proj4,以及在Cesium三维开发中使用。

读取储存在minio中的tif文件

/**

 * 在Cesium中加载和处理GeoTIFF图像

 * @param url - GeoTIFF文件的URL

 * @returns Promise<void>

 */

async function geotiffinit(url: string): Promise<void> {

    try {

        console.log('Starting GeoTIFF processing for URL:', url);

        // 1. 加载和解析GeoTIFF

        const tiff = await fromUrl(url);

        console.log('GeoTIFF loaded successfully');

        const image = await tiff.getImage();

        console.log('GeoTIFF image extracted');

       

        // 2. 获取图像基本信息

        const width = image.getWidth();

        const height = image.getHeight();

        const [west, south, east, north] = image.getBoundingBox();

        console.log('Image dimensions:', width, 'x', height);

        console.log('Bounding box:', { west, south, east, north });

       

        // 3. 处理投影信息

        const projectionInfo = await getProjectionInfo(image);

        console.log('Projection info:', projectionInfo);

        const {convertedSW, convertedNE} = await convertCoordinates(west, south, east, north, projectionInfo);

        console.log('Converted coordinates:', { convertedSW, convertedNE });

       

        // 4. 读取和处理图像数据

        const imageData = await processImageData(image, width, height);

        console.log('Image data processed');

       

        // 5. 在Cesium中加载图像

        await loadImageToCesium(imageData, convertedSW, convertedNE);

       

        console.log('GeoTIFF successfully loaded and processed');

    } catch (error) {

        console.error('Error in geotiffinit:', error);

        if (error instanceof Error) {

            throw new Error(`Failed to load GeoTIFF: ${error.message}`);

        } else {

            throw new Error(`Failed to load GeoTIFF: Unknown error`);

        }

    }

}

/**

 * 获取和设置投影信息

 * @param image - GeoTIFF图像对象

 */

async function getProjectionInfo(image: GeoTIFFImage) {

    // 检查并获取投影代码

    let epsgCode = '';

    try {

        // 尝试获取投影代码

        const projectedCSType = image.geoKeys?.ProjectedCSTypeGeoKey;

        const geographicType = image.geoKeys?.GeographicTypeGeoKey;

       

        // 如果投影代码是数字,转换为EPSG格式

        if (typeof projectedCSType === 'number') {

            epsgCode = `EPSG:${projectedCSType}`;

        } else if (typeof geographicType === 'number') {

            epsgCode = `EPSG:${geographicType}`;

        } else if (projectedCSType) {

            epsgCode = String(projectedCSType);

        } else if (geographicType) {

            epsgCode = String(geographicType);

        } else {

            epsgCode = 'EPSG:4326'; // 默认使用WGS84

        }

       

        console.log(`Detected projection code: ${epsgCode}`);

    } catch (error) {

        console.warn('Failed to get projection code:', error);

        epsgCode = 'EPSG:4326'; // 出错时默认使用WGS84

    }

   

    // 注册常用UTM投影

    // 注册UTM投影区域 (1-60)

    for (let zone = 1; zone <= 60; zone++) {

        const utmCode = `EPSG:${32600 + zone}`;

        if (!proj4.defs(utmCode)) {

            proj4.defs(utmCode, `+proj=utm +zone=${zone} +datum=WGS84 +units=m +no_defs`);

        }

    }

   

    // 确保WGS84投影已注册

    if (!proj4.defs('EPSG:4326')) {

        proj4.defs('EPSG:4326', '+proj=longlat +datum=WGS84 +no_defs');

    }

    return epsgCode;

}

/**

 * 转换坐标

 * @param west - 西边界

 * @param south - 南边界

 * @param east - 东边界

 * @param north - 北边界

 * @param sourceProjection - 源投影

 */

async function convertCoordinates(

    west: number,

    south: number,

    east: number,

    north: number,

    sourceProjection: string

) {

    const convertedSW = proj4(sourceProjection, 'EPSG:4326', [west, south]);

    const convertedNE = proj4(sourceProjection, 'EPSG:4326', [east, north]);

   

    return { convertedSW, convertedNE };

}

/**

 * 处理图像数据

 * @param image - GeoTIFF图像对象

 * @param width - 图像宽度

 * @param height - 图像高度

 */

async function processImageData(image: GeoTIFFImage, width: number, height: number) {

    // 读取光谱数据

    const [red = [], green = [], blue = []] = await image.readRasters();

   

    // 创建canvas并处理图像数据

    const canvas = document.createElement('canvas');

    canvas.width = width;

    canvas.height = height;

   

    const ctx = canvas.getContext('2d');

    if (!ctx) throw new Error('Failed to get canvas context');

   

    const imageData = ctx.createImageData(width, height);

   

    // 优化: 使用TypedArray提高性能

    const data = new Uint8ClampedArray(width * height * 4);

    for (let i = 0; i < width * height; i++) {

        const offset = i * 4;

        data[offset] = red[i];

        data[offset + 1] = green[i] || 0;

        data[offset + 2] = blue[i] || 0;

        data[offset + 3] = red[i] === 0 ? 0 : 255;

    }

   

    imageData.data.set(data);

    ctx.putImageData(imageData, 0, 0);

    console.log(canvas.toDataURL())

   

    return canvas.toDataURL();

}

/**

 * 将处理后的图像加载到Cesium

 * @param imageUrl - 图像数据URL

 * @param convertedSW - 转换后的西南角坐标

 * @param convertedNE - 转换后的东北角坐标

 */

async function loadImageToCesium(imageUrl: string, convertedSW: number[], convertedNE: number[]) {

    // 创建Cesium矩形

    const rectangle = new Cesium.Rectangle.fromDegrees(

        convertedSW[0], // west

        convertedSW[1], // south

        convertedNE[0], // east

        convertedNE[1]  // north

    );

    // 添加图像到Cesium

    const layer = root.$aMap.viewer.imageryLayers.addImageryProvider(

        new Cesium.SingleTileImageryProvider({

            url: imageUrl,

            rectangle

        })

    );

    // 调整视角

    await root.$aMap.viewer.camera.flyTo({

        destination: rectangle,

        duration: 1.5

    });

}

通过坐标转换获取位置很准确,加载效果也还可以,但是文件大的话加载会很慢或者程序计算崩溃,适合加载一些比较小文件.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值