天津港爆炸事件后,除了安置群眾、追究事故責任外,人們最關心的莫過於爆炸污染物對於周邊環境的影響,其中最重要的一塊就是飲用水的安全。所幸的是,水源的安全監測是實實在在有據可依的。環保單位和供水企業在建設自己的飲用水水源監控系統,實時的監控民生水源安全。
最近我們承接了一個水源地自動化監控系統的項目。由於水源地一般都會遠離生產、生活區,例如各地的水庫、地下水、井等,派駐人員實時進入水源腹地進行數據監測,是不實際的,為了增強監測的實效性,遠程的自動化水源監控系統是必不可少的。該系統除了能夠監控各種水質指標外,還可以遠程監測水源井的工作情況,遠程監控水泵工作狀態,同時還可以將監測指標以圖形顯示方式發布到各級監管單位或者管理領導的工作平台或者移動工作終端(平板、手機等)。
自動化監控產品並不少見,這次項目真正吸引客戶眼球的是3D呈現效果。以往的監控系統都是以平面的方式來呈現,例如下圖:
或者是這樣的假3D效果:
傳統的平面方式除了越來越難以滿足客戶日漸提高的要求之外,的確也難以直觀展現出水源井結構、泵體安裝位置和工作狀態。3D模型本身不具備交互功能,通常需要做大量的開發工作,並且需要在系統中安裝插件。這次的項目,我們采用了Legolas開發平台,結合TWaver IOT平台完成了模型構建和數據驅動,不但實現了監控場景的3D化,還能同步顯示各類監控指標,讓調度、管理人員對於水源井的水質和工作情況一目了然,提升了管理效率,並能有效增強各級工作的服務質量。
上一張手持設備截圖:
這不是一張死圖,而是可以旋轉、拖拽、可交互的3D場景,水位的高低、閥門的開關,都會根據實際采集上的數據變化。水源井模型包含了以下部分:井、泵,傳感器、閥門和管道。模型的構建可以通過直接導入3D文件,或者用TWaver Mono Design建模工具生成。
例如,我們找美工mm在3DMax中,對泵進行建模后導出obj文件,引入到場景中:
{
type: 'obj',
src: 'pump',
size: [100,200,100],
translate: [320,-380,80],
rotation: [0, 90, 0],
specularStrength: 4,
color: '#FF1700',
},
loadObj: function(box, json){
var loader = new mono.OBJMTLLoader();
varsrc = json.src;
var size = json.size;
varpos = json.translate;
var style = json.style;
var rotation = json.rotation;
loader.load("images/"+src+".obj", "images/"+src+".mtl", json.images || "", function (object) {
var bb = object.getBoundingBoxWithChildren();
var max = bb.max, min = bb.min, w = max.x - min.x, h = max.y-min.y, l = max.z - min.z;
object.getDescendants().forEach(function(child, i){
child.setEditable(false);
});
box.addByDescendant(object);
object.setPosition(pos[0],pos[1],pos[2]);
varos = {'x': w,'y':h,'z':l};
object.setScale(size[0]/os.x,size[1]/os.y,size[2]/os.z);
if(style){
object.s(style);
}
if(rotation){
var f = demo.Util.getArc;
object.setRotation(f(rotation[0]), f(rotation[1]), f(rotation[2]));
}
});
},
大致如下圖所示:
對於較為簡單的閥門對象,我們使用了自己的MONO Design編輯器,可視化構建了閥門模型,並轉換為相關JSON文件:
{
type: 'mono',
url: 'resource/yali.json',
scale: [0.5,0.5,0.5],
translate: [-250, -155,0],
rotation: [0, -90, 0],
},
well.Default.registerFilter('mono', function(box, json){
initModelLib();
mono.Toolkits.loadTemplateUrl(box, json.url, null, null, function(object){
var translate = json.translate;
object.setPosition(translate[0], translate[1], translate[2]);
var scale = json.scale;
if(scale){
object.setScale(scale[0], scale[1], scale[2]);
}
var rotation = json.rotation;
if(rotation){
var f = demo.Util.getArc;
object.setRotation(f(rotation[0]), f(rotation[1]), f(rotation[2]));
}
if(json.color){
object.getDescendants().forEach(function(child){
child.s({
'm.color': json.color,
'm.ambient': json.color,
});
});
}
});
});
閥門的模型如下:
對於井體對象,由於其結構較為簡單,並且用戶也很關注該井體的環境結構,我們直接使用TWaver3D的API代碼來生成模型,並采用了光照貼圖等技術來增強其環境效果。
{
type: 'cable',
color: '#BEC9BE',
direction: 0.05,
repeat: [10,1],
data:[
[-320, -180, 0],
[800, -180, 0],
[800, -1200, 0],
[1500, -1200, 0],
],
},
well.Default.registerFilter('cable', function(box, json){
var path = demo.Default.create3DPath(json.data);
path = mono.PathNode.prototype.adjustPath(path, 5);
var cable=new mono.PathNode(path, 100, 10);
var repeat = json.repeat || [10,1];
cable.s({
'm.type': 'phong',
'm.specularStrength': 4,
'm.color': json.color,
'm.ambient': json.color,
'm.texture.image': 'images/w002.jpg',
'm.texture.repeat': new mono.Vec2(repeat[0], repeat[1]),
'm.texture.offset': new mono.Vec2(0,0.7),
});
cable.setClient('flow', json.flow);
cable.setStartCap('plain');
cable.setEndCap('plain');
box.add(cable);
});
場景中水管都是通過API方式創建的,其中罐體、水位、擋板這些模型涉及到模型的加減,通過mono design或API都可以生成。
靜態模型和場景搭建完畢后,通過TWaver的IOT平台完成了境內采集數據的綁定,已經可以用實時數據來驅動場景中的對象了。用戶希望能有更加逼真的交互效果,希望我們能增加一些動畫支持。水的流動,泵的啟停,水位的升降這些動作使用水井內的工作狀態更形象逼真。
下面是模型的動畫的使用方式舉例:
varoffsetAnimate = new twaver.Animate({
from: 0 ,
to: 1,
type: 'number',
dur: 3000,
repeat:Number.POSITIVE_INFINITY,
reverse: false,
onUpdate: function(value){
cable.s({
'm.texture.offset': new mono.Vec2(value, 0),
});
},
});
offsetAnimate.play();
數據驅動是借助TWaver的IOT平台完成的數據采集、分發、控制和數據綁定,這里就先不贅述了。感興趣的朋友可以給我們發郵件:tw-service@servasoft.com, 多多交流和溝通想法和意見。