技术标签: cesium
/* eslint-disable no-param-reassign */
/* eslint-disable class-methods-use-this */
/* eslint-disable no-undef */
export class Roaming {
/**
* Creates an instance of Roaming.
* @param {*} viewer 需要传入
* @param {*} options.model 模型的相关配置 需要传入
* @param {*} options.time 漫游时间 需要传入
* @param {*} options.data 点集合 需要传入
* @param {*} options.isPathShow 路径是否显示 默认显示
* @memberof Roaming
* @example
* const options = {
data: '', // url 或者直接数据,格式和以前一样
view: { pitch: '', range: '' }, // 默认不传
model: {
url: ''// 和cesium中model的配置一致
},
isPathShow: true, // 漫游路径是否显示
speed: '', // 默认可不传
time: 500// 此次漫游所需要的总时间,单位:秒
};
*/
constructor(viewer, options) {
this.viewer = viewer;
this.updateOptionsParams(options);
this.entity = undefined;
this.start = undefined;
this.stop = undefined;
this.isPlay = true; // 鼠标控制漫游是否播放的变量
this.addRoamingHandler(); // 添加鼠标事件管理器
}
init(options) {
this.removeRoaming();
// 根据新的配置更新内部参数
this.updateOptionsParams(options);
const result = this.loadData(this.data);
if (result && (typeof result === 'object' || typeof result === 'function') && typeof result.then === 'function') { // 判断是否为promise
result.then((sections) => {
// 路径数据
const data = sections.path;
this.createRoaming(data);
});
} else {
this.createRoaming(result);
}
}
/**
* 更新漫游可配置的内部参数
* @param {object} options 漫游的配置项
*/
updateOptionsParams(options) {
this.view = options.view;
this.model = options.model || {};
this.time = options.time;
this.data = options.data;
this.multiplier = options.speed || 10;
this.isPathShow = Cesium.defined(options.isPathShow) ? options.isPathShow : true;
this.multiplier = options.speed || 10;
}
/**
* 创建漫游
* @param {array} data
* @memberof Roaming
*/
createRoaming(data) {
if (data && Array.isArray(data)) {
// 加载路径数据
const positions = this.processData(data);
// 根据基础路径生成漫游路线
this.property = this.computeRoamingLineProperty(positions, this.time);
this.createEntity(this.property, this.start, this.stop, this.isPathShow);
// TODO 默认是否添加鼠标控制
this.controlMouseEvent();
}
}
/**
* 载入数据
* @param {string|array} url
* @return {*}
* @memberof Roam
*/
loadData(url) {
let data;
if (Cesium.defined(url) && typeof url === 'string') { // 如果传入的是字符串,默认是json路径,加载json数据
data = Cesium.Resource.fetchJson(url); // 不应该用其私有方法
} else {
data = url;
}
return data;
}
/**
* 处理读取到的数据
* @param {array} data
*/
processData(data) {
const positions = [];
data.forEach((position) => {
const car3Position = Cesium.Cartesian3.fromDegrees(position[0], position[1], position[2]); // 给定默认值
positions.push(car3Position);
});
return positions;
}
/**
* 创建位置集合
* @param {cartesian3} coordinates 点集合
* @param {*} time 漫游时间
* @returns
*/
computeRoamingLineProperty(coordinates, time) {
const property = new Cesium.SampledPositionProperty();
const coordinatesLength = coordinates.length;
const tempTime = time - (time % coordinatesLength);
const increment = tempTime / coordinatesLength;
const start = Cesium.JulianDate.now();
const stop = Cesium.JulianDate.addSeconds(start, tempTime, new Cesium.JulianDate());
this.start = start;
this.stop = stop;
this.setClockTime(start, stop, this.multiplier);
for (let i = 0; i < coordinatesLength; i += 1) {
const time1 = Cesium.JulianDate.addSeconds(start, i * increment, new Cesium.JulianDate());
const position = coordinates[i];
property.addSample(time1, position);
}
return property;
}
/**
* 设置漫游事件系统
* @param {*} start
* @param {*} stop
* @param {*} multiplier
* @memberof Roaming
*/
setClockTime(start, stop, multiplier) {
// 将当前日期转为JulianDate
this.viewer.clock.startTime = start.clone();
this.viewer.clock.stopTime = stop.clone();
this.viewer.clock.currentTime = start.clone();
this.viewer.clock.multiplier = multiplier;
// 默认循环漫游
this.viewer.clock.clockRange = Cesium.ClockRange.LOOP_STOP;
// 时钟在此模式下前进的间隔当前间隔乘以某个系数
this.viewer.clock.clockStep = Cesium.ClockStep.SYSTEM_CLOCK_MULTIPLIER;
}
/**
* 创建entity
* @param {*} position computeRoamingLineProperty计算的属性
* @param {*} start 开始时间节点
* @param {*} stop 结束时间节点
* @param {*} isPathShow path路径是否显示
* @memberof Roaming
*/
createEntity(position, start, stop, isPathShow) {
this.entity = this.viewer.entities.add({
availability: new Cesium.TimeIntervalCollection([new Cesium.TimeInterval({
start,
stop,
})]),
// 位置
position,
// 计算朝向
orientation: new Cesium.VelocityOrientationProperty(position),
// 加载模型
model: { // 模型路径
uri: this.model.url,
// 模型最小刻度
minimumPixelSize: 64,
maximumSize: 128,
// 设置模型最大放大大小
maximumScale: 200,
// 模型是否可见
show: true,
// 模型轮廓颜色
silhouetteColor: Cesium.Color.WHITE,
// 模型颜色 ,这里可以设置颜色的变化
// color: color,
// 仅用于调试,显示模型绘制时的线框
debugWireframe: false,
// 仅用于调试。显示模型绘制时的边界球。
debugShowBoundingVolume: false,
scale: 20,
runAnimations: true, // 是否运行模型中的动画效果
...this.model,
},
path: {
resolution: 1,
material: new Cesium.PolylineGlowMaterialProperty({
glowPower: 0.1,
color: Cesium.Color.YELLOW,
}),
width: 10,
show: isPathShow,
},
});
this.entity.position.setInterpolationOptions({ // 点插值
interpolationDegree: 5,
interpolationAlgorithm: Cesium.LagrangePolynomialApproximation,
});
this.addSceneEvent((time) => {
this.getRoamingPosition(time);
});
}
/**
* 设置漫游路径是否可见
* @param {boolean} visible
* @memberof Roaming
*/
setRoamingPathVisibility(visible) {
if (this.entity) {
this.entity.path.show = visible;
}
// 更新全局漫游路径是否可见参数
this.isPathShow = visible;
}
/**
* 设置漫游模型是否可见
* @param {boolean} visible
* @memberof Roaming
*/
setRoamingModelVisibility(visible) {
if (this.entity) {
this.entity.model.show = visible;
}
}
/**
* 设置相机位置
* @param {cartesian3} position
* @param {object} options
* @memberof Roaming
*/
setCameraPosition(position, options) {
if (position) {
// 最新传进来的坐标(后一个位置)
this.position2 = this.cartesian3ToWGS84(position);
let heading = 0;
// 前一个位置点位
if (this.position1) {
// 计算前一个点位与第二个点位的偏航角
heading = this.bearing(this.position1.latitude, this.position1.longitude,
this.position2.latitude, this.position2.longitude);
}
this.position1 = this.cartesian3ToWGS84(position);
if (position) {
const dynamicHeading = Cesium.Math.toRadians(heading);
const pitch = Cesium.Math.toRadians(options.pitch || -20.0);
const range = options.range || 2000.0;
this.viewer.camera.lookAt(position, new Cesium.HeadingPitchRange(dynamicHeading, pitch, range));
}
}
}
/**
* @name bearing 计算两点的角度 heading
* @param startLat 初始点的latitude
* @param startLng 初始点的longitude
* @param destLat 第二个点的latitude
* @param destLng 第二个点的latitude
* @return {number} heading值
*/
bearing(startLat, startLng, destLat, destLng) {
startLat = this.toRadians(startLat);
startLng = this.toRadians(startLng);
destLat = this.toRadians(destLat);
destLng = this.toRadians(destLng);
const y = Math.sin(destLng - startLng) * Math.cos(destLat);
const x = Math.cos(startLat) * Math.sin(destLat) - Math.sin(startLat) * Math.cos(destLat) * Math.cos(destLng - startLng);
const brng = Math.atan2(y, x);
const brngDgr = this.toDegrees(brng);
return (brngDgr + 360) % 360;
}
/**
* cartographic 转Degrees下地理坐标
* @param point radius下的WGS84坐标
* @return degrees下的WGS84坐标
*/
cartesian3ToWGS84(point) {
const cartographic = Cesium.Cartographic.fromCartesian(point);
const lat = Cesium.Math.toDegrees(cartographic.latitude);
const lng = Cesium.Math.toDegrees(cartographic.longitude);
const alt = cartographic.height;
return {
longitude: lng,
latitude: lat,
height: alt,
};
}
/**
* 监听场景渲染事件
* @param callback
*/
addSceneEvent(callback) {
// addEventListener() → Event.RemoveCallback
// 监听之前先销毁
if (this.handler instanceof Function) {
this.handler();
this.handler = null;
}
this.handler = this.viewer.scene.preRender.addEventListener((scene, time) => {
callback(time);
});
}
/**
* 根据时刻获取漫游位置
* @param {object} time
* @memberof Roaming
*/
getRoamingPosition(time) {
if (this.entity) {
const position = this.entity.position.getValue(time);
this.setCameraPosition(position, this.view || {});
}
}
/**
* 添加屏幕事件管理器
* @memberof Roaming
*/
addRoamingHandler() {
if (!this.roamingHandler) {
this.roamingHandler = new Cesium.ScreenSpaceEventHandler(this.viewer.scene.canvas);
}
}
/**
* 监听鼠标事件
*/
controlMouseEvent() {
// 防止重复注册
this.cancelMouseEvent();
this.addRoamingHandler();
// 左键单击停止;
this.roamingHandler.setInputAction(() => {
// 暂停漫游
this.pauseOrContinue(!this.isPlay);
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
// 右键单击继续
this.roamingHandler.setInputAction(() => {
// 开启漫游
this.pauseOrContinue(this.isPlay);
}, Cesium.ScreenSpaceEventType.RIGHT_CLICK);
}
/**
* 取消鼠标事件
*/
cancelMouseEvent() {
// TODO 销毁后需要重新new 需要判断它是否存在
if (this.roamingHandler && !this.roamingHandler.isDestroyed()) {
this.roamingHandler.destroy();
this.roamingHandler = null;
}
}
/**
* 漫游的暂停和继续
* @param {boolean} state false为暂停,ture为继续
*/
pauseOrContinue(state) {
if (state) {
// 继续播放
if (!this.handler && this.entity) {
this.addSceneEvent((time) => {
this.getRoamingPosition(time);
});
}
} else if (this.handler) {
// 停止监听屏幕绘制事件(停止相机变化)
this.handler();
this.handler = null;
// 解锁相机视角
this.viewer.camera.lookAtTransform(Cesium.Matrix4.IDENTITY);
}
this.viewer.clock.shouldAnimate = state;
}
/**
* 改变飞行的速度
* @param {*} value 整数类型
*/
changeRoamingSpeed(value) {
this.viewer.clock.multiplier = value;
}
/**
* 移除漫游
*/
removeRoaming() {
if (this.entity !== undefined) {
if (this.handler instanceof Function) {
this.handler();
this.handler = null;
}
// 清空实体
this.viewer.entities.remove(this.entity);
// 清空内部数据
this.data = null;
// 销毁鼠标事件
this.cancelMouseEvent();
// 解锁相机视角
this.viewer.camera.lookAtTransform(Cesium.Matrix4.IDENTITY);
this.entity = null;
}
}
}
文章浏览阅读618次。QMA8658A 是一款功能强大的6轴加速度传感器,其内置了3轴加速度计和3轴陀螺仪,能够同时测量三个方向的加速度和角速度。该传感器广泛应用于无人机、机器人、智能手机等领域。为了帮助开发人员快速评估和开发基于QMA8658A的解决方案,我们推出了QMA8658A-EVB全面的评估板。该评估板精心设计,预置了所有必需的硬件接口,兼容I2C和SPI接口,方便与任意MCU处理器进行连接和通信。此外,我们还提供了详细的驱动程序和使用指南,以便开发者能够轻松使用该评估板进行二次开发。4.1 I2C接口。_qmi8658a中文资料
文章浏览阅读551次。点击蓝字 关注我们缺血性心脏病相关肠道微生物及菌群代谢物研究进展iMeta主页:http://www.imeta.science综 述●原文链接DOI: https://doi.org/10.1002/imt2.94● 2023年2月26日,宁波大学附属第一医院崔翰斌团队、浙江省动脉粥样硬化疾病精准医学研究重点实验室范勇团队在iMeta在线发表了题为“Microbiota-related ..._与急性心肌梗死有关的微生物
文章浏览阅读2.6k次,点赞2次,收藏5次。刚在Github上分享了一些不错的代码http://hhoppe.com/ Hugues Hoppe »DemosPublicationsTalksAcademicProfessionalMisc Hugues Hoppe [pronunciation]Principal researche_automated video looping with progressive dynamism
文章浏览阅读497次。AOP实现权限拦截注解名称:CheckUnSysAdmin注解实现类:CommonAspectController层方法上引入注解名称:CheckUnSysAdminpackage com.sf.XWFS.aop;import java.lang.annotation.*;/** * @author cc * Desc 校验除超管外的角色,都进行拦截 */@Documented@Retention(RetentionPolicy.RUNTIME)@Target(ElementType_apo拦截控制层
文章浏览阅读52次。时隔4个月后,瑞星杀毒造假案又有了戏剧性的变化。近日,瑞星杀毒造假案的主角——北京市公安局网监处原处长于兵的二审结果仍维持一审的死缓判决。而据于兵的最新供认资料,相当一部分病毒是杀毒软件公司自己的科技力量研制的。于兵供认,瑞星公司向其行贿时就提出条件,由公安机关发出病毒警报,提示用户下载该公司杀毒软件进行杀毒,而病毒则是由瑞星公司“研制”的。“其实这是杀毒软件行业里的公开秘密。”国内一家知名...
文章浏览阅读6k次,点赞4次,收藏35次。考试重点1. 密码体制分类对称密码体制和非对称密码体制;2. DES和AES算法的特点(结构、密钥长度,分组长度,DES弱密钥)及其过程(置换过程,S盒查表过程),AES的轮结构DESDES结构首先是一个初始置换IP,用于重排明文分组的64比特;相同功能的16轮变换,每轮都有置换和代换;第16轮的输出分为左右两半并被交换次序;最后经过一个逆初始置换产生64比特密文;DES结构图如下:密钥长度:56分组长度:64DES弱密钥:待续了解即可DES 分组长度_移位密码和vigenere密码的异同是什么
文章浏览阅读7.7k次,点赞5次,收藏33次。一、问题为什么要进行网页授权?首先我们进行网页授权的需求是,获取用户信息、最主要是获取openid唯一值,可以用于用户登录、支付等功能,这时候就需要进行网页授权获取用户的信息以及openid。二、静默授权/非静默授权在操作之前可以先提前看看网页授权官方文档静默授权snsapi_base (不弹出授权页面,直接跳转,只能获取用户openid;用来获取进入页面的用户的openid的,并且自动跳转到回调页的。用户感知的就是直接进入了回调页(往往是业务页面)。非静默授权snsapi_user_微信公众号静默授权
文章浏览阅读235次。A Key Volume Mining Deep Framework for Action Recognition_a key volume mining deep framework for action recognition
文章浏览阅读3.9k次。广告关闭腾讯云11.11云上盛惠 ,精选热门产品助力上云,云服务器首年88元起,买的越多返的越多,最高返5000元!2、python生成目录树上述 cmd 方式虽然可以生成目录树,但是并不美观,让我们用 python 实现。 2.1 标准库pathlib介绍python有一个标准文件路径处理库 os.path ,从 python3.4 开始,python 又加入了一个标准库 pathlib ,该库..._python创建一个窗口
文章浏览阅读5.1k次,点赞5次,收藏10次。时序图(Sequence Diagram)是显示对象之间交互的图,这些对象是按时间顺序排列的。顺序图中显示的是参与交互的对象及其对象之间消息交互的顺序。时序图中包括的建模元素主要有:角色(Actor)、对象(Object)、生命线(Lifeline)、控制焦点(Focus of control)/ 激活(Activation)、消息(Message)、组合片段(Combined Fragments_使用powerdesiger 画出时序图有接口 控制
文章浏览阅读1.2k次。文章目录一. 动态分区概述1.1 原理1.2 使用方式1.3 动态分区规则参数1.4 创建历史分区规则1.5 注意事项二. 案例2.1 案例12.2 案例22.3 案例3参考:一. 动态分区概述动态分区是在 Doris 0.12 版本中引入的新功能。旨在对表级别的分区实现生命周期管理(TTL),减少用户的使用负担。目前实现了动态添加分区及动态删除分区的功能。动态分区只支持 Range 分区。名词解释:FE:Frontend,Doris 的前端节点。负责元数据管理和请求接入。BE:Backend_dynamic_partition.history_partition_num
文章浏览阅读309次。笔记_禅道的运行日志放在哪