基于 HTML5 WebGL 的楼宇智能化集成系统(三)



// 通过 moveCamera 改变 eye 和 center 来移动场景视角为大楼的正视面
moveCamera(g3d, [134, 399, 1617], [7, 40, 144], {
duration: 2000,
easing: t => t * t,
finishFunc: () => {
// 开启场景大楼模型的可透明为 true
this.building.eachChild(c => {
c.s({
'shape3d.transparent': true,
});
});
// 大楼模型线框的颜色变化
tweenColor(this.building, 'wf.color', 'rgba(72,149,232,1)', 'rgba(56,156,255,0.03)', {
duration: 2000,
easing: t => t
});
// 大楼模型整体染色的颜色变化
tweenColor(this.building, 'shape3d.blend', 'rgba(120,180,255,1)', 'rgba(120,180,255,0)', {
duration: 2000,
easing: t => t,
finishFunc: () => {
// 楼层设置为可见
this.floor.eachChild(c => {
setNodeVisible(c, true);
});
this.floorLighting = 1;
// 显示大楼建筑信息的动画
this.showBuilding();
}
});
}
});
- node:改变颜色的图元节点;
- startColor:起始颜色的 rgba 值;
- endColor:变化后颜色的 rgba 值;
- animParams:过渡动画参数;
tweenColor(node, property, startColor, endColor, animParams) {
animParams = animParams || {};
if (!animParams.frames && !animParams.duration)
animParams.duration = 5000;
if (!animParams.easing)
animParams.easing = t => t;
startColor = ht.Default.toColorData(startColor);
endColor = ht.Default.toColorData(endColor);
const dx = endColor[0] - startColor[0];
const dy = endColor[1] - startColor[1];
const dz = endColor[2] - startColor[2];
const da = endColor[3] - startColor[3];
const postAction = animParams.postAction;
animParams.action = (v, t) => {
const x = startColor[0] + v * dx;
const y = startColor[1] + v * dy;
const z = startColor[2] + v * dz;
const a = (startColor[3] + v * da) / 255;
node.s(property, ('rgba(' + ([x, y, z, a]).join(', ')) + ')');
if (postAction) postAction(('rgba(' + ([x, y, z, a]).join(', ')) + ')');
}
return ht.Default.startAnim(animParams);
}

// 面板显示
showPanel(data) {
ht.Default.startAnim({
duration: 1000,
easing: t => t,
action: (v,t) => {
data.setScaleX(data.getScaleX() + (1 - data.getScaleX()) * v);
}
});
} // 面板隐藏
hidePanel(data) {
ht.Default.startAnim({
duration: 1000,
easing: t => t,
action: (v,t) => {
data.setScaleX(data.getScaleX() + (0 - data.getScaleX()) * v);
}
});
}

elevatorAnimation(data) {
const g3d = this.g3d;
const tag = data.getTag();
const e = data.getElevation();
const label = data.getChildAt(0);
// 判断现在所处楼层
let now = Math.ceil(e / 50);
// 下一层楼层取1~7随机数
let next = randomNumber(1, 7);
// 根据现在的楼层和下一个楼层,判断电梯运行的范围
let range = numBetween(now, next);
this.animationElevatorMap[tag] = ht.Default.startAnim({
duration: range * 800,
easing: t => t,
action: (v, t) => {
// 电梯运行位置设定
data.setElevation(now < next ? (e + (range * 50) * v) : (e - (range * 50) * v));
// 设置电梯楼层面板显示并根据电梯位置设定
if (!label) return;
const floor = Math.ceil(data.getElevation() / 50);
if (floor === label.a('text')) return;
label.a('text', floor);
// 手动刷新电梯面板信息
g3d.invalidateShape3dCachedImage(label);
},
finishFunc: () => {
// 销毁电梯间隔动画
delete this.timeoutElevatorMap[tag];
// 执行电梯间隔动画后回调电梯运行动画
this.timeoutElevatorMap[tag] = setTimeout(() => {
this.elevatorAnimation1(data);
}, Math.floor(Math.random() * 5000) + 2000);
}
});
}

park(car, key = 'Path', finishFunc) {
const dm = car.dm();
const tag = car.getTag();
const forwardPath = dm.getDataByTag(tag + '_forward' + key);
const backwardPath = dm.getDataByTag(tag + '_backward' + key);
this.animationMap[tag] = move(car, forwardPath, 'forward', undefined, 24, {
pathEndFunc: () => {
this.animationMap[tag].stop();
this.animationMap[tag] = move(car, backwardPath, 'backward', undefined, undefined, {
pathEndFunc: () => {
this.animationMap[tag].stop();
delete this.animationMap[tag];
if (finishFunc) finishFunc();
return true;
}
});
return true;
}
});
}
move 是节点沿着路径平滑移动的封装函数,主要参数为:
- node:动画节点;
- path:运行路径;
- direction:节点朝向 forward | backward;
- animParams:动画参数;
通过绘制一条运行路线的管道,ht.Default.getLineCacheInfo() 得到这条管道的点位和分割信息 cache,然后管道信息通过 ht.Default.getLineLength() 得到管道的长度,并且通过 ht.Default.getLineOffset() 来获取连线或者管道指定比例的偏移信息,从而达到移动的效果,注意的是,这里还设定了 direction 来规定动画节点的朝向,主要是为了通过 node.lookAtX() 来获取节点下一个面对的朝向的位置信息,并设置节点此时的位置,从而达到节点沿着路径平滑移动的效果。
move(node, path, direction, step = 6, interval = 75, animParams) {
let cache = path.__cache__;
if (!cache)
cache = path.__cache__ = ht.Default.getLineCacheInfo(path.getPoints(), path.getSegments());
const len = ht.Default.getLineLength(cache);
animParams = animParams || {};
const face = direction === 'forward' ? 'front' : direction === 'backward' ? 'back' : direction;
let currentLen = 0;
const pathEndFunc = animParams.pathEndFunc;
const action = animParams.action;
animParams.action = (v, t) => {
if (currentLen >= len) {
// 档 pathEndFunc 返回 true 是,认为是要结束动画, 不执行后面档 action
if (pathEndFunc && pathEndFunc())
return;
}
currentLen = currentLen % len;
const offset = ht.Default.getLineOffset(cache, currentLen);
const point = offset.point;
node.lookAtX([point.x, node.getElevation(), point.z], face);
node.p3(point.x, node.getElevation(), point.z);
currentLen = currentLen + step;
if (action) action();
};
return loop(animParams.action, interval);
}
与此同时,我们还可以看到车辆行驶到车位或者离开时,车位上方的红绿灯则表示着这个车位的停放信息,是根据车辆的情况实时设定车位的状况,通过改变其信号灯 image 的 json 图标并手动刷新缓存来实现的。而缓存机制对于整体场景的流畅度是至关重要的,对于一些不必要实时刷新的面板信息,我们可以采取缓存的方式,并且在下一次更新的时候调用 Graph3dView.invalidateShape3dCachedImage(node)来手动刷新这个节点,从而大大提高了场景的性能,有关 3D 面板的属性可以参考 <HT 的 3D 手册 billboard 公告板>。
updateLight(view, light, color) {
light.s('shape3d.image', 'symbols/parking/' + color + 'Light.json');
view.invalidateShape3dCachedImage(light);
}

基于 HTML5 WebGL 的楼宇智能化集成系统(三)的更多相关文章
- 基于 HTML5 WebGL 的楼宇智能化集成系统(一)
前言 随着现代通信技术.计算机技术.控制技术的飞速发展,智能建筑已经成为现代建筑发展的主流.智能建筑是以建筑物为平台,兼备信息设施系统.信息化应用系统.建筑设备管理系统.公共安全系统等.集 ...
- 基于 HTML5 WebGL 的楼宇智能化集成系统(二)
前言 一套完整的可视化操作交互上,必不可少 2D/3D 的融合,在上期我们介绍了有关 3D 场景的环视漫游.巡视漫游以及动画效果,还包括了冷站场景.热站场景以及智慧末端的实现原理,本期主要 ...
- 基于 HTML5 + WebGL 实现 3D 挖掘机系统
前言 在工业互联网以及物联网的影响下,人们对于机械的管理,机械的可视化,机械的操作可视化提出了更高的要求.如何在一个系统中完整的显示机械的运行情况,机械的运行轨迹,或者机械的机械动作显得尤为的重要,因 ...
- 基于 HTML5 WebGL 的 CPU 监控系统
前言 科技改变生活,科技的发展带来了生活方式的巨大改变.随着通信技术的不断演进,5G 技术应运而生,随时随地万物互联的时代已经来临.5G 技术不仅带来了更快的连接速度和前所未有的用户体验,也为制造业, ...
- 基于 HTML5 + WebGL 的 3D 太阳系系统
前言 近年来随着引力波的发现.黑洞照片的拍摄.火星上存在水的证据发现等科学上的突破,以及文学影视作品中诸如<三体>.<流浪地球>.<星际穿越>等的传播普及,宇宙空间 ...
- 基于 HTML5 WebGL 的医疗物流系统
前言 物联网( IoT ),简单的理解就是物体之间通过互联网进行链接.世界上的万事万物,都可以通过数据的改变进行智能化管理.ioT 的兴起在医疗行业中具有拯救生命的潜在作用.不断的收集用户信息并且实时 ...
- 基于 HTML5 + WebGL 实现的垃圾分类系统
前言 垃圾分类,一般是指按一定规定或标准将垃圾分类储存.分类投放和分类搬运,从而转变成公共资源的一系列活动的总称.分类的目的是提高垃圾的资源价值和经济价值,力争物尽其用.垃圾在分类储存阶段属于公众的私 ...
- 基于 HTML5 WebGL 的地铁站 3D 可视化系统
前言 工业互联网,物联网,可视化等名词在我们现在信息化的大背景下已经是耳熟能详,日常生活的交通,出行,吃穿等可能都可以用信息化的方式来为我们表达,在传统的可视化监控领域,一般都是基于 Web SCAD ...
- 基于 HTML5 + WebGL 实现 3D 可视化地铁系统
前言 工业互联网,物联网,可视化等名词在我们现在信息化的大背景下已经是耳熟能详,日常生活的交通,出行,吃穿等可能都可以用信息化的方式来为我们表达,在传统的可视化监控领域,一般都是基于 Web SCAD ...
随机推荐
- webStorm -> Version Control _> Repository -> Filter By User 查看svn日志
webStorm -> Version Control _> Repository -> Filter By User 查看svn日志
- 适用于 macOS 下 2K 显示器开启 HiDPI 的简便解决方案
前阵子入手了一款2k的显示器用于mbp的拓展屏幕,但由于苹果系统的严格限制,只有在4K及以上显示器上才能开启自带的HiDPI进行缩放以达到retina显示屏的效果.2k显示器下的字体会偏小发虚,使用1 ...
- 会话(cookie的使用,路径和Session的工作原理,使用)
1.状态管理----Cookie 1.1 为什么需要状态管理 HTTP协议是无状态的,不能保存每次提交的信息,即当服务器返回与请求相对应的应答之后,这次事务的所有信息就丢掉了. 如果用户发来一个新的请 ...
- 记录一次线上bug
记录一次线上bug,总的来说就是弱网和重复点击.特殊值校验的问题. 测试场景一: 在3g网络或者使页面加载速度需要两秒左右的时候,输入学号,提交学生的缴费项目,提交完一个 学生的缴费后, ...
- [状态压缩,折半搜索] 2019牛客暑期多校训练营(第九场)Knapsack Cryptosystem
链接:https://ac.nowcoder.com/acm/contest/889/D来源:牛客网 时间限制:C/C++ 2秒,其他语言4秒 空间限制:C/C++ 262144K,其他语言52428 ...
- C# 录音和播放录音-NAudio
在使用C#进行录音和播放录音功能上,使用NAudio是个不错的选择. NAudio是个开源,相对功能比较全面的类库,它包含录音.播放录音.格式转换.混音调整等操作,具体可以去Github上看看介绍和源 ...
- Attention-based Extraction of Structured Information from Street View Imagery:基于注意力的街景图像提取结构化信息
基于注意力的街景图像提取结构化信息 一种用于真实图像文本提取问题的TensorFlow模型. 该文件夹包含在FSNS数据集数据集上训练新的注意OCR模型所需的代码,以在法国转录街道名称. 您还可以使用 ...
- HDU - 1166 树状数组模板(线段树也写了一遍)
题意: 汉语题就不说题意了,用到单点修改和区间查询(树状数组和线段树都可以) 思路: 树状数组的单点查询,单点修改和区间查询. 树状数组是巧妙运用二进制的规律建树,建树就相当于单点修改.这里面用到一个 ...
- Servlet读取前端的request payload
这几天遇见了一个很头疼的事,当我想用表单上传文件时,后端servlet读取不到文件的信息 网上搜索,说是要将form添加这个属性enctype="multipart/form-data&qu ...
- ——JAVA基础部分
1. 我们能不能声明main()方法为非静态?√ 不能,main()方法必须声明为静态的,这样JVM才可以调用main()方法而无需实例化它的类. 如果从main()方法去掉“static”这个声明, ...