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
- use the manual/by-hand find tool in Navisworks
- on that screen, there is an export button – look at the XML – the internal names are the key
- then – to understand how that XML stuff helps you decode/use the find in code be it the COM API or the .net API. Lets see how this all fits together.
- [UPDATE Jan 2016] Also, see my other post, save hours of time and know why Document.StayOpen is so critical when automating a live version of Navisworks Simulate.
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]
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