基于WebGL架构的ThingJS可视化平台—城市地下管线3D可视化

3次阅读

共计 10888 个字符,预计需要花费 28 分钟才能阅读完成。

前言城市管网是城市最重要的公共基础设施之一,与城市的发展和居民日常生活息息相关。根据不同的市政建设,管网分供水、排污、供暖、通信、电力等多种类别,其广泛分布遍及地下。随着城市发展建设所衍生出空间分布复杂,变化大,种类繁多等问题,可视化管理是未来发展最好的解决方案。
Demo 预览

实现
第一步,加载场景
// 加载场景代码
var app = new THING.App({
// 场景地址
“url”: “http://www.thingjs.com/./uploads/wechat/S2Vyd2lu/scene/Demo_地下管线 ”,
// 背景设置
“skyBox”: “BlueSky”
});
第二步,创建管线以及创建管线信息面板。这里 PolygonLine 这种类型我们在之前的 Demo 中使用过没看过的同学可以点进去看一下,当然那篇比较糙还是没有这篇好看的,可以两篇对比一下效果,文章地址。这里这个 renderOrder 属性划重点,这里将 line 的 visible 属性设置为 false,当场景加载完成后我们的管线就已经创建好了为了能更好的配合我们的面板所以给他先隐藏掉了,等到开关触发再对他进行展示。
function createLine(name, color, points) {
var line = null;
line = app.create({
type: ‘PolygonLine’,
name: name,
points: points,
style: {
color: color,
},
});
line.renderOrder = -10000;
line.scrollUV = true;
line.visible = false;
return line;
}

function createInfo(obj, position) {
var panel = new THING.widget.Panel({
template: ‘default2’,
width: ‘120px’,
cornerType: ‘polyline’
})
var dataObj = {
name: obj.name,
color: obj.style.color
}
panel.addString(dataObj, ‘name’).caption(‘ 名称 ’);
panel.addString(dataObj, ‘color’).caption(‘ 颜色 ’);
var uiAnchor = app.create({
type: ‘UIAnchor’,
parent: obj,
element: panel.domElement,
position: [position[0], -1, position[2]],
pivot: [-0.2, 2.1]
});
return uiAnchor;
}
第三步,创建功能面板以及创建各种类管线。
// 管线的模拟数据
var dataJson = [{‘id’: ‘BJ002’, ‘starId’: ‘2TAG001’, ‘stopId’: ‘2TAG002’, ‘starDeep’: ‘-1.5’, ‘stopDeep’: ‘-1.5’, ‘material’: ‘ASTNX01’, ‘pressure’: ‘120’},
{‘id’: ‘BJ002’, ‘starId’: ‘2TAG001’, ‘stopId’: ‘2TAG002’, ‘starDeep’: ‘-1.5’, ‘stopDeep’: ‘-1.5’, ‘material’: ‘ASTNX01’, ‘pressure’: ‘120’},
{‘id’: ‘BJ002’, ‘starId’: ‘2TAG001’, ‘stopId’: ‘2TAG002’, ‘starDeep’: ‘-1.5’, ‘stopDeep’: ‘-1.5’, ‘material’: ‘ASTNX01’, ‘pressure’: ‘120’}];
app.on(‘load’, function () {

// init_camera
app.camera.flyTo({
‘position’: [-6.199233956799988, 49.47465259648085, 113.74453304853118],
‘target’: [-4.002967317456267, 26.055382001258867, 37.65111202780902],
‘time’: 2000,
});

// 创建场景
var controlPanel = new THING.widget.Panel({
titleText: ‘ 地下管线 Demo’,
hasTitle: true, // 是否有标题
zIndex: 999, // 设置层级
});
var data = {
totalOpen: false,
viewOpen: false,
waterOpen: false,
blowOffOpen: false,
heatOpen: false
};

//openTotal 按钮控制
var totalOpen = controlPanel.addBoolean(data, ‘totalOpen’).caption(‘ 状态切换 ’);
totalOpen.on(‘change’, function (ev) {
if (ev) {
// 将 campus 下所有的 obj 的 opacity = 0.4,将 name = Uncorrelated 的 obj 的 visiable = false
app.query(‘Campus’)[0].style.opacity = 0.3;
app.query(‘Uncorrelated’)[0].visible = false;
} else {
// 反之初始化
app.query(‘Campus’)[0].style.opacity = 1;
app.query(‘Uncorrelated’)[0].visible = true;
}
});

//viewOpen 视角控制
var viewOpen = controlPanel.addBoolean(data, ‘viewOpen’).caption(‘2D/3D’);
viewOpen.on(‘change’, function (ev) {
if (ev) {
app.camera.viewMode = THING.CameraView.TopView;
} else {
app.camera.viewMode = THING.CameraView.Normal;
app.skyBox = ‘BlueSky’;
}
});

//waterOpen 供水管线 color #0000FF
var waterOpen = controlPanel.addBoolean(data, ‘waterOpen’).caption(‘ 供水管线 ’);
var waterLine = [];
waterLine.push(createLine(‘ 供水管线 ’, ‘https://thingjs.com/static/images/poly_line_04.png’, [[-61.736, -1.5, 10], [74.408, -1.5, 10]]));
waterLine.push(createLine(‘ 供水管线 ’, ‘https://thingjs.com/static/images/poly_line_04.png’, [[-61.736, -1.50, 8], [-16.126, -1.50, 8], [-16.126, -1.50, -20], [-10.126, -1.50, -20], [-10.126, -1.50, 8], [74.408, -1.5, 8]]));
waterLine.push(createLine(‘ 供水管线 ’, ‘https://thingjs.com/static/images/poly_line_04.png’, [[-61.736, -1.50, 12], [-45.001, -1.5, 15.755], [-20.736, -1.5, 12], [74.408, -1.5, 12]]));
waterLine.push(createLine(‘ 供水管线 ’, ‘https://thingjs.com/static/images/poly_line_04.png’, [[4, -1.5, 46], [4, -1.50, 13.809], [4, -2, 13.809], [4, -2, 6], [4, -1.50, 6], [4, -1.5, -34]]));
waterLine.push(createLine(‘ 供水管线 ’, ‘https://thingjs.com/static/images/poly_line_04.png’, [[6, -1.50, 46], [6, -1.50, 13.809], [6, -2, 13.809], [6, -2, 6], [6, -1.50, 6], [6, -1.5, -34]]));
waterLine.push(createLine(‘ 供水管线 ’, ‘https://thingjs.com/static/images/poly_line_04.png’, [[8, -1.50, 46], [8, -1.50, 13.809], [8, -2, 13.809], [8, -2, 6], [8, -1.50, 6], [8, -1.5, -34]]));
createInfo(waterLine[0], dataJson[0],[-28.847, -1.5, 7.957]);
waterOpen.on(‘change’, function (ev) {
waterLine.forEach(function (obj) {
obj.visible = ev;
})
});

//blowOffLine 排污管线 color #FFEC8B
var blowOffOpen = controlPanel.addBoolean(data, ‘blowOffOpen’).caption(‘ 排污管线 ’);
var blowOffLine = [];
blowOffLine.push(createLine(‘ 排污管线 ’, ‘https://thingjs.com/static/images/poly_line_03.png’, [[-2, -3, 46], [-2, -3, -34]]));
blowOffLine.push(createLine(‘ 排污管线 ’, ‘https://thingjs.com/static/images/poly_line_03.png’, [[0, -3, 46], [0, -3, -34]]));
blowOffLine.push(createLine(‘ 排污管线 ’, ‘https://thingjs.com/static/images/poly_line_03.png’, [[-61.736, -3, 4], [74.408, -3, 4]]));
blowOffLine.push(createLine(‘ 排污管线 ’, ‘https://thingjs.com/static/images/poly_line_03.png’, [[-61.736, -3, 2], [74.408, -3, 2]]));
createInfo(blowOffLine[0], dataJson[1],[15.299, -1.5, 1.87]);
blowOffOpen.on(‘change’, function (ev) {
blowOffLine.forEach(function (obj) {
obj.visible = ev;
})
});

//heatLine 供热管线 color #FF7F24
var heatOpen = controlPanel.addBoolean(data, ‘heatOpen’).caption(‘ 供热管线 ’);
var heatLine = [];
heatLine.push(createLine(‘ 供热管线 ’, ‘https://thingjs.com/static/images/poly_line_02.png’, [[-61.736, -2, 0], [65.736, -2, 0], [74.408, -2, -8]]));
heatLine.push(createLine(‘ 供热管线 ’, ‘https://thingjs.com/static/images/poly_line_02.png’, [[-61.736, -2, -2], [65.736, -2, -2], [74.408, -2, -10]]));
heatLine.push(createLine(‘ 供热管线 ’, ‘https://thingjs.com/static/images/poly_line_02.png’, [[-4, -2, 46], [-4, -2, -34]]));
heatLine.push(createLine(‘ 供热管线 ’, ‘https://thingjs.com/static/images/poly_line_02.png’, [[-6, -2, 46], [-6, -2, -34]]));
createInfo(heatLine[0], dataJson[2],[-6.041, -1.817, 8.865]);
heatOpen.on(‘change’, function (ev) {
heatLine.forEach(function (obj) {
obj.visible = ev;
})
});
小结这个取点坐标的方法在上文中没有告诉大家,只是因为我原来用的方法就比较傻了,我是自己写了一个全局的 singleclick 事件,触发之后打印出当前鼠标的 pickedPosistion 记录下来再写进数组中,这无疑的是很麻烦的操作。其实 ThingJS 已经给我们写好了一个工具叫做拾取场景坐标,他的使用方式下面我会给大家贴几张图。整个代码 100+ 行还是比较简洁了(作者能力有限,已经努力精简了下文可以给作者多提意见,虚心接受)。最后附上完整代码!

完整代码
// 加载场景代码
var app = new THING.App({
// 场景地址
“url”: “http://www.thingjs.com/./uploads/wechat/S2Vyd2lu/scene/Demo_地下管线 ”,
// 背景设置
“skyBox”: “BlueSky”
});

app.on(‘load’, function () {

// init_camera
app.camera.flyTo({
‘position’: [-6.199233956799988, 49.47465259648085, 113.74453304853118],
‘target’: [-4.002967317456267, 26.055382001258867, 37.65111202780902],
‘time’: 2000,
});

// 创建场景
var controlPanel = new THING.widget.Panel({
titleText: ‘ 地下管线 Demo’,
hasTitle: true, // 是否有标题
zIndex: 999, // 设置层级
});
var data = {
totalOpen: false,
viewOpen: false,
waterOpen: false,
blowOffOpen: false,
heatOpen: false
};

//openTotal 按钮控制
var totalOpen = controlPanel.addBoolean(data, ‘totalOpen’).caption(‘ 状态切换 ’);
totalOpen.on(‘change’, function (ev) {
if (ev) {
// 将 campus 下所有的 obj 的 opacity = 0.4,将 name = Uncorrelated 的 obj 的 visiable = false
app.query(‘Campus’)[0].style.opacity = 0.3;
app.query(‘Uncorrelated’)[0].visible = false;
} else {
// 反之初始化
app.query(‘Campus’)[0].style.opacity = 1;
app.query(‘Uncorrelated’)[0].visible = true;
}
});

//viewOpen 视角控制
var viewOpen = controlPanel.addBoolean(data, ‘viewOpen’).caption(‘2D/3D’);
viewOpen.on(‘change’, function (ev) {
if (ev) {
app.camera.viewMode = THING.CameraView.TopView;
} else {
app.camera.viewMode = THING.CameraView.Normal;
app.skyBox = ‘BlueSky’;
}
});

//waterOpen 供水管线 color #0000FF
var waterOpen = controlPanel.addBoolean(data, ‘waterOpen’).caption(‘ 供水管线 ’);
var waterLine = [];
waterLine.push(createLine(‘ 供水管线 ’, ‘https://thingjs.com/static/images/poly_line_04.png’, [[-61.736, -1.5, 10], [74.408, -1.5, 10]]));
waterLine.push(createLine(‘ 供水管线 ’, ‘https://thingjs.com/static/images/poly_line_04.png’, [[-61.736, -1.50, 8], [-16.126, -1.50, 8], [-16.126, -1.50, -20], [-10.126, -1.50, -20], [-10.126, -1.50, 8], [74.408, -1.5, 8]]));
waterLine.push(createLine(‘ 供水管线 ’, ‘https://thingjs.com/static/images/poly_line_04.png’, [[-61.736, -1.50, 12], [-45.001, -1.5, 15.755], [-20.736, -1.5, 12], [74.408, -1.5, 12]]));
waterLine.push(createLine(‘ 供水管线 ’, ‘https://thingjs.com/static/images/poly_line_04.png’, [[4, -1.5, 46], [4, -1.50, 13.809], [4, -2, 13.809], [4, -2, 6], [4, -1.50, 6], [4, -1.5, -34]]));
waterLine.push(createLine(‘ 供水管线 ’, ‘https://thingjs.com/static/images/poly_line_04.png’, [[6, -1.50, 46], [6, -1.50, 13.809], [6, -2, 13.809], [6, -2, 6], [6, -1.50, 6], [6, -1.5, -34]]));
waterLine.push(createLine(‘ 供水管线 ’, ‘https://thingjs.com/static/images/poly_line_04.png’, [[8, -1.50, 46], [8, -1.50, 13.809], [8, -2, 13.809], [8, -2, 6], [8, -1.50, 6], [8, -1.5, -34]]));
createInfo(waterLine[0], dataJson[0],[-28.847, 0, 7.957]);
waterOpen.on(‘change’, function (ev) {
waterLine.forEach(function (obj) {
obj.visible = ev;
})
});

//blowOffLine 排污管线 color #FFEC8B
var blowOffOpen = controlPanel.addBoolean(data, ‘blowOffOpen’).caption(‘ 排污管线 ’);
var blowOffLine = [];
blowOffLine.push(createLine(‘ 排污管线 ’, ‘https://thingjs.com/static/images/poly_line_03.png’, [[-2, -3, 46], [-2, -3, -34]]));
blowOffLine.push(createLine(‘ 排污管线 ’, ‘https://thingjs.com/static/images/poly_line_03.png’, [[0, -3, 46], [0, -3, -34]]));
blowOffLine.push(createLine(‘ 排污管线 ’, ‘https://thingjs.com/static/images/poly_line_03.png’, [[-61.736, -3, 4], [74.408, -3, 4]]));
blowOffLine.push(createLine(‘ 排污管线 ’, ‘https://thingjs.com/static/images/poly_line_03.png’, [[-61.736, -3, 2], [74.408, -3, 2]]));
createInfo(blowOffLine[0], dataJson[1],[15.299, 0, 1.87]);
blowOffOpen.on(‘change’, function (ev) {
blowOffLine.forEach(function (obj) {
obj.visible = ev;
})
});

//heatLine 供热管线 color #FF7F24
var heatOpen = controlPanel.addBoolean(data, ‘heatOpen’).caption(‘ 供热管线 ’);
var heatLine = [];
heatLine.push(createLine(‘ 供热管线 ’, ‘https://thingjs.com/static/images/poly_line_02.png’, [[-61.736, -2, 0], [65.736, -2, 0], [74.408, -2, -8]]));
heatLine.push(createLine(‘ 供热管线 ’, ‘https://thingjs.com/static/images/poly_line_02.png’, [[-61.736, -2, -2], [65.736, -2, -2], [74.408, -2, -10]]));
heatLine.push(createLine(‘ 供热管线 ’, ‘https://thingjs.com/static/images/poly_line_02.png’, [[-4, -2, 46], [-4, -2, -34]]));
heatLine.push(createLine(‘ 供热管线 ’, ‘https://thingjs.com/static/images/poly_line_02.png’, [[-6, -2, 46], [-6, -2, -34]]));
createInfo(heatLine[0], dataJson[2],[-6.041, 0, 8.865]);
heatOpen.on(‘change’, function (ev) {
heatLine.forEach(function (obj) {
obj.visible = ev;
})
});

});

function createLine(name, image, points) {
var line = null;
line = app.create({
type: ‘PolygonLine’,
name: name,
points: points,
image: image
});
line.renderOrder = -10000;
line.scrollUV = true;
line.visible = false;
return line;
}

function createInfo(obj,json, position) {
var panel = new THING.widget.Panel({
template: ‘default2’,
width: ‘200px’,
cornerType: ‘polyline’
})
// panel.zIndex = -10000;
panel.renderOrder = -1000;
var dataObj = {
name: ‘ ‘,
id: json.id,
starId: json.starId,
stopId: json.stopId,
starDeep: json.starDeep,
stopDeep: json.stopDeep,
material: json.material,
pressure: json.pressure,
}
panel.addString(dataObj, ‘name’).caption(obj.name);
panel.addString(dataObj, ‘id’).caption(‘ 管线编号 ’);
panel.addString(dataObj, ‘starId’).caption(‘ 起点编号 ’);
panel.addString(dataObj, ‘stopId’).caption(‘ 终点编号 ’);
panel.addString(dataObj, ‘starDeep’).caption(‘ 起点深度 ’);
panel.addString(dataObj, ‘stopDeep’).caption(‘ 终点深度 ’);
panel.addString(dataObj, ‘material’).caption(‘ 材料 ’);
panel.addString(dataObj, ‘pressure’).caption(‘ 压力 ’);
var uiAnchor = app.create({
type: ‘UIAnchor’,
parent: obj,
element: panel.domElement,
position: [position[0], 0, position[2]],
pivot: [-0.2, 2.1]
});
return uiAnchor;
}

var dataJson = [{‘id’: ‘BJ002’, ‘starId’: ‘2TAG001’, ‘stopId’: ‘2TAG002’, ‘starDeep’: ‘-1.5’, ‘stopDeep’: ‘-1.5’, ‘material’: ‘ASTNX01’, ‘pressure’: ‘120’},
{‘id’: ‘BJ002’, ‘starId’: ‘2TAG001’, ‘stopId’: ‘2TAG002’, ‘starDeep’: ‘-1.5’, ‘stopDeep’: ‘-1.5’, ‘material’: ‘ASTNX01’, ‘pressure’: ‘120’},
{‘id’: ‘BJ002’, ‘starId’: ‘2TAG001’, ‘stopId’: ‘2TAG002’, ‘starDeep’: ‘-1.5’, ‘stopDeep’: ‘-1.5’, ‘material’: ‘ASTNX01’, ‘pressure’: ‘120’}];

正文完
 0