Missing properties (Globalds) from IFC file in viewer - autodesk-forge

To resume the steps leading to my issue:
Upload a file to bucket in Forge.
Convert the file.
Extract the IFC data using external tool.
Now I am trying to get (using the Viewer) the GlobalIds of each element, as in IFC they are unique and match them to the data that I already have by this property.
Currently in the converted file that is shown in the viewer, not all the elements from the geometry are providing the correct data on click.
For example: If I open a IFC file in viewer and I click on the Roof element, it does not select the IfcRoof element, but some IfcElement that is lower in the structure and that neither have a GlobalId, nor has some data attached, cause it is not supposed to. So now it is not possible to get the proper properties of the element using the viewer because it does not selects the right element, which I need to match the data that I extract with the external tool.
Any ideas how I can proceed with that?

Can you simply traverse the structure from the lower level element upwards until you reach an element that does provide a valid global id?

So the clue is that you should iterate the response's __parent's till you get an element with type 'IFC' and get his GlobalId. It works in most cases.

Related

Node element not in instance tree

I'm trying to hide some elements of a model using the Forge viewer API, but I can't access some of them because their dbIds aren't found in the model instance tree.
It's very strange because I can't hide them using the context menu either, in the properties panel it shows undefined in the name, and it's also not found in the model browser panel.
Any ideas about how can I find those elements and show or hide them programmatically?
In the model that has this problem, those objects are curtain wall profiles.
In the SVF format it's common to have dbIDs without any visual representation. There might be different reasons for that but the one that's most common IMHO is instancing - you can have one object as a "template" (with no geometry), and a couple of objects (with geometries) that are "instances" of that template, inheriting its properties. That is also why the dbIDs of these "template" objects are not found in the model hierarchy.

How to restore viewer state directly from MarkupEdit or MarkupView mode?

With reference of https://forge.autodesk.com/cloud_and_mobile/2016/02/playing-with-the-new-view-data-markup-api.html, I am implementing 2D markup feature in forge viewer.
I'm using Autodesk.Viewing.MarkupsCore library to draw annotations over model in forge viewer. For that I'm loading Autodesk.Viewing.MarkupsCore extension as _markupsExtension .
I tried drawing some markup annotation and saved viewer state. When I tried loading these previously drawn annotations, It failed to restore viewer state, but it was loading annotations data properly.
// To draw and save markup
viewer.loadExtension("Autodesk.Viewing.MarkupsCore").then(function(markupExt) {
_markupsExtension = markupExt;
_state = _markupsExtension.viewer.getState();
_markupsExtension.hide();
_markupsExtension.enterEditMode();
//From now on, while in EditMode, the user will be drawing text boxes
_data = _markupsExtension.generateData(); //Annotations data can be generated
_state = _markupsExtension.viewer.getState(); //to store viewer state information
_markupsExtension.leaveEditMode();
viewer.unloadExtension("Autodesk.Viewing.MarkupsCore"); //User can navigate within model
});
// To load previously drawn markup
viewer.loadExtension("Autodesk.Viewing.MarkupsCore").then(function(markupExt) {
_markupsExtension = markupExt;
_markupsExtension.leaveEditMode();
_markupsExtension.show();
_markupsExtension.viewer.restoreState(_state); //it fails to restore state
_markupsExtension.viewer.impl.invalidate(true);
_markupsExtension.loadMarkups(_data, 'aaa'); //loads markup data while keeping viewerstate unchanged.
});
Why does it fail to restore state while being in markup viewing mode?
What is difference between _markupsExtension.viewer.restoreState(_state) and viewer.restoreState(_state)
================================ EDITED =============================
Is there any way where I could stay within editing mode/viewing mode and change viewer's state?
I am saving all markups in a list view in different sessions or file per session (referring https://forge.autodesk.com/cloud_and_mobile/2016/02/playing-with-the-new-view-data-markup-api.html ).
e.g. 1) I moved model to the top and drawn arrow pointing to particular object and I saved it with name "MarkupA.json".
2) I moved model to front and zoomed it out so that it went far from camera. Then I drawn Square markup and stored it with name "MarkupB.json".
3) Then again I kept model to default iso (home) mode and drawn text annotation and saved it with name "MarkupC.json".
All these markups are listed in the UI panel like a tree. So when am clicking on any particular name, that markup and its model viewer state has to get restored without change in any markup mode.
I have checked this similar functionality in bim360. When I stored different markups in BIM360, it stored all markups in its database and small thumbnail screenshot appeared for its relevant markup card. I viewed all markups in markup panel or comment panel.
When I clicked on specific thumbnail, every markup appeared with appropriate stored viewer state.
I am trying to get similar functionality in forge viewer using new Markups core extension and customised its markup code to store states with markups. When I tried to load each markup, it seems like markup is getting loaded but its viewer state is not able to get restored neither in edit mode nor in viewing mode. I understood that restoring state is not possible if we are in markups mode. But what if I want to show the previously stored drawn markup on particular view?
The workaround which I tried to switch between markup is as follow,
On click of another markup -
a) leave viewing mode
b) restore model with stored state
c) enter viewing mode.
d) load its markup svg.
The issue with this is it is taking too much time taking too much time to reload markup with restored state.
Can you please tell me if we have any other workaround or approach to achieve loading and restoring markup and its viewer state synchronously?
Why does it fail to restore state while being in markup viewing mode?
When in markup mode the camera is locked so you will need to drop out of edit mode before restoring Viewer states and then go back.
What is difference between _markupsExtension.viewer.restoreState(_state) and viewer.restoreState(_state)
No difference as _markupsExtension.viewer is just a reference of the plugin to the master Viewer object

Highlighting only the geometry of a parent object in autodesk's online viewer

We have revit model in which a parent element has both children and its own geometry. In the online viewer it is possible to select the parent through clicking the respective geometry, in which case only the geometry for the parent is highlighted. (selected through a click)
If I select the element through the tree the whole model gets highlighted.
(selected through the model browser)
In our web application, we are unable to get the former behavior. When passing the dbId of the parent to viewer.select, the parent plus all the children get highlighted. Same happens when we click the parent element's geometry. How can we select only the parent object programmatically?
We have tried passing different selection modes (overlayed, regular, mixed) to viewer.select but that didn't help and all objects got selected regardless of that parameter.
In this question it is mentioned by autodesk staff that only leaf nodes have geometries. That doesn't seem to be the case here:
Determine if node is an assembly or part in viewer
Thanks for the sample file. I did the following: open the model, select manually and, via console, typed .getSelection(), which returns me the dbId of the selected element. Now unselect everything. Then run .select(2890) and the result is as expected: only the top element is selected (as shown in the image below). I'm using Viewer 3.3.
You can try my sample live here, it uses the Basic Application tutorial.

How to write Javascript code for model browser while using autodesk-forge-viewer API

I am trying to replicate a part of demo shown here using autodesk-forge-viewer api. Particularly, I am not able to find code snippet around how can I do navigation for a particular area of 3D model. For example, if render 3D model is house, I require that If a click on "Bed Room" which is a link somewhere in browser, 3D rendered model should show me that "Bed Room". In sample app shown, they are providing the same as a feature of "Model Browser".
Could anyone please help me with that?
You first need to know the dbId's of the nodes you are interested in, most viewer API methods take dbIds as input. You get those either by listening to selection events, see that post, or by parsing the instance tree and checking the properties of the nodes to see if those are the ones you looking for.
You can then use methods such as viewer.fitToView([dbIds]), viewer.hide([dbIds]), viewer.show([dbIds]) ... Here is another article that might be useful: Hidding completely viewer nodes (no ghosting).
Hope that helps.

Retrieving all address information along Google Maps route

I am developing an Windows Forms application using VB.NET that offers the user to lookup addresses on Google Maps through a Web Browser. I can also successfully show the directions between two points to the user, as well as allow the user to drag the route as he/she pleases. My question now is - is it possible for me to get the lattitude/longitude information of the route, i.e. the overview_polyline array of encoded lattitude/longitude points and save it to e.g. a text file on my computer? Or is it possible to get a list of all the addresses located both sides of the route over the entire length of the route, and then save the data to a file on my computer? I'm using HTML files to access and display the Google Maps data in the Web Browser item.
Thank you
This is actually pretty simple if your just looking for the screen coordinates.
// this probably should be in your form initialization
this.MouseClick += new MouseEventHandler(MouseClickEvent);
void MouseClickEvent(object sender, MouseEventArgs e)
{
// do whatever you need with e.Location
}
if your strictly looking for the point in the browser, you need to consider the functions
browser.PointToClient();
browser.PointToScreen();
So, this method is usable if you know exactly where your form is (easy to get its coords) and where you webbrowser control is (easy to get coords of this as well since it's just a control in your form) and then, as long as you know how many pixels from the left or right, and from the top or bottom the image will be displayed, once you get the global mouse click coords (which is easy) you can predict where it was clicked on the image.
Alternatively, there are some scarier or uglier ways to do it here...
You can use the ObjectForScripting property to embed code to do this in the webbrowser. It's ugly to say the least. MSDN has some documentation on the process here: http://msdn.microsoft.com/en-us/library/system.windows.forms.webbrowser.objectforscripting.aspx
Because its really ugly, maybe a better solution is to use AxWebBrowser - it's ugly too but not so scary.
In addition, I found this post of someone wanting to do it on a pdf document, and a MSFT person saying its not possible, but really what he is trying to say is that it isn't built in, even with a pdf document its still possible to predict with high to certain accuracy where it was clicked if you use the first method i described. Here is the post anyway: http://social.msdn.microsoft.com/Forums/en/csharpgeneral/thread/2c41b74a-d140-4533-9009-9fcb382dcb60
However, it is possible, and there are a few ways to do it, so don't get scared from that last link I gave ya.
Also, this post may help if you want to do it in javascript:
http://www.devx.com/tips/Tip/29285
Basically, you can add an attribute on the image through methods available in the webbrowser control, you can add something like onclick="GetCoords();" so when it is clicked, the JavaScript function will get the coords, and then you can use javascript to place the values in a hidden input field (input type="hidden") which you can add through the webbrowser control, or if there is one already on the page, you can use that. So, once you place the coords using javacript into that input field, you can easily grab the value in that using the webbrowser control, eg:
webbrowser1.document.getElementById("myHiddenInputField").value
That will get the value in that field, which you've set through JavaScript. Also, the "GetCoords()" function i mentioned is called SetValues() in the javascript method link i provided above (in the devx.com site) but I named it GetCoords because it makes more sense and didn't want to confuse you with the actual name they used, you can change this to any name you want of course. Here is the javascript they were using, this only gets the coords into a variable, doesn't put it into a hidden input field, we will need to do that in addition (at the end of the javascript SetValues/GetCoords function).
function SetValues()
{
var s = 'X=' + window.event.clientX + ' Y=' + window.event.clientY ;
document.getElementById('divCoord').innerText = s;
}
These guys are just saving it inside a div element, which is visible to users, but you can make the div invisible if you want to use a div field, there is no advantage or disadvantage in doing that, you would just need to set the visible property to false using javascript or css, but still, it is easier to use a hidden input field so you don't need to mess with any of that.
Let me know how you get along.