当前位置: 首页 » 风电资讯 » 风电百科 » 正文

科技前沿:基于 HTML5 WebGL 的 3D风力发电场

放大字体  缩小字体 发布日期:2023-02-09   来源:风电叶片   作者:风力发电   浏览次数:155
核心提示:前言风能是一种开发中的洁净能源,它取之不尽、用之不竭。当然,建风力发电场首先应考虑气象条件和社会自然条件。近年来,我国海上和陆上风电发展迅猛。海水、陆地为我们的风力发电提供了很好地质保障。正是这些场地为我们的风力提供了用之不竭的能源。现在我们正在努力探索这些领域。今天分享的文章我使用用了 Hightopo 的 HT for Web 产品搭建的一个可视化系统, 实现了风力发电场的整体流程,能让大家看到一套完整风力发电预览体系。界面效果预览大致流程下面是整个项目的流程图。我们从首页可以进入到场区分布页面和集控

   

前言风能是一种开发中的洁净能源,它取之不尽、用之不竭。
当然,建风力发电场首先应考虑气象条件和社会自然条件。
近年来,我国海上和陆上风电发展迅猛。
海水、陆地为我们的风力发电提供了很好地质保障。
正是这些场地为我们的风力提供了用之不竭的能源。
现在我们正在努力探索这些领域。
今天分享的文章我使用用了 Hightopo 的 HT for Web 产品搭建的一个可视化系统, 实现了风力发电场的整体流程,能让大家看到一套完整风力发电预览体系。
界面效果预览大致流程下面是整个项目的流程图。
我们从首页可以进入到场区分布页面和集控页面。
场区分布页面又包括两个不同的 3D 场景,分别是陆地风机场和海上风机场。
点击两个 3D 风机场最终都会进入到 3D 风机场景。
实现分析:首页:1. 世界地图效果2. 中国地图效果3. 城市地图效果集控中心页面(没有动画效果):场区分布页面(没有动画效果):陆地风机场:海上风机场:代码实现我们可以看到,首页的地球有三种视角状态,世界地图、中国地图、城市地图。
点击每个状态相机就会转到对应的位置。
在这之前我们要先预先存一下对应的 center 和 eye 。
我们最好新建一个 data.js 文件,专门用来提供数据。
相关伪代码如下:// 记录位置var cameraLocations = { earth: { eye: [-73, 448, 2225], center: [0, 0, 0] }, china: { eye: [-91, 476, 916], center: [0, 0, 0] }, tsankiang: { eye: [35, 241, 593], center: [0, 0, 0] }};好了,有了数据之后。
我们接下来该监听事件了。
我们可以点击按钮,也可以点击高亮区域(世界地图只有按钮可以点击)进入到中国地图视角。
我们可以这样先获取这两个节点,然后对它们的点击事件进行相同的处理。
但是,我觉得这种方式可以进行优化,更换一种思考方式。
我们可以先将事件进行过滤,我们创建两个数组,一个保存着类似 click、onEnter 这样可以执行的事件,一个保存着所有可以触发事件的节点。
这样可以有利于我们维护,也可以使结构更加清晰。
下图,我们可以看到,如果当前节点没有事件权限或者当前事件本身就没有权限的话,就会被过滤掉。
如果都可以正确返回,则执行对应的事件。
只要我们当前要执行的节点符合要求,我们就会把 event (当前执行的事件) 和 tag (节点标签) 传给执行函数 nodeEvent 执行。
这样就不会浪费资源去处理那些无效的事件或者节点了。
我们接下来来看看 nodeEvent 怎么处理吧!相关伪代码如下:bubblesEvent(event, propertyName) { var dm = this.dm var account = dm.getDataByTag('account') var currentNode = dm.getDataByTag(propertyName) var self = this var clickData = function() { // 执行清除动作 self.clearAction() } var onEnter = function() { // do something } var onLeave = function() {    // do something } var allEvent = { clickData, onEnter, onLeave } allEvent[event] && allEvent[event]()}可以看到,我们可以利用 propertyName(节点标签) 字符串拼接组成一个方法名。
比如当前拿到的节点标签是 bubbles , this[`${ properName }Event`] 之后,拿到就是 this['bubblesEvent'] 这个方法。
当然,这个方法是我们事先定义好的。
在具体的节点方法里面,我们创建了对应的事件函数。
根据传过来的 event 来判断是否拥有对应的方法。
如果有的话执行,否则返回 false 。
这样做的好处是:解耦、结构简洁、出现问题能够快速定位。
但是,如果我们仔细想想,我们点击世界地图和中国地图的时候,功能都差不多!如果我们可以将他们合并的话,就会方便很多了!!我们来改造一下代码。
相关伪代码如下:function nodeEvent(event, propertyName) { // 过滤是否有可以合并的事件 var filterEvents = function(propertyName) { var isCombine = false     var self = this if (['earth', 'china'].includes(propertyName)) { self.changeCameraLocaltions(event, propertyName) isCombine = true } return !isCombine } var eventFun = this[`${propertyName}Event`] // 执行对应的节点事件 filterEvents(propertyName) && eventFun && eventFun(event, propertyName)}我们事先判断当前事件是否能合并,如果能的话返回 false ,不再执行下面的代码,然后执行自己的函数。
这时候,我们就可以通过对应的节点标签,从 data.js 的 cameraLocations 变量中取到对应的 center、eye 。
移动镜头动画使用到了 gv 的 moveCamera 方法,该方法接受 3 个参数,eye (相机),center (目标),animConfig (动画配置) 。
然后我们把当前动画返回给 globalAnim 的 moveCameraAnim 属性,方便我们进行清理。
接下来,就是切换页面了,这点需要非常小心谨慎。
因为一旦没有把某个属性清除的话,将会导致内存泄漏等问题,性能会越来越慢。
将会导致页面卡死的情况!所以我们需要一个专门用来清除数据模型的函数 clearAction 。
我们应该把所有的动画对象放到一个对象或者数组中。
这样方便切换页面的时候清理掉。
相关伪代码如下:clearAction(index) { var { dm, gv } = this var { g3d, d3d } = window allListener.mi3d && g3d.umi(allListener.mi3d) allListener.mi2d && gv.umi(allListener.mi2d) dm.removeScheduleTask(this.schedule) dm && dm.clear() d3d && d3d.clear() window.d3d = null window.dm = null for (var i in globalAnim) { globalAnim[i] && globalAnim[i].pause() globalAnim[i] = null } // 清除对应的 3D 图纸 ht.Default.removeHTML(g3d) gv.addToDOM() ht.Default.xhrLoad(`displays/HT-project_2019/风电/${index}.json`, function (text) { let json = ht.Default.parse(text) gv.deserialize(json, function(json, dm2, gv2, datas) { if (json.title) document.title = json.title if (json.a['json.background']) { let bgJSON = json.a['json.background'] if (bgJSON.indexOf('scenes') === 0) { var bgG3d if (g3d) { bgG3d = g3d } else { bgG3d = new ht.graph3d.Graph3dView() } var bgG3dStyle = bgG3d.getView() bgG3dStyle.className = index === 1 ? '' : index === 3 ? 'land' : 'offshore' bgG3d.deserialize(bgJSON, function(json, dm3, gv3, datas) { init3d(dm3, gv3) }) bgG3d.addToDOM() gv.addToDOM(bgG3dStyle) } gv.handleScroll = function () {} } init2d(dm2, gv2) }) })}首先我们需要把 dm(数据模型) 和 gv(图纸) 清除掉。
还要注意:mi(监听函数)、schedule(调度任务) 应该在 dm.clear() 之前 remove。
所有的动画进行 stop() 操作,然后将其值设为 null 。
这里需要注意的是, 执行 stop 之后,会调用一次 finishFunc 回调函数。
当我们的 2D 图纸里面包含 3D 背景的情况下,需要判断是否已经存在了 3D 的实例,如果存在不需要再次创建。
有兴趣可以了解一下 webGL 的应用内存泄漏问题。
当进入两个 3D 场景场景的时候,我们需要一个开场动画,如开头效果 gif 图一样。
所以我们,需要把两个开场动画的 center 和 eye 都存到我们已经定义好的 cameraLocations 中。
offshoreStart、offshoreEnd、landStart、landEnd 表示海上和陆上发电场的开始位置和结束位置。
我们需要判断当前加载的是海上发电场还是陆上发电场。
我们可以在加载对应图纸的时候添加 className 。
我们在 clearAction 这个函数已经定义了 index 这个参数,如果点击的是陆地发电场传的就是数字3,如果是海上发电场的话,就是数字4。
比如我需要加载陆地发电场,那么就可以通过判断 g3d.className = index === 3 ? 'land' : 'offshore' 来添加 className 。
然后在 init 里面进行初始化的判断。
相关伪代码如下:function init() { var className = g3d.getView().className // 执行单独的事件 this.selfAnimStart(className) this.initData() // 监听事件 this.monitor()}我们拿到对应的 className ,传入相对应的类型并且执行对应的初始化事件,通过我们已经定义好的 moveCameraAnim 函数进行相机的动画。
相关伪代码如下:function selfAnimStart(type) { var gv = this.gv var { eye, center } = cameraLocations[`${type}End`] var config = { duration: 3000, eye, center, } this.moveCameraAnim(gv, config)}总结这个项目让我们更加了解了风力发电。
不管是风力发电场的地区优势,还是风机的结构、运转原理。
关于风机的讲解可以通过我们的往期文章:《科技将带给我们什么变化?讲述基于 HTML5 WebGL 的 3D 科幻风机》了解~做完这个项目,自己得到了很多的成长和感悟。
对于技术快速成长的一个好方法就是去不断的抠细节。
项目是一件艺术品,需要不断对其进行打磨,要做到自己满意为止。
每个细微的点都会影响后面的性能。
所以,我们应该以匠人的精神去做任何事。
当然,我也希望一些伙伴能够勇于探索工业互联网领域。
我们能够实现的远远不止于此。
这需要发挥我们的想象力,为这个领域增添更多好玩的、实用的 demo。
而且还能学到很多工业领域的知识。
2019 我们也更新了数百个工业互联网 2D/3D 可视化案例集,在这里你能发现许多新奇的实例,也能发掘出不一样的工业互联网:《分享数百个 HT 工业互联网 2D 3D 可视化应用案例 》,更多行业应用实例可以参考官网案例链接可点击下方查看更多。
大家可以给小编留言想看关于什么行业内容知识,我将给陆续奉上~

 
 
[ 风电资讯搜索 ]  [ 加入收藏 ]  [ 告诉好友 ]  [ 打印本文 ]  [ 违规举报 ]  [ 关闭窗口 ]

免责声明:
本网站部分内容来源于合作媒体、企业机构、网友提供和互联网的公开资料等,仅供参考。本网站对站内所有资讯的内容、观点保持中立,不对内容的准确性、可靠性或完整性提供任何明示或暗示的保证。如果有侵权等问题,请及时联系我们,我们将在收到通知后第一时间妥善处理该部分内容。
扫扫二维码用手机关注本条新闻报道也可关注本站官方微信账号:"风电之家",每日获得互联网最前沿资讯,热点产品深度分析!
 
 
0条 [查看全部]  相关评论

 
推荐图文
推荐风电资讯
点击排行