Cesium加载矢量数据探索——从geojson到矢量切片

2023-11-01

矢量数据由于包含确定的坐标信息,通常用于表达准确的空间位置实体,在cesium中,不支持对shp进行加载,而是需要对shp数据进行转换,一般cesium支持的shp格式如下:

  • geojson
  • topojson
  • kml
  • czml

通常来说,对于简单的shp数据,最常规的处理方式是通过geojson格式在cesium中进行加载,而cesium也为加载geojson及后续操作提供了丰富的api。链接

Cesium常规加载

cesium提供的api加载方式

const viewer = new Cesium.Viewer('cesiumContainer');
viewer.dataSources.add(Cesium.GeoJsonDataSource.load('../../SampleData/ne_10m_us_states.topojson', {
  stroke: Cesium.Color.HOTPINK,
  fill: Cesium.Color.PINK,
  strokeWidth: 3,
  markerSymbol: '?'
}));
  • cesium的GeoJsonDataSource类提供了geojson的加载方式,并且可以在加载的同时,给数据提供自定义样式。
  • 但是,在加载geojson数据过大是(上万点),场景会非常卡顿,这是什么原因 呢?
Entity图元
  • 其实,翻看上述加载geojson的实现逻辑,其本质上是通过读取geojson中每个feature的属性和坐标,然后通过一个cesium的一个图元来实例化这个feature(包含坐标、样式、属性等信息),然后依次将图元加载到图层上。
  • 因此,上述加载代码也可以改成:
//读取geojson中的每个feature
for (var i = 0; i < geojson.features.length; i++) {
    var ifeature = boundary.features[i];
    let coordinates = [];
    ifeature.geometry.coordinates[0].forEach(lnglat => {
        coordinates.push(lnglat[0]);
        coordinates.push(lnglat[1]);
    });
    let positions2 = Cesium.Cartesian3.fromDegreesArray(coordinates);
    viewer.entities.add({
        polyline: {
            positions: positions2,
            clampToGround: true,
            width: 5,
            material: new Cesium.PolylineOutlineMaterialProperty({
                color: Cesium.Color.ORANGE,
                outlineWidth: 2,
                outlineColor: Cesium.Color.BLACK
            })
        }
    });
 }
  • 可以看到,cesium根据geojson中的每个feature要素的空间属性信息,创建对应的point、polygon、polyline,然后存放入Entities集合中,在场景中进行渲染。可以说,每一个图元要素,都是创建了一个entity。
    • Cesium中,entity是指一个可视化对象,它可以代表一个物体、一个位置或其他类型的数据。一个entity可以包括多个属性,例如位置、姿态、几何形状、颜色、标签等等。它可以被创建、修改、删除,并且可以在地球上进行实时的交互式浏览。
    • 可以看到,cesium就是靠着封装了一个图元类:Entity,这个类包装类丰富的api,来保证渲染要素并且便捷的操作要素。

image.png

  • 不足点:
    • Entity实体类是Cesium提供的标准的加载实体单元的类,并给用户提供了大量便捷操作的API,但是,正式由于它的便捷性。导致了它在加载大量geojson时,大量entity实体被创建和渲染到图层中,性能随之变得卡顿。
privitive像元

Cesium为开发者提供了丰富的图形绘制和空间数据管理的API,可以分为两类,一类是面向图形开发人员的低层次API,通常被称为Primitive API,另一类是用于驱动数据可视化的高层次API,称为Entity API

  • 和Entity的区别:
    • priviutive偏向底层,图形绘制效率更高,但封装程度较低,不包含实时交互功能。
  • 简单的说,privitive更偏向于webgl,只包含了图形绘制的方法,不包含其它便于用户交互、更改、查询等API,而本质上,Entity是privitive的进一步 包装。
  • priivitive由两个部分组成:
    • Geometry
      • 定义几何形状
    • Appearance
      • 定义着色
  • privitive最大的优化在于,加载大量genjson时,可以不用像entity一样,依次挨个加载,而是将大量privitive实例进行合并,最终一次渲染,而这种方式,是其性能大幅提升的关键。
for (let i = 0; i < features.length; i++) {
              const coordinates = features[i].geometry.coordinates[0];
              const lineArray = coordinates[0].slice(0, 2).concat(coordinates[1].slice(0, 2));
              const polyline = new Cesium.SimplePolylineGeometry({
                positions: Cesium.Cartesian3.fromDegreesArray(lineArray),
                // width: 3.0,
                // vertexFormat: Cesium.PolylineMaterialAppearance.VERTEX_FORMAT,
              });

              instances.push(
                new Cesium.GeometryInstance({
                  geometry: polyline,
                  id: `${name}-${i}`, //记录索引
                  attributes: {
                    color: new Cesium.ColorGeometryInstanceAttribute(
                      76 / 255,
                      57 / 255,
                      38 / 255,
                      1,
                    ),
                  },
                }),
              );
              //改成LineString类型
              features[i].geometry.coordinates = coordinates;

              features[i].geometry.type = 'LineString';
            }
            const primitive = new Cesium.Primitive({
              geometryInstances: instances, //合并
              appearance: new Cesium.PerInstanceColorAppearance({
                flat: true,
                renderState: {
                  lineWidth: Math.min(3.0, self._viewer.scene.maximumAliasedLineWidth),
                },
              }),
            });
  • 可以看到,以上加载geojson的方式要比entity代码量多了很多,但是,其性能却是飞速提升。
  • 不足点:
    • primitive带来的性能提升仅仅是从渲染方面解决,当面对大量geojson数据时,保证cesium端能流畅渲染,然是geojson的大量数据必定在后端向前端的网络传输过程中,造成一定时间的等待,客观上也是属于界面的卡顿。参考1参考2
    • primitie的高速渲染,带来加载的性能优化的同时,也造成了工作量的增加,而且其附属操作成本也会更高,如点击添加的某条线段,读取属性,使该线段高亮:
      • 这种操作适用entity可以很简单的实现,因为有现成的api。
      • 换成primitive实现方式则需要自己手动去实现:
        • 创建每个primitive时更定一独特索引
        • 点击时,读取索引,进而拿到该primitive
        • 根据该primitive,重现渲染该颜色

如何加载矢量切片

cesium支持矢量切片的加载在其论坛里呼声很高,但是ceisum依然坚持3dtiles的标准。

  • cesium加载3dtiles可以说也是一种切片的加载方式,这种方式将海量的模型数据,以瓦片的形式,高速率传输,理论上,基本可以实现不限数据量。
  • 这种加载方式在二维地图中经常看到,无论是影像数据还是矢量、栅格,通过切片方式加载,根据缩放层级和图层范围展示对应的数据是一种十分重要且流行的方案。
  • 但是,cesium本身没有对该方案做什么扩展,也就是说,依靠cesiuim无法实现矢量切片的加载,那么从头实现这个方法显然不现实。因此,有人开始走“曲线救国”的路线:
    • cesium支持加载不用数据源的图层,如天地图、mapbox、openlayer等。
    • 这些地图均包含加载矢量切片的功能,是否可以参考其中的源码,借助其功能,实现相关操作?
    • 经过测试,确实可以。参考3

openlayer的尝试

  • 参考4
  • 前人分享的一个根据openlayer改写的渲染方式,经过测试,换成自己发布的数据,确实可以实现mbtiles格式的切片数据加载。但是没一会,电脑开始发热,因为后台在不断请求切片数据,即使场景没有变化,也是在不断请求。因此还需要再继续完善,

mapbox的尝试

  • openlayer作为图层的方式似乎更简洁一些,但是性能上,mapbox几乎可以说是更快更强,因此我没有继续在上个前辈分享的openlayer的基础上继续学习和优化(如果后面有时间,可以多花点时间去学习)
  • 这个开源项目的地址:参考5,项目给创建了添加矢量栅格的方法,并且给出了范例,对新手很友好。
  • 但是,由于我水平有限,依然在这里踩了很多坑,因此我写这篇文章的主要目的,是分享一下我的踩坑的经过,一来加深印象,二来,要是有小伙伴在我的经过里知道有好的方案可以教教我。
踩坑:
  1. 引入mapbox-gl,可以看到,项目依赖于mapbox-gl.js文件,在此基础之上,创建了一个矢量加载类,在实际使用时,只需要实例化该类,像使用mapbox一样,传入定义好的style,即可实现加载。但实际上,很多人会报一个错:mapbox.BasicRenderer类不存在
    1. 其实原因是,项目中提供的mapbox-gl并不是真正的mapbox项目中的mapbox-gl.js文件,而是由另一位大神,根据mapbox源码中的渲染方式进行改进,从而可以实现基于mapbox的方式加载矢量切片的图层,该项目最终打包命名为mapbox-gl.js,参考6,恰好和mapbox中的文件重名。因此,有些评论里说遇到这恶鬼报错是因为mapbox-gl版本不对,其实不是一回事,不是一个项目。
    2. 在vite中使用报错,原因是该项目由webpack打包成的cmj规范,而vite恰恰不支持cmj规范,只支持ems规范。
      1. 因此,后面的思路变成:如何让vite支持cms规范和如何将cms规范转换为ems规范的问题。参考7
        1. 利用rollup插件进行重新打包。 参考8
        2. 通过第三方包进行转换。链接
      2. 这些方式都可以实现cmj->ems,但是,最终还是会有一些问题,报错:_requestTransformFn未定义
        1. 原因是this指针的问题,在源码里修改后即可

。至此,引入MVTImageryProvider进行实例化,加载到cesium中即可实现矢量瓦片的加载。

onMounted(() => {
  const cesiumViewer = new Cesium.Viewer('cesiumContainer', {
    infoBox: false
  })
  const provider = new MVTImageryProvider({
    style: sx,//mapbox风格自定义样式
   
  });
  provider.readyPromise.then(()=>{
  cesiumViewer.imageryLayers.addImageryProvider(provider)

  })
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Cesium加载矢量数据探索——从geojson到矢量切片 的相关文章

随机推荐

  • Windows下搭建PHP调试环境(phpstudy+VScode)

    Windows下搭建PHP调试环境 phpstudy VScode 0x00 问题背景 0x01 配套环境 0x02 php Xdebug简介 官方介绍 Xdebug扩展启用 0x03 php ini配置 0x04 vscode配置 VSc
  • k8s dashboard安装

    安装 wget https raw githubusercontent com kubernetes dashboard v2 5 1 aio deploy recommended yaml kubectl apply f recommen
  • springboot集成log4j2

    一 前言 1 为什么要使用log4j2作为我们的日志记录管理框架呢 答 springboot默认使用logback作为日志记录框架 常见的日志记录框架有log4j logback log4j2 2 我们在项目中经常使用一个叫SLF4J的依赖
  • 十分钟学会写shell脚本

    大家好 我是handsomecui 下面我为大家讲解一下shell脚本的写法 讲的不好的地方 欢迎大家留言拍砖 1 在linux下会写shell脚本是非常重要的 下面我参照例子给大家展示几个脚本 顺带这学习shell 的语法 什么时候hel
  • 汇编语言(1)——从机器到汇编

    汇编语言 王爽 著 读书笔记 1 汇编语言的出现 最早期出现的计算机 是名副其实的 计算 机 这个机器可以执行一系列特定的指令 即机器指令 而由机器指令构成的集合被称为指令集 也就是我们说的机器语言 机器指令是由一系列的二进制数字0和1构成
  • EMC整改流程及常见问题

    电磁兼容EMC整改专题 目录 EMC整改流程及常见问题 1EMC整改意见 2EMC整改流程 3EMC整改的一些小建议 4总结 电磁兼容 EMC EMC小结之时钟辐射问题 一前言 二测试数据分析 三辐射超标的原因 四结语 EMC整改流程及常见
  • 人机交互期末复习要点

    文章pdf下载 点击下载pdf 注 我们网上的作业 老师说的考试题目 可能会考的重点 无 可能会考选择题 也可能会考大题 比如 人机交互设备 我们这次期末考试就考了 绪论 什么是人机交互技术 是指关于设计 评价和实现供人们使用的交互式计算机
  • matlab中float类型的_数据类型(一)——数值类型

    数值类型包括两种 整数类型和浮点数类型 整数类型 uint8 分别表示有 不带u 无 带u 符号和对应的数值范围 或者说是整数的位数 浮点数类型 单精度 single 和双精度 float 或者直接输入小数 因为matlab默认即为双精度
  • ARM定义特殊寄存器(*(volatile unsigned long *))的理解

    以前老是对ARM程序中 volatile unsigned long 不理解 今天看了两篇文章 觉得对理解这个很有用 当然这个不止在定义内部特殊寄存器有用 在用到外部总线时 根据具体情况 定义外部器件的地址也可以用 下面是文章一 终于理解了
  • 常用IDE正则表达式

    目录 1 notepad 正则表达式 2 VScode正则表达式 3 pycharm正则表达式 梳理常用工具的正则表达式使用 逐步增加其他工具 1 notepad 正则表达式 注意 Notepad 正则表达式字符串最长不能超过69个字符 转
  • Unity做MMD(一)资源处理

    文章目录 unity插件 Blender插件 两者对比 要想把mmd 的模型拿到unity中处理 主要有两个方法 第一个是通过unity的插件将pmx模型文件转化为fbx 第二个就是通过第三方软件将pmx处理 例如blender 如果是想把
  • acwing算法基础__提高__进阶_课

    文章目录 1 排序 1 1 快速排序 分治 1 2 归并排序 分治 2 二分 2 2 整数二分 2 3 小数二分 浮点数二分 3 高精度 4 前缀和与差分 5 双指针算法 6 位运算 7 离散化 8 区间合并 总结 要求 把算法的思想搞懂
  • Mybatis中ResultType和ResultMap的区别

    MyBatis中的ResultType和ResultMap都是用来映射查询结果到Java对象的 ResultType适合简单查询结果的映射 而ResultMap适合复杂查询结果及自定义映射关系的情况 ResultType指定了返回值类型 即
  • 【Unity2D】相机移动以及设置相机边界

    添加相机 添加相机时 首先需要在unity中添加 Cinemachine 包 第一次使用这个包时 需要在Package Manager中搜索并安装 安装Camera Mechine包后 添加2D Camera 设置跟随对象为Ruby 从Hi
  • 在线一键JS混淆还原

    当今 随着互联网的发展 越来越多的网站开始使用JavaScript来实现动态交互和用户体验 但是 由于JavaScript代码的开放性和易于复制 网站管理员需要采取一些措施来保护他们的代码 这就是JavaScript混淆工具产生的原因 js
  • 【经验-强制HTTPS-web】在服务器301强制HTTPS跳转,套上腾讯云CDN后,第一次访问发生不强制跳转HTTPS的问题解决方法

    我的个人站网址 https mdzz pro 今天偶然在编程群里展示了下个人站 没想到大佬居然说我的网站没有开Https 我当场懵逼了 不可能啊 面板上我开了强制Https啊 于是我自己用edge访问了一下 结果发现真是这样 第一次 第二次
  • vim常用设置---(.vimrc详细配置)

    vimrc配置文件内容如下 一般设定 设定默认解码 set fenc utf 8 set fencs utf 8 usc bom euc jp gb18030 gbk gb2312 cp936 不要使用vi的键盘模式 而是vim自己的 se
  • 设计模式--外观模式

    外观模式 属于结构型模式 基本原理 隐藏系统复杂性 为系统开放一个便于使用的接口 主要流程 1 创建系统和子系统 2 创建一个外观类 统一管理子系统的功能 并对外提供接口 注意 外观类是管理子系统和对外提供接口 include
  • 数据库DDL,DML

    数据库DDL DML 一 DDL操作数据库 查询数据库 SHOW DATABASE 创建数据库 创建 CREATE DATABASE 数据库名称 创建 判断 如果不存在则创建 CREATE DATABASE IF NOT EXISTS 数据
  • Cesium加载矢量数据探索——从geojson到矢量切片

    矢量数据由于包含确定的坐标信息 通常用于表达准确的空间位置实体 在cesium中 不支持对shp进行加载 而是需要对shp数据进行转换 一般cesium支持的shp格式如下 geojson topojson kml czml 通常来说 对于