fix(Navisworks): Corrects path hash collision handling (#1310)
.NET Build and Publish / build-connectors (push) Has been cancelled
.NET Build and Publish / deploy-installers (push) Has been cancelled

* update hash generation method in PathKey

* remove byte order mark in namespace declaration

* fix potential substring exception

* replace hash strings with path strings

* improve setter access modifiers

* remove byte order mark from import statement

* change delimiter in ToPathString method

* simplify ToPathString implementation
This commit is contained in:
Jonathon Broughton
2026-03-06 11:32:45 +00:00
committed by GitHub
parent 5290859bf0
commit ab0ebd5f46
4 changed files with 12 additions and 24 deletions
@@ -1,4 +1,4 @@
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging;
using Speckle.Connector.Navisworks.HostApp;
using Speckle.Connectors.Common.Builders;
using Speckle.Connectors.Common.Caching;
@@ -366,13 +366,13 @@ public class NavisworksRootObjectBuilder(
{
var groupKey = kvp.Key;
var geometries = kvp.Value;
var groupKeyHash = groupKey.ToHashString();
var groupKeyPath = groupKey.ToPathString();
var defProxy = new InstanceDefinitionProxy
{
name = $"Shared Geometry {groupKeyHash}",
name = $"Shared Geometry {groupKeyPath}",
objects = geometries.Select(g => g.applicationId ?? "").Where(id => !string.IsNullOrEmpty(id)).ToList(),
applicationId = $"{DEFINITION_ID_PREFIX}{groupKeyHash}",
applicationId = $"{DEFINITION_ID_PREFIX}{groupKeyPath}",
maxDepth = 0
};
@@ -18,6 +18,6 @@ public class DisplayValueExtractor(
/// <summary>
/// Gets the underlying geometry converter for accessing cache statistics.
/// </summary>
internal GeometryToSpeckleConverter GeometryConverter { get; } =
private GeometryToSpeckleConverter GeometryConverter { get; } =
geometryConverter ?? throw new ArgumentNullException(nameof(geometryConverter));
}
@@ -1,4 +1,4 @@
namespace Speckle.Converter.Navisworks.Paths;
namespace Speckle.Converter.Navisworks.Paths;
public readonly record struct PathKey
{
@@ -84,21 +84,9 @@ public readonly record struct PathKey
return true;
}
public override string ToString()
{
if (Data == null || Data.Length == 0)
{
return string.Empty;
}
return string.Join(",", Data);
}
public override string ToString() => Data == null || Data.Length == 0 ? string.Empty : string.Join(".", Data);
/// <summary>
/// Returns a compact string representation using the hash value as an unsigned integer.
/// Suitable for use as application IDs and definition IDs.
/// This avoids negative numbers in IDs by treating the hash as unsigned.
/// </summary>
public string ToHashString() => unchecked((uint)Hash).ToString();
public string ToPathString() => Data == null || Data.Length == 0 ? "0" : string.Join(".", Data);
}
internal sealed class PathKeyComparer : IEqualityComparer<PathKey>
@@ -108,10 +108,10 @@ public sealed class GeometryToSpeckleConverter(
var transformedWorld = _isUpright ? instanceWorld : TransformMatrixYUpToZUp(instanceWorld);
var invDefWorld = GeometryHelpers.InvertRigid(transformedWorld);
var definitionGeometry = UnbakeGeometry(geometries, invDefWorld);
var groupKeyHash = groupKey.ToHashString();
var groupKeyPath = groupKey.ToPathString();
for (int i = 0; i < definitionGeometry.Count; i++)
{
definitionGeometry[i].applicationId = $"{GEOMETRY_ID_PREFIX}{groupKeyHash}_{i}";
definitionGeometry[i].applicationId = $"{GEOMETRY_ID_PREFIX}{groupKeyPath}_{i}";
}
_registry.StoreDefinitionGeometry(groupKey, definitionGeometry);
@@ -123,10 +123,10 @@ public sealed class GeometryToSpeckleConverter(
var transformedWorld = _isUpright ? instanceWorld : TransformMatrixYUpToZUp(instanceWorld);
var instanceProxy = new InstanceProxy
{
definitionId = $"{InstanceConstants.DEFINITION_ID_PREFIX}{groupKey.ToHashString()}",
definitionId = $"{InstanceConstants.DEFINITION_ID_PREFIX}{groupKey.ToPathString()}",
transform = ConvertToMatrix4X4(transformedWorld),
units = _settings.Derived.SpeckleUnits,
applicationId = $"{InstanceConstants.INSTANCE_ID_PREFIX}{itemPathKey.ToHashString()}",
applicationId = $"{InstanceConstants.INSTANCE_ID_PREFIX}{itemPathKey.ToPathString()}",
maxDepth = 0
};