combine model on Autodesk Forge - autodesk-forge

I have couple of questions about combine model on forge viewer (load list urn to 1 viewer):
when i combine model. i only can get data from 1 main model in that combine. for instance, 
var instanceTree = GlobalViewer.model.getData().instanceTree;
var allDbIdsStr = Object.keys(instanceTree.nodeAccess.dbIdToIndex);
var list = allDbIdsStr.map(function (id) { return parseInt(id) });
list will return all dbid of main model, how can i access all data of all model when i combine?
what is the unique id for object in combine model. i do some function with dbid and i realize it can appear in others model too.
When i combine 3d model(revit) with 2d model(autocad). it has 2 case: if 3d model load first i can rotate like normal, if 2d model load first i cant rotate the model any more. how can i force it always can rotate?
Autocad unit seems different with model in viewer. it always scale down compare with the model. how can i fix that?
Appreciate any comments,

Regarding #1: viewer.model obviously only references one of the models (I believe it's the last one you loaded), but you can use viewer.getVisibleModels() or viewer.getHiddenModels() to get other loaded models as well.
Regarding #2: dbIDs are only unique within a single model; many of the viewer methods accept an additional parameter specifying the model on which to operate, for example, you could say viewer.select([123, 456], oneOfMyModels).
Regarding #3: that's a good question; loading a 2D model first puts the viewer into 2D viewing mode (where only zoom and pan is allowed); if you know you will be working with 3D models, I'd recommend always loading those first
Regarding #4: yes, each loaded model can have different units; when loading a model using the loadDocumentNode method you can specify additional options (for example, a placement transform for the loaded geometries), and one of them is an object called applyScaling, for example, like so:
viewer.loadDocumentNode(doc, viewable, {
applyScaling: { to: 'mm' }
});

Related

Forge viewer: how to isolate custom objects?

We use custom objects to visualize ifc space data (mostly rooms). As a guidance, we used this very helpful blog. After drawing the objects, we would also like to select the custom objects from outside and isolate them in the viewer. As the tutorial suggests, we change the model builder's changeFragmentsDbId function to set DbIds that do not exist yet and therefor do not overlap with already existing DbIds. One approach is to use the negative space [-1, -2, -3...] for our custom objects DbIds like this:
const roomFragId = this.modelBuilder.addFragment(roomGeometryId, materialName, transform);
this.modelBuilder.changeFragmentsDbId(roomFragId, -roomFragId);
Another one is to find the maximum DbId (eg. 4905) and use numbers higher than this maximum DbId for our custom objects DbIds (eg. [4906, 4907, 4908...]):
const roomFragId = this.modelBuilder.addFragment(roomGeometryId, materialName, transform);
this.modelBuilder.changeFragmentsDbId(roomFragId, maxDbId + roomFragId);
However, when we try to isolate a custom drawn object (viewer.isolate(-1) or viewer.isolate(4906)), the viewer kind of refreshs itself, but no object gets isolated...
Thus, we would like to know how we can isolate custom objects?
The other way, when we select the object in the viewer works for the negative space approach => we get the DbId (eg. -1) in the aggregate selection event.
Thank you for any kind of help!
To isolate or select custom objects created by the SceneBuilder ext, you need to pass model object to Viewer3D#isolate / Viewer3D#select like the below. Otherwise, viewer will use viewer.model instead.
viewer.isolate( [4906, 4907, 4908...], this.modelBuilder.model )
viewer.select( [4906, 4907, 4908...], this.modelBuilder.model )

Splitting a feature collection by system index in Google Earth Engine?

I am trying to export a large feature collection from GEE. I realize that the Python API allows for this more easily than the Java does, but given a time constraint on my research, I'd like to see if I can extract the feature collection in pieces and then append the separate CSV files once exported.
I tried to use a filtering function to perform the task, one that I've seen used before with image collections. Here is a mini example of what I am trying to do
Given a feature collection of 10 spatial points called "points" I tried to create a new feature collection that includes only the first five points:
var points_chunk1 = points.filter(ee.Filter.rangeContains('system:index', 0, 5));
When I execute this function, I receive the following error: "An internal server error has occurred"
I am not sure why this code is not executing as expected. If you know more than I do about this issue, please advise on alternative approaches to splitting my sample, or on where the error in my code lurks.
Many thanks!
system:index is actually ID given by GEE for the feature and it's not supposed to be used like index in an array. I think JS should be enough to export a large featurecollection but there is a way to do what you want to do without relying on system:index as that might not be consistent.
First, it would be a good idea to know the number of features you are dealing with. This is because generally when you use size().getInfo() for large feature collections, the UI can freeze and sometimes the tab becomes unresponsive. Here I have defined chunks and collectionSize. It should be defined in client side as we want to do Export within the loop which is not possible in server size loops. Within the loop, you can simply creating a subset of feature starting from different points by converting the features to list and changing the subset back to feature collection.
var chunk = 1000;
var collectionSize = 10000
for (var i = 0; i<collectionSize;i=i+chunk){
var subset = ee.FeatureCollection(fc.toList(chunk, i));
Export.table.toAsset(subset, "description", "/asset/id")
}

Viewer3D's getIsolatedNodes and getHiddenNodes not working for multiple models

I'm loading multiple IFC's with their SVF derivatives into the Forge viewer. This works fine, but I cannot seem to get the Viewer3D's getIsolatedNodes or getHiddenNodesto work.
I'm using the GuiViewer3D class like this:
// initializing:
const viewer = new Autodesk.Viewing.Private.GuiViewer3D(viewerDiv);
...
// load model1
viewer.start(model1Url ....
...
// load model2
viewer.loadModel(model2Url, ...
...
// after having loaded the models:
console.log(viewer.getIsolatedNodes());
The last line here only prints node ids if model1 has isolated nodes. If isolating nodes from model2, the last line prints an empty array. Is there a way to make this work with multiple models?
You can get access to the viewer's visibility manager via viewer.impl.visibilityManager, and call its methods for a specific model ID, for example:
viewer.impl.visibilityManager.getIsolatedNodes(modelID);
viewer.impl.visibilityManager.getHiddenNodes(modelID);
viewer.impl.visibilityManager.getAggregateHiddenNodes(); // across all models

How to select by dbid in viewer when several models are loaded?

I load several models in my scene. I would like to:
Fit to view from dbId -> this can be done with viewer.fitToView(objectIds,model)
Select an element from dbid on a particular model. But viewer.select(dbids,selectionType) does not offer possibility to select the model.
How can we make a selection on a dbid, on specific model, when several models are loaded?
Thanks
Looking at the code of Forge Viewer v6, the select method is defined as
Viewer3D.prototype.select = function (dbids, model) { ... }
So the second parameter should actually be the model, not a selection type.

SAPUI5 copy model and break binding?

On initialization I read an oData service to get a small list of values and I store the model for further use in the application.
sap.ui.getCore().setModel(oODataJSONModel, "xlist");
At multiple stages, I want to make a copy of the original model, make changes to the values list and use it in a Select drop down. I've tried multiple different things, but every time I update/delete the copied model values, it is instantly reflected in the original model. This seems like a simple ask, but is there a way to break the link between the original model and the copied model, ideally I want to keep the original list intact so that list can be re-used over and over, regardless of what changes are made to the copies?
var oModelCpy = new sap.ui.model.json.JSONModel();
var cpyModelArray = oOrigModel.getData();
cpyModelJsonData = { results : [ cpyModelArray ] };
oModelCpy.setData(cpyModelJsonData );
When I remove entries from the copy model, it also removes entries from the original model, which in this case is not what i want.
Any suggestions?
A better approach is to save your data in the success handler:
oODataJSONModel.read("/yourService",
null,
null,
false,
function(oData, oResponse){
var oODataJSONModel = new sap.ui.model.json.JSONModel();
oODataJSONModel.setData(oData);
this.getView().setModel(oODataJSONModel, "jsonModel");
}
);
EDIT
I just stumbled upon this question while I was browsing through the list of UI5 questions, and it dawned to me what is causing your underlying copy issue! :-)
If you copy an array of objects to a new array (which is also happens if you copy model data to another model), you won't get a new array with new objects
Instead, you actually will get a new array, but with references to the old objects. So any change you make to a value in an object inside an array in model 1, will end up having that same value in model 2
So, in effect, you need to create new objects based on the old ones. Luckily, you don't need costly for loops and hardcoded value-copying logic to achieve this; one single line should be ok.
Let's say your original data is referenced by an array aData.
You then copy this data (a true copy) to a new array using JSON:
var aDataCopy = JSON.parse(JSON.stringify(aData));
If you now set this aDataCopy as the data for your second model, it will not have any references to the old model anymore.
Hope this helps!
Try using jquery extend() method to make a copy of the data. I had similar troubles earlier.
var newObject = $.extend({},oldObject);
Try this for once. Find the reference at http://api.jquery.com/jquery.extend/