From ad1b5201862170a91943bd298895b2f6320c30c4 Mon Sep 17 00:00:00 2001 From: Jonathon Broughton Date: Thu, 16 Jan 2025 01:10:35 +0000 Subject: [PATCH] Rename DisplayPathHelper.cs to HierarchyHelper.cs - Renamed the file from "DisplayPathHelper.cs" to "HierarchyHelper.cs" - Updated all references to the renamed file Refactor helper class for generating display paths - Refactored the helper class to extract hierarchical context from Navisworks model items in a single traversal - Changed the method name from "GenerateDisplayPath" to "ExtractContext" - Modified the method signature to return a tuple of strings (Name, Path) - Updated the implementation logic accordingly Improve traversal and extraction logic - Improved the traversal logic by collecting both name and path information while traversing up the tree once - Extracted meaningful name and path information from model items in a more efficient way - Handled cases where model item has no meaningful name or is a geometry node --- .../Helpers/DisplayPathHelper.cs | 60 ------------------- .../Helpers/HierarchyHelper.cs | 59 ++++++++++++++++++ ...ckle.Converters.NavisworksShared.projitems | 2 +- 3 files changed, 60 insertions(+), 61 deletions(-) delete mode 100644 Converters/Navisworks/Speckle.Converters.NavisworksShared/Helpers/DisplayPathHelper.cs create mode 100644 Converters/Navisworks/Speckle.Converters.NavisworksShared/Helpers/HierarchyHelper.cs diff --git a/Converters/Navisworks/Speckle.Converters.NavisworksShared/Helpers/DisplayPathHelper.cs b/Converters/Navisworks/Speckle.Converters.NavisworksShared/Helpers/DisplayPathHelper.cs deleted file mode 100644 index 55fd14aa9..000000000 --- a/Converters/Navisworks/Speckle.Converters.NavisworksShared/Helpers/DisplayPathHelper.cs +++ /dev/null @@ -1,60 +0,0 @@ -namespace Speckle.Converter.Navisworks.Helpers; - -/// -/// Helper class for generating display paths by traversing meaningful Navisworks model item ancestors. -/// -public static class DisplayPathHelper -{ - private const char PATH_DELIMITER = '>'; - - /// - /// Generates a display path string for a ModelItem by traversing its meaningful ancestors. - /// - public static string GenerateDisplayPath(NAV.ModelItem modelItem) - { - if (modelItem == null) - { - throw new ArgumentNullException(nameof(modelItem)); - } - - var ancestorPath = new List(); - - // Start with the root document name if available - if (modelItem.HasModel && !string.IsNullOrEmpty(modelItem.Model.FileName)) - { - ancestorPath.Add(Path.GetFileNameWithoutExtension(modelItem.Model.FileName)); - } - - // Work backwards through ancestors, skipping empty or geometry nodes - var current = modelItem.Parent; - while (current != null) - { - // Skip nodes without meaningful names or geometry nodes - if (!string.IsNullOrEmpty(current.DisplayName) && !IsGeometryNode(current)) - { - // Don't add duplicate names in sequence - if (ancestorPath.Count == 0 || ancestorPath.Last() != current.DisplayName) - { - ancestorPath.Add(current.DisplayName); - } - } - - current = current.Parent; - } - - // Reverse to get root->leaf order - ancestorPath.Reverse(); - // if (ancestorPath.Count > 1) - // { - // ancestorPath.RemoveAt(ancestorPath.Count - 1); - // } - - return string.Join($" {PATH_DELIMITER} ", ancestorPath); - } - - private static bool IsGeometryNode(NAV.ModelItem item) - { - // A geometry node typically has geometry but no meaningful display name - return item.HasGeometry && string.IsNullOrEmpty(item.DisplayName); - } -} diff --git a/Converters/Navisworks/Speckle.Converters.NavisworksShared/Helpers/HierarchyHelper.cs b/Converters/Navisworks/Speckle.Converters.NavisworksShared/Helpers/HierarchyHelper.cs new file mode 100644 index 000000000..47113e2c8 --- /dev/null +++ b/Converters/Navisworks/Speckle.Converters.NavisworksShared/Helpers/HierarchyHelper.cs @@ -0,0 +1,59 @@ +namespace Speckle.Converter.Navisworks.Helpers; + +/// +/// Helper class for extracting hierarchical context from Navisworks model items in a single traversal. +/// +public static class HierarchyHelper +{ + private const char PATH_DELIMITER = '>'; + + /// + /// Extracts the meaningful name and path from a ModelItem in a single traversal. + /// + public static (string Name, string Path) ExtractContext(NAV.ModelItem modelItem) + { + if (modelItem == null) + { + throw new ArgumentNullException(nameof(modelItem)); + } + + var ancestors = new List(); + var meaningfulName = string.Empty; + var current = modelItem; + + // Start with the root document name if available + if (modelItem.HasModel && !string.IsNullOrEmpty(modelItem.Model.FileName)) + { + ancestors.Add(Path.GetFileNameWithoutExtension(modelItem.Model.FileName)); + } + + // Traverse up the tree once, collecting both name and path information + while (current != null) + { + if (IsMeaningfulNode(current)) + { + // First meaningful name we find is our object name (if we haven't found one yet) + if (string.IsNullOrEmpty(meaningfulName)) + { + meaningfulName = current.DisplayName; + } + // Add to ancestors if it's not a duplicate + else if (ancestors.Count == 0 || ancestors.Last() != current.DisplayName) + { + ancestors.Add(current.DisplayName); + } + } + current = current.Parent; + } + + // Build path excluding the name we found + ancestors.Reverse(); + + var path = string.Join($" {PATH_DELIMITER} ", ancestors); + + return (meaningfulName, path); + } + + private static bool IsMeaningfulNode(NAV.ModelItem item) => + !string.IsNullOrEmpty(item.DisplayName) && (!item.HasGeometry || !string.IsNullOrEmpty(item.ClassDisplayName)); +} diff --git a/Converters/Navisworks/Speckle.Converters.NavisworksShared/Speckle.Converters.NavisworksShared.projitems b/Converters/Navisworks/Speckle.Converters.NavisworksShared/Speckle.Converters.NavisworksShared.projitems index be488d16f..d791e58b9 100644 --- a/Converters/Navisworks/Speckle.Converters.NavisworksShared/Speckle.Converters.NavisworksShared.projitems +++ b/Converters/Navisworks/Speckle.Converters.NavisworksShared/Speckle.Converters.NavisworksShared.projitems @@ -22,7 +22,7 @@ - +