前言

随着现代通信技术、计算机技术、控制技术的飞速发展,智能建筑已经成为现代建筑发展的主流。智能建筑是以建筑物为平台,兼备信息设施系统、信息化应用系统、建筑设备管理系统、公共安全系统等。集结构、系统、服务、管理及其优化组合为一体,向人们提供一个安全、高效、便携、节能、环保、健康的建筑环境。

IBMS(Intelligent Building Management System),即智能化集成系统,是指在 BAS 的基础上更进一步的与通信网络系统、信息网络系统实现更高一层的建筑集成管理系统。在信息化时代的今天,诸多建筑与集成的管理系统融合,生成了一套高效的智慧建筑集成解决方案。IBMS 更多突出的是管理方面的功能,即如何的全面实现优化控制和管理,节能降耗、高效、舒适、环境安全这样一个目的,可以这样说,判断一个建筑物是否具有智能建筑特点,要看它是否具有 IBMS 的系统集成。这是很重要的判定条件。另一个重要的前提是,在做好这项工程的同时不要忽视了同步建设的信息化工程。一个成功的 IBMS 系统集成会在诸多的管理方面能发挥其显著的经济优势。

传统的 智慧楼宇/楼宇自动化/楼宇安防/智慧园区 常会采用 BIM(建筑信息模型 Building information modeling)软件,如 Autodesk 的 Revit 或 Bentley 这类建筑和工程软件,但这些 BIM 建模模型的数据往往过于庞大臃肿,绝大部分细节信息对楼宇自控意义不大,反而影响拖累了行业 Web SCADA 或 Web 组态监控的趋势,所以我们采用以HightopoHT for Web产品轻量化 HTML5/WebGL 建模的方案,实现快速建模、运行时轻量化到甚至手机终端浏览器即可 3D 可视化运维的良好效果。

本系列文章为了帮助用户更直观友好的浏览当前的楼宇智控系统,分成了三个小节来介绍场景以及效果实现的运用:

1、冷站热站,**中央空调末端智慧群控系统 **以及 3D 动画效果以及切换漫游;

2、面板组件动画效果和 **楼层监控系统 **视频的引入;

3、智慧楼宇管理系统、**电梯监控系统 **以及 停车场管理系统

界面简介及效果预览

界面初始化及漫游效果

场景在加载的时候会读取模型信息,确认模型加载完毕后才开始执行动画效果,然后通过场景的漫游效果,可以直观地去巡视整座大楼建筑的场景信息。

冷站场景效果:优化冷水机组效率,按需供给

在智慧楼宇的中央空调冷热源系统中,冷站场景分有冷却水系统、冷水机组以及冷冻水系统所组成。冷却水系统的作用是为冷水机组的冷凝器提供冷却水,吸收制冷剂的冷凝热量,并将冷凝热量转移到大气中去。冷冻水系统的作用是为冷水机组的蒸发器提供的冷量通过冷冻水输送到各类冷水用户。

热站场景效果:优化热泵机组效率,按需供给

在智慧楼宇的中央空调冷热源系统中,热站场景分有冷却机组系统和热水泵系统所组成。通过冷却机组系统的换热器不断加热了中央空调系统内的空调水,并通过热水循环中的热水泵系统进行循环给用户提供热量。

中央空调末端智慧群控系统场景效果:灵活对应多样智能调节空间

在智慧楼宇的中央空调冷热源系统中,末端智能节能控制系统,通过室内温湿度可以进行模块内部的调节送风温度,水阀开度及风机频率,在保证末端舒适度的前提下,使供冷量与需求相匹配,最大限度地降低风机能耗。

智慧楼宇管理系统优化效果

主要包括冷站、热站和中央末端智慧群控的联合作用,以及楼层智慧照明,通过清晰的动画体现出整栋大楼智慧节能运作的流程,可以通过面板详情的演示细致地介绍每个场景的作用以及串联的用处。

电梯以及楼层监控效果

可视化地实时监控电梯在楼层间的工作运行状态,并且能够准确地浏览每个电梯内的实时监控画面。

停车场管理系统监控效果

停车场作为现在楼宇监控不可缺失的一环,这里主要可以体现出实时的车位监控,通过简单的动画演示来表现出整个停车场车辆的运行状态,方便管理。

代码实现

一、场景搭建

界面通过 2D 图纸叠加在3D 场景上来实现 2D 界面 与 3D 场景的融合,2D 界面通过自动布局的机制实现了手机端与电脑端的响应式呈现。

通过 2D 视图的组件ht.graph.**GraphView 和 3D 视图的组件ht.graph3d.****Graph3dView**创建出呈现 2D 视图的组件类 g2d 以及呈现 3D 视图的组件类 g3d,在分别获取各自的数据模型 DataModel,来对图纸场景做一些数据可视化的操作,这里值得一提的是,我对于 2D 界面和 3D 场景的融合,是通过把 getView() 获取到 g3d 拓扑组件的根层 div,然后 addToDOM() 将 g2d 组件加入到指定的 DOM 元素底下。

可以通过<HT的入门手册>了解到更多视图与数据模型之间的内容。

// 创建二维拓扑视图
this.g2d = new ht.graph.GraphView(); this.g2dDm = this.g2d.dm(); // 创建三维拓扑视图
this.g3d = new ht.graph3d.Graph3dView(); this.g3dDm = this.g3d.dm(); // 将二维图纸嵌入到三维场景中
this.g2d.addToDOM(this.g3d.getView()); // 修改左右键交互方式
let mapInteractor = new ht.graph3d.MapInteractor(this.g3d); this.g3d.setInteractors([mapInteractor]); // 修改最大仰角为 PI / 2
mapInteractor.maxPhi = Math.PI / 2;const G = {};
window.G = G; // 事件派发
G.event = new ht.Notifier();

3D 场景加载主视图为:


首先我搭建了一个 3D 的场景用来放置我们的 json 场景数据,利用ht.Default.xhrLoad函数解析 json 场景数据,并通过 deserialize 将反序列化的对象加入DataModel来显示加载 3D 场景,有兴趣的可以通过<HT的序列化手册>来了解这一机制的实现。

ht.Default.xhrLoad('scenes/demo.json', (json) => {if (!json) return;g3dDm.deserialize(json);// 设置三维视图的中心点和相机位置g3d.setCenter([-342, -64, 389]);g3d.setEye([-355, 10833, 2642]);// 设置最远距离g3d.setFar(1000000);// 获取球图标,设置为天空球let skybox = g3dDm.getDataByTag('skyBox');g3d.setSkyBox(skybox);// 模型加载完后执行动画const modelList = [];g3dDm.each(d => {const shape3d = d.s('shape3d');if (!shape3d || !shape3d.endsWith('.json')) return;if (ht.Default.getShape3dModel(shape3d)) return;modelList.push(shape3d);});ht.Default.handleModelLoaded = (name, model) => {const index = modelList.indexOf(name);if (index < 0) return;modelList.splice(index, 1);if (modelList.length > 91) return;ht.Default.handleModelLoaded = () => {};// 模型加载完侯,默认执行场景切换动画g3d.moveCamera([257, 713, 1485], [7, 40, 144], {duration: 2000,finishFunc: () => {this.load2D();}});};
});

2D 面板加载视图为:

同样,我搭建了一个 2D 的场景用来放置我们的 json 矢量图,利用ht.Default.xhrLoad函数将 json 矢量背景图反序列化显示在 2D 面板数据。

ht.Default.xhrLoad('displays/demo.json', (json) => { if (!json) return;g2dDm.deserialize(json); // 面板动画入口this.tittleAnim(); this.panelTime(); // 2D图纸加载完后执行事件处理this.loaded2DHandler();
});

二、3D 动画效果以及切换漫游

对于 3D 建模下的楼宇建筑,加上场景的全方位漫游,可使用户达到一种沉浸式的体验,更加直观地去感受这个楼宇下各个场景的联系,依次地介绍了冷站、智慧末端以及热站的位置以及功能运作的动画 。主要运用的方法是通过借助HT提供的ht.Shape图元类型,可以在GraphViewGraph3dView组件上展示出各种二维和三维的形状效果,而漫游的管道路线就是由其扩展子类ht.Polyline去绘制实现一条三维的管道,然后用这条绘制的管道加上漫游的时间去调用这个漫游的方法,其本质上是围绕着中心点,然后根据管道去不断地改变视角下的eyecenter的数值,达到环视这个建筑的整体视角。

这里可以了解一下关于空间轨道的绘制,详见<HT的形状手册>的空间管线章节。

以下是环视漫游动画的伪代码:

polyLineRoam(polyLine, time) {const g3d = this.g3d;const g3dDm = this.g3dDm;this.roamButton.a('active', true);this.roamAnim = ht.Default.startAnim({duration: time,easing: t => t,action: (v, t) => {let length = this.main.g3d.getLineLength(polyLine),offset = this.main.g3d.getLineOffset(polyLine, length * v),point = offset.point,px = point.x,py = point.y,pz = point.z;g3d.setEye(px, py, pz);g3d.setCenter(7, 40, 144);},finishFunc: () => {this.roam1();}});
}
  在整体建筑的环视漫游完后,我们可以通过拉近各个场景的视角,来依次巡视各个场景所执行的动画。在根据管道改变**eye**和**center**环视漫游方法结束后,用动画的结束回调**finishFunc**去调用下一个动画的执行,而巡视漫游就在这里去调用,以下我们以巡视冷站的漫游动画为例去介绍实现的方法。

巡视漫游的主要实现方法是通过HT核心包的相机移动moveCamera来实现的, 通过参数 (eye, center, animation) 来调用这个方法:

  • eye:新的相机位置,形如[-291, -8, 283],如果为 null 则使用当前相机的位置;

  • center:新的目标中心点位置(相机看向的位置),形如[148, -400, 171],如果为 null 则使用当前中心点位置;

  • animation:默认 false,是否启用动画,可以设置为 true 或者 flase 或者 animation 动画对象;

    每次执行完一个场景的视角移动后,再通过相机移动动画的结束回调 finishFunc 调用下一个相机移动的动画,达到巡视漫游的效果。

// 切换到冷站视角
roam1() {const g3d = this.g3d;const g3dDm = this.g3dDm;this.roamAnim = g3d.moveCamera([-291, -8, 283], [148, -400, 171], {duration: 500,easing: t => t * t,finishFunc: () => {this.roam2();}});
}

在环视漫游和巡视漫游的执行下,我们也可以触发 2D 图纸右面板下的按钮面板去观看我们想要浏览的指定场景,这时候就会关闭当前在执行的环视漫游或者巡视漫游,再次点击改按钮则返回场景的主视角,或者点击左上角漫游按钮又可以进入环视漫游,这样的交互体验,可以方便用户即使地查看想要浏览的场景,而不用依靠等待逐一漫游下去查看,也不会干扰到漫游的整体体验。相应地通过介绍冷站按钮的点击触发介绍一下实现的方法。

一般的交互方式存在三种事件交互的方法,包括事件通知管理器 ht.Notifier类,内置的 Interator在交互过程会派发出事件和数据绑定的监听来实现,而这里使用的是第三种交互方式。

通过数据绑定监听到 onDown 执行按下的事件后,通过改变按下和再次按下的按钮状态 active 来分别执行相机移动去切换视角,主要实现的伪代码如下:

// 设置图元可交互
this.coolingCentralStationButton.s('interactive', true);
// 通过数据绑定监听到onDown执行按下的事件
this.coolingCentralStationButton.s('onDown', () => {
// 切换到冷站时,2d面板所执行的切换动画
this.switchToColdStation();
// 按钮初始化
this.buttonTearDown();
// 按钮按下效果的状态let active = this.coolingCentralStationButton.a('active');// button为按钮集合数组,当按下电梯按钮,其他按钮默认falsebutton.forEach(btn => {btn.a('active', false);});// 冷站按钮的状态切换this.coolingCentralStationButton.a('active', !active);// 根据冷站按钮的状态执行切换到冷站或者切换回主视角if (active) {// 相机移动切换到主视角moveCamera(g3d, [257, 713, 1485], [7, 40, 144], {duration: 2000,easing: t => t * t});} else {// 漫游动画对象如果不为空,则暂停漫游动画对象并且设置为空if (this.roamAnim !== null) {this.roamAnim.pause();this.roamAnim = null;}// 相机移动切换到冷站视角coolingCentralStationAnimation = moveCamera(g3d, [-291, -8, 283], [148, -400, 171], {duration: 2000,easing: t => t * t});}
});

当然,在 3D 场景下还有一些很有趣的动画效果,比如车流效果、飞光效果和圆环扩散效果。车流效果主要通过采用了贴图的 uv 的偏移来实现达到车流穿梭的科技感效果;而飞光效果则是采用调度动画的方法来间隔设置飞光的高度,达到最高点则消失然后重新轮回动画展示;圆环扩散效果则是同样采用调度动画的方法来间隔设置圆环的缩放值和透明度,来达到扩散消失的效果。

对于间隔的调度动画,为了实现动画的流畅性,这里调度使用的 loop 是运用到自己封装HT的动画ht.Default.startAnim的一个方法:

  • **frames **动画帧数,这里不锁定帧数,可以适应本身动画的帧数;
  • **interval **动画间隔,单位ms,默认设置20ms。
loop(action, interval = 20) { return ht.Default.startAnim({frames: Infinity,interval: interval,action: action});
}

然后通过调用这个 loop 的间隔动画方法,我们来实现车流效果、飞光效果和圆环扩散效果,实现的参考伪代码如下:

// 车流图元的初始化
let traffic = g3dDm.getDataByTag('traffic');
// 圆环扩散图元的初始化
let lightRing = this.lightRing = g3dDm.getDataByTag('lightRing');
// 飞光图元设置三种透明状态数组集合flyMap的初始化
[1, 2, 3].forEach(i => {const data = flyMap['fly' + i] = g3dDm.getDataByTag('fly' + i);data.eachChild(d => {d.s({// 打开透明度'shape3d.transparent': true,// 根据不同的数组集合设置不同的透明度'shape3d.opacity': i === 3 ? 0.5 : 0.7,// 设置沿着y轴自动旋转'shape3d.autorotate': 'y'});});
});if (this.flyAnim) return;
this.flyAnim = loop(() => {// 飞光根据间隔设置高度来达到上升的效果for (let k in flyMap) {const data = flyMap[k];let e = data.getElevation() + flyDltMap[k];if (e >= 500) e = -400;data.setElevation(e);}// 车流根据设置间隔增长uv偏移量来实现穿梭的效果traffic.eachChild(c => {c.s('all.uv.offset', [location, 0]);});location -= 0.03;// 旋转震荡波透明度渐降let percent = lightRing.a('percent') || 0,scale = 15 * percent + 0.5;lightRing.setScale3d([scale + 1, scale, scale + 1]);lightRing.s('shape3d.opacity', (1 - percent) * 0.5);percent += 0.01;if (percent >= 1) {percent = 0;}lightRing.a('percent', percent);
}, 50);

三、冷站场景和热站场景的动画实现

场景动画中机组的风扇、集水器的蓄满以及水的流动效果:

动画的实现主要还是通过HT自带的ht.Default.startAnim 动画函数,支持 Frame-Based 和 Time-Based 两种方式的动画。同样的,我们这里使用的是 Frame-Based 来封装一个 loop 函数来执行每一帧间隔的动画。

一般来说,动画可通过自行配置来达到自己想要实现的方法,这里可以了解< HT 的入门手册>关于动画函数的介绍。

if (this.stationAnim) return;
this.stationAnim = loop(() => {// 冷站水管流动coldFlow_blue.eachChild(c => {c.s('shape3d.uv.offset', [-location, 0]);});coldFlow_yellow.eachChild(c => {c.s('shape3d.uv.offset', [location, 0]);});// 热站水管流动heatFlow_blue.eachChild(c => {c.s('shape3d.uv.offset', [-location, 0]);});heatFlow_yellow.eachChild(c => {c.s('shape3d.uv.offset', [location, 0]);});location -= 0.03;// 冷站风扇旋转cold_fan.eachChild(c => {c.setRotation3d(c.r3()[0], c.r3()[1] + (Math.PI / 10), c.r3()[2]);});// 热站风扇旋转heat_fan.eachChild(c => {c.setRotation3d(c.r3()[0], c.r3()[1] + (Math.PI / 10), c.r3()[2]);});// 集水器水位变化HotWaterTankTall += 0.25;if (HotWaterTankTall > 15) {HotWaterTankTall = 0;}coldWaterTankTall1 += 0.25;if (coldWaterTankTall1 > 20) {coldWaterTankTall1 = 0;}coldWaterTankTall2 += 0.25;if (coldWaterTankTall2 > 20) {coldWaterTankTall2 = 0;}hotWaterTank.setTall(HotWaterTankTall);coldWaterTank1.setTall(coldWaterTankTall1);coldWaterTank2.setTall(coldWaterTankTall2);
}, 50);

四、中央空调末端智慧群控系统场景效果

这里采用了模拟数据的方式来体现末端智能节能控制的效果。应用于真实项目的时候,可以采用数据接口的方式来实时对接真实数据,可以达到实时监控的效果。

我使用了自己 mock 的末端群控的数据参数,格式如下:

var boxData = [[{ // 设备编号id: 'box1', // 设备的温度temperature: 23.8, // 设备的频率frequency: 45.8 }, ...]...];

这里的实现也是通过 loop 循环执行数据的读取,当数组指标 index 读取到最后一个数据时,立即关闭循环并清空 loop调度。

boxAnimation = loop(() => {for (let i = 0, l = 16; i <= l-1; i++) {let roomTag, roomBox, tag;tag = i+1;roomTag = 'boxPanel' + tag;roomBox = 'box' + tag;let panel = g3dDm.getDataByTag(roomTag);let box = g3dDm.getDataByTag(roomBox);if (panel) {panel.a('valueT', boxData[index][i].temperature + '℃');panel.a('valueK', boxData[index][i].frequency + 'Hz');// 手动更新缓存的面板信息g3d.invalidateShape3dCachedImage(panel);// 根据温度判断设备的颜色if (box && parseFloat(panel.a('valueT')) < 26) {box.s('shape3d.blend', 'rgb(4,67,176)');box.s('wf.color', 'rgb(4,67,176)');} else if (box && parseFloat(panel.a('valueT')) >= 26 && parseFloat(panel.a('valueT')) <= 28) {box.s('shape3d.blend', 'rgb(28,189,87)');box.s('wf.color', 'rgb(28,189,87)');} else if (box && parseFloat(panel.a('valueT')) > 28) {box.s('shape3d.blend', 'rgb(181,43,43)');box.s('wf.color', 'rgb(181,43,43)');}}}index++;if (index >= 10) {boxAnimation.pause();boxAnimation = null;}}, 500);

总结

IBMS 智能化集成系统管理对于建筑园区管理的重要性日趋上升,在信息时代里不仅可以很好地体现出信息数据管理的明确性,也体现了智慧管理的便利有效性。通过 3D 场景楼宇园区的动画加上环视漫游和巡视漫游的配合,充分体现了 3D 场景的拟真优点,但是如何实现场景动画的触发实现呢?这里当然必不可少了 2D 面板上的交互和动画,在下期我们会为大家介绍一些 2D 面板的交互和动画实现,带您解读不一样的 2D/3D 融合。

2019 我们也更新了数百个工业互联网 2D/3D 可视化案例集,在这里你能发现许多新奇的实例,也能发掘出不一样的工业互联网:https://mp.weixin.qq.com/s/ZbhB6LO2kBRPrRIfHlKGQA

同时,你也可以查看更多案例及效果:https://www.hightopo.com/demos/index.html

基于 HTML5 WebGL 的楼宇智能化集成系统(一)相关推荐

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

    前言 2018年7月,信息化部印发了<工业互联网平台建设及推广指南>和<工业互联网平台评价方法>,掀起了 工业互联网 的浪潮,并成为热词写入了报告中.同为信息发展下的产物 建筑 ...

  2. 基于 HTML5 WebGL 的 CPU 监控系统

    前言 科技改变生活,科技的发展带来了生活方式的巨大改变.随着通信技术的不断演进,5G 技术应运而生,随时随地万物互联的时代已经来临.5G 技术不仅带来了更快的连接速度和前所未有的用户体验,也为制造业, ...

  3. 基于 HTML5 WebGL 的虚拟现实可视化培训系统

    前言 2019 年 VR, AR, XR, 5G, 工业互联网等名词频繁出现在我们的视野中,信息的分享与虚实的结合已经成为大势所趋,5G 是新一代信息通信技术升级的重要方向,工业互联网是制造业转型升级 ...

  4. 基于 HTML5 WebGL 的计量站三维可视化监控系统 Web 组态工控应用

    前言 得益于 HTML5 WebGL 技术的成熟,从技术上对工控管理的可视化,数据可视化变得简单易行!完成对工控设备的管理效率,资源管理,风险管理等的大幅度提高,同时也对国家工业4.0计划作出有力响应 ...

  5. 基于 HTML5 WebGL + WebVR 的 3D 虚实现实可视化培训系统

    前言 2019 年 VR, AR, XR, 5G, 工业互联网等名词频繁出现在我们的视野中,信息的分享与虚实的结合已经成为大势所趋,5G 是新一代信息通信技术升级的重要方向,工业互联网是制造业转型升级 ...

  6. 基于 HTML5 WebGL 的发动机 3D 可视化系统

    前言 工业机械产品大多体积庞大.运输成本高,在参加行业展会或向海外客户销售时,如果没有实物展示,仅凭静态.简单的图片说明书介绍,无法让客户全面了解产品,不仅工作人员制作麻烦,客户看得也费力.如果能在 ...

  7. c#web页面显示弹窗_基于 HTML5 WebGL 的 3D 风机 Web 组态工业互联网应用

    前言 在目前大数据时代背景之下,数据可视化的需求也变得越来越庞大,在数据可视化的背景之下,通过智能机器间的链接并最终将人机链接,结合软件和大数据分析的工业互联网也将变得越来越容易实现! 国家也敏锐意识 ...

  8. 基于 HTML5 WebGL 的加油站 3D 可视化监控

    前言 随着数字化,工业互联网,物联网的发展,我国加油站正向有人值守,无人操作,远程控制的方向发展,传统的人工巡查方式逐渐转变为以自动化控制为主的在线监控方式,即采用数据采集与监控系统 SCADA.SC ...

  9. OpenGL,WebGL基于HTML5/WebGL的建模及构建3D场景

    一.OpenGL和WebGL WebGL基于OpenGL ES,它缺少常规OpenGL具有的许多功能,例如仅支持顶点和片段着色器.OpenGL具有WebGL所不具备的功能,例如几何体着色器,镶嵌细分着 ...

最新文章

  1. 在LINUX终端和VIM下复制粘贴
  2. 关于地图中轨迹的平滑移动的实现
  3. 利用反射,泛型,静态方法快速获取表单值到Model。
  4. SAP错误问题汇总(转)
  5. 从夫妻吵架中看项目管理
  6. 理解分布式id生成算法--雪花算法(SnowFlake)
  7. com词根词缀_背单词想过目不忘?看这篇文章学会用“词缀”记单词
  8. 实用常识 | HTML嵌入处理MARKDOWN合并单元格
  9. [Silverlight入门系列]用TransformToVisual和Transform取得元素绝对位置(Location)
  10. C# 客户端PDF文件打印方法大全
  11. 借了你的爱,用我一辈子来还
  12. python自然语言处理答案_《用Python进行自然语言处理》 第一章练习题答案
  13. jsp:include和%@include file=%有什么区别
  14. java游戏源码合集,已整理成文档
  15. 【动态规划】HDU 1081 XMU 1031 To the Max
  16. 蓝桥杯练习题之十六进制转八进制
  17. JAVA 类的继承(私有属性、自动转型)(入门级小白一看就懂)
  18. CosFace:Large Margin Cosine Loss
  19. 如何开启Chrome内核浏览器(360极速版、QQ、UC)的多线程下载模式来提高浏览器的下载速度?
  20. vue echarts使用教程

热门文章

  1. 怎样用你自己的邮箱号登陆MSN?
  2. 中移物联网JAVA开发工程师一面
  3. DMU-单性状动物模型-学习笔记2
  4. 连载 大学生求职七大昏招 二 说谎 1
  5. 以产业区块链提升数字化转型质量
  6. 调试AVIN后视注册消息BUG改正记录保存
  7. java at发短信_Java开发网 - 通过at指令怎样发送短信????
  8. html 语音识别输入法,从游戏语音输入说起:语音识别如何引领输入法变局
  9. 配置核心交换机到交换机的链路聚合实现主机虚拟机多网段地址(实操)
  10. 薄膜太阳能电池板模块市场现状及未来发展趋势