百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 热门文章 > 正文

在Cesium中加载OD线

bigegpt 2025-01-17 11:02 4 浏览

前言

在地理信息系统(GIS)和3D地图应用中,"OD线"(Origin-Destination Line)是一种重要的视觉工具,用于表示两点之间的各种关系,例如航班线路、人口迁徙、交通流量和经济往来。

随着大数据和可视化技术的发展,OD线的应用越来越广泛,对可视化手段也提出了新的要求,包括二维和三维、静态和动态、以及不同数据量的处理。

实现

1. 北京公交动态OD线

为了实现动态OD线的渲染,我们需要自定义MaterialProperty,因为Cesium提供的内置MaterialProperty类型无法满足需求。

以下是北京公交动态OD线的自定义MaterialProperty实现:

// 导入线材质图片
import lineImage from './images/shortFlowColor.png';

/**
 * SpriteLineMaterialProperty构造函数
 * @param {Object} options - 构造对象
 */
export default class SpriteLineMaterialProperty {
    constructor(options) {
        options = Cesium.defaultValue(options, Cesium.defaultValue.EMPTY_OBJECT);

        // 定义变化事件
        this._definitionChanged = new Cesium.Event();
        // 初始化颜色属性
        this._color = undefined;
        // 颜色属性订阅
        this._colorSubscription = undefined;
        // 设置颜色
        this.color = options.color;
        // 设置持续时间,默认1000毫秒
        this.duration = Cesium.defaultValue(options.duration, 1000);
        // 设置当前时间
        this._time = (new Date()).getTime();
    }
}

// 定义属性
Object.defineProperties(SpriteLineMaterialProperty.prototype, {
    // 是否常量
    isConstant: {
        get: function () {
            return false;
        }
    },
    // 定义变化事件
    definitionChanged: {
        get: function () {
            return this._definitionChanged;
        }
    },
    // 颜色属性
    color: Cesium.createPropertyDescriptor('color')
});

/**
 * 获取材质类型
 * @param {Number} time - 时间
 * @returns {String} 材质类型
 */
SpriteLineMaterialProperty.prototype.getType = function (time) {
    return 'SpriteLine';
};

/**
 * 获取材质值
 * @param {Number} time - 时间
 * @param {Object} result - 结果对象
 * @returns {Object} 材质值
 */
SpriteLineMaterialProperty.prototype.getValue = function (time, result) {
    if (!Cesium.defined(result)) {
        result = {};
    }
    // 获取颜色值
    result.color = Cesium.Property.getValueOrClonedDefault(this._color, time, Cesium.Color.WHITE, result.color);
    // 设置线材质图片
    result.image = Cesium.Material.SpriteLineImage;
    // 计算时间比例
    result.time = (((new Date()).getTime() - this._time) % this.duration) / this.duration;
    return result;
};

/**
 * 判断是否相等
 * @param {SpriteLineMaterialProperty} other - 另一个对象
 * @returns {Boolean} 是否相等
 */
SpriteLineMaterialProperty.prototype.equals = function (other) {
    return this === other ||
        (other instanceof SpriteLineMaterialProperty && Cesium.Property.equals(this._color, other._color))
};

// 注册材质属性和材质类型
Cesium.SpriteLineMaterialProperty = SpriteLineMaterialProperty;
Cesium.Material.SpriteLineType = 'SpriteLine';
Cesium.Material.SpriteLineImage = lineImage;
Cesium.Material.SpriteLineSource = `czm_material czm_getMaterial(czm_materialInput materialInput)
{
    czm_material material = czm_getDefaultMaterial(materialInput);
    vec2 st = materialInput.st;
    vec4 colorImage = texture(image, vec2(fract(st.s - time), st.t));
    material.alpha = colorImage.a * color.a;
    material.diffuse = color.rgb * 1.5;
    return material;
}
`;
Cesium.Material._materialCache.addMaterial(Cesium.Material.SpriteLineType, {
    fabric: {
        type: Cesium.Material.SpriteLineType,
        uniforms: {
            color: new Cesium.Color(1.0, 0.0, 0.0, 0.5),
            image: Cesium.Material.SpriteLineImage,
            time: 0,
        },
        source: Cesium.Material.SpriteLineSource
    },
    translucent: function (material) {
        return true;
    }
});

2. 三维OD线

三维OD线用于在三维场景下展示OD数据,例如网络攻击、全球资本流动和全球航班轨迹等。以下是实现三维OD线的步骤:

根据起终点获取弧线

/**
 * 根据起终点获取弧线
 * @param {Object} startPoint - 起点坐标
 * @param {Object} endPoint - 终点坐标
 * @param {Number} ratio - 弧度比率,默认0.5
 * @returns {Array} 弧线坐标数组
 */
function getParabolaLine(startPoint, endPoint, ratio = 0.5) {
    // 方程 y=-(4h/L^2)*x^2+h h:顶点高度 L:横纵间距较大者
    const h = Cesium.Cartesian3.distance(
        Cesium.Cartesian3.fromDegrees(startPoint.lng, startPoint.lat),
        Cesium.Cartesian3.fromDegrees(endPoint.lng, endPoint.lat),
    ) * ratio;
    const L = Math.abs(startPoint.lng - endPoint.lng) > Math.abs(startPoint.lat - endPoint.lat)
        ? Math.abs(startPoint.lng - endPoint.lng)
        : Math.abs(startPoint.lat - endPoint.lat);

    const num = 99;
    const result = [];
    let dlt = L / num;
    if (Math.abs(startPoint.lng - endPoint.lng) > Math.abs(startPoint.lat - endPoint.lat)) {
        //以 lng 为基准
        const delLat = (endPoint.lat - startPoint.lat) / num;
        if (startPoint.lng - endPoint.lng > 0) dlt = -dlt;
        for (let i = 0; i < num; i++) {
            const tempH = h - (Math.pow(-0.5 * L + Math.abs(dlt) * i, 2) * 4 * h) / Math.pow(L, 2);
            const lng = startPoint.lng + dlt * i;
            const lat = startPoint.lat + delLat * i;
            result.push({ lng, lat, height: tempH });
        }
    } else {
        //以 lat 为基准
        let delLng = (endPoint.lng - startPoint.lng) / num;
        if (startPoint.lat - endPoint.lat > 0) dlt = -dlt;
        for (let i = 0; i < num; i++) {
            const tempH = h - (Math.pow(-0.5 * L + Math.abs(dlt) * i, 2) * 4 * h) / Math.pow(L, 2);
            const lng = startPoint.lng + delLng * i;
            const lat = startPoint.lat + dlt * i;
            result.push({ lng, lat, height: tempH });
        }
    }
    // 落地
    result.push({lng: endPoint.lng, lat: endPoint.lat, height: endPoint.height || 0});

    return result;
}

自定义三维OD线材质

/**
 * ODLineMaterialProperty构造函数
 * @param {Object} options - 构造对象
 */
export default class ODLineMaterialProperty {
    constructor(options) {
        options = Cesium.defaultValue(options, Cesium.defaultValue.EMPTY_OBJECT);

        this._definitionChanged = new Cesium.Event();
        this._color = undefined;
        this._speed = undefined;
        this._percent = undefined;
        this._gradient = undefined;
        this._gradientColor = undefined;
        this.color = options.color;
        this.speed = options.speed;
        this.percent = options.percent;
        this.gradient = options.gradient;
        this.gradientColor = options.gradientColor;
    }
}
Object.defineProperties(ODLineMaterialProperty.prototype, {
    // 是否常量
    isConstant: {
        get: function () {
            return false;
        }
    },
    // 定义变化事件
    definitionChanged: {
        get: function () {
            return this._definitionChanged;
        }
    },
    // 颜色属性
    color: Cesium.createPropertyDescriptor('color'),
    speed: Cesium.createPropertyDescriptor('speed'),
    percent: Cesium.createPropertyDescriptor('percent'),
    gradient: Cesium.createPropertyDescriptor('gradient'),
    gradientColor: Cesium.createPropertyDescriptor('gradientColor')
});

/**
 * 获取材质类型
 * @param {Number} time - 时间
 * @returns {String} 材质类型
 */
ODLineMaterialProperty.prototype.getType = function (time) {
    return 'ODLine';
};

/**
 * 获取材质值
 * @param {Number} time - 时间
 * @param {Object} result - 结果对象
 * @returns {Object} 材质值
 */
ODLineMaterialProperty.prototype.getValue = function (time, result) {
    if (!Cesium.defined(result)) {
        result = {};
    }
    result.color = Cesium.Property.getValueOrDefault(this._color, time, Cesium.Color.RED, result.color);
    result.speed = Cesium.Property.getValueOrDefault(this._speed, time, 5.0, result.speed);

总结

本文介绍了在 Cesium 中实现 OD 线(Origin-Destination Line)的两种方法:动态OD线和三维OD线。

通过自定义 MaterialProperty,我们能够创建出满足特定需求的OD线效果,这些效果不仅增强了数据的可视化表现力,也提升了用户体验。

– 欢迎点赞、关注、转发、收藏【我码玄黄】,各大平台同名。

相关推荐

10w qps缓存数据库——Redis(redis缓存调优)

一、Redis数据库介绍:Redis:非关系型缓存数据库nosql:非关系型数据库没有表,没有表与表之间的关系,更不存在外键存储数据的形式为key:values的形式c语言写的服务(监听端口),用来存...

Redis系列专题4--Redis配置参数详解

本文基于windowsX64,3.2.100版本讲解,不同版本默认配置参数不同在Redis中,Redis的根目录中有一个配置文件(redis.conf,windows下为redis.windows....

开源一夏 | 23 张图,4500 字从入门到精通解释 Redis

redis是目前出场率最高的NoSQL数据库,同时也是一个开源的数据结构存储系统,在缓存、数据库、消息处理等场景使用的非常多,本文瑞哥就带着大家用一篇文章入门这个强大的开源数据库——Redis。...

redis的简单与集群搭建(redis建立集群)

Redis是什么?是开源免费用c语言编写的单线程高性能的(key-value形式)内存数据库,基于内存运行并支持持久化的nosql数据库作用主要用来做缓存,单不仅仅是做缓存,比如:redis的计数器生...

推荐几个好用Redis图形化客户端工具

RedisPlushttps://gitee.com/MaxBill/RedisPlusRedisPlus是为Redis可视化管理开发的一款开源免费的桌面客户端软件,支持Windows、Linux...

关于Redis在windows上运行及fork函数问题

Redis在将数据库进行持久化操作时,需要fork一个进程,但是windows并不支持fork,导致在持久化操作期间,Redis必须阻塞所有的客户端直至持久化操作完成。微软的一些工程师花费时间在解决在...

你必须懂的Redis十大应用场景(redis常见应用场景)

Redis作为一款高性能的键值存储数据库,在互联网业务中有着广泛的应用。今天,我们就来详细盘点一下Redis的十大常用业务场景,并附上Golang的示例代码和简图,帮助大家更好地理解和应用Redis。...

极简Redis配置(redis的配置)

一、概述Redis的配置文件位于Redis安装目录下,文件名为redis.conf(Windows名为redis.windows.conf,linux下的是redis.conf)你可以通过C...

什么是redis,怎么启动及如何压测

从今天起咱们一起来学习一下关于“redis监控与调优”的内容。一、Redis介绍Redis是一种高级key-value数据库。它跟memcached类似,不过数据可以持久化,而且支持的数据类型很丰富。...

一款全新Redis UI可视化管理工具,支持WebUI和桌面——P3X Redis UI

介绍P3XRedisUI这是一个非常实用的RedisGUI,提供响应式WebUI访问或作为桌面应用程序使用,桌面端是跨平台的,而且完美支持中文界面。Githubhttps://github....

windows系统的服务器快速部署java项目环境地址

1、mysql:https://dev.mysql.com/downloads/mysql/(msi安装包)2、redis:https://github.com/tporadowski/redis/r...

window11 下 redis 下载与安装(windows安装redis客户端)

#热爱编程是一种怎样的体验#window11下redis下载与安装1)各个版本redis下载(windows)https://github.com/MicrosoftArchive/r...

一款轻量级的Redis客户端工具,贼好用!

使用命令行来操作Redis是一件非常麻烦的事情,我们一般会选用客户端工具来操作Redis。今天给大家分享一款好用的Redis客户端工具TinyRDM,它的界面清新又优雅,希望对大家有所帮助!简介Ti...

一个.NET开发且功能强大的Windows远程控制系统

我们致力于探索、分享和推荐最新的实用技术栈、开源项目、框架和实用工具。每天都有新鲜的开源资讯等待你的发现!项目介绍SiMayRemoteMonitorOS是一个基于Windows的远程控制系统,完...

Redis客户端工具详解(4款主流工具)

大家好,我是mikechen。Redis是大型架构的基石,也是大厂最爱考察内容,今天就给大家重点详解4款Redis工具@mikechen本篇已收于mikechen原创超30万字《阿里架构师进阶专题合集...