前言

智能城市是一个系统。也称为网络城市、数字化城市、信息城市。

智能城市建设是一个系统工程:首先实现的是城市管理智能化,由智能城市管理系统辅助管理城市,通过管理系统人们可以监视城市的运行,了解城市每天中发生的变化,以及及时的根据这些变化做出相应的管理;其次是包括智能交通、智能电力、智能安全等基础设施的智能化,交通是一个城市的驱动,交通的畅通加速了城市的发展,通过 Web 可视化的交通管理,可以更及时的了解交通情况,做出处理;智能城市也包括智能医疗、智能家庭、智能教育等社会智能化和智能企业、智能银行、智能商店的生产智能化,从而全面提升城市生产、管理、运行的现代化水平。

本 demo 使用 HT for Web 产品轻量化 HTML5/WebGL 建模的方案,构建了城市建筑群场景,添加了城市道路,实现了智能城市 Web 可视化,还通过动画模拟了城市的运行。

demo 地址:http://www.hightopo.com/demo/intelligent-city/entry/dest/index.html

预览图:

代码实现

加载场景

首先新建一个场景,并将场景添加到页面中。

let dm = this.dm = new ht.DataModel();
let entryG3d = this.entryG3d = new ht.graph3d.Graph3dView(dm);
entryG3d.addToDOM(); // 将场景添加到页面中

HT 的组件一般都会嵌入 BorderPane、SplitView 和 TabView 容器中使用,而最外层的 HT 组件则需要用户手工将 getView() 返回的底层 div 元素添加到页面的 DOM 元素中,这里需要注意的是,当父容器大小变化时,如果父容器是 BorderPane 和 SplitView 等这些 HT 预定义的容器组件,则 HT 的容器会自动递归调用孩子组件 invalidate 函数通知更新。但如果父容器是原生的 html 元素, 则 HT 组件无法获知需要更新,因此最外层的 HT 组件一般需要监听 window的窗口大小变化事件,调用最外层组件 invalidate 函数进行更新。

为了最外层组件加载填充满窗口的方便性,HT 的所有组件都有 addToDOM 函数,其实现逻辑如下,其中 iv 是 invalidate 的简写:

addToDOM = function(){
var self = this,
view = self.getView(), // 获取组件 div
style = view.style;
document.body.appendChild(view); // 将组件添加到文档对象中
style.left = '0';
style.right = '0';
style.top = '0';
style.bottom = '0';
window.addEventListener('resize', function () { self.iv(); }, false); // 监听窗口变化,刷新组件
}

接下来反序列化城市场景 json。

ht.Default.xhrLoad('scenes/园区/城市demo.json', (text) => {
let json = ht.Default.parse(text); // 还原 json 字符串
let scene = json.scene; // 获取 json 中设置的投影参数
entryG3d.setEye(scene.eye); // 设置视角
entryG3d.setCenter(scene.center); // 设置目标中心点
entryG3d.setFar(scene.far); // 设置远端截面位置
entryG3d.setNear(scene.near); // 设置近端截面位置
dm.deserialize(text); // 场景反序列化
this.setSkyBox(entryG3d); // 设置天空球
this.initentryG3dEvent(); // 添加场景监听事件
this.startAnimate(); // 启动城市动画
this.startCarAnimate(['car1Line'], dm.getDataByTag('car1')); // 启动消防小车1动画
this.startCarAnimate(['car2Line'], dm.getDataByTag('car2')); // 启动消防小车2动画
});

场景渲染

1. 环境光贴图:将贴图影像渲染在场景中,通过 node.s('envmap', 0.5) 来设置节点的渲染程度,主要用于地板添加物体倒影效果,也可像本 demo 一样添加星光点缀。

dataModel.setEnvmap('环境光贴图.png'); // 贴图要求宽高像素为 2^n
node.s('envmap', 0.1);

对比图:

     

右图中环境光贴图为星光,城市中心区域有了蓝色的星空色,在 demo 中旋转场景也能看到明显的星光变化。

2. 辉光:本是指低压气体中气体放电的物理现象,用在 3D 场景中将亮色突出显示,呈现一种发光的效果,可控制辉光强度,辉光显示的范围和发光阀值。

g3d.enablePostProcessing('Bloom', true); // 开启辉光
module = g3d.getPostProcessingModule('Bloom');
module.strength = 0.18; // 强度
module.threshold = 0.62; // 阈值
module.radius = 0.4; //范围
g3d.iv(); // 刷新拓扑

对比图:

     

3. 景深:对场景中心周围的清晰程度的控制,将周围虚化,美化画面,突出主体,增强透视,可控制景深阀值(周围模糊范围程度)。

g3d.enablePostProcessing('Dof', true); // 开启景深
module = g3d.getPostProcessingModule('Dof');
module.aperture = 0.18; // 景深阀值
module.image= '景深贴图.png'; // 景深贴图
g3d.iv(); // 刷新拓扑

对比图:

     

可以看到右图中卫星区域和最左侧变得模糊。

4. 天空球:将场景模型放置在一个大的球体中,球体内部进行贴图,来模拟天空。

node = new ht.Node()
node.s({
'shape3d':'sphere', // 球体
'shape3d.image': 'earth' // 贴图路径
});
node.s3(10000, 10000, 10000);
g3d.dm().add(node);
g3d.setSkyBox(node); // 设置天空球

动画实现

加载后的城市场景如下图所示:

我们可以看到建筑物群有各自的数据展示面板,围绕着中心大楼有一个光圈列车模型,是模拟的城市中心列车,还有右边一个城市卫星,现在我们来让数据面板数据变化,让列车、卫星开始动起来。

动画的实现是用调度函数来实现的(调度手册),我们先了解一下调度函数的用法:

HT 中调度进行的流程是,先通过 dataModel 添加调度任务,dataModel 会在调度任务指定的时间间隔到达时, 遍历 dataModel 所有图元回调调度任务的 action 函数,可在该函数中对传入的 data 图元做相应的属性修改以达到动画效果。

dataModel.addScheduleTask(task) 添加调度任务,其中 task 为 json 对象,可指定如下属性:

  • interval:间隔毫秒数,默认值为10
  • enabled:是否启用开关,默认为 true
  • action:间隔动作函数,该函数必须设置

dataModel.removeScheduleTask(task) 删除调度任务,其中 task 为以前添加过的调度任务对象。

动画实现代码如下:

startAnimate() {
let dr = Math.PI / 180 * 2, PI2 = Math.PI * 2;
let dm = this.dm;
let rotateOval = dm.getDataByTag('rotateOval'); // 获取城市列车模型
let logo = dm.getDataByTag('logo'); // 获取城市卫星模型

   // 设置动画参数 
let roatateTask = this.roatateTask = {
interval: 100,
action: function(data){
if(data === rotateOval || data === logo){
data.setRotation((data.getRotation() - dr) % PI2);
}
}
};
dm.addScheduleTask(roatateTask); // 将动画加入到调度任务中

   // 获取建筑物数据面板
let dglsd = dm.getDataByTag('dglsd'); // 戴谷岭隧道
let xlsd = dm.getDataByTag('xlsd'); // 杏林隧道
let xmg = dm.getDataByTag('xmg'); // 厦门港
let jcglzx = dm.getDataByTag('jcglzx'); // 机场管理中心    // 模拟建筑物数据面板的动态展示
let valueChangeTask = this.valueChangeTask = {
interval: 1000,
action: function(data){
if(data === dglsd){
data.a('carHour', util.randomNumBetween(3000, 6000));
}
if(data === xlsd){
data.a('carHour', util.randomNumBetween(3000, 6000));
}
if(data === xmg){
data.a('ttl', util.randomNumBetween(3, 10));
data.a('zy', util.randomNumBetween(0, 100));
}
if(data === jcglzx){
data.a('sskll', util.randomNumBetween(500, 2000));
}
}
};
dm.addScheduleTask(valueChangeTask); // 将数据变化加入到调度任务中
}

实现的动画效果如下图:

demo 还模拟了消防车赶往火灾发生地,动画如下:

消防车的行驶用到了 ht.Default.startAnim,我们先来了解一下:

ht.Default.startAnim({
frames: 12, // 动画帧数
interval: 10, // 动画帧间隔毫秒数
easing: function(t){ return t * t; }, // 动画缓动函数,默认采用 ht.Default.animEasing
finishFunc: function(){ console.log('Done!') }, // 动画结束后调用的函数。
action: function(v, t){ // action函数必须提供,实现动画过程中的属性变化。
node.setPosition( // 此例子展示将节点`node`从位置`p1`动画到位置`p2`。
p1.x + (p2.x - p1.x) * v,
p1.y + (p2.y - p1.y) * v
);
}
});

以上为 Frame-Based 方式动画, 这种方式用户通过指定 frames 动画帧数,以及 interval 动画帧间隔参数控制动画效果。

ht.Default.startAnim({
duration: 500, // 动画周期毫秒数,默认采用`ht.Default.animDuration`
action: function(v, t){
...
}
});

以上为 Time-Based 方式动画,该方式用户只需要指定 duration 的动画周期的毫秒数即可,HT 将在指定的时间周期内完成动画。

由于 js 语言无法精确控制 interval 时间间隔, 采用 Frame-Based 不能精确控制动画时间周期,即使相同的 frames 和 interval 参数在不同的环境,可能会出现动画周期差异较大的问题, 因此 HT 默认采用 Time-based 的方式,如果不设置 duration 和 frames 参数,则 duration 参数将被系统自动设置为 ht.Default.animDuration 值。

消防车行驶实现代码如下:

startCarAnimate(polylineTagArr, airNode) { // 传入消防车行驶路线 tag(唯一标签)组和消防车模型节点
let dm = this.dm;
let entryG3d = this.entryG3d;
let curIndex = 0;
let polyline = dm.getDataByTag(polylineTagArr[curIndex]); // 获取消防路线 ht.PolyLine(http://www.hightopo.com/guide/guide/core/shape/ht-shape-guide.html#ref_different
let prePos = airNode.p3(); // 获取节点初始位置
let preRotate = airNode.r3(); // 获取节点初始旋转角度
let lineLength = entryG3d.getLineLength(polyline); // 获取管道长度
let params = { // 设置消防车行驶动画参数
duration: 10000,
easing: function(t){
return t * t;
},
action: function(v, t){
let offset = entryG3d.getLineOffset(polyline, lineLength * v), // 获取管道指定比例的偏移信息
point = offset.point,
px = point.x,
py = point.y,
pz = point.z,
tangent = offset.tangent,
tx = tangent.x,
ty = tangent.y,
tz = tangent.z;
airNode.p3(px, py, pz); // 移动消防车到下一位置
airNode.lookAt([px + tx, py + ty, pz + tz], 'front'); // 消防车沿着管道方向转向
},
finishFunc: function(){
if(curIndex < polylineTagArr.length - 1) { // 进入下一段路线
curIndex++;
}
else {
curIndex = 0; // 返回第一段路线
}
if(curIndex === 0) { // 消防车返回原点
airNode.p3(prePos);
airNode.r3(preRotate);
}
polyline = dm.getDataByTag(polylineTagArr[curIndex]);
lineLength = entryG3d.getLineLength(polyline);
this.carAni = ht.Default.startAnim(params); // 执行下一段行驶动画
}
};
this.carAni = ht.Default.startAnim(params);
}

消防车的行驶可总结为先获取行驶道路的管线长度信息,计算一定比例的管线偏移点,移动消防车位置到计算的偏移点,调整消防车模型的朝向,计算下一偏移点进行位移,直到到达当前管线尾,然后获取下一管线的长度信息,继续进行偏移。

代码中提到的三个方法:getLineLength、getLineOffset、lookAt,我们来了解一下。

  1. g3d.getLineLength(edgeOrPolyLine)

  根据参数 edgeOrPolyLine 方法命名我们就可以知道此方法是获取连线或管道的长度。

  2. g3d.getLineOffset(edgeOrPolyLine, offset)

    • edgeOrPolyLine  连线或者管道
    • offset 偏移百分比

  此方法获取连线或者管道的偏移信息,返回 { point, tangent },其中 point 是 3D 坐标,tangent 是 point 点沿当前线的切线向量。

  3. node.lookAt(point, direction)

    • point 3D 坐标点
    • direction 节点某一面,值可为 ‘front | back | left  | right | top | bottom’

  将节点的某一面朝向空间某坐标点。

消防车行驶转向示意图:

  1. 起始位置;

  2. 通过 setPosition3d(point.x, point.y, point.z) 到达下一位置,红线为 tangent 切线向量;

  3. 通过 node.lookAt([point.x + tangent.x, point.y + tangent.y, point.z + tangent.z], 'front'); 将车头摆向切线方向;

  4.5. 重复以上步骤。

  其中 [point.x + tangent.x, point.y + tangent.y, point.z + tangent.z] 即为目标点 target 的坐标。

  

总结

智能城市系统还包括智能楼宇的管理:

http://www.hightopo.com/demo/ht-smart-building/

地铁是一个城市的核心交通工具,地铁站的管理也必不可少:

http://www.hightopo.com/demo/ht-subway/

基于 HTML5 WebGL 智能城市的模拟运行的更多相关文章

  1. 基于 HTML5 WebGL 的智慧城市(一)

    前言 中共中央.国务院在今年12月印发了<长江三角洲区域一体化发展规划纲要>(下文简称<纲要>),并发出通知,要求各地区各部门结合实际认真贯彻落实. <纲要>强调, ...

  2. 基于 HTML5 WebGL 的地铁站 3D 可视化系统

    前言 工业互联网,物联网,可视化等名词在我们现在信息化的大背景下已经是耳熟能详,日常生活的交通,出行,吃穿等可能都可以用信息化的方式来为我们表达,在传统的可视化监控领域,一般都是基于 Web SCAD ...

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

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

  4. 基于 HTML5 WebGL 的 3D 风机 Web 组态工业互联网应用

    基于 HTML5 WebGL 的 3D 风机 Web 组态工业互联网应用 前言 在目前大数据时代背景之下,数据可视化的需求也变得越来越庞大,在数据可视化的背景之下,通过智能机器间的链接并最终将人机链接 ...

  5. 基于 HTML5 + WebGL 实现 3D 可视化地铁系统

    前言 工业互联网,物联网,可视化等名词在我们现在信息化的大背景下已经是耳熟能详,日常生活的交通,出行,吃穿等可能都可以用信息化的方式来为我们表达,在传统的可视化监控领域,一般都是基于 Web SCAD ...

  6. 基于 HTML5 + WebGL 的地铁 3D 可视化系统

    前言 工业互联网,物联网,可视化等名词在我们现在信息化的大背景下已经是耳熟能详,日常生活的交通,出行,吃穿等可能都可以用信息化的方式来为我们表达,在传统的可视化监控领域,一般都是基于 Web SCAD ...

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

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

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

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

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

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

随机推荐

  1. Selenium IDE录制脚本

    一.当Selenium IDE中Format没有转换格式时,操作:Options—Options...—勾选Enable experimental features

  2. php 在字符串指定位置插入新字符

    因为项目用到DataTable表格加载后台数据,要连表查询虚拟机选中的策略状态,所以想到先把策略表内容取出来,组成一个'<select><option value="1&q ...

  3. centos7上安装python3

    一.安装环境及版本 CentOS 6.5 Python 3.6.1 二.安装依赖包 1.安装静态库 # yum install -y openssl-static 注:如果不安装该静态库,会导致pyt ...

  4. js只对等号左边的进行变量提升

    ### 只对等号左边的进行变量提升 > =:赋值,左边是变量,右边都应该是值 ```javascript //之前 i%2 === 0?item.className = 'c1':item.cl ...

  5. python之路——网络基础

    你现在已经学会了写python代码,假如你写了两个python文件a.py和b.py,分别去运行,你就会发现,这两个python的文件分别运行的很好.但是如果这两个程序之间想要传递一个数据,你要怎么做 ...

  6. [Swift] 使用Playground

    使用Playground 1. 新建Playground 2. 写最简单的代码

  7. December 10th 2016 Week 50th Saturday

    Storms make trees take deeper roots. 风暴使树木深深扎根. Sometimes, you may feel frustrated for failing to wi ...

  8. December 17th 2016 Week 51st Saturday

    Great minds have purpose, others only have wishes. 杰出的人有着目标,其他人只拥有愿望. Are you clear about the differ ...

  9. Mac sshw 使用

    sshw ssh client wrapper for automatic login. install use go get go get -u github.com/yinheli/sshw/cm ...

  10. Git commit comment 汇总标准

    参考汇总互联网其它文章建议,结合PEP 257 Docstring Conventions的描述,总结的Git 注释风格,作为个人执行的标准.内容如下: 遵循标准: 1,所有注释尽量坚持使用英文,如果 ...