Cesium源码解析六(3dtiles属性获取、建筑物距离计算、建筑物着色及其原理分析)
快速导航
Cesium源码解析一(搭建开发环境)
Cesium源码解析二(terrain文件的加载、解析与渲染全过程梳理)
Cesium源码解析三(metadataAvailability的含义)
Cesium源码解析四(metadata元数据拓展中行列号的分块规则解析)
Cesium源码解析五(Quantized-Mesh(.terrain)格式文件在CesiumJS和UE中加载情况的对比)
Cesium源码解析六(3dtiles属性获取、建筑物距离计算、建筑物着色及其原理分析)
目录
- 快速导航
- 前言
- 1.代码示例
- 2.属性获取原理分析
- 3.建筑物距离计算原理分析
- 4.建筑物着色原理分析
- 5.总结
前言
在本文中,我们将探讨如何使用 CesiumJS 来加载和显示 3D 建筑物数据,并根据用户点击的位置进行动态着色。我们将使用 CesiumJS 的 OpenStreetMap 建筑物数据集,通过点击地图上的建筑物,根据距离计算并动态地为这些建筑物着色。这不仅增强了地图的交互性,还为用户提供了直观的地理空间数据可视化体验。我们将逐步讲解如何设置 Cesium Viewer,加载 3D 建筑物数据,处理用户点击事件,以及根据距离进行建筑物的颜色处理。希望通过本文,您能深入理解 CesiumJS 的强大功能,并能够在自己的项目中应用这些技术。
1.代码示例
// 创建一个Cesium Viewer实例,指定目标DOM元素的id为 "cesiumContainer"
var viewer = new Cesium.Viewer("cesiumContainer", {baseLayerPicker: false, // 禁用基础图层选择器
});// 创建一个事件处理器,用于处理屏幕空间事件(如点击、拖动)
var handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);// 创建OpenStreetMap(OSM)建筑物的3D模型
var osmBuildings = Cesium.createOsmBuildings();// 将OSM建筑物添加到场景的primitives集合中
viewer.scene.primitives.add(osmBuildings);// 设置相机视图,定位到指定的经纬度(西雅图附近)和高度
viewer.scene.camera.setView({destination: Cesium.Cartesian3.fromDegrees(-122.3472, 47.598, 370),orientation: {heading: Cesium.Math.toRadians(10), // 方向(水平旋转角度)pitch: Cesium.Math.toRadians(-10) // 倾斜(垂直旋转角度)}
});// 定义一个函数,用于获取和打印特征的属性
function getFeatureProperty(feature) {let names = feature.getPropertyNames(); // 获取特征属性的名称数组for (var i = 0; i < names.length; i++) {var prop = feature.getProperty(names[i]); // 获取每个属性的值if (prop) console.log(names[i], prop); // 打印属性名称和值}
}// 定义一个函数,用于根据距离着色
function showByDistance() {colorByDistanceToCoordinate(47.62051, -122.34931); // 默认根据指定经纬度着色// 内部函数处理点击事件function move(movement) {viewer.selectEntiy = undefined;var pickBuilding = viewer.scene.pick(movement.position); // 获取点击位置的建筑物if (pickBuilding) {getFeatureProperty(pickBuilding); // 获取点击建筑物的属性var latitude = pickBuilding.getProperty("cesium#latitude");var longitude = pickBuilding.getProperty("cesium#longitude");colorByDistanceToCoordinate(latitude, longitude); // 根据点击的建筑物位置进行着色}}// 设置鼠标左键点击事件的处理函数handler.setInputAction(move, Cesium.ScreenSpaceEventType.LEFT_CLICK);
}// 定义一个函数,根据指定经纬度着色建筑物
function colorByDistanceToCoordinate(pickLatitude, pickLongitude) {osmBuildings.style = new Cesium.Cesium3DTileStyle({defines: {// 定义着色器中的distance变量,计算每个建筑物与指定坐标的距离distance: "distance(vec2(${feature['cesium#longitude']},${feature['cesium#latitude']})," + `vec2(${pickLongitude},${pickLatitude}))`},color: {conditions: [["${distance} > 0.014", "color('blue')"], // 大于0.014的距离,颜色为蓝色["${distance} > 0.010", "color('green')"], // 大于0.010的距离,颜色为绿色["${distance} > 0.006", "color('yellow')"],// 大于0.006的距离,颜色为黄色["${distance} > 0.0001", "color('red')"], // 大于0.0001的距离,颜色为红色["true", "color('white')"], // 其他距离,颜色为白色]}});
}
// 定义一个函数,根据距离渲染建筑物
function showByDistance() {// 首先调用 colorByDistanceToCoordinate,以特定坐标(47.62051, -122.34931)为参考点进行初始着色colorByDistanceToCoordinate(47.62051, -122.34931);// 定义一个内部函数 move 用于处理点击事件function move(movement) {viewer.selectEntiy = undefined; // 清除当前选择的实体// 获取点击位置的建筑物特征var feature = viewer.scene.pick(movement.position);if (feature) { // 如果点击位置有建筑物特征getFeatureProperty(feature); // 获取并打印该建筑物的属性// 获取建筑物的经度和纬度var latitude = feature.getProperty("cesium#latitude");var longitude = feature.getProperty("cesium#longitude");// 调用 colorByDistanceToCoordinate 以点击位置的建筑物为参考点重新着色colorByDistanceToCoordinate(latitude, longitude);}}// 设置鼠标左键点击事件的处理函数,将其与 move 函数绑定handler.setInputAction(move, Cesium.ScreenSpaceEventType.LEFT_CLICK);
}// 调用 showByDistance 函数以启动初始着色和点击事件处理
showByDistance();
2.属性获取原理分析
当我们点击一个建筑物时,Cesium
会自动展示这个建筑物的信息。我们也在控制台输出一下自己获取到的属性信息,看看能不能对应的上。
可以看到完全对应的上。而当我们看下源码就会发现属性获取的调用过程如下:
sequenceDiagram
participant User as 用户
participant Scene as Cesium.Scene
participant Handler as ScreenSpaceEventHandler
participant Feature as Cesium3DTileFeature
participant BatchTable as Cesium3DTileBatchTable
User->>Handler: 点击事件
Handler->>Scene: pick(movement.position)
Scene-->>Handler: 返回Cesium3DTileFeature
Handler->>Feature: 获取属性名
Feature->>BatchTable: getPropertyNames()
BatchTable-->>Feature: 返回属性名数组
Feature-->>Handler: 返回属性名数组
Handler->>Feature: 获取属性值(name)
Feature->>BatchTable: getProperty(batchId, name)
BatchTable-->>Feature: 返回属性值
Feature-->>Handler: 返回属性值
Handler-->>User: 打印属性名和值
3.建筑物距离计算原理分析
在CesiumJS
中,建筑物之间的距离计算是通过 GLSL
着色器来实现的,计算每个建筑物与一个参考点之间的欧几里得距离。以下是距离计算的步骤:
-
定义距离计算表达式:
defines: {distance: "distance(vec2(${feature['cesium#longitude']}, ${feature['cesium#latitude']}), vec2(" + `${pickLongitude}, ${pickLatitude}))` }
defines
部分定义了 GLSL 表达式,用于计算每个建筑物与参考点的距离。distance
是 GLSL(OpenGL Shading Language)中的函数,用于计算两个二维向量(坐标)之间的欧几里得距离。vec2
是 GLSL 中表示二维向量的构造函数。${feature['cesium#longitude']}
和${feature['cesium#latitude']}
分别表示建筑物的经度和纬度。${pickLongitude}
和${pickLatitude}
表示参考点(如用户点击位置)的经度和纬度。
-
计算距离:
GLSL 表达式
distance
计算每个建筑物的位置与参考点之间的距离。这个距离值将用于后续的颜色条件判断。float distance = distance(vec2(buildingLongitude, buildingLatitude), vec2(referenceLongitude, referenceLatitude));
-
应用距离值:
这个计算的距离值会被应用到每个建筑物,用于在着色器中进行条件判断,决定建筑物的颜色。
osmBuildings.style = new Cesium.Cesium3DTileStyle({defines: {distance: "distance(vec2(${feature['cesium#longitude']}, ${feature['cesium#latitude']}), vec2(" + `${pickLongitude}, ${pickLatitude}))`} });
4.建筑物着色原理分析
在 CesiumJS
中,建筑物的着色是基于计算出的距离,并通过条件语句来设置颜色的。在 Cesium3DTileStyle
中定义颜色条件,根据计算出的距离为建筑物设置颜色。
osmBuildings.style = new Cesium.Cesium3DTileStyle({defines:{distance:"distance(vec2(${feature['cesium#longitude']},${feature['cesium#latitude']}),"+`vec2(${pickLongitude},${pickLatidude}))`},color:{conditions:[["${distance} > 0.014","color('blue')"],["${distance} > 0.010","color('green')"],["${distance} > 0.006","color('yellow')"],["${distance} > 0.0001","color('red')"],["true","color('white')"],]}
})
-
定义部分:
defines
部分定义了 GLSL 表达式,用于计算每个建筑物与参考点的距离。distance
函数使用建筑物的经纬度和参考点的经纬度,计算欧几里得距离。
-
颜色条件部分:
color
部分定义了颜色条件,根据distance
值设置不同的颜色。- 使用条件数组
conditions
,依次匹配distance
的值,并根据匹配的条件设置颜色。
这两个原理共同作用,为用户提供了一个动态且交互的建筑物着色效果,根据点击的位置和距离进行直观的展示。
5.总结
本文中我们通过代码示例展示了如何在Cesiumjs
中对3dtiles
进行属性获取、建筑物距离计算、建筑物着色及其原理分析,深入的理解了其原理,回见~
相关文章:

Cesium源码解析六(3dtiles属性获取、建筑物距离计算、建筑物着色及其原理分析)
快速导航 Cesium源码解析一(搭建开发环境) Cesium源码解析二(terrain文件的加载、解析与渲染全过程梳理) Cesium源码解析三(metadataAvailability的含义) Cesium源码解析四(metadata元数据拓展…...

AI 情感聊天机器人之旅 —— 相关论文调研
开放域闲聊场景 Prompted LLMs as Chatbot Modules for Long Open-domain Conversation 发布日期:2023-05-01 简要介绍:作者提出了 MPC(模块化提示聊天机器人),这是一种无需微调即可创建高质量对话代理的新方法&…...

WPF Prism框架搭建
WPF Prism框架搭建 1.引入Prism框架 在Nuget包管理器中搜索Prism,并添加到项目中 2.在项目中使用prism框架 2.1 修改app.xaml 删除项目中自带的StartupUri 修改Application节点为prism:PrismApplication 引入prism命名空间 <prism:PrismApplication x:C…...

MyBatisplus使用报错--Invalid bound statement
报错如下 org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.lotus.mybatis.mapper.UserMapper.selectListat org.apache.ibatis.binding.MapperMethod$SqlCommand.<init>(MapperMethod.java:235)at com.baomidou.mybatisplus.cor…...

QT-QPainter实现一个动态充电的电池
1、效果 2、核心代码 #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QTimer>...

【云原生】Kubernetes----Metrics-Server组件与HPA资源
目录 引言 一、概述 (一)Metrics-Server简介 (二)Metrics-Server的工作原理 (三)HPA与Metrics-Server的作用 (四)HPA与Metrics-Server的关系 (五)HPA与…...

模拟原神圣遗物系统-小森设计项目,设计圣遗物(生之花,死之羽,时之沙,空之杯,理之冠)抽象类
分析圣遗物 在圣遗物系统,玩家操控的是圣遗物的部分 因此我们应该 物以类聚 人与群分把每个圣遗物的部分,抽象出来 拿 生之花,死之羽为例 若是抽象 类很好的扩展 添加冒险家的生之花 时候继承生之花 并且名称冒险者- 生之花 当然圣遗物包含…...

仿真模拟--telnet服务两种认证模式(自作)
自己做的笔记,有问题或看不懂请见解一下~ 目录 两个路由器间实现telnet服务(password认证模式) server client 两个路由器间实现telnet服务(aaa认证模式) server client 改名 tab键补齐 不会就扣问号 ? save 两个路由器间实现telnet服务…...

Apple Phone Memory
Apple Phone Memory 苹果手机内存查询,哪些应用程序(app)占用内存: 设置 通用 iPhone储存空间 清理下QQ音乐:...

Kubernetes容器运行时:Containerd vs Docke
容器化技术笔记 Kubernetes容器运行时:Containerd vs Docke - 文章信息 - Author: 李俊才 (jcLee95) Visit me at CSDN: https://jclee95.blog.csdn.netMy WebSite:http://thispage.tech/Email: 291148484163.com. Shenzhen ChinaAddress of this arti…...
【java 线程的状态】
介绍 Java 线程在运⾏的⽣命周期中的指定时刻只可能处于下⾯ 6 种不同状态的其中⼀个状态 状态名称说明NEW初始状态,线程被构建,但是还没有调用start()方法RUNNABLE运行状态,Java线程将操作系统中的就绪和运行两种状态统称为"运行中"BLOCKED阻塞状态,表示线程阻塞于…...
php加密验签
签名生成步骤(小程序端/前端): 确定参与签名的参数:选择需要参与签名的请求参数,通常包括请求的时间戳、随机数、请求的数据等。 参数排序与拼接:将所有参与签名的参数按照字母顺序排序,并拼接成…...

【Golang - 90天从新手到大师】Day06 - 数组
系列文章合集 Golang - 90天从新手到大师 数组是golang中最常用的一种数据结构,数组就是同一类型数据的有序集合 定义一个数组 格式: var name [n]type n为数组长度,n>0 且无法修改,type为数组的元素类型如: var a [2]int上面的例子定义了一个长度为2,元素类型为int的数组…...
java的有参构造方法
java的有参构造方法和无参构造方法类似,区别是构造方法名称里后面跟着一个括号,括号里是参数的定义 示例代码如下 class student4{private String name;private int age;public student4(String n,int a) {namen;agea;System.out.println("调用了…...

Vue66-vue-默认插槽
一、默认插槽需求 1-1、原本的写法: 在每个category组件中用v-show来做条件渲染,但是不方便! 1-2、默认插槽 img标签,ul标签,video标签,都是在app组件中完成解析之后,塞到category组件中的&…...
tsf-consul的使用
在腾讯云微服务平台TSF中使用Consul作为服务发现组件,通常需要遵循以下步骤: ### 1. 创建应用 首先,您需要在TSF控制台创建一个应用。在创建应用时,选择合适的业务类型、开发语言、开发框架等信息。对于使用Consul作为服务发现组件的Spring Cloud应用,您需要选择“业务应…...

【perl】基本语法 /备忘录/
分享 perl 语言学习资源 Perl 教程|极客教程 (geek-docs.com) Perl [zh] (runebook.dev) Perl 运算符 | 菜鸟教程 (runoob.com) Perl Documentation - Perldoc Browser Search the CPAN - metacpan.org 当然还有一些经典书籍,不再列举。 1、数字 1.1、数字表…...

mongodb 集群安装
整体架构图: 1. 配置域名 Server1: OS version: CentOS Linux release 8.5.2111 hostnamectl --static set-hostname mongo01 vi /etc/sysconfig/network # Created by anaconda hostnamemong01 echo "192.168.88.20 mong1 mongo01.com mongo…...

绿茶集团重启IPO:流量渐退、业绩波动,还能讲出好故事吗?
近日,绿茶集团有限公司(下称“绿茶集团”)向港交所递交上市申请,花旗、招银国际为其联席保荐人。 回望绿茶集团的上市之路,可谓有诸多坎坷。该公司于2021年3月首度向港交所发起冲击,但却将中文版招股书中的“流动负债总额”错写成…...
Git与SSH
Git Git是一种分布式版本控制系统,最初由Linus Torvalds为管理Linux内核开发而设计并开发。Git可以帮助开发团队协作管理代码,跟踪代码变更历史,并在需要时回溯到特定版本。 分布式版本控制:每个开发者都可以拥有完整的代码仓库…...
React hook之useRef
React useRef 详解 useRef 是 React 提供的一个 Hook,用于在函数组件中创建可变的引用对象。它在 React 开发中有多种重要用途,下面我将全面详细地介绍它的特性和用法。 基本概念 1. 创建 ref const refContainer useRef(initialValue);initialValu…...

新能源汽车智慧充电桩管理方案:新能源充电桩散热问题及消防安全监管方案
随着新能源汽车的快速普及,充电桩作为核心配套设施,其安全性与可靠性备受关注。然而,在高温、高负荷运行环境下,充电桩的散热问题与消防安全隐患日益凸显,成为制约行业发展的关键瓶颈。 如何通过智慧化管理手段优化散…...

零基础设计模式——行为型模式 - 责任链模式
第四部分:行为型模式 - 责任链模式 (Chain of Responsibility Pattern) 欢迎来到行为型模式的学习!行为型模式关注对象之间的职责分配、算法封装和对象间的交互。我们将学习的第一个行为型模式是责任链模式。 核心思想:使多个对象都有机会处…...

【OSG学习笔记】Day 16: 骨骼动画与蒙皮(osgAnimation)
骨骼动画基础 骨骼动画是 3D 计算机图形中常用的技术,它通过以下两个主要组件实现角色动画。 骨骼系统 (Skeleton):由层级结构的骨头组成,类似于人体骨骼蒙皮 (Mesh Skinning):将模型网格顶点绑定到骨骼上,使骨骼移动…...

自然语言处理——Transformer
自然语言处理——Transformer 自注意力机制多头注意力机制Transformer 虽然循环神经网络可以对具有序列特性的数据非常有效,它能挖掘数据中的时序信息以及语义信息,但是它有一个很大的缺陷——很难并行化。 我们可以考虑用CNN来替代RNN,但是…...

【Redis】笔记|第8节|大厂高并发缓存架构实战与优化
缓存架构 代码结构 代码详情 功能点: 多级缓存,先查本地缓存,再查Redis,最后才查数据库热点数据重建逻辑使用分布式锁,二次查询更新缓存采用读写锁提升性能采用Redis的发布订阅机制通知所有实例更新本地缓存适用读多…...

android13 app的触摸问题定位分析流程
一、知识点 一般来说,触摸问题都是app层面出问题,我们可以在ViewRootImpl.java添加log的方式定位;如果是touchableRegion的计算问题,就会相对比较麻烦了,需要通过adb shell dumpsys input > input.log指令,且通过打印堆栈的方式,逐步定位问题,并找到修改方案。 问题…...
ThreadLocal 源码
ThreadLocal 源码 此类提供线程局部变量。这些变量不同于它们的普通对应物,因为每个访问一个线程局部变量的线程(通过其 get 或 set 方法)都有自己独立初始化的变量副本。ThreadLocal 实例通常是类中的私有静态字段,这些类希望将…...
32位寻址与64位寻址
32位寻址与64位寻址 32位寻址是什么? 32位寻址是指计算机的CPU、内存或总线系统使用32位二进制数来标识和访问内存中的存储单元(地址),其核心含义与能力如下: 1. 核心定义 地址位宽:CPU或内存控制器用32位…...
C++ 类基础:封装、继承、多态与多线程模板实现
前言 C 是一门强大的面向对象编程语言,而类(Class)作为其核心特性之一,是理解和使用 C 的关键。本文将深入探讨 C 类的基本特性,包括封装、继承和多态,同时讨论类中的权限控制,并展示如何使用类…...