🔍 Navisworks APIadvancedClash Detection

Automate Navisworks Clash Detection with API

Run clash tests, filter results, and generate reports programmatically using the Navisworks .NET API.

0 views12/14/2025

Automate Navisworks Clash Detection with API

Application: Navisworks API
Category: Clash Detection & Coordination
Difficulty: Advanced
Language: C#

Problem

You need to automate clash detection workflows in Navisworks - running clash tests, filtering results, generating reports, and integrating with issue tracking systems for large coordination projects.

Solution

Use the Navisworks .NET API to programmatically run clash tests, access results, apply filters, and export reports. This enables batch processing and integration with external systems.

Code Example: Run Clash Test and Export Results

using Autodesk.Navisworks.Api;
using Autodesk.Navisworks.Api.Clash;
using Autodesk.Navisworks.Api.DocumentParts;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;

namespace NavisworksClashAutomation
{
    public class ClashDetectionAutomation
    {
        public void RunClashTests()
        {
            // Get active document
            Document doc = Autodesk.Navisworks.Api.Application.ActiveDocument;
            
            if (doc == null)
            {
                Console.WriteLine("No active document found.");
                return;
            }
            
            // Get clash test document
            DocumentClash clashDoc = doc.GetClash();
            DocumentClashTests clashTests = clashDoc.TestsData;
            
            Console.WriteLine($"Found {clashTests.Tests.Count} clash tests");
            
            // Run all tests
            foreach (ClashTest test in clashTests.Tests)
            {
                Console.WriteLine($"\nRunning clash test: {test.DisplayName}");
                
                // Run the test
                test.Run();
                
                // Get results
                ClashResultRoot results = test.Children;
                int clashCount = CountClashes(results);
                
                Console.WriteLine($"  Total clashes found: {clashCount}");
                
                // Export results
                ExportClashResults(test, @"C:\Temp\ClashReports");
            }
        }
        
        private int CountClashes(ClashResultRoot results)
        {
            int count = 0;
            
            foreach (ClashResult result in results)
            {
                if (result is ClashResultItem)
                {
                    count++;
                }
                else if (result is ClashResultGroup group)
                {
                    count += CountClashes(group.Children);
                }
            }
            
            return count;
        }
        
        private void ExportClashResults(ClashTest test, string outputFolder)
        {
            if (!Directory.Exists(outputFolder))
                Directory.CreateDirectory(outputFolder);
            
            string fileName = $"{test.DisplayName}_{DateTime.Now:yyyyMMdd_HHmmss}.html";
            string filePath = Path.Combine(outputFolder, fileName);
            
            // Export to HTML
            test.Export(filePath, ClashReportFormat.Html);
            
            Console.WriteLine($"  Report exported: {filePath}");
        }
    }
}

Advanced: Filter and Categorize Clashes

public class ClashAnalysis
{
    public void AnalyzeClashes()
    {
        Document doc = Autodesk.Navisworks.Api.Application.ActiveDocument;
        DocumentClash clashDoc = doc.GetClash();
        
        foreach (ClashTest test in clashDoc.TestsData.Tests)
        {
            Console.WriteLine($"\n=== Analyzing: {test.DisplayName} ===");
            
            var clashStats = new Dictionary<string, int>
            {
                { "New", 0 },
                { "Active", 0 },
                { "Reviewed", 0 },
                { "Approved", 0 },
                { "Resolved", 0 }
            };
            
            var severityStats = new Dictionary<string, int>
            {
                { "Hard", 0 },
                { "Clearance", 0 }
            };
            
            // Analyze clash results
            AnalyzeClashResults(test.Children, clashStats, severityStats);
            
            // Print statistics
            Console.WriteLine("\nStatus Breakdown:");
            foreach (var stat in clashStats)
            {
                Console.WriteLine($"  {stat.Key}: {stat.Value}");
            }
            
            Console.WriteLine("\nSeverity Breakdown:");
            foreach (var stat in severityStats)
            {
                Console.WriteLine($"  {stat.Key}: {stat.Value}");
            }
        }
    }
    
    private void AnalyzeClashResults(
        ClashResultRoot results,
        Dictionary<string, int> statusStats,
        Dictionary<string, int> severityStats)
    {
        foreach (ClashResult result in results)
        {
            if (result is ClashResultItem item)
            {
                // Count by status
                string status = item.Status.ToString();
                if (statusStats.ContainsKey(status))
                    statusStats[status]++;
                
                // Count by severity
                string severity = item.IsHard ? "Hard" : "Clearance";
                severityStats[severity]++;
            }
            else if (result is ClashResultGroup group)
            {
                AnalyzeClashResults(group.Children, statusStats, severityStats);
            }
        }
    }
}

Create Clash Test Programmatically

public class CreateClashTest
{
    public void CreateStructuralMEPClashTest()
    {
        Document doc = Autodesk.Navisworks.Api.Application.ActiveDocument;
        DocumentClash clashDoc = doc.GetClash();
        DocumentClashTests clashTests = clashDoc.TestsData;
        
        // Create new clash test
        ClashTest newTest = new ClashTest();
        newTest.DisplayName = "Structural vs MEP";
        newTest.TestType = ClashTestType.Hard;
        newTest.Tolerance = 0.01; // 10mm tolerance
        
        // Set selection sets for test
        // Selection A: Structural elements
        Search structuralSearch = new Search();
        structuralSearch.Selection.SelectAll();
        structuralSearch.SearchConditions.Add(
            SearchCondition.HasCategoryEquals("Structural"));
        
        newTest.SelectionA.Selection = structuralSearch.FindAll(doc, false);
        
        // Selection B: MEP elements
        Search mepSearch = new Search();
        mepSearch.Selection.SelectAll();
        mepSearch.SearchConditions.Add(
            SearchCondition.HasCategoryEquals("MEP"));
        
        newTest.SelectionB.Selection = mepSearch.FindAll(doc, false);
        
        // Add test to document
        clashTests.Tests.Add(newTest);
        
        // Run the test
        newTest.Run();
        
        Console.WriteLine($"Created and ran clash test: {newTest.DisplayName}");
        Console.WriteLine($"Found {CountClashes(newTest.Children)} clashes");
    }
    
    private int CountClashes(ClashResultRoot results)
    {
        int count = 0;
        foreach (ClashResult result in results)
        {
            if (result is ClashResultItem)
                count++;
            else if (result is ClashResultGroup group)
                count += CountClashes(group.Children);
        }
        return count;
    }
}

Export Clash Data to Excel

using OfficeOpenXml;

public class ExportClashesToExcel
{
    public void ExportToExcel(string outputPath)
    {
        Document doc = Autodesk.Navisworks.Api.Application.ActiveDocument;
        DocumentClash clashDoc = doc.GetClash();
        
        using (ExcelPackage package = new ExcelPackage())
        {
            foreach (ClashTest test in clashDoc.TestsData.Tests)
            {
                // Create worksheet for each test
                ExcelWorksheet worksheet = package.Workbook.Worksheets.Add(test.DisplayName);
                
                // Add headers
                worksheet.Cells[1, 1].Value = "Clash Name";
                worksheet.Cells[1, 2].Value = "Status";
                worksheet.Cells[1, 3].Value = "Distance";
                worksheet.Cells[1, 4].Value = "Item 1";
                worksheet.Cells[1, 5].Value = "Item 2";
                worksheet.Cells[1, 6].Value = "Assigned To";
                worksheet.Cells[1, 7].Value = "Description";
                worksheet.Cells[1, 8].Value = "Grid Location";
                
                // Add data
                int row = 2;
                ExportClashItems(test.Children, worksheet, ref row);
                
                // Auto-fit columns
                worksheet.Cells.AutoFitColumns();
            }
            
            // Save file
            FileInfo file = new FileInfo(outputPath);
            package.SaveAs(file);
        }
        
        Console.WriteLine($"Clash data exported to: {outputPath}");
    }
    
    private void ExportClashItems(
        ClashResultRoot results,
        ExcelWorksheet worksheet,
        ref int row)
    {
        foreach (ClashResult result in results)
        {
            if (result is ClashResultItem item)
            {
                worksheet.Cells[row, 1].Value = item.DisplayName;
                worksheet.Cells[row, 2].Value = item.Status.ToString();
                worksheet.Cells[row, 3].Value = item.Distance;
                worksheet.Cells[row, 4].Value = GetItemPath(item.Item1);
                worksheet.Cells[row, 5].Value = GetItemPath(item.Item2);
                worksheet.Cells[row, 6].Value = item.AssignedTo;
                worksheet.Cells[row, 7].Value = item.Description;
                worksheet.Cells[row, 8].Value = item.GridLocation;
                
                row++;
            }
            else if (result is ClashResultGroup group)
            {
                ExportClashItems(group.Children, worksheet, ref row);
            }
        }
    }
    
    private string GetItemPath(ModelItem item)
    {
        if (item == null) return string.Empty;
        
        List<string> path = new List<string>();
        ModelItem current = item;
        
        while (current != null)
        {
            path.Insert(0, current.DisplayName);
            current = current.Parent;
        }
        
        return string.Join(" > ", path);
    }
}

Batch Process Multiple Models

public class BatchClashDetection
{
    public void ProcessMultipleModels(string[] modelPaths, string outputFolder)
    {
        foreach (string modelPath in modelPaths)
        {
            try
            {
                Console.WriteLine($"\nProcessing: {Path.GetFileName(modelPath)}");
                
                // Open model
                Document doc = Autodesk.Navisworks.Api.Application.OpenDocumentFile(modelPath);
                
                // Run clash tests
                DocumentClash clashDoc = doc.GetClash();
                
                foreach (ClashTest test in clashDoc.TestsData.Tests)
                {
                    Console.WriteLine($"  Running test: {test.DisplayName}");
                    test.Run();
                    
                    // Export results
                    string reportName = $"{Path.GetFileNameWithoutExtension(modelPath)}_{test.DisplayName}.html";
                    string reportPath = Path.Combine(outputFolder, reportName);
                    test.Export(reportPath, ClashReportFormat.Html);
                }
                
                // Save model with updated clash results
                doc.SaveFile(modelPath);
                
                // Close document
                doc.Dispose();
                
                Console.WriteLine($"  ✓ Completed");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"  ✗ Error: {ex.Message}");
            }
        }
    }
}

Key Points

  • ClashTest.Run() executes the clash detection
  • Results are hierarchical: ClashResultRoot → ClashResultGroup → ClashResultItem
  • Clash status: New, Active, Reviewed, Approved, Resolved
  • Hard clashes (geometry overlap) vs Clearance clashes (tolerance violation)
  • Export formats: HTML, XML, CSV
  • Selection sets define what to clash test

Common Pitfalls

Mistake: Not running test before accessing results

// WRONG - results may be outdated
int count = CountClashes(test.Children);

// CORRECT - run test first
test.Run();
int count = CountClashes(test.Children);

Mistake: Forgetting to handle groups in results

// WRONG - only counts top-level items
int count = test.Children.Count;

// CORRECT - recursively count all items
int count = CountClashes(test.Children); // Recursive function

Mistake: Not disposing documents in batch processing

// WRONG - memory leak
Document doc = Application.OpenDocumentFile(path);
// ... process ...
// Document never closed!

// CORRECT - dispose properly
Document doc = Application.OpenDocumentFile(path);
try
{
    // ... process ...
}
finally
{
    doc.Dispose();
}

Related Topics

  • Viewpoint creation for clashes
  • Clash grouping strategies
  • Integration with BIM 360 Issues
  • Automated clash resolution workflows
  • Clash matrix configuration
  • Time-based clash detection (4D)

Code Example

C#
using Autodesk.Navisworks.Api;
using Autodesk.Navisworks.Api.Clash;
using Autodesk.Navisworks.Api.DocumentParts;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;

namespace NavisworksClashAutomation
{
    public class ClashDetectionAutomation
    {
        public void RunClashTests()
        {
            // Get active document
            Document doc = Autodesk.Navisworks.Api.Application.ActiveDocument;
            
            if (doc == null)
            {
                Console.WriteLine("No active document found.");
                return;
            }
            
            // Get clash test document
            DocumentClash clashDoc = doc.GetClash();
            DocumentClashTests clashTests = clashDoc.TestsData;
            
            Console.WriteLine($"Found {clashTests.Tests.Count} clash tests");
            
            // Run all tests
            foreach (ClashTest test in clashTests.Tests)
            {
                Console.WriteLine($"\nRunning clash test: {test.DisplayName}");
                
                // Run the test
                test.Run();
                
                // Get results
                ClashResultRoot results = test.Children;
                int clashCount = CountClashes(results);
                
                Console.WriteLine($"  Total clashes found: {clashCount}");
                
                // Export results
                ExportClashResults(test, @"C:\Temp\ClashReports");
            }
        }
        
        private int CountClashes(ClashResultRoot results)
        {
            int count = 0;
            
            foreach (ClashResult result in results)
            {
                if (result is ClashResultItem)
                {
                    count++;
                }
                else if (result is ClashResultGroup group)
                {
                    count += CountClashes(group.Children);
                }
            }
            
            return count;
        }
        
        private void ExportClashResults(ClashTest test, string outputFolder)
        {
            if (!Directory.Exists(outputFolder))
                Directory.CreateDirectory(outputFolder);
            
            string fileName = $"{test.DisplayName}_{DateTime.Now:yyyyMMdd_HHmmss}.html";
            string filePath = Path.Combine(outputFolder, fileName);
            
            // Export to HTML
            test.Export(filePath, ClashReportFormat.Html);
            
            Console.WriteLine($"  Report exported: {filePath}");
        }
    }
}