可视化场景内任意绘制线段并测量距离 原创

ThingJS数字孪生引擎
发布于 2021-8-16 14:52
浏览
0收藏

在数字孪生可视化场景中,可能会遇到这个问题,即需要测量数字孪生可视化场景中的不同目标之间的距离。通过这个测量,可以明确的知道可视化场景中各个目标的位置以及各个目标之间的距离,便于做出合理的规划。这个需求并不难,我们需要做的是确定需要测量的对象的坐标点起点和终点位置。
运行效果如下:
可视化场景内任意绘制线段并测量距离-鸿蒙开发者社区
在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(); // 调用方法
    }
![image.png](https://dl-harmonyos.51cto.com/images/202108/99cccb5304553a1bf6b575f6eaffbed84b6532.png?x-oss-process=image/resize,w_554,h_266)

3、单击鼠标左键添加点位,双击或单击鼠标右键结束。如果是多线段测量,移动鼠标可以持续绘制。
在数字孪生可视化场景中,可能会遇到这个问题,即需要测量数字孪生可视化场景中的不同目标之间的距离。通过这个测量,可以明确的知道可视化场景中各个目标的位置以及各个目标之间的距离,便于做出合理的规划。这个需求并不难,我们需要做的是确定需要测量的对象的坐标点起点和终点位置。
运行效果如下:
在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 =
                    `<div id="line` + _this.opts.modelNum + _this.numIndex + `" class="card-label card-line` + _this.opts.modelNum + `">
                        <span class="text">`;
                if (_this.lineDistanceAll != null) {
                    _this.template += _this.lineDistanceAll + `米`;
                } else {
                    _this.template += `<span style="color:#f45905; border-right: 1px solid #ccc;margin-right: 5px">` + _this.lineId + `</span> 起点`
                }
                _this.template +=
                    `</span>
                    <span><img id="linePoints` + _this.opts.modelNum + _this.numIndex + `" src="/guide/examples/images/measure/remove.png"></span> 
                    </div>`;
                _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]
        });
    }

通过以上的操作,可以实现多点线段绘制并计算出多点线段之间的距离。上图展示了多点线段长度的测试结果。快来试试看吧!


可视化场景内任意绘制线段并测量距离-鸿蒙开发者社区

通过以上的操作,可以实现多点线段绘制并计算出多点线段之间的距离。上图展示了多点线段长度的测试结果。快来试试看吧!

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
收藏
回复
举报
回复
    相关推荐