10 Mar 2015

Transform built-in object in Viewer by Autodesk View & Data API

Default blog image

In last blog, I talked about fragments. Some of the manipulations are related to fragments such as transformation, texture, geometries etc.

viewer.impl.getRenderProxy(model, fragId) returns the Mesh object of Three.js. fragId is the index of the same geometry fragment in the various fragments arrays of the model's internal data model. You can query the fragId from the collection of viewer.model.getData().fragments. In many scenarios, we would run our workflow in the event: SELECTION_CHANGED_EVENT. When the item is selected, it also tells fragId of the selection.

Mesh.matrixWorld stores the matrix of the transformation. It follows the standard sequence of the 4X4 transformation matrix of graphics. So, it is much easy to modify any matrix values with your requirement.

You can also apply a transformation to the mesh.matrixWorld directly, and then set mesh.matrixWorldNeedsUpdate = true. This will also update the transformation.

In Three.js, we can call some movement methods of Mesh object such as translateOnAxis,rotateOnAxis. However in order to conserve memory, we skip initialization of some terms of the THREE.Mesh which prevents some of the convenience movement APIs from working. In particular those are position, rotation, quaternion, scale and matrix. The translateOnAxis function uses position and quaternion, so it will fail.

The code demo below shows the 3 methods mentioned above. It assumes you have started a View and delegated the event of selection change.

//deletate selection change event

_viewer.addEventListener(Autodesk.Viewing.SELECTION_CHANGED_EVENT,

  onSelectedCallback);

 

function onSelectedCallback(event) {

 

    //get the first fragment of the selection           

    var fragId = event.fragIdsArray[0];

 

    //if nothing is selected

    if (typeof fragId == 'undefined') {

        return;

    }

 

    //Note: a fragment might contain sub fragments. 

    var fragIdsArray = (Array.isArray(fragId) ?

        fragId :

           [fragId]);

 

    //move every fragment of the mesh

    fragIdsArray.forEach(function (subFragId) {

 

        //get Mesh of this fragment

        var mesh = _viewer.impl.getRenderProxy(

                    _viewer,

                    subFragId);

 

        var method = 1; // 2 or 3 // method we want to test

 

        //Method 1: translate the mesh by explicitly setting the matrix values

        if (method == 1) {

            // WCS transformation of the mesh

            var mtx_for_method1 = mesh.matrixWorld.elements;

 

            //e.g. move along (X=10,Y-10,Z=10)

            mtx_for_method1[12] += 50;

            mtx_for_method1[13] += 50;

            mtx_for_method1[14] += 50;

        }

 

            //Method 2: apply a transformation to the .matrixWorld property

        else if (method == 2) {

 

            //prepare a transformation

            //rotate around X-Y-Z

            var transMat = new THREE.Matrix4();

 

            var m1 = new THREE.Matrix4();

            var m2 = new THREE.Matrix4();

            var m3 = new THREE.Matrix4();

 

            var alpha = 0;

            var beta = Math.PI;

            var gamma = Math.PI / 2;

 

            m1.makeRotationX(alpha);

            m2.makeRotationY(beta);

            m3.makeRotationZ(gamma);

 

            transMat.multiplyMatrices(m1, m2);

            transMat.multiply(m3);

 

            //apply a transformation

            var mtx_for_method2 = mesh.matrixWorld;

            mtx_for_method2.multiply(transMat);

            mtx_for_method2.matrixWorldNeedsUpdate = True;

        }

 

        //Method 3: movement methods of Mesh object

        if (method == 3) {

            //vector to translate

            var vector = new THREE.Vector3(10, 0, 0);

            //it will fail!

            mesh.translateOnAxis(vector, 10);

        }

    });

    _viewer.impl.invalidate(true);

 

}

image

The viewer.model.getData().fragments also stores the transforms , but they are not actively used during rendering. Those store the original positions of the model elements, in order to allow resetting the model after explode. So it is NOT recommended to modify viewer.model.getData()fragments.transforms.

My colleague Philippe produced an extension https://github.com/Autodesk-Forge/forge-rcdb.nodejs/tree/master/src/client/viewer.components/Viewer.Extensions.Dynamic/Viewing.Extension.Transform. It demos the transformation along with mouse moving.

Related Article