前言

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

智能城市建设是一个系统工程:首先实现的是城市管理智能化,由智能城市管理系统辅助管理城市,通过管理系统人们可以监视城市的运行,了解城市每天中发生的变化,以及及时的根据这些变化做出相应的管理;其次是包括智能交通、智能电力、智能安全等基础设施的智能化,交通是一个城市的驱动,交通的畅通加速了城市的发展,通过 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. 算法day01

  2. Software Testing Techniques LAB 01: test Junit and Eclemma

    1. Installing  1. Install Junit and hamcrest First, I download the Junit-4.12.jar and hamcrest-core- ...

  3. java笔记--ASCII编码认知和转换

    ASCII是基于拉丁字母的一套电脑编码系统,主要用于显示英语字符是当今最通用的单字节编码.包括128个字符. --如果朋友您想转载本文章请注明转载地址"http://www.cnblogs. ...

  4. 如何找回SQL Server实例安装时的序列号

    当需要再次安装SQL Server时,如果序列号找不到了,可以试着从已经安装的实例里找回序列号,因为安装完SQL Server后,序列号(Product Key)被保存在注册表里: MSDN订阅下载的 ...

  5. Asp.Net MVC Identity 2.2.1 使用技巧(三)

    使用用户管理器之用户注册 用户管理的基本功能模块中已经做好了,我们现在做一些调整. 1.修改用户名注册规则. 上一篇中可选操作已经详解了这里把基本的设置简介下. 打开App_Start/identit ...

  6. December 07th 2016 Week 50th Wednesday

    Life is a flower, and love is the honey of the flower. 人生是花儿,而爱情就是花的蜜. My life is not as beautiful a ...

  7. December 22nd 2016 Week 52nd Thursday

    The best hearts are always the bravest. 心灵最高尚的人,往往也是最勇敢的人. Keep conscience clear, don't let too many ...

  8. git团队操作

    1.git命令行 1)分支的创建 git branch 分支名 分支创建之后,就会自动pull master的内容 2)分支的查询 git branch 3)分支的进入 git checkout 分支 ...

  9. PetaPoco轻量级ORM框架 - 入门安装

    PetaPoco 是一个开源轻量级ORM,够小,够快,单文件 在GitHub上有很高的人气 1377星,几年来作者一直在更新 当前版本6.0.317 - Netstandard 2.0(同时支持.ne ...

  10. SVN There are unfinished transactions detected

    在ECLIPSE中报这个错,不能提交和更新代码和clean up 解决办法:关闭ECLIPSE,使用工具对SVN执行 clean up. 重新启动ECLIPSE,解决冲突文件,可以正常使用SVN