I am currently looking at trying to get a very simple solution working as a proof of concept before going any further with forge. I have gone through the basic application quick start guide and the basic extension guide and the viewer it self works perfectly with a file I created using Autodesk pipe 3D (tried both as a dwg file and a dwfx).
All I am trying to do is change the colour of the model, all the guides I could find all use similar methods but they all require you to get the list of FragIDs to apply a material
var it = viewer.model.getData().instanceTree;
var allDbIds = Object.keys(it.nodeAccess.dbIdToIndex);
for (var i=0; i<allDbIds.length; i++) {
var dbid = allDbIds[i];
var fragIds = []
try {
it.enumNodeFragments(dbid, function(fragId){
fragIds.push(fragId)
})
}catch(error) {
console.error(error);
}
fragIds.forEach(function(fragId) {
//code to actually change colour
})
It manages to get the dbid fine and brings back many however when it tries to get the frag ids it doesnt bring back anything. It does not break it just brings back nothing but am having trouble finding where to actually look in to why or where to even start
First thing would be to define the fragIds array outside of the for loop, so it's not getting overridden at each iteration.
You can use the following code to set a specific material to a fragId:
fragIds.forEach((fragId) => {
model.getFragmentList().setMaterial(
fragId, material)
})
Take a look at this thread for more info how the topic:
Forge Viewer THREE.MeshLambertMaterial
Related
I am trying to display a point on model displayed in the Autodesk forge viewer. However I am unable to figure out how to transform the point. I found the next question that seems to resolve this question:
Transform point from DWG model coordinates to autodesk forge viewer coordinates
When I try to use the function of this question:
var vpXform = viewer.model.getPageToModelTransform(viewportId).clone();
var invVpXform = new WGS.LmvMatrix4(true);
invVpXform.getInverse(vpXform, true);
var ptInCadX = ...;
var ptInCadY = ...;
var verticesInViewer = new THREE.Vector3().set(ptInCadX, ptInCadY, 0).applyMatrix4(invVpXform);
It shows the next error: Uncaught ReferenceError: WGS is not defined
And if I try it without the WGS.LmvMatrix4, it shows the following error: Uncaught ReferenceError: new LmvMatrix4 is not defined
I'm using the latest version of the Forge Viewer, v7.Can someone help me finding what am I doing wrong?
Thank you very much.
Here's an updated version of the snippet:
// Start by getting a list of all viewports in your model
let viewports = viewer.model.getData().viewports;
// Choose a viewport you want to use for the design-to-viewer coordinate mapping (it must include a `transform` property);
// in my case I'll just pick the first one
let viewport = viewports[0];
// Load the viewport transform into a three.js matrix
let xform = new THREE.Matrix4().fromArray(viewport.transform);
// Compute the inverse transxform
let inverse = new THREE.Matrix4().getInverse(xform, true);
// Use the inverse transform to convert design coordinates to paper coordinates
let someX = 0, someY = 0;
let viewerCoords = new THREE.Vector3().set(someX, someY, 0).applyMatrix4(inverse);
function newMarkupGUI(viewer, options) {
Autodesk.Viewing.Extension.call(this, viewer, options);
thisViewerId = options.id;
this.viewer.loadExtension("Autodesk.Viewing.MarkupsCore").then(() => {
let extension = this.viewer.getExtension("Autodesk.Viewing.MarkupsCore");
extension.enterEditMode();
console.log(extension.enterEditMode());
});
}
When I am inside my main js file where I initialize the viewer, I am able to access functions such as enterEditMode() like so:
var extension = viewer.getExtension("Autodesk.Viewing.MarkupsCore");
extension.enterEditMode();
This works. But inside my extension called newMarkupsGUI, it seems getExtension() does not work. I am confused about how this all works, as the documentation is pretty sparse. I would rather keep my extension separate and not hard code the functionality of markups where I am initializing the viewer. Any help would be appreciated, thank you.
I think your problem is related to the viewer reference. You don't need to use this.viewer if you have your viewer as function parameter.
When using viewer.loadExtension().then() the loaded extension is returned in the promise.
You can do something like that :
viewer.loadExtension("Autodesk.Viewing.MarkupsCore").then((markupExtension) =>
{
markupExtension.enterEditMode();
});
I am using forge viewer for displaying AutoCAD files.
Also using the drawing tool over viewer based on the sample source.
I will draw the area by using box or sphere draw tools.
I need to save the current viewer including box or sphere area which I was marked over viewer and when again loading same file the area which has been marked that should be bind default.
How it is possible please help me
Suggest any way to implement this scenario.
Thanks in advance.
You can do that with 2 steps.
First, taking advantage of Object3D.toJSON() method.
Let's summarize in a sample where we generate a JSON object from our mesh:
//here we create a BoxGeometry
let geom = new THREE.BufferGeometry().fromGeometry(new THREE.BoxGeometry(100,100,100));
let phongMaterial = new THREE.MeshPhongMaterial({
color: new THREE.Color(1, 0, 0)
});
let mesh = new THREE.Mesh(geom, phongMaterial);
if (!viewer.overlays.hasScene("CustomScene")) {
viewer.overlays.addScene("CustomScene");
}
viewer.overlays.addMesh(mesh, "CustomScene");
viewer.impl.sceneUpdated(true);
//here we generate the JSON from the mesh and download it
let jsonObject = JSON.stringify(mesh.toJSON())
download(jsonObject, 'Box.json', 'text/plain');
download function can be found here.
The next step is about generating the box from the saved JSON.
For that, we'll use ObjectLoader.parse method.
And again, we can summarize in the code below:
//here we read the JSON object from our generated file
var request = new XMLHttpRequest();
request.open("GET", "js/Box.json", false);
request.send(null)
var my_JSON_object = JSON.parse(request.responseText);
//here we generate the mesh
let mesh = new THREE.ObjectLoader().parse(my_JSON_object);
if (!viewer.overlays.hasScene("CustomScene")) {
viewer.overlays.addScene("CustomScene");
}
viewer.overlays.addMesh(mesh, "CustomScene");
viewer.impl.sceneUpdated(true);
Refer here for the function to read objects from JSON file.
It seems to be possible to view and navigate Revit Drafting View(s) graphics using the Forge API's based on how the BIM 360 Document Management web browser interface does it with our own Revit (.rvt) model having published Drafting Views where it list the 2D Drafting Views (thumbnails) in the left panel and the actual detail of the selected Drafting View in the right viewer. We do have one of the more recent Forge API Viewer examples setup and working, and tried modifying some of its code, but is seems to be designed to only work with Models (.rvt) components in the left panel, and its not obvious where and what code needs to be modify to change it to list 2D sheets/views like the Document Manager does. We are having difficulty locating a Forge API example that shows how to do this using the Forge API's and would like to obtain a working example that illustrates how to do this using the Forge API's?
Tried changing the ViewingApplication.bubble.search to include role 2d type view
function onDocumentLoadSuccess(doc) {
// We could still make use of Document.getSubItemsWithProperties()
// However, when using a ViewingApplication, we have access to the
*bubble** attribute,
// which references the root node of a graph that wraps each object from the Manifest JSON.
//var viewables = viewerApp.bubble.search({ 'type': 'geometry' });
var viewables = viewerApp.bubble.search({ 'role': '2d', 'type': 'view' });
if (viewables.length === 0) {
console.error('Document contains no viewables.');
return;
}
The drafting view is kind of 2d role geometry, Therefore you can load it with the same way for the 2D view.
const rootItem = doc.getRoot();
const filter = { type: 'geometry', role: '2d' };
const viewables = rootItem.search( filter );
if( viewables.length === 0 ) {
return onLoadModelError( 'Document contains no viewables.' );
}
// Take the first viewable out as the loading target
const initialViewable = viewables[0];
const loadOptions = {
sharedPropertyDbPath: doc.getPropertyDbPath()
};
viewer.loadDocumentNode(doc, initialViewable.data, modelOptions).then(onItemLoadSuccess).catch(onItemLoadFail);
To show a list of views like the BIM360 Docs, you could load Autodesk.DocumentBrowser extension. It will show viewable items on it, and just click on it to switch. See below snapshot:
My goal is to highlight a room by adding new geometry to the viewer based on lines I have created in revit like they do here Link
but i can not figure out how to access those lines ids.
I know what they are in revit (element_id) but not how they are mapped as dbid.
Following this Blog Post
I want to access the objectTree in my extension to find out, but it always comes back as undefined.
var tree;
//old way - viewer is your viewer object - undefined
viewer.getObjectTree(function (objTree) {
tree = objTree;
});
//2.5 - undefined
var instanceTree = viewer.model.getData().instanceTree;
var rootId = this.rootId = instanceTree.getRootId();
//- undefined
var objectTree = viewer.getObjectTree();
Can anyone tell me if its still works for them I am using the v2 of the API for the rvt conversion to svf and 2.9 of the viewer3D.js
note I can see a list of dbid if I call this
var model = viewer.impl.model;
var data = model.getData();
var fragId2dbIdArray = data.fragments.fragId2dbId ;
but have no way of mapping back to the Revit element_id
As of version 2.9 this is still working. Here's my console:
Here's a couple of things you can try:
Is viewer undefined? Are you in the correct scope when grabbing the viewer?
The document have to be loaded before you can grab the instance tree. When the document is loaded, an event called Autodesk.Viewing.GEOMETRY_LOADED_EVENT will be fired, then you can start manipulating the instance tree.
Simply do this:
viewer.addEventListener(Autodesk.Viewing.GEOMETRY_LOADED_EVENT, function () {
var instanceTree = viewer.model.getData().instanceTree;
});
For more structured code, follow this guide to add an extension.
There's a more detailed blog post on which event to listen for. It's still using the old way to get instance tree, though.
Shiya Luo was correct the viewer had not yet finished loading the geometry
in my extentions Load function I added two event listeners and made sure they both fired before trying to access the instanceTree
viewer.addEventListener(Autodesk.Viewing.GEOMETRY_LOADED_EVENT, function () {
finishedGEOMETRY_LOADED_EVENT = true;
if(finishedGEOMETRY_LOADED_EVENT && finishedOBJECT_TREE_CREATED_EVENT ){
afterModelLoadEvents(viewer);
}
});
viewer.addEventListener(Autodesk.Viewing.OBJECT_TREE_CREATED_EVENT, function () {
finishedOBJECT_TREE_CREATED_EVENT = true;
if(finishedGEOMETRY_LOADED_EVENT && finishedOBJECT_TREE_CREATED_EVENT ){
afterModelLoadEvents(viewer);
}
});