在 Autodesk Forge 查看器中的元素下拾取 [英] Picking under elements of an element in Autodesk Forge viewer

查看:27
本文介绍了在 Autodesk Forge 查看器中的元素下拾取的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想完成一项我可以在 Three.js 中完成但在 Autodesk Forge 查看器中无法完成的功能.这是测试链接:http://app.netonapp.com/JavaScript/Three.js/select_inner_objects.html

I would like to accomplish a feature that I can do in Three.js but cannot in Autodesk Forge viewer. Here is the link to test: http://app.netonapp.com/JavaScript/Three.js/select_inner_objects.html

要求是选择对象内的对象.这项工作可以在上面的演示中使用 THREE.Raycaster 来完成,使用 raycaster 来检测光线穿过的线上的所有元素.然后我可以将对象放在另一个对象后面或内部.

The requirement is to select objects inside an object. This job can be done with THREE.Raycaster in the above demo, to use a raycaster to detect all elements which are on the line the ray going through. Then I can get objects behind or inner another object.

我在 Autodesk Forge 查看器中尝试了这个概念,但没有成功.代码如下:

I tried this concept in Autodesk Forge viewer but having no success. Here is the code:

// Change this to:
// true to use original Three.js
// false to use Autodesk Forge Viewer API
var useThreeJS = true;

var container = $('div.canvas-wrap')[0];

container.addEventListener('mousedown', function (event) {
    if (useThreeJS) {
        var canvas = _viewer.impl.canvas;
        var containerWidth = canvas.clientWidth;
        var containerHeight = canvas.clientHeight;

        var camera = _viewer.getCamera();

        var mouse = mouse || new THREE.Vector3();
        var raycaster = raycaster || new THREE.Raycaster();

        mouse.x = 2 * (event.clientX / containerWidth) - 1;
        mouse.y = 1 - 2 * (event.clientY / containerHeight);
        mouse.unproject(camera);

        raycaster.set(camera.position, mouse.sub(camera.position).normalize());
        var intersects = raycaster.intersectObjects(objects);

        if (intersects.length == 1) {
            var obj = intersects[0].object;
            obj.material.color.setRGB(1.0 - i / intersects.length, 0, 0);
        } else if (intersects.length > 1) {
            // Exclude the first which is the outer object (i == 0)
            for (var i = 1; i < intersects.length; i++) {
                var obj = intersects[i].object;
                obj.material.color.setRGB(1.0 - i / intersects.length, 0, 0);
            }
        }
    } else {
        var vp = _viewer.impl.clientToViewport(event.canvasX, event.canvasY);
        var renderer = _viewer.impl.renderer();

        var dbId = renderer.idAtPixel(vp.x, vp.y);
        if (dbId) {
            console.debug("Selected Id: " + dbId);
            _viewer.select(dbId);
            _viewer.impl.invalidate(true);
        }
    }
}, false);

我发现 Forge 查看器具有 viewer.impl.renderer().idAtPixel 方法,该方法非常适合在拾取像素处获取元素.但是,我希望它做更多的事情,在拾取像素处选择所有元素(位于下方或嵌套).我如何使用 Forge Viewer API 做到这一点?

I found the Forge viewer has viewer.impl.renderer().idAtPixel method which is great to get an element at the picking pixel. However, I want it to do more, to select all elements (which are under or nested) at the picking pixel. How I can do it with the Forge Viewer API?

推荐答案

基于钟武在另一个post,这里是选择位于另一个元素之下或内部的元素的最终解决方案.我创建了一个 Autodesk Forge 查看器扩展来轻松使用它.

Based on the suggestion of Zhong Wu in another post, here is the final solution to select element which is under or inside another element. I created an Autodesk Forge viewer extension to use it easily.

///////////////////////////////////////////////////////////////////////////////
// InnerSelection viewer extension
// by Khoa Ho, December 2016
//
///////////////////////////////////////////////////////////////////////////////
AutodeskNamespace("Autodesk.ADN.Viewing.Extension");

Autodesk.ADN.Viewing.Extension.InnerSelection = function (viewer, options) {

    Autodesk.Viewing.Extension.call(this, viewer, options);

    var _self = this;

    var _container = viewer.canvas.parentElement;
    var _renderer = viewer.impl.renderer();
    var _instanceTree = viewer.model.getData().instanceTree;
    var _fragmentList = viewer.model.getFragmentList();
    var _eventSelectionChanged = false;
    var _viewport;
    var _outerDbId;

    _self.load = function () {

        _container.addEventListener('mousedown',
            onMouseDown);

        viewer.addEventListener(
            Autodesk.Viewing.SELECTION_CHANGED_EVENT,
            onItemSelected);

        console.log('Autodesk.ADN.Viewing.Extension.InnerSelection loaded');

        return true;
    };

    _self.unload = function () {

        _container.removeEventListener('mousedown',
            onMouseDown);

        viewer.removeEventListener(
            Autodesk.Viewing.SELECTION_CHANGED_EVENT,
            onItemSelected);

        console.log('Autodesk.ADN.Viewing.Extension.InnerSelection unloaded');

        return true;
    };

    function onMouseDown(e) {

        var viewport = viewer.impl.clientToViewport(e.canvasX, e.canvasY);
        _viewport = viewport; // Keep this viewport to use in onItemSelected()

        var dbId = _renderer.idAtPixel(viewport.x, viewport.y);

        if (_outerDbId == dbId) {
            _outerDbId = -1;

            // Deselect everything
            viewer.select();
        } else {
            _outerDbId = dbId;

            // Hide outer element temporarily to allow picking its behind element
            viewer.hideById(dbId);

            _eventSelectionChanged = true;
        }

        viewer.impl.sceneUpdated(true);
    }

    function onItemSelected(e) {

        if (_eventSelectionChanged) {

            // Prevent self looping on selection
            _eventSelectionChanged = false;

            // Show outer element back
            viewer.show(_outerDbId);

            // Get inner element Id after the outer element
            // was just hidden on mouse down event
            var innerDbId = _renderer.idAtPixel(_viewport.x, _viewport.y);

            if (innerDbId > -1) {
                // Select the inner element when it is found
                viewer.select(innerDbId);

                console.debug("Selected inner Id: " + innerDbId);

            } else if (_outerDbId > -1) {
                // Select the outer element if the inner element is not found
                viewer.select(_outerDbId);

                console.debug("Selected outer Id: " + _outerDbId);

            }
        }
    }

};

Autodesk.ADN.Viewing.Extension.InnerSelection.prototype =
    Object.create(Autodesk.Viewing.Extension.prototype);

Autodesk.ADN.Viewing.Extension.InnerSelection.prototype.constructor =
    Autodesk.ADN.Viewing.Extension.InnerSelection;

Autodesk.Viewing.theExtensionManager.registerExtension(
    'Autodesk.ADN.Viewing.Extension.InnerSelection',
    Autodesk.ADN.Viewing.Extension.InnerSelection);

这篇关于在 Autodesk Forge 查看器中的元素下拾取的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆