可视化场景内任意绘制线段并测量距离
在数字孪生可视化场景中,可能会遇到这个问题,即需要测量数字孪生可视化场景中的不同目标之间的距离。通过这个测量,可以明确的知道可视化场景中各个目标的位置以及各个目标之间的距离,便于做出合理的规划。这个需求并不难,我们需要做的是确定需要测量的对象的坐标点起点和终点位置。
运行效果如下:
文章图片
在ThingJS中要知道场景中两点间的空间距离可以通过调用三维空间内所有坐标点,计算两个坐标点的距离去量算出两点之间的空间距离,需要通过鼠标点击才能获取到两点之间的空间距离。比如我要知道场景中某两个场景距离有多长,就可以通过鼠标点击两个甚至多个场景位置,来计算三维场景中任意三维点的空间距离。下面一起看一下操作步骤:
1、添加注册事件,注册测量详情界面拖拽事件,设置可拖拽范围不能超出屏幕。
registerEvent() {
var _this = this;
// 注册测量详情界面关闭按钮点击事件
$('#dataDetails .tj-close').on('click', function() {
$('#dataDetails').css('display', 'none');
});
// 注册测量详情界面拖拽事件,设置可拖拽范围,不能超出屏幕
$('#dataDetails .tj-title').on('mousedown', function(ev) {
ev.preventDefault();
var domEle = $('#dataDetails .tj-panel');
var spacX = ev.pageX - domEle[0].offsetLeft;
var spacY = ev.pageY - domEle[0].offsetTop;
$(document).bind('mousemove', function(event) {
var x = event.pageX - spacX;
var y = event.pageY - spacY;
if (event.pageX < 0 || event.pageX > $(window).width() || event.pageY < 0 || event.pageY > $(window).height()) {
$(document).unbind('mousemove');
}
if (x <= 0) x = 0;
if (x > ($(window).width() - domEle.width())) {
x = $(window).width() - domEle.width();
}
if (y <= 0) y = 0;
if (y > ($(window).height() - domEle.height())) {
y = $(window).height() - domEle.height();
}
domEle.css('left', x + 'px').css('top', y + 'px');
});
}).on('mouseup', function() {
$(document).unbind('mousemove');
});
// 注册单击事件,创建测距线段实例
app.on(THING.EventType.SingleClick, '*', function(e) {
if (e.button == 0) {
_this.lineNum++;
let line = new DrawLine({
app: app,
modelNum: _this.lineNum,
currPosition: e.pickedPosition
})
app.pauseEvent(THING.EventType.SingleClick, '*', '创建测距线');
}
}, "创建测距线");
}
}
2、ThingJS使用 Constructor () 作为对象构造器函数,用来构造一种“对象类型”,即创建相同类型的对象框架。Constructor () 构造器为对象的属性赋初始值,JS中可以任意扩展构造参数option,实现动态绑定。绘制测量线的构造参数创建如下:
class DrawLine {
/**
* 构造器
* @param {JSON} option - 构造参数
*/
constructor(option) {
this.opts = option;
this.pointsArr = [this.opts.currPosition];
// 鼠标移动中坐标点的集合
this.coordinatesArr = [this.opts.currPosition];
// 存储鼠标点击后坐标点的集合
this.ePosition = null;
// 存储触发事件后鼠标的位置
this.lineCoor = [this.opts.currPosition];
// 存储当前两个坐标点
this.disArr = [];
// 存储所有坐标点与坐标点间的距离
this.numIndex = 0;
// 自增变量
this.reSetDistance;
// 存储两点间的距离
this.lastStatus = false;
// 判断是否绘制结束值为false为未结束true为结束
this.pointsObjArr = [];
this.rianleyDom = $('#marker');
// 跟随鼠标的提示
this.pointCardDom = $('#pointMarker');
// 鼠标移动至节点的提示
this.init();
// 初始化
this.appClick();
// 调用方法
}
文章图片
【可视化场景内任意绘制线段并测量距离】3、单击鼠标左键添加点位,双击或单击鼠标右键结束。如果是多线段测量,移动鼠标可以持续绘制。
appClick() {
var _this = this;
// 点击左键添加节点右键结束绘制
_this.opts.app.on('SingleClick', function(e) {
if (e.button == 0) {
if (!e.picked) return;
_this.numIndex++;
_this.ePosition = e.pickedPosition;
_this.createPoint(_this.ePosition);
_this.coordinatesArr.push(_this.ePosition);
_this.lineCoor.push(_this.ePosition);
_this.createLine(_this.coordinatesArr);
_this.getDistance();
_this.template =
`
`;
if (_this.lineDistanceAll != null) {
_this.template += _this.lineDistanceAll + `米`;
} else {
_this.template += `` + _this.lineId + ` 起点`
}
_this.template +=
`
文章图片
`;
_this.boardId = 'line' + _this.opts.modelNum + _this.numIndex;
_this.createCard(_this.regionPoint);
_this.pointsObj = {
id: 'linePoints' + _this.opts.modelNum + _this.numIndex,
parent: 'line' + _this.opts.modelNum + _this.numIndex,
coor: _this.ePosition,
distance: _this.lineDistance
}
_this.pointsObjArr.push(_this.pointsObj);
_this.cardClick();
} else {
if (_this.coordinatesArr.length < 2) {
_this.destroyAll();
_this.rianleyDom.css('display', 'none');
return;
};
_this.end();
}
_this.rianleyDom.css('display', 'none');
}, '点击');
// 鼠标移动持续绘制测量线段
_this.opts.app.on('MouseMove', function(e) {
if (e.picked) {
_this.ePosition = e.pickedPosition;
_this.pointsArr = [..._this.coordinatesArr, _this.ePosition];
_this.createLine(_this.pointsArr);
_this.line.style.color = '#f88020';
if (_this.pointsArr.length >= 2) {
_this.moveDistance = THING.Math.getDistance(_this.pointsArr[_this.pointsArr.length - 1], _this.pointsArr[_this.pointsArr.length - 2]);
let countNum = 0;
_this.disArr.forEach(v => {
countNum += parseFloat(v);
});
countNum = 1 * parseFloat(countNum).toFixed(2) + 1 * parseFloat(_this.moveDistance).toFixed(2);
_this.rianleyDom.css('display', 'block');
_this.rianleyDom.find('span.value').text(countNum.toFixed(2));
_this.rianleyDom.css('left', e.clientX + 10 + 'px');
_this.rianleyDom.css('top', e.clientY + 'px');
}
}
}, '移动');
// 结束绘制当前测量线段
_this.opts.app.on('DBLClick', function(ev) {
if (_this.coordinatesArr.length < 2) {
_this.destroyAll();
_this.rianleyDom.css('display', 'none');
return;
};
_this.end();
}, '双击');
}
/**
* 创建节点
* @param {Array} ePosition - 坐标点
*/
createPoint(ePosition) {
var _this = this;
_this.regionPoint = _this.opts.app.create({
type: 'Sphere',
id: 'linePoints' + _this.opts.modelNum + _this.numIndex,
name: 'linePoints' + _this.opts.modelNum,
radius: 0.2, // 半径
widthSegments: 16,
heightSegments: 16,
position: ePosition, // 球体坐标
style: {
color: '#c10000',
roughness: 50,
opacity: 0.8
}
});
}
4、创建节点、线段和节点顶牌这些基本元素,确定起点、各个节点的坐标。其中线段属于所有鼠标点击后的坐标点集合,即测量的总距离。
createPoint(ePosition) {
var _this = this;
_this.regionPoint = _this.opts.app.create({
type: 'Sphere',
id: 'linePoints' + _this.opts.modelNum + _this.numIndex,
name: 'linePoints' + _this.opts.modelNum,
radius: 0.2, // 半径
widthSegments: 16,
heightSegments: 16,
position: ePosition, // 球体坐标
style: {
color: '#c10000',
roughness: 50,
opacity: 0.8
}
});
}
/**
* 创建线段
* @param {Array} coordinates - 所有鼠标点击后的坐标点集合
*/
createLine(coordinates) {
let id = this.opts.modelNum >= 10 ? this.opts.modelNum : '0' + this.opts.modelNum;
if (this.line) {
this.line.destroy();
}
this.lineId = 'Line' + id;
this.line = this.opts.app.create({
type: 'PolygonLine',
name: 'line',
id: 'Line' + id,
width: 0.05,
points: coordinates,
style: {
color: '#f45905',
roughness: 5,
opacity: 0.9
}
});
}
/**
* 计算两个坐标点间的距离
*/
getDistance() {
if (this.lineCoor.length < 2) return;
if (this.coordinatesArr.length > 2) {
this.lineCoor.shift();
}
this.lineDistance = THING.Math.getDistance(this.lineCoor[0], this.lineCoor[1]);
this.lineDistance = this.lineDistance.toFixed(2);
this.disArr.push(this.lineDistance);
let countNum = 0;
this.disArr.forEach(v => {
countNum += parseFloat(v);
});
this.lineDistanceAll = countNum.toFixed(2);
}
/**
* 创建节点顶牌
* @param {Object} parent - 顶牌父物体
*/
createCard(parent) {
$('#div3d').append(this.template);
this.srcElem = document.getElementById(this.boardId);
this.imgElem = document.getElementById('linePoints' + this.opts.modelNum + this.numIndex);
this.ui = this.opts.app.create({
type: 'UIAnchor',
parent: parent,
element: this.srcElem,
localPosition: [0.4, 0.3, 0.4],
pivotPixel: [0, 0]
});
}
文章图片
通过以上的操作,可以实现多点线段绘制并计算出多点线段之间的距离。上图展示了多点线段长度的测试结果。快来试试看吧!
—————————————————
数字孪生可视化:https://www.thingjs.com/
推荐阅读
- JAVA(抽象类与接口的区别&重载与重写&内存泄漏)
- 期刊|期刊 | 国内核心期刊之(北大核心)
- 你有婚内虐待行为吗()
- 标签、语法规范、内联框架、超链接、CSS的编写位置、CSS语法、开发工具、块和内联、常用选择器、后代元素选择器、伪类、伪元素。
- ?【段子图】内裤为啥湿呢(想想好邪恶啊...)
- 放下心中的偶像包袱吧
- angular2内置管道
- 也许,是我记性不好,也许是社会太吵,内心太躁。
- 操作系统|[译]从内部了解现代浏览器(1)
- 为什么孩子一定要学会可视化思维!