Extraction of Conflict Data Issue with API NET

Extraction of Conflict Data Issue with API NET

rayane_ailem_1
Explorer Explorer
1,669 Views
10 Replies
Message 1 of 11

Extraction of Conflict Data Issue with API NET

rayane_ailem_1
Explorer
Explorer

 

Context: I am developing a Navisworks plugin in C# to extract clash detection results into a JSON format. My goal is to retrieve grouped clashes (ClashResultGroup), including the clash name, involved elements, element types, level (as detected by Clash Detective), clash distance, and clash point coordinates.

However, I am facing multiple issues when trying to retrieve and process the data correctly.


Current Issues:

  1. Type Conversion Error

    • Error: Cannot convert 'Autodesk.Navisworks.Api.ModelItemCollection' to 'Autodesk.Navisworks.Api.Clash.ClashSelection'
    • Problem: I am trying to retrieve the elements involved in a clash (Selection1 and Selection2), but the API does not allow direct conversion between ModelItemCollection and ClashSelection.
  2. Clash Selection Methods Not Found

    • Error: 'ClashSelection' does not contain a definition for 'Any'
    • Problem: I am trying to check if Selection1 or Selection2 contains any items using .Any(), but ClashSelection does not support this method.
  3. ClashResultGroup Iteration Issue

    • Error: 'foreach' implicitly converts 'Autodesk.Navisworks.Api.SavedItem' to 'Autodesk.Navisworks.Api.Clash.ClashResult'. Add an explicit cast.
    • Problem: When looping through ClashResultGroup, it seems that SavedItem objects are not directly castable to ClashResult.
  4. Missing Properties for Clash Data

    • Error: 'ClashResult' does not contain a definition for 'Level' or 'GridIntersection'
    • Problem: I want to retrieve the level (floor) of the clash and the grid intersection where the clash occurs, but these properties do not seem to be available directly in ClashResult.

What I Need Help With:

  1. Correct way to extract the elements in conflict (Selection1 and Selection2) with their names and types.
  2. How to properly iterate through ClashResultGroup to retrieve all grouped conflicts.
  3. Retrieving clash location details (Level and Grid Intersection) from Clash Detective without manually computing them from Z-coordinates.
  4. Avoiding type conversion errors between ModelItemCollection and ClashSelection.

Current Code Snippet Where Issues Occur:

 

 

private ClashConflict ExtractConflictInfo(ClashTest test, ClashResult clash)
{
return new ClashConflict
{
TestName = test.DisplayName,
ClashName = clash.DisplayName,
Element1 = GetElementName(clash.Selection1), // Selection1 issue here
Element2 = GetElementName(clash.Selection2), // Selection2 issue here
ClashPoint = clash.Center,
Distance = clash.Distance,
Status = clash.Status.ToString(),
Level = clash.Level, // ClashResult does not contain 'Level'
GridIntersection = clash.GridIntersection // ClashResult does not contain 'GridIntersection'
};
}

private string GetElementName(ClashSelection selection)
{
if (selection != null && selection.Any()) // ClashSelection does not support .Any()
{
return selection.First().DisplayName ?? "Unknown Element";
}
return "Unknown


0 Likes
1,670 Views
10 Replies
Replies (10)
Message 2 of 11

naveen.kumar.t
Autodesk Support
Autodesk Support

Hi @rayane_ailem_1 ,

Correct way to extract the elements in conflict (Selection1 and Selection2) with their names and types. & How to properly iterate through ClashResultGroup to retrieve all grouped conflicts.

private void ExtractNamesAndTypes()
 {
     Document doc = Autodesk.Navisworks.Api.Application.ActiveDocument; 
     DocumentClash documentClash = doc.GetClash(); 
     SavedItemCollection collection = documentClash.TestsData.Tests;
     ClashTest test = collection.First() as ClashTest;   
     foreach (SavedItem item in test.Children)
     {
        if(item.IsGroup)
        {
             ClashResultGroup clashResultGroup = item as ClashResultGroup;
             foreach(ClashResult clashResult in clashResultGroup.Children)
             {
                   AccessClashResultDetails(clashResult);
             }                    
        }
        else
        {
                ClashResult clashResult = item as ClashResult;  
                AccessClashResultDetails(clashResult);   
        }
     }
 }

 private void AccessClashResultDetails(ClashResult clashResult)
 {
    //Access Clashed Elements
    ModelItem item1 = clashResult.Item1;
    ModelItem item2 = clashResult.Item2;

     ModelItemCollection collection1 = clashResult.Selection1;
     ModelItemCollection collection2 = clashResult.Selection2;

     //Access Names and their types
 }


Avoiding type conversion errors between ModelItemCollection and ClashSelection

ModelItemCollection collection = doc.CurrentSelection.SelectedItems;
ClashSelection clashSelection = new ClashSelection();
clashSelection.Selection.CopyFrom(collection);     


Retrieving clash location details (Level and Grid Intersection) from Clash Detective without manually computing them from Z-coordinates.

 

The Navisworks API usually supports features available in the user interface. I’m not sure what you mean by accessing Level and Grid Intersections from the Clash Detective. Can you do this manually in the UI?

To understand your workflow better, could you explain the steps you take in the UI to get the desired result?

If a clash occurs, you can try using the ClashResult.Center property to get the clash point. Check if it returns the result you expect.

 


Naveen Kumar T
Developer Technical Services
Autodesk Developer Network

0 Likes
Message 3 of 11

rayane_ailem_1
Explorer
Explorer

Hi Naveen,

Thank you for your detailed suggestions!

I’m working on a Navisworks plugin to extract grouped clash conflict data into a structured JSON format. My goal is to capture crucial information such as the IFC data, clash names, involved elements, types, distance, and other relevant details, which can later be used for machine learning analysis to differentiate between conflicts, without relying on images.

However, I am encountering difficulties in retrieving all of the expected data, especially for grouped clashes (ClashResultGroup). I’m particularly interested in the following information:

  • IFC names and types of the involved elements (both Selection1 and Selection2)
  • Clash name and details
  • Clash distance and point coordinates (if possible, including the level and grid intersection)
  • Any other data that would help differentiate the conflicts

Could you guide me on how to properly access this information using the Navisworks API, specifically for grouped clashes? For example, I would like to correctly iterate through the ClashResultGroup and ensure that I can extract the IFC names, element types, and other relevant data for each clash.

Thank you for your help!

Best regards,

 



rayane_ailem_1_0-1740949623214.png

 

 

0 Likes
Message 4 of 11

naveen.kumar.t
Autodesk Support
Autodesk Support

Hi @rayane_ailem_1 ,

 

Could you please provide a simple sample file along with a detailed explanation of the expected versus observed results? I will analyze the issue on my end and get back to you.


Naveen Kumar T
Developer Technical Services
Autodesk Developer Network

0 Likes
Message 5 of 11

rayane_ailem_1
Explorer
Explorer

Dear Naveen,

Thank you for your guidance so far. I would like to provide further context regarding the extraction of clash data in Navisworks, which might help in clarifying my requirements.

I am exporting IFC models or NWC model for by examples both architectural and structural elements into Navisworks, and I then run the Clash Detective to identify any conflicts. Once the clashes are detected, I utilize the Navisworks Coordination Issues Add-in to group these clashes effectively. It is at this point that I aim to extract as much relevant data as possible for each ClashResultGroup.

The data I wish to extract includes the IFC Class or the revit category of each element in a conflict group, the material, discipline, clash distance, intrusion volume, angle between elements, type of conflict, clash status, and any additional parameters that can help classify the conflict further. My ultimate goal is to capture this information in a structured format such as JSON or CSV, which I can then use for machine learning algorithms to differentiate between real conflicts and false positives.

I know that some of this information is available in the Navisworks UI, specifically from the HTML Tabular report I export (screenshot attached). I am trying to automate this extraction process as much as possible and capture all relevant details programmatically, including the ones shown in that HTML report.

This is my first experience using C#, and I am utilizing LLM (Large Language Models) to help structure the plugin code. Below is the code I have so far, which attempts to extract this data, but I am encountering challenges in retrieving certain details, particularly for grouped clashes. I would appreciate your assistance in refining this extraction process, ensuring that the necessary data is captured correctly.

 

 

 

 

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Windows.Forms;
using Autodesk.Navisworks.Api;
using Autodesk.Navisworks.Api.Clash;
using Autodesk.Navisworks.Api.Plugins;
using Newtonsoft.Json;

namespace NavisworksConflictExtractor
{
    [Plugin("ConflictExtractor", "SNC", DisplayName = "Extract Conflict Groups")]
    public class ConflictExtractor : AddInPlugin
    {
        // Define the output directory for saving the extracted data.
        private const string OutputPath = "C:\\temp\\ClashData\\";

        // Entry point of the plugin that gets triggered during execution
        public override int Execute(params string[] parameters)
        {
            try
            {
                // Get the active document in Navisworks
                Document doc = Autodesk.Navisworks.Api.Application.ActiveDocument;

                // Check if the document or the Clash tests are available, if not show an error
                if (doc == null || doc.GetClash() == null || doc.GetClash().TestsData == null)
                {
                    MessageBox.Show(" No tests found in Clash Detective!", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    return 1;
                }

                // Get all available Clash tests and check if there are any
                List<ClashTest> availableTests = doc.GetClash().TestsData.Tests.Cast<ClashTest>().ToList();
                if (availableTests.Count == 0)
                {
                    MessageBox.Show(" No Clash Detective tests available!", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    return 1;
                }

                // Show a dialog to select a specific test
                string selectedTestName = ShowTestSelectionDialog(availableTests);
                if (string.IsNullOrEmpty(selectedTestName))
                {
                    MessageBox.Show(" No test selected. Cancellation.", "Information", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                    return 1;
                }

                // Retrieve the selected test from the list of available tests
                ClashTest selectedTest = availableTests.FirstOrDefault(t => t.DisplayName == selectedTestName);
                if (selectedTest == null)
                {
                    MessageBox.Show(" The selected test was not found.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    return 1;
                }

                // Extract the grouped conflict data for the selected test
                List<MLClashGroup> groupedConflicts = ExtractClashGroups(selectedTest);

                // Ensure the output directory exists, if not, create it
                if (!Directory.Exists(OutputPath)) Directory.CreateDirectory(OutputPath);

                // Define the file path for saving the output as a JSON file
                string filePath = Path.Combine(OutputPath, $"ML_ClashData_{selectedTestName}.json");

                // Serialize the grouped conflicts into JSON format
                string jsonOutput = JsonConvert.SerializeObject(groupedConflicts, Formatting.Indented);
                
                // Write the JSON output to a file
                File.WriteAllText(filePath, jsonOutput);

                // Show a success message with the file path
                MessageBox.Show($" Conflict groups exported to JSON at:\n{filePath}", "Success", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
            catch (Exception ex)
            {
                // If any exception occurs, show the error message
                MessageBox.Show($" Error: {ex.Message}\n{ex.StackTrace}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }

            return 0;
        }

        // Method to extract the grouped conflicts from the selected ClashTest
        private List<MLClashGroup> ExtractClashGroups(ClashTest test)
        {
            // List to store the grouped conflicts
            List<MLClashGroup> groupedConflicts = new List<MLClashGroup>();

            // Iterate over the children of the ClashTest (which includes groups of conflicts)
            foreach (SavedItem item in test.Children)
            {
                // Check if the item is a ClashResultGroup
                if (item is ClashResultGroup group)
                {
                    // Get the individual conflicts in the group
                    var conflicts = group.Children.OfType<ClashResult>().ToList();

                    // If there are no conflicts, continue to the next group
                    if (conflicts.Count == 0)
                        continue;

                    // Create a new MLClashGroup object to hold the group information
                    MLClashGroup clashGroup = new MLClashGroup
                    {
                        GroupName = group.DisplayName, // Name of the clash group
                        ConflictCount = conflicts.Count, // Count of conflicts in the group
                        Element1_IFC = GetIFCType(conflicts.First().Selection1), // Get the IFC type of the first element
                        Element2_IFC = GetIFCType(conflicts.First().Selection2), // Get the IFC type of the second element
                        Level = GetClashLevel(group), // Get the level of the conflict group
                        GridLocation = GetClashGrid(conflicts.First()), // Get the grid location of the conflict
                        AverageDistance = conflicts.Average(c => c.Distance), // Calculate the average distance of conflicts
                        AverageClashPoint = new ClashPoint(
                            conflicts.Average(c => c.Center.X), // Average X coordinate of the conflict points
                            conflicts.Average(c => c.Center.Y), // Average Y coordinate of the conflict points
                            conflicts.Average(c => c.Center.Z)  // Average Z coordinate of the conflict points
                        )
                    };

                    // Add the grouped conflict to the list
                    groupedConflicts.Add(clashGroup);
                }
            }
            return groupedConflicts;
        }

        // Method to get the IFC type from the first element in a ClashSelection
        private string GetIFCType(ModelItemCollection selection)
        {
            if (selection != null && selection.Count > 0)
            {
                ModelItem element = selection.First();
                return GetProperty(element, "IFC Type");
            }
            return "Unknown Type";
        }

        // Helper method to extract a specific property from a ModelItem
        private string GetProperty(ModelItem item, string propertyName)
        {
            try
            {
                // Attempt to find and return the property value
                return item.PropertyCategories
                           .SelectMany(pc => pc.Properties)
                           .FirstOrDefault(p => p.DisplayName.Contains(propertyName))?.Value.ToString() ?? "Undefined";
            }
            catch
            {
                // Return "Undefined" if the property cannot be found or an error occurs
                return "Undefined";
            }
        }

        // Method to get the level of the conflict group (in this case, it uses the group display name)
        private string GetClashLevel(ClashResultGroup group)
        {
            return group.DisplayName; // The level is often represented in the group name
        }

        // Method to get the grid location of the conflict (using the clash result display name)
        private string GetClashGrid(ClashResult clash)
        {
            return clash.DisplayName; // The grid intersection is often represented in the conflict display name
        }

        /// <summary>
        ///  Method to show a dialog for selecting a Clash Detective test.
        /// </summary>
        private string ShowTestSelectionDialog(List<ClashTest> availableTests)
        {
            using (Form form = new Form())
            {
                // Set up the form for test selection
                form.Text = "Select a Clash Detective Test";
                form.Width = 400;
                form.Height = 250;
                form.FormBorderStyle = FormBorderStyle.FixedDialog;
                form.StartPosition = FormStartPosition.CenterScreen;

                Label label = new Label() { Left = 20, Top = 20, Text = "Select a test:", Width = 350 };
                ComboBox comboBox = new ComboBox() { Left = 20, Top = 50, Width = 350 };
                Button okButton = new Button() { Text = "OK", Left = 250, Width = 100, Top = 100, DialogResult = DialogResult.OK };
                Button cancelButton = new Button() { Text = "Cancel", Left = 140, Width = 100, Top = 100, DialogResult = DialogResult.Cancel };

                // Add available tests to the ComboBox
                foreach (var test in availableTests)
                {
                    comboBox.Items.Add(test.DisplayName);
                }
                comboBox.SelectedIndex = 0;

                // Add controls to the form
                form.Controls.Add(label);
                form.Controls.Add(comboBox);
                form.Controls.Add(okButton);
                form.Controls.Add(cancelButton);

                // Show the form and return the selected test name
                form.AcceptButton = okButton;
                form.CancelButton = cancelButton;

                return form.ShowDialog() == DialogResult.OK ? comboBox.SelectedItem.ToString() : null;
            }
        }
    }

    // Class to store information about each conflict group
    public class MLClashGroup
    {
        public string GroupName { get; set; }
        public int ConflictCount { get; set; }
        public string Element1_IFC { get; set; }
        public string Element2_IFC { get; set; }
        public string Level { get; set; }
        public string GridLocation { get; set; }
        public double AverageDistance { get; set; }
        public ClashPoint AverageClashPoint { get; set; }
    }

    // Class to store the coordinates of a conflict point
    public class ClashPoint
    {
        public double X { get; set; }
        public double Y { get; set; }
        public double Z { get; set; }

        public ClashPoint(double x, double y, double z)
        {
            X = x;
            Y = y;
            Z = z;
        }
    }
}  

 

 

 

 

 

As I am working with Visual Studio 2022 and Navisworks 2025, the Navisworks API should support these functionalities, but some additional data may require further processing or accessing specific properties within the Navisworks model or ClashDetective. I would appreciate your insight into any missing pieces or adjustments I can make to properly capture all the data possible to enable a good classification.

Please let me know if you need any further clarifications.

Thank you and best regards,

Rayane A



0 Likes
Message 6 of 11

naveen.kumar.t
Autodesk Support
Autodesk Support

Hi @rayane_ailem_1 ,

 

The questions you asked can be addressed by snooping the clash results/clash test. To do this, please install the Navisworks Lookup tool. I recommend installing the Navisworks Lookup tool and exploring the clash results for a detailed analysis.

 

Once installed, open Navisworks and navigate to the "NavisLookup" tab. In the "NavisLookup" panel, select "Snoop ClashResult Search." Enter the clash result name or GUID to retrieve all relevant details.

 

With these information, you can implement your functionality using the API.

 

For example, to determine the angle between two elements, you can access the clashed model items bounding boxes, extract the minimum and maximum values, compute the direction vectors, and use the dot product to calculate the angle.

Currently, in Navisworks, it is not possible to calculate the area of the clash. 


Naveen Kumar T
Developer Technical Services
Autodesk Developer Network

Message 7 of 11

rayane_ailem_1
Explorer
Explorer

Hey Naveen, 

Thank you a lot for your advices, i'll try this option and let you know where that lead me soon.😁


0 Likes
Message 8 of 11

rayane_ailem_1
Explorer
Explorer

Hello,

I am developing a plugin for Navisworks Manage 2025 using the .NET API. I am trying to update the statuses of clash results (after an ML analysis of conflicts which returns a JSON containing the new statuses) in a transactional way to ensure that changes are applied atomically. I found some references online suggesting the use of DocumentPartTransaction for this purpose, but I am getting the following error:

"The type or namespace name 'DocumentPartTransaction' could not be found (are you missing a using directive or an assembly reference?)"

Here is the code I am trying to use:

// Access clash tests in Navisworks
DocumentClash clashDoc = NavisworksApp.MainDocument.GetClash();
DocumentClashTests clashTests = clashDoc.TestsData;

// Start a transaction to modify the clash statuses
using (DocumentPartTransaction transaction = NavisworksApp.ActiveDocument.BeginTransaction("Update clash statuses"))
{
    int updatedCount = 0;

    foreach (ClashTest test in clashTests.Tests)
    {
        foreach (IClashResult result in test.Children)
        {
            if (result is ClashResult clashResult)
            {
                // Find the corresponding prediction
                var prediction = predictions.FirstOrDefault(p => p.ClashName == clashResult.DisplayName);
                if (prediction != null)
                {
                    // Map the prediction to a Navisworks status
                    ClashResultStatus newStatus = MapPredictionToStatus(prediction.Prediction);
                    clashResult.Status = newStatus;
                    updatedCount++;
                    LogError($"Status of clash '{clashResult.DisplayName}' updated: {newStatus}");
                }
            }
        }
    }

    // Commit the transaction
    transaction.Commit();
    LogError($"Number of clashes updated: {updatedCount}");
    MessageBox.Show($"Status update completed. {updatedCount} clashes have been updated.", "Success", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}
catch (Exception ex)
{
    LogError($"Error while updating clash statuses: {ex.Message}");
    MessageBox.Show($"Error while updating statuses: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}

 

I also checked the Navisworks API documentation for the Autodesk.Navisworks.Api.DocumentParts namespace, and DocumentPartTransaction is not listed there. I am referencing Autodesk.Navisworks.Api.dll from the Navisworks 2025 installation folder (C:\Program Files\Autodesk\Navisworks Manage 2025\).

My questions are:

  1. Does DocumentPartTransaction exist in the Navisworks 2025 API? If not, what is the recommended way to manage transactions when updating clash statuses following my automatic analysis ?
  2. I found that the COM API (InwOpState10) can be used for transactions with methods like BeginUndoGroup and EndUndoGroup. Is this the best alternative?

Any help or guidance would be greatly appreciated!

Thank you,

Rayane AILEM 



0 Likes
Message 9 of 11

naveen.kumar.t
Autodesk Support
Autodesk Support

Hi @rayane_ailem_1 ,

 

I have never used DocumentPartTransaction.What is it, and where can I find information confirming its availability in Navisworks?

I typically use the Transaction class and the NavisworksTransaction class.

Could you provide more details about DocumentPartTransaction to check it on my end?


Naveen Kumar T
Developer Technical Services
Autodesk Developer Network

0 Likes
Message 10 of 11

rayane_ailem_1
Explorer
Explorer

rayane_ailem_1_0-1743436893103.pngrayane_ailem_1_1-1743436932998.png

rayane_ailem_1_2-1743436982316.png

Hi Naveen,

I initially thought I needed to use DocumentDatabase members instead of the transaction method and DocumentParts namespace, but it turns out that this approach is still not suitable and i also misused the documentpart namespace.

Could you guide me on how to automatically update the status of Clash Detective results when I provide a JSON file containing the clash name and its new status? I'm struggling to find the right way to implement this. do i have to use transaction for sure ?

Thanks in advance for your help!


Best,

Rayane 

0 Likes
Message 11 of 11

naveen.kumar.t
Autodesk Support
Autodesk Support

Hi @rayane_ailem_1 ,

 

 

I contacted the Navisworks Engineering team on your behalf. Unlike traditional databases, Navisworks operates differently under the hood(unlike say in Revit). The team confirmed that using the Transaction object is the recommended approach and should address both of your questions from the previous post.

The Transaction object allows you to group multiple edits into a single operation. Once committed, all edits are applied and recorded as a single undoable action. However, since transactions cannot be rolled back, it is crucial to commit them after completing your changes.

 


Naveen Kumar T
Developer Technical Services
Autodesk Developer Network

0 Likes