Autodesk Forge - Absolute coordinates - autodesk-forge

from the Forge viewer is it possible to retrieve the absolute coordinates of the objects?
With the following code I was able to obtain the relative coordinates of the selected object:
const viewer = NOP_VIEWER;
const dbId = NOP_VIEWER.getSelection()[0];
const selSet = viewer.getSelection();
const targetElem = selSet[0];
const model = viewer.model;
const instanceTree = model.getData().instanceTree;
const fragList = model.getFragmentList();
let bounds = new THREE.Box3();
instanceTree.enumNodeFragments( dbId, ( fragId ) => {
let box = new THREE.Box3();
fragList.getWorldBounds( fragId, box );
bounds.union( box );
}, true );
const position = bounds.center();
With the getAecModelData method I was able to retrieve the refPointTransformation:
What do the values ​​in this array refer to?
TIA
Alder

I'm not sure what exactly you mean by absolute coordinates but if we're talking about geolocation, note that there's actually a Geolocation extension for the viewer:
https://forge.autodesk.com/en/docs/viewer/v6/reference/Extensions/GeolocationExtension
The extension leverages the refPointTransformation in AEC Model Data, letting you transform lat/long (WGS84) coordinates to viewer coordinates and vice versa.
Here's a related blog post that might also help: https://forge.autodesk.com/blog/mini-map-geolocation-extension.

Related

x, y, z coordinates of an object for a nwc file in forge viewer

I am trying to find x,y,z coordinates of an object inside nwc model, and I am using below code.
Despite that this code was working for rvt files, it is not working for nwc model.
Is there a way to get x,y,z coordinates from a nwc model?
getFragmentWorldMatrixByNodeId(nodeId) {
let result = {
fragId: [],
matrix: [],
};
let viewer = this.viewer;
this.tree.enumNodeFragments(nodeId, function (frag) {
let fragProxy = viewer.impl.getFragmentProxy(viewer.model, frag);
let matrix = new THREE.Matrix4();
fragProxy.getWorldMatrix(matrix);
result.fragId.push(frag);
result.matrix.push(matrix);
});
return result;
}
You mentioned you are looking for the "x,y,z coordinates of an object". What exactly do you mean by that? I'm going to assume that you want the coordinates of the center point of the object's bounding box, as that is what people ask for usually. In your code snippet, however, you're retrieving the entire transformation matrix, not a position.
If the center point of a bounding box works for you, you could obtain it like so:
function getObjectBoundingBox(model, dbid) {
const tree = model.getInstanceTree();
const frags = model.getFragmentList();
let totalBounds = new THREE.Box3();
tree.enumNodeFragments(dbid, function (fragid) {
let fragBounds = new THREE.Box3();
frags.getWorldBounds(fragid, fragBounds);
totalBounds.union(fragBounds);
}, true);
return totalBounds;
}
getObjectBoundingBox(viewer.model, 123).center();

Forge Viewer, raster images

Is possible to directly load a raster image (PNG, JPG, TIFF) to Forge Viewer?
I see the Autodesk.PDF add-in that can load PDF, I cant find any Autodesk.IMAGE add-in...
Otherwise I need to prior convert Image into PDF and than load it through Autodesk.PDF.
The Autodesk Forge Viewer is based on Three.js - therefore you can use the Three.js API to load an image/texture, there is no need of a Viewer extension for that.
However it depends what you want to do. In case you just want to load an image in the scene, that code is enough.
const texture = THREE.ImageUtils.loadTexture( "thumbnail256.png" );
const material = new THREE.MeshBasicMaterial({ map : texture });
const geometry = new THREE.PlaneGeometry(5, 20, 32);
const planeMesh = new THREE.Mesh(geometry, material);
const planeMesh.position.set(1, 2, 3);
NOP_VIEWER.overlays.addScene('custom-scene');
NOP_VIEWER.overlays.addMesh(planeMesh, 'custom-scene');
But if you want to apply the texture on an existing element in the loaded scene, you need to proceed like this:
const texture = THREE.ImageUtils.loadTexture( "thumbnail256.png" );
const material = new THREE.MeshBasicMaterial({ map : texture, side: THREE.DoubleSide });
NOP_VIEWER.impl.matman().addMaterial('custom-material', material, true);
const model = NOP_VIEWER.model;
model.unconsolidate(); // If the model is consolidated, material changes won't have any effect
const tree = model.getInstanceTree();
const frags = model.getFragmentList();
const dbids = NOP_VIEWER.getSelection();
for (const dbid of dbids) {
tree.enumNodeFragments(dbid, (fragid) => {
frags.setMaterial(fragid, material);
});
}
NOP_VIEWER.impl.invalidate(true, true, false);
Note you may need to work out the texture uv, depending on the geometry.

Forge Viewer: Properties Window

The Properties window does not populate any properties even though the 2D view has properties info for the selected room
Here is the function that loads the model. what am I missing?
function loadModel() {
var initialViewable = viewables[indexViewable];
var svfUrl = lmvDoc.getViewablePath(initialViewable);
var modelOptions = {
sharedPropertyDbPath: lmvDoc.getFullPath(lmvDoc.getRoot().findPropertyDbPath())
};
viewer.loadModel(svfUrl, modelOptions, onLoadModelSuccess, onLoadModelError);
}
One line missing in your code, please try the following instead:
var sharedDbPath = initialViewable.findPropertyDbPath();
sharedDbPath = lmvDoc.getFullPath( sharedDbPath );
var modelOptions = {
sharedPropertyDbPath: sharedDbPath
};
However, you should not need to specify the sharedPropertyDbPath manually now. You can take advantage of the Viewer3D#loadDocumentNode to load the model directly. It will automatically determine the path for you. (started from v7 viewer)
const initialViewable = viewables[0];
viewer.loadDocumentNode( lmvDoc, initialViewable, loadOptions )
.then( onLoadModelSuccess )
.catch( onLoadModelError );

How to include different images in my autodesk forge viewer floorplan

Im currently working on a project with the autodesk forge viewer. My viewer is showing an uploaded and converted floorplan. In this plan I would like to show different logos for my rooms from a database. I have made multiple extensions for my viewer already but I have not discovered any possibility for my logo project so far. Maybe you have any ideas for implementing.
Thx,
JT
The easiest way that comes to mind is to append an element containing your logos to the canvas - see this blog here to get started.
Basically you'd need to attach images to the rooms' locations hovering over the canvas and subscribe to the camera change event to adjust their locations/coordinates per camera movement. You can retrieve the coordinates of your room by calculating their bounding boxes with their dbid with:
function get2DBounds(dbId, model){
const find2DBounds = function(fragList, fragId, dbId, bc) {
const mesh = fragList.getVizmesh( fragId );
const vbr = new Autodesk.Viewing.Private.VertexBufferReader( mesh.geometry );
vbr.enumGeomsForObject( dbId, bc );
}
const it = model.getData().instanceTree;
const fragList = model.getFragmentList();
let bounds = new THREE.Box3();
let bc = new Autodesk.Viewing.Private.BoundsCallback( bounds );
const dbId2fragId = model.getData().fragments.dbId2fragId;
const fragIds = dbId2fragId[dbId];
if( Array.isArray( fragIds ) ) {
for( let i = 0; i < fragIds.length; i++ ) {
find2DBounds( fragList, fragIds[i], dbId, bc );
}
} else if( typeof fragIds === 'number' ) {
find2DBounds( fragList, fragIds, dbId, bc );
}
return bc.bounds;
}
const boundingBox = get2DBounds( dbId, viewer.model );
const position = boundingBox.center()

Get THREE.Mesh elements in Autodesk Forge Viewer

I would like to get the THREE.Mesh object of an element in Autodesk Forge Viewer. Here is the code:
var dbId; // geometry node Id of an element
var viewer; // GuiViewer3D
var mesh = viewer.impl.getRenderProxy(viewer.model, dbId);
The return mesh object is a THREE.Mesh object but with null Geometry and Material, so it is useless. How can I get the real THREE.Mesh object?
Thank you.
It depends what you want to do with the mesh: if you want to change the render style, you need to get the renderProxy, if you want to transform the component position or rotation, you need to get the fragmentProxy.
Those methods take as input the fragment ids not the dbId.
Find examples for both at:
Viewing.Extension.Material
Viewing.Extension.Transform
You get the fragment Ids for a given dbId either from the selection event, as illustrated in the above samples, or by using enumNodeFragments:
var instanceTree = model.getData().instanceTree
var fragIds = []
instanceTree.enumNodeFragments(dbId, function(fragId){
fragIds.push(fragId)
})
// to change material or transform, need to iterate all
// fragments of a given dbId and apply same material/transform
fragIds.forEach(function(fragId) {
var renderProxy = viewer.impl.getRenderProxy(viewer.model, fragId)
var fragmentproxy = viewer.impl.getFragmentProxy(viewer.model, fragId)
})