- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report
Tl;dr
We are trying to find the “ModelItems” in our document that do not equal a certain property value using a plugin for Navisworks 2025. In our implementation we filter items from our model and create a selection. We hide or unhide items from this selection and then save it to a viewpoint (using COM). This way we can also validate if our not equal filter solution works.
Contrast this to the Navisworks GUI where we go about this by applying a search set, selecting a category, property, condition and value.
Seems simple, but there is no “not equals” condition in the API. We’ve tried and found various solutions and leads, but nothing works so far. Has anyone been successful in implementing a not equal filter?
What we’ve tried so far
1. Documentation
First solution is found in the documentation where it is mentioned that you can use the “Negate” method or “NotEqual” under SearchConditionComparison Enumeration. However, this does not work. We decompiled the .dll and NotEqual doesn’t exist. Attempting to use negate in this fashion will result in an empty ModelSelection. We know this, because our script saves it to a viewpoint, and contrary to s1, the s2 viewpoint is completely empty. Here is the example from the documentation example:
//set a search condition
SearchCondition s1 = SearchCondition.HasCategoryByName(PropertyCategoryNames.Transform);
//invert the search, i.e. NOT Has Category By Name
SearchCondition s2 = s1.Negate();
2. NET
Next, we tried to make a custom filter using NET. A very basic not equal filter on the entire document could be made with a workaround. Consider three sets of model items. All the items in the model, set A. All the items in the model equal to phase created 1, set B. All the items in the model not equal to phase created B. We know that A = B + C. Therefore C = A -B. I made a script from this, since we already have the equal value, we call B as variable ”results”. We loop through all the items in the model, A, which we get from the variable “doc” and check if it is a member of B and then add it to C. Problem with this script is that it never finishes running, probably because something is wrong with it or my dataset is too large (we have more than 800 thousand items in the model) and the script is inefficient.
public static void NotEqualFilter(Document doc,ModelItemCollection results)
{
// Reference collection A. Get the itmes in the current model
ModelItemCollection referenceItems = doc.Models.RootItem.DescendantsAndSelf; // This SHOULD select all unhidden items.
// Build HashSet of B for fast lookup
HashSet<int> searchHashes = new HashSet<int>();
foreach (ModelItem item in results)
{
searchHashes.Add(item.GetHashCode());
}
// Collection C: items in A,referenceItems, but not in B,results.
ModelItemCollection filteredItems = new ModelItemCollection();
foreach (ModelItem item in referenceItems)
{
if (!searchHashes.Contains(item.GetHashCode()))
{
filteredItems.Add(item);
}
}
// Optional: update current selection
doc.CurrentSelection.CopyFrom(filteredItems);
}
3. Linq
The third thing we’ve tried was using linq for finding items, filtering on item.HasGeometry and negating the search condition. See link below but couldn’t get that one to work. So, we quickly went on to try using COM.
4. COM
The fourth thing we’ve tried was converting it to COM, which did work. We followed post 6 in https://forums.autodesk.com/t5/navisworks-api-forum/hide-items/td-p/3313411 The script is as follows:
doc.CurrentSelection.CopyFrom(results); //results is the ModelItemCollection “equal to”
InwOpState10 myState = Autodesk.Navisworks.Api.ComApi.ComApiBridge.State;
InwOpSelection2 myCurrentSelection = myState.CurrentSelection.Copy() as InwOpSelection2; // Create a copy of current selection
InwOpSelection2 myRestOfModel = myState.ObjectFactory(nwEObjectType.eObjectType_nwOpSelection, null, null) as InwOpSelection2; // Create a new empty selection
myRestOfModel.SelectAll(); // Get the new selection to contain the entire model
myRestOfModel.SubtractContents(myCurrentSelection); // Subtract the current selection, so it contains the unselected part of model
ModelItemCollection netSelection = ComApiBridge.ToModelItemCollection(myRestOfModel); // Convert back to .net api
doc.CurrentSelection.CopyFrom(netSelection);
Problem with this method is that it didn’t produce the results as expected. It filtered parents and hid them (because we did not filter on HasGeometry), but more problematic, items that were supposed to be hidden or unhidden were not. This would also happen to sibling items under one parent. E.g. filter on phase created not equal to 1, then some phase created 61 items would be hidden and others unhidden with the same parent, same phase creation and with no other explanation. See picture. This indicated to me that something went wrong under the hood. We didn’t do any garbage collection, but we doubt this is the cause, since some items are selected and we use this function only once during the test. At this point we decided it was time to ask for help given the brittle and opaque nature of it all.
In conclusion
At this point we found that:
- Solutions in the documentation don’t work (negate() or NotEqual)
- Using COM API seems the best path
- COM is opaque and we found little documentation, but the API reference manual and the 2016 NavisWorks labs
- We don’t know about memory limitations, and it could just stop adding items to the collection because I try to select more than 700k items.
- Need to filter out items with no geometry, but this impedes performance.
- It should also ignore any items that don't have this category instead of selecting them by the not equal filter.
- We need to implement garbage collection, although we doubt this is the root cause of the issue
- We believe we overcomplicated things and that there should be an easy way to implement this
Any help would be appreciated!
Solved! Go to Solution.