cesium模拟3dTiles构建过程

93 阅读3分钟

1、加载3dTiles

let timeData;
let tileset;
//初始视角定义
const longitude = 116.46;
const latitude = 39.92;
const height = 0;
const rotation = 0; 

//加载3dTiles模型
const add3dTiles = () => {
    //生成模型进度模拟数据
    timeData = createJson();
    
    //时间轴初始化
    setClock3dTiles();
    
    //设置模型的矩阵位置--模型带地理位置时无需设置
    let modelMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(Cesium.Cartesian3.fromDegrees(longitude, latitude, height));
    Cesium.Matrix4.multiplyByMatrix3(modelMatrix, Cesium.Matrix3.fromRotationZ(Cesium.Math.toRadians(rotation)), modelMatrix);

    tileset = viewer.scene.primitives.add(new Cesium.Cesium3DTileset({
        url: "/public/model/tileset.json", //需要替换成自己模型的链接
        modelMatrix: modelMatrix     //模型的矩阵位置,内部无坐标位置的模型(人工模型)使用
    }));
    //模型着色--根据指定属性着色--DbId属性值需要根据自己模型替换--实现效果如下图片所示
    // tileset.style = new Cesium.Cesium3DTileStyle({
    //     color:{
    //         conditions:[
    //             ['${DbId} < 2000', 'color("#ff0000")'],
    //             ['${DbId} >= 2000 && ${DbId} < 5000', 'rgb(198, 106, 11)'],
    //             ['${DbId} >= 5000', 'color("#00ff00")'],
    //             ['true', 'color("#00f")'],
    //         ]
    //     }
    // })

    viewer.zoomTo(tileset, new Cesium.HeadingPitchRange(0, -0.5, 0));

    //鼠标左键点击事件--获取模型属性信息
    // let handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
    // handler.setInputAction((movement) =>{
    //     let feature = viewer.scene.pick(movement.position);
    //     if (feature instanceof Cesium.Cesium3DTileFeature) {
    //         let propertyNames = feature.getPropertyNames(); //获取Cesium3DTileFeature属性
    //         //遍历获取所有属性名以及其对应的值
    //         let length = propertyNames.length;
    //         for (let i = 0; i < length; ++i) {
    //             let propertyName = propertyNames[i];
    //             console.log(propertyName + ': ' + feature.getProperty(propertyName));
    //         }
    //     }
    // }, Cesium.ScreenSpaceEventType.LEFT_CLICK);
}

2、自定义3dTiles构建数据

interface timeData{
    "id": number,
    "startTime": number,
    "endTime": number,
}
const startTime= 1700186430; //2023-11-17 10:00:30
const endTime= 1700190030; //2023-11-17 11:00:30
//自定义模型结构进度数据--json生成方法
//起止时间:"startTime": 1700186430, ,"endTime": 1700190030,2023-11-17 11:00 30 
//起止id: 1-9312,模型数据对应id
const createJson = () => {
    const max = 9312; //模型对应最大id
    const diffTime = 3600;
    let data:Array<timeData> = [];
    for(let i=1; i<=max;i++){
        const time1 = startTime + getRandomInt(diffTime, 1); 
        const time2 = startTime + getRandomInt(diffTime, 1);
        let start,end;
        if(time1 < time2){
            start = time1;
            end = time2;
        }else if(time1 == time2){
            start = time1;
            end = time1 + 5;
        }else{
            start = time2;
            end = time1;
        }
        data.push({
            "id": i, 
            "startTime": start, 
            "endTime": end
        })
    }
    return data;
} 

//生成随机数
const getRandomInt = (min:number, max:number) => {
    return Math.floor(Math.random() * (max - min)) + min;
}

3、监听时间轴模拟3dTiles构建构成

let vm;
const startDate = '2023-11-17 09:55:00';
const endDate = '2023-11-17 11:03:00';
let proTimeStamp:number = 0;
// 时间轴初始化
const setClock3dTiles = () => {
    proTimeStamp = timeToTimestamp(startDate);
    let start = Cesium.JulianDate.fromDate(new Date(startDate));//开始时间
    start = Cesium.JulianDate.addHours(start, 0, new Cesium.JulianDate());
    viewer.clock.currentTime = start.clone();
    viewer.clock.canAnimate = true;
    viewer.clock.shouldAnimate = true;
    viewer.clock.multiplier = 120;
    viewer.clock.clockRange = Cesium.ClockRange.LOOP_STOP;
    let stop = Cesium.JulianDate.fromDate(new Date(endDate));//结束时间
    viewer.clock.startTime = start.clone();
    viewer.clock.stopTime = stop.clone();
    viewer.timeline.zoomTo(start, stop);
    //时间轴监听
    getClock3dTiles();
}
//时间轴监听
const clockRelay = (clock:any) =>{
    let start = Cesium.JulianDate.addHours(clock.currentTime, 8, new Cesium.JulianDate());
    let t = Cesium.JulianDate.toGregorianDate(start)
    let currentTime = t.year + "/" + t.month + "/" + t.day + " " + twoDigits(t.hour) + ":" + twoDigits(t.minute) + ":" + twoDigits(t.second);
    let curTimeStamp = (timeToTimestamp(currentTime)) / 1000;
    if (proTimeStamp == curTimeStamp) {
        return;
    } else{
        proTimeStamp = curTimeStamp;
        if(curTimeStamp >= startTime && curTimeStamp <= endTime){
            //进行中
            vm.curIndex = 1;
            vm.diff = curTimeStamp;
        }else if(curTimeStamp < startTime){
            //未开始
            vm.curIndex = 0;
        }else{
            //已完成
            vm.curIndex = 2;
        }
    }
}
const getClock3dTiles = () => {
    viewer.clock.onTick.addEventListener(clockRelay);
};
//日期转时间戳--13位
const timeToTimestamp = (day:string) =>{
    let date = new Date(day);
    let time = date.getTime(); 
    return time; 
};
//如果是一位数,在十位数上补0--时间显示
const twoDigits = (s:number) =>{
    if (s < 10)
        return "0" + s;
    else
        return s;
}

4、模型动态着色

//根据状态设置模型样式
//stage--模型构建状态,time--时间轴上对应当前时间戳
const showStatusByStyle = (stage:number,time:number)=>{
    let conditions:any = [];
    if(stage === 0){
        //尚未开始构建模型
        conditions = [
            ["true", "color('#f2f2f2')"]
        ]
    }else if(stage === 2){
        //模型构建完成
        conditions = [
            ["true", "color('#00ff00')"]
        ]
    }else{
        //模型构建中
        timeData.forEach((item:timeData) => {
            let temp:Array<string> = [];
            if(time < item.startTime){
                //未开始
                temp = ["(${DbId} === "+ item.id + ") ", "color('#ff0000')"]
            }else if(time > item.endTime){
                //已完成
                temp = ["(${DbId} === "+ item.id + ") ", "color('#00ff00')"]
            }else{
                //进行中
                temp = ["(${DbId} === "+ item.id + ") ", "color('#ffff00')"]
            }
            conditions.push(temp);

        })
    }
    //给已加载的3dTiles着色
    tileset.style = new Cesium.Cesium3DTileStyle({
        color: {
            conditions: conditions
        }
    })
}

//数据监听--watcher为自定义数据监听类,类似vue wacth,网上实现很多,这里不进行具体阐述
const customWatcher = () => {
    vm = new watcher({
        data:{
            curIndex: -1,
            diff: 0
        },
        watch:{
            curIndex(newVal:number,oldVal:number){
                //设置模型样式
                showStatusByStyle(newVal,0);
            },
            diff(newVal:number,oldVal:number){
                //设置模型样式
                showStatusByStyle(1, newVal);
            }
        }
    })
}

4、实现效果

1)模型静态着色 image.png

2)模型动态构建过程

www.ixigua.com/73171761576…

项目地址:github.com/DLFouge/vue…

欢迎指正与star