Distinguish different 'types' of nodes in the InstanceTree of the viewer - autodesk-forge

We are running some processing on the contents of the InstanceTree, were the goal is to only collect the nodes which have a direct (geometric element) counterpart in the model -> meaning they are directly selectable by clicking on a model element in the viewer.
At first, it seemed like this was solved by focusing on the leaf nodes in the tree, traversing it recursively via enumNodeChildren(node, callback, recursive) and storing the node only if getChildCount(dbId) was 0, thus indicating we reached a leaf.
However, there seem to be constellations where there is geometry connected to non-leaf nodes as well as to their children. This seems to be the case where these nodes represent certain Revit Family Types with independent geometry.
We then tried to find a way to distinguish nodes with directly attached geometry vs. nodes which only act as "grouping" for real geometry nodes. But none of the API methods under https://forge.autodesk.com/en/docs/viewer/v7/reference/Private/InstanceTree/ seem to help in this case (not even the promising getNodeType(dbId) as just returns 0 for all nodes involved).
A rather dirty fix for now is that we check for a id suffix in the node's name, which only seems to be present if there is directly related geometry. But I guess this also only just works if the viewable originates from a Revit file. See this image for clarification. It shows a parent node with no geometry, an intermediate node with geometry and several leaf nodes with geometry.
Is there a better way to solve this problem?

Related

Retrieve object data with Forge Viewer (nested Families)

I am trying to use forge-Viewer with dashboards to analyze the data within the model. For that, I am using the getAllLeafComponent() method expressed in the Forge Tutorials: https://learnforge.autodesk.io/#/viewer/extensions/panel?id=enumerate-leaf-nodes.
Nevertheless, I am having some trouble with this method, because it will not recognize objects that have children (i.e. Revit Families with nested items).
Element with nested item (space of operation)
In the attached image, the green tetrahedron represents the transformer space of operation, and it is a nested item inside the transformer, so with the getAllLeafComponent() method I am unable to retrieve the transformer data, which is the important one; as this method does not recognize the transformer as a leaf, but rather as a parent element, which indeed it is, but it is also a model object, not a category or a family symbol.
Has anyone comes up with the same problem and/or with a way to solve it?
It is of uttermost importance for my Forge application, otherwise, I would not have reliable model information to analyze it.
Best Regards,
The Model Derivative service uses a specific, "reasonable" logic for each individual input file format to decide how granular it should go when building the logical hierarchy for the viewer. In case of Revit designs, the processing stops at the instance level, in other words, family instances are always output as leaf nodes, even if their families have some nested elements. For example, doors are always output as the smallest selectable elements, and you cannot select just the door knob. I'm afraid the same applies to your space of operation nested within the transformer family.
If you need to extract information that the Model Derivative service does not provide, you could consider using the Design Automation service instead. This service lets you execute your custom Revit (or AutoCAD, or Inventor, or 3ds Max) plugin on our servers, creating, modifying, or analyzing designs in any way you need, remotely.

What is the relationship between each of the references to nodeId, frame, frameTreeNodeId, layerId and layerTreeId (and others) in a chrome trace file

I'm looking for current documentation in relation to the structure of a chrome trace file.
In a trace file, for example, there are frames that relate to each other using a parent property. There are frames that are associated with a nodeId, but there are also nodeId’s that do not have an associated frame. Similarly, there are frames with layerId’s and frames without.
Is there a document anywhere that describes how all these objects relate to each other? Are they parallel structures? Are they part of one hierarchy? Are nodes referred to uniquely, or can a different nodeId refer to the same object?
Here's what I've found so-far:
In my search for an answer, I’ve discovered the Chrome DevTools Protocol documentation [1] which seems to refer to each of these, but I’ve been unable to discover how they relate to each other.
I’ve grepped through the 19 GB of chrome source code with nothing much to show for, other than finding TimelineModel.ts [2] with many (if not all) of those references.
I’ve also discovered the Trace Event Format [3], which describes some of the fields in a trace file, but it was last updated in 2016 and does not contain references to nodeId’s or layerId’s.
Although not directly related to chrome, a WebKit file [4] I’ve discovered has all of these references and includes extras such as a shadow tree, a compositing tree and an accessibility structure.
Any help would be welcome.
https://chromedevtools.github.io/devtools-protocol/
https://chromium.googlesource.com/devtools/devtools-frontend/+/af7ba130f6fe898ebe08c15e29438b83e7c40d7d/front_end/models/timeline_model/TimelineModel.ts
https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/preview
https://raw.githubusercontent.com/WebKit/WebKit/main/Source/WebInspectorUI/Versions/Inspector-iOS-13.0.json

Do Forge Viewer SVF pack files use parent-child linked transforms?

Context: I've been extracting geometry data from the Forge SVF structures into an OBJ format using the Forge Extract code by Petr. These data are then transparently sent to a different rendering system for the project upon which I'm working. However, I'm noticing that there are incorrect rotations in groups of extracted objects. Not all objects, just groupings.
As an example, here is the Forge Viewer rendering of a group of objects (the long poles), with correct rotation. You can see all the poles evenly placed along the base-plate's edge and equally placed with regards to each other.
Whereas in the rendered extracted geometry, the grouping of objects are correctly placed with relation to each other (equally, 3x3), but the group as a whole is rotated slightly along the Z-axis in relation to the bottom plate.
This is the type of behaviour I would expect if the individual poles were all child objects of some parent object (perhaps an invisible grouping object), and the rotation of the parent would pivot all the poles in the SVF but that rotation wasn't applied during geometry extraction.
This happens with all groupings with regards to individual objects in a scene.
While looking at this question, I get the strong impression that there is a 2nd rotational aspect but I cannot see how that applies when reading the SVF directly.
Question:
Obviously I'm not looking for a direct code solution, but to confirm the structure of the SVF pack files. Looking at the extraction, I don't see anything which would imply a parent-child grouping but haven't managed to think of an alternative cause.
So, are there such parent-child transform relationships in the SVF pack files, or a global rotational component which only applies to certain objects? If so, where is that placed within the pack file. And if not, what else could cause this type of systematic rotation of groups?
The SVF file format doesn't use parent-child transforms - all fragment transforms are basically world transforms. It's possible that my code for parsing the fragment transforms handles one of the transform types incorrectly. I'd try debugging the getTransform method for the dbId of the base or one of the poles, and compare the transform with the one parsed by Forge Viewer.
Also, I'm wondering if it's the base that's slightly off, and not the 3x3 poles?

Term for manipulating zero, one or more items as a single object

Let's say we have a tree structure, DOM for instance, and we wish to make a function for finding all nodes meeting certain criteria and returning them in some way.
The naive way to do this is to return an array, list or similar of found nodes. However, doing so requires the use of loops or higher-order functions (such as map) to process all entries.
jQuery and some other DOM traversal frameworks I've seen partially abstracts the individual nodes away, instead working with specialized sets that can contain any number of nodes (or none at all). These objects have all the methods you'd expect the nodes to have, except it applies the calls to all the nodes in the set (where applicable), ignoring the call if the set is empty.
As an example, jQuery allows you to use $('img').css('opacity', 0.5) to find all images on a page and make them all partially transparent. The traversal of the matched nodes and application of the call to the individual images happens behind the scenes.
Is there a term for this way of ignoring the plurality of elements and operating on zero, one or more as if they were a single object? More specifically, do these objects themselves have a name?

ClojureScript, Om and Core.async: How to handle events properly

I have had a look at using Om for rich client website design. This also is my first time using core.async. Reading the tutorial https://github.com/swannodette/om/wiki/Basic-Tutorial I have seen the usage of a core.async channel to handle the delete operation (as opposed to doing all the work in the handler). I was under the impression that using that channel for deletion was merely done because the delete callback was declared in a scope where you have a cursor on an item-level where you actually want to manipulate the list containing that item.
To get more insights into channels I have seen Rich Hickey's talk http://www.infoq.com/presentations/clojure-core-async where he explains how its a good idea to use channels to get application logic out of event-callbacks. This made me wonder whether the actual purpose of the delete channel in the tutorial was to show that way of structuring an application. If so,
what are best practices associated with that pattern?
Should one create individual channels for all kinds of events? I.e. If I add a controller to create a new event, would I also create a new channel for object creations that is then used to get objects to be added to the global state at another place in the application?
Lets say I have a list of items, and one items has a detailed/concise state flag. If detailed? is true it will display more information, if detailed? is false it will display fewer information. I have associated a on-click event that uses om/transact! on the cursor (being a view to the list item within the global state object).
(let [toggle-detail-handler
(fn [e]
(om/transact! (get-in myitem [:state])
#(conj % {:detailed? (not (:detailed? %))})))]
(html [:li {:on-click toggle-detail-handler}
"..." ]))
I realize that this might be a very succinct snippet where the overall benefit of using channels as a means to decouple the callback event from the acutal logic changes does at first not seem worth the effort but the overall benefits with more complex examples outweigh this. But on the other hand introducing an extra channel for such detail-not-detailed toggling seems to add a fair amount of load to the source code as well.
It would be great if you could give some hints/tips or other thoughts on the whole design issue and put them into perspective. I feel a little lost there.
I use channels to communicate between components that cannot communicate through cursors.
For example, I use channels when:
the communicating components do not share app state (eg, their cursors are pointing down different branches of a hierarchical data structure)
the changes being communicated live outside of the app state (for example, component A wants to change component B's local state AND component B is not a child of A (otherwise this can be done by passing :state to om/build)
I want to communicate with something outside of the Om component tree
Note that I like to keep the "domain state" in the app state atom and the GUI state in the component local state. That is, app state is what is being rendered and local state is how. (where "how" also refers to which part) For example, if you are writing a text editor, the app state is the document being edited and the local state is what page is being edited, whether bold is selected so forth.
In general, I use a single communication channel onto which I place [topic value] pairs. I then use pub and sub to route the messages. Eg, (def p (async/pub ch first)) to use the topic to dispatch events and (om/sub p my-ch :foo) to receive messages with topic :foo to my-ch. I generally store this single communication channel in Om's shared state.
Sometimes I will use multiple channels, but I would do this to set up specific pipelines or workflows, rather than for general purpose messaging. For example, if I have a pipeline of processing components doing stuff to a stream of data, then I might set this up as a chain of channels with the endpoints connected into my Om application. For general UI development, this is rare.
I'm also playing around with a Qt-esque signals/slots system for my Om components and I'm still experimenting with using a shared signals channels vs having each signal be its own channel. I'm as yet undecided which approach is better.