03-Cesium轨迹线封装类

这段代码定义了一个名为 Trajectory 的类,用于在 Cesium 中管理和展示轨迹。以下是对代码的详细解析,包括各个方法的功能和作用:

代码解析

  1. 构造函数

    • constructor(options, map):接收配置选项和 Cesium 地图对象 map,并初始化各种属性。
    • 属性包括轨迹坐标、图标地址、缩放倍数、速度、颜色、图层 ID 等。
    • 解析轨迹坐标、创建图层和元素。
  2. 轨迹坐标转换

    • parsePath():将轨迹的 WKT 格式坐标转换为 Cesium 可用的笛卡尔坐标。
    • 使用正则表达式处理字符串,去掉多余的括号并转换为数组。
  3. 初始化图层

    • createLayer():检查是否已存在指定 ID 的图层,若不存在则创建一个新的 Cesium.CustomDataSource
  4. 获取地形高程

    • getTerrainHeight(position):通过给定的 Cartesian3 坐标获取相应的地形高程,返回调整后的坐标。
  5. 获取当前点索引

    • getCurrentIndex(time):根据当前时间获取轨迹坐标中对应的索引。
  6. 创建元素

    • createFeature():创建未完成和已完成的轨迹实体。
    • 使用 Cesium.CallbackProperty 动态更新位置和线条的颜色,形成动画效果。
  7. 计算飞行路径

    • createProperty():创建 SampledPositionProperty 对象,计算每个轨迹点的时间,并将其添加到属性中。
  8. 设置速度

    • setSpeed(speed):根据传入的速度更新播放速率。
  9. 播放与暂停

    • play():设置播放状态为 true
    • paus():设置播放状态为 false
  10. 移除元素

    • remove():从图层中移除未完成和已完成的轨迹实体。

总结

  • Trajectory 类封装了轨迹的加载、展示和管理逻辑。它通过 Cesium 提供的 API,允许开发者创建动态的轨迹动画。
  • 类中使用 Cesium.CallbackProperty 来动态更新位置,形成实时动画效果。
  • 通过设定速度、播放、暂停等方法,用户可以灵活控制轨迹的展示。

这段代码展示了如何利用 Cesium 的强大功能来实现复杂的地理空间可视化。

/**
 * 轨迹
 */
class Trajectory{
    /**
     * 轨迹
     * @param {Object} options 
     * @param {String} options.layerId 图层ID
     * @param {String} options.path  轨迹坐标
     * @param {String} options.url   图标地址
     * @param {Number} options.scale 图标缩放倍数,默认1
     * @param {Number} options.speed 图标运动速度,单位m/s 默认10
     * @param {String} options.completedColor 已完成的轨迹颜色,默认值:ffff00
     * @param {String} options.incompleteColor 未完成的轨迹颜色 默认值:00ff00
     * @param {Number} options.lineWidth 轨迹线的颜色
     * @param {map} map 
     * @example
     */
    constructor(options,map){
        this.path = options.path;
        this.url = options.url;
        this.scale = options.scale||1;
        this.speed = options.speed||10;
        this.completedColor = options.completedColor||'#ffff00';
        this.incompleteColor = options.incompleteColor||'#00ff00';
        this.layerId = options.layerId||'trajectoryLayer';
        this.dataType = options.dataType||'wkt';
        this.lineWidth = options.lineWidth||3;
        this.layer = null;
        this.timeConsumed = 0;
        this.currentIndex = 0;
        // 循环
        this.loop = options.loop||false;
        this.rate = 1;
        this.isPlay = true;
        this.map = map;
        // wkt坐标转成笛卡尔坐标
        this.parsePath()
        this.createProperty()
        // 创建图层
        this.createLayer()
        // 创建元素
        this.createFeature();
    }
    /**
     * 轨迹坐标转换
     */
    parsePath(){
        console.log('this.dataType',this.dataType);
        let coords = this.map.typeDataChange({
            type: this.dataType,
            wkt: this.path,
        })
        // 去掉所有的[]括号,并在最外面添加一个[]
        // 使用正则表达式替换所有出现的特定字符 "g" 标志表示全局搜索   
        var newStr = "[" + String(coords).replace(new RegExp("[" + "|" + "]", "g"), "") + "]"
        let newCoords = JSON.parse(newStr)
        this.points = Cesium.Cartesian3.fromDegreesArray(newCoords);
    }
    /**
     * 初始化图层
     */
    createLayer(){
        // 没有图层则创建
        let layers = this.map.viewer.dataSources.getByName(this.layerId)
        if (layers.length == 0) {
            // 未初始化过图层
            const dataSource = new Cesium.CustomDataSource(this.layerId);
            this.map.viewer.dataSources.add(dataSource);
            this.layer = dataSource;
        }else{
            this.layer = layers[0]
        }
    }
    /**
     * 获取地形高程
     * @param {*} position 
     * @returns 
     */
    getTerrainHeight(position){
        let cartographic = Cesium.Cartographic.fromCartesian(position);
        let height = this.map.viewer.scene.globe.getHeight(cartographic);
        if(height){
            let lon = cartographic.longitude;
            let lat = cartographic.latitude;
            return Cesium.Cartesian3.fromRadians(lon,lat,height)
        }else{
            return position
        }
    }
    /**
     * 获取当前点在的轨迹坐标中索引
     * @param {*} time 
     * @returns 
     */
    getCurrentIndex(time){

        let times = this.property._property._times;
        for(let i = this.currentIndex,j = times.length;i<j;i++){
            let t = Cesium.JulianDate.compare(time,times[i]);
            if(t<0){
                return i;
            }
        };
        return 0;

    }
    /**
     * 创建元素
     */
    createFeature(){
        let incompletePoints = this.points.slice(this.currentIndex);
        let completedPoints = [];
        
        let nowT = new Date()
        // 未完成的轨迹
        let entity = new Cesium.Entity({
            position:new Cesium.CallbackProperty(()=>{
                // 更新坐标
                let t = new Date();
                if(this.isPlay){
                    this.timeConsumed = this.timeConsumed+(t-nowT)*this.rate;
                }
                nowT = t;
                t = Cesium.JulianDate.addSeconds(this.startTime, this.timeConsumed/1000, new Cesium.JulianDate);
                let position = this.property.getValue(t,new Cesium.Cartesian3());
                let count = this.getCurrentIndex(t);
                if(this.currentIndex != count){
                    this.currentIndex = count;
                }
                if(position){
                    incompletePoints = [position].concat(this.points.slice(this.currentIndex));
                    completedPoints = this.points.slice(0,this.currentIndex).concat(position)
                    return this.getTerrainHeight(position)
                }else{
                    if(this.loop){
                        this.timeConsumed = 0;
                        t = Cesium.JulianDate.addSeconds(this.startTime, this.timeConsumed/1000, new Cesium.JulianDate);
                        let position = this.property.getValue(t,new Cesium.Cartesian3());
                        if(position){
                            incompletePoints = [position].concat(this.points.slice(this.currentIndex));
                            completedPoints = this.points.slice(0,this.currentIndex).concat(position)
                            return this.getTerrainHeight(position)
                        }else{
                            this.currentIndex = 0;
                            incompletePoints = this.points.slice(this.currentIndex);
                            completedPoints = []
                            return this.getTerrainHeight(this.points[0])
                        }
                    }else{
                        this.currentIndex = this.points.length-1;
                        incompletePoints = [];
                        completedPoints = this.points.slice(0)
                        return this.getTerrainHeight(this.points.at(-1))
                    }
                }
            },false),
            billboard:{
                image:this.url,
                scale:this.scale,
                horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
                verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
                disableDepthTestDistance: Number.POSITIVE_INFINITY,
            },
            polyline: {
                positions: new Cesium.CallbackProperty(function () { 
                  return incompletePoints;
                }, false),
                // positions:this.points,
                width: this.lineWidth,
                material:Cesium.Color.fromCssColorString(this.incompleteColor),
                clampToGround: true
            }
        })
        this.incompleteEntity = entity;
        this.layer.entities.add(this.incompleteEntity);
        // 已完成的轨迹
        let entity2 = new Cesium.Entity({
            polyline: {
                positions: new Cesium.CallbackProperty(function () { 
                  return completedPoints;
                }, false),
                width: this.lineWidth,
                material:Cesium.Color.fromCssColorString(this.completedColor),
                clampToGround: true
            }
        })
        this.completedEntity = entity2;
        this.layer.entities.add(this.completedEntity);
    }

    /**
     * 计算飞行路径
     * @param source 数据坐标
     * @returns {SampledPositionProperty|*}
     */
    createProperty() {
        let start = Cesium.JulianDate.fromDate(new Date());
        let property = new Cesium.SampledPositionProperty();
        property.addSample(start, this.points[0]);
        let time = 0;
        for(let i=1,j=this.points.length;i<j;i++){
            let position = this.points[i];
            let dis = Cesium.Cartesian3.distance(this.points[i-1],position);
            let t = dis/this.speed;
            time+=t;
            t = Cesium.JulianDate.addSeconds(start, time, new Cesium.JulianDate);
            property.addSample(t, position);
        };

        this.property = property;
        this.startTime = start;
    }
    /**
     * 设置速度
     * @param {Number} speed 
     */
    setSpeed(speed){
        if(speed){
            this.rate = speed/this.speed;
        }
    }
    /**
     * 播放
     */
    play(){
        this.isPlay= true;
    }   
    /**
     * 暂停
     */
    paus(){
        this.isPlay=false
    }
    /**
     * 移除元素
     */
    remove(){
        if(this.layer){
            this.incompleteEntity&&this.layer.entities.remove(this.incompleteEntity);
            this.completedEntity&&this.layer.entities.remove(this.completedEntity);
        }
    }
}

export default Trajectory;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值