Navisworks COM API – a little old and REALLY cantakerous. But I finally I can ‘FIND’ an object by name

So about 4 hours of hacking and I FINALLY figured out how the whole thing is put together I want to drive Navis from Excel. Why? Because all engineers and managers use excel!. We are using Navisworks Simulate 2013 (or internally the com API is NavisworksAutomationAPI10). The key to understanding all we need to make this work is

I am using VBA – because that is native to Excel -put it in an add-in and everyone can enjoy without having to know or do anything – just click and “Trust Macros” and zoom to the part of interest.

Next, I knew one person online who seemed to ‘get it’ and use it successfully is Xiaodong Liang as well as a co-worker who worked with Navis who said – yes, look here and there (in the GUI interface). Next, know where the help files are  – they are on your hard drive – I was trying to hard online to find the docs. Look under C:\Program Files\Autodesk\Navisworks Simulate 2013\api\COM – and open the .chm file.

Next, hacking around with getting to the active navisworks running on your computer – I found out a few things. First, the not user Dim myNewVar New MyFavoriteType. Just – simply Dim WITHOUT the New. With the COM API – you have to use a factory creation idea. So

[vb]

Dim find As New NavisworksIntegratedAPI10.InwOpFind ‘ won’t work!!!

‘ try this instead

Dim find As NavisworksIntegratedAPI10.InwOpFind ‘it will be ‘Nothing’ as expected
Set find = mstate.ObjectFactory(eObjectType_nwOpFind) ‘now it will be initialized and filled with some goodness

[/vb]

Lets go back – what I am looking for is Category=Item, Property=Name, Value = _A1 . Putting this in perspective – the find window would look like

insert aa_whatiwant.jpg here when wordpress finally decides to work

Simple right? Well 4 hours later – I finally followed Xiaodong’s example using something LIKE HIS and … really? Just leave “Item” out- because the internal name … well does not exist.

Lets try Xiaodong’s example. Put in the find, make sure it works, export the find xml, look at it. Then adjust the code using the INTERNAL names (another annoying thing you have to know) … oh my it works!!! I see the pattern here. (see bottom of article for the code differences)

So then I can make the code work for mine … hey – choosing “Item” make the category isn’t there … so in the code that means DONT do the line of code findCond.SetAttributeNames. Also use the internal name for “Name” which is “LcOaSceneBaseUserName” and crap – it worked …. finally finally finally. I was about to post on the forum but no nee now.

insert aa_whatitried.jpg here when wordpress finally decides to work

Final code

[vb]

Sub FindThisName()
Dim nwObj As NavisworksAutomationAPI10.Document
Set nwObj = GetObject(, "Navisworks.Document.10") ‘nw 2013

nwObj.Visible = True
nwObj.StayOpen ‘ YOU HAVE TO DO THIS and do it following the line above… why? because the "GetObject" above says "attach onto the existing running copy of navisworks" … and if you don’t do this stayopen thing, the ability to attach to it disappears. You have been warned – took me HOURS to figure this stupid tidbit out) – I had to restart navis all the time, which … is stupid for live automation (it is ok to do it for background processing)

Dim mstate As InwOpState
Set mstate = nwObj.state

Dim find As NavisworksIntegratedAPI10.InwOpFind
Set find = mstate.ObjectFactory(eObjectType_nwOpFind)

Dim findSpec As InwOpFindSpec
Set findSpec = mstate.ObjectFactory(eObjectType_nwOpFindSpec)

‘ adpated from http://adndevblog.typepad.com/aec/2012/05/navisworks-net-api-find-item.html

Dim findCond As InwOpFindCondition
Set findCond = mstate.ObjectFactory(eObjectType_nwOpFindCondition)

If (findSpec.Conditions.count > 0) Then
find.findSpec.Conditions.Clear
End If

findCond.Condition = eFind_CONTAINS

findCond.SetPropertyNames "LcOaSceneBaseUserName"
findCond.StartGroup = False
findCond.value = "_A1"

findCond.ValueCaseSensitive = False

Debug.Print "******* NEW SEARCH DOUBLE CHECK"
Debug.Print "AttributeInternalName:" & findCond.AttributeInternalName
Debug.Print "AttributeUserName:" & findCond.AttributeUserName
Debug.Print "PropertyInternalName:" & findCond.PropertyInternalName
Debug.Print "AttributeUserName:" & findCond.AttributeUserName
Debug.Print "value:" & findCond.value

findSpec.Selection.SelectAll
findSpec.Conditions.Add findCond
find.findSpec = findSpec

Dim results As InwOpSelection
Set results = find.FindAll
‘results.SelectAll ‘ this selects everything – but it makes all the other commands below work

Debug.Print "Found this many items" & results.Paths.count
mstate.CurrentSelection = results.Copy ‘ this seems to work once something is in results
mstate.ZoomInCurViewOnCurSel

End Sub

[/vb]

A ‘find’ XML export example

Well – there is a section called “category” missing – well how do we know that? Well look below where I snapped and just did Xiaodong’s example because “if he knows so well – and no one refutes it… lets try it”. Well there is a whole other section … oooooooh!!!!!! The key to solving the mystery is to STOP SETTING THE ATTRIBUTE TO ITEM!!! Just don’t have that line in our code. It worked.

[xml]

<exchange xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://download.autodesk.com/us/navisworks/schemas/nw-exchange-8.0.xsd" units="mm">
<findspec mode="all" disjoint="0">
<conditions>
<condition test="equals" flags="16">
<category>
<name internal="LcOpDwgEntityAttrib">Entity Handle</name>
</category>
<property>
<name internal="LcOaNat64AttributeValue">Value</name>
</property>
<value>
<data type="wstring">1A00</data>
</value>
</condition>
</conditions>
<locator>lcop_property_tree/Entity Handle/Value/1A00</locator>
</findspec>
</exchange>

[/xml]

Code to do set the find criteria and the XML that taught us.

Xiaodong, did YET ANOTHER post on how to do And and Or’s in your finds. Having condition groupings means ‘OR’, adding conditions within a grouping is an AND. This does not have that complexity but follows Xiaodong’s example online.

[vb]

findCond.Condition = eFind_CONTAINS
findCond.SetAttributeNames "LcOpDwgEntityAttrib", "LcOaSceneBaseUserName"
findCond.SetPropertyNames "LcOaNat64AttributeValue", "LcOaSceneBaseUserName"
findCond.StartGroup = False
findCond.value = "1A00"

[/vb]

Remember, doing a find manually in the GUI, and doing an export – gives an XML file that should be able to help us properly develop the code and understand how to do so. In the xml above, see how there is a category section? Now look below – it is NOT there! Category “Item” is above. We DO NOT WANT IT in our code – so if it is not in the XML, don’t put it as a criteria in your code. I got fooled that for “Item” as a category, the had to be a category, but it is not in the XML so don’t put it in the code. I wonder if in the past, item used to be the only show in town, then the others were added. Item seems to be a special category – the “no category” category. Now we know. We want to match the XML below which is the correct output for doing a find by hand and choosing “Item” from the find tree on the left of the find window. That is how we got to the code above AND why I commented out so many lines (cause I didn’t get it until it worked – then I a saw the pattern and wrote this article).

[xml]

<exchange xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://download.autodesk.com/us/navisworks/schemas/nw-exchange-8.0.xsd" units="mm">
<findspec mode="all" disjoint="0">
<conditions>
<condition test="equals" flags="16">
<property>
<name internal="LcOaSceneBaseUserName">Name</name>
</property>
<value>
<data type="wstring">_A1</data>
</value>
</condition>
</conditions>
<locator>/</locator>
</findspec>
</exchange>

[/xml]

 

One thought on “Navisworks COM API – a little old and REALLY cantakerous. But I finally I can ‘FIND’ an object by name

  1. Hi,
    Your contribution in Navisworks-VBA is excellent. Since there is no proper examples or help form AutoDesk, this web page makes great contribution in this field. Based on your code I have made a VBA macro to find a particular “LcOaSceneBaseUserName” which is working fine. Now I want to select all the geometry items, so I have modified the code as below. But unfortunately, this code couldn’t find give the result. Hope you can figure it out. Thank you.

    Sub FindGeometryItems()
    Dim nwObj As NavisworksAutomationAPI15.Document
    Set nwObj = GetObject(, “Navisworks.Document”)

    nwObj.StayOpen
    Dim mstate As nwOpState
    Set mstate = nwObj.state

    Dim find As NavisworksIntegratedAPI15.InwOpFind
    Set find = mstate.ObjectFactory(eObjectType_nwOpFind)

    Dim findSpec As InwOpFindSpec
    Set findSpec = mstate.ObjectFactory(eObjectType_nwOpFindSpec)

    Dim findCond As InwOpFindCondition

    If (findSpec.Conditions.Count > 0) Then
    find.findSpec.Conditions.Clear
    End If

    Set findCond = mstate.ObjectFactory(eObjectType_nwOpFindCondition)

    findCond.Condition = eFind_EQUAL
    findCond.SetAttributeNames “LcOaNodeIcon”

    findCond.StartGroup = False
    findCond.Value = “Geometry”
    findCond.ValueCaseSensitive = False

    findSpec.Selection.SelectAll
    findSpec.Conditions.Add findCond
    find.findSpec = findSpec
    Dim results As InwOpSelection
    Set results = find.FindAll

    Debug.Print “Found this many items” & results.Paths.Count
    mstate.CurrentSelection = results.Copy
    End Sub

Comments are closed.