using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using Autodesk.Navisworks.Api;
namespace NavisworksTransport.PathPlanning
{
///
/// GridMap缓存键,用于标识唯一的GridMap生成配置
/// 基于所有物流属性构件、车辆尺寸、网格尺寸等关键参数
///
public class GridMapCacheKey : IEquatable
{
///
/// 物流数据哈希值(所有物流属性构件,包括通道、门、无关项等)
///
public string LogisticsDataHash { get; set; }
///
/// 边界范围哈希
///
public string BoundsHash { get; set; }
///
/// 网格单元大小(模型单位)
///
public double CellSize { get; set; }
///
/// 车辆半径(米)
///
public double VehicleRadius { get; set; }
///
/// 安全间隙(米)
///
public double SafetyMargin { get; set; }
///
/// 车辆高度(米)
///
public double VehicleHeight { get; set; }
///
/// 构造函数
///
public GridMapCacheKey(string logisticsDataHash, string boundsHash, double cellSize,
double vehicleRadius, double safetyMargin, double vehicleHeight)
{
LogisticsDataHash = logisticsDataHash ?? throw new ArgumentNullException(nameof(logisticsDataHash));
BoundsHash = boundsHash ?? throw new ArgumentNullException(nameof(boundsHash));
CellSize = cellSize;
VehicleRadius = vehicleRadius;
SafetyMargin = safetyMargin;
VehicleHeight = vehicleHeight;
}
///
/// 检查两个缓存键是否相等
///
public bool Equals(GridMapCacheKey other)
{
if (other == null) return false;
if (ReferenceEquals(this, other)) return true;
return LogisticsDataHash == other.LogisticsDataHash &&
BoundsHash == other.BoundsHash &&
Math.Abs(CellSize - other.CellSize) < 1e-6 &&
Math.Abs(VehicleRadius - other.VehicleRadius) < 1e-6 &&
Math.Abs(SafetyMargin - other.SafetyMargin) < 1e-6 &&
Math.Abs(VehicleHeight - other.VehicleHeight) < 1e-6;
}
///
/// 重写Equals方法
///
public override bool Equals(object obj)
{
return Equals(obj as GridMapCacheKey);
}
///
/// 计算哈希码,用于Dictionary键
///
public override int GetHashCode()
{
unchecked
{
int hash = 17;
hash = hash * 23 + (LogisticsDataHash?.GetHashCode() ?? 0);
hash = hash * 23 + (BoundsHash?.GetHashCode() ?? 0);
hash = hash * 23 + CellSize.GetHashCode();
hash = hash * 23 + VehicleRadius.GetHashCode();
hash = hash * 23 + SafetyMargin.GetHashCode();
hash = hash * 23 + VehicleHeight.GetHashCode();
return hash;
}
}
///
/// 生成可读的字符串表示
///
public override string ToString()
{
var logisticsPreview = LogisticsDataHash != null ?
LogisticsDataHash.Substring(0, Math.Min(8, LogisticsDataHash.Length)) :
"NULL";
var boundsPreview = BoundsHash != null ?
BoundsHash.Substring(0, Math.Min(8, BoundsHash.Length)) :
"NULL";
return $"GridMapKey[Logistics={logisticsPreview}, Bounds={boundsPreview}, " +
$"Cell={CellSize:F2}, VR={VehicleRadius:F1}m, SM={SafetyMargin:F1}m, VH={VehicleHeight:F1}m]";
}
///
/// 根据参数生成GridMap缓存键
///
/// 边界范围
/// 网格大小
/// 车辆半径(米)
/// 安全间隙(米)
/// 车辆高度(米)
/// 缓存键
public static GridMapCacheKey CreateFrom(BoundingBox3D bounds,
double cellSize, double vehicleRadius,
double safetyMargin, double vehicleHeight)
{
var logisticsDataHash = ComputeLogisticsDataHash();
var boundsHash = ComputeBoundsHash(bounds);
return new GridMapCacheKey(logisticsDataHash, boundsHash, cellSize,
vehicleRadius, safetyMargin, vehicleHeight);
}
///
/// 计算物流数据哈希值
/// 基于所有物流属性构件(包括通道、门、无关项等)的ID、属性、几何等信息
///
/// 物流数据哈希
private static string ComputeLogisticsDataHash()
{
try
{
using (var sha256 = SHA256.Create())
{
var hashBuilder = new StringBuilder();
// 获取所有有物流属性的模型项(不仅仅是可通行项)
var allLogisticsItems = CategoryAttributeManager.GetAllLogisticsItems();
// 按InstanceGuid排序确保一致性
var sortedItems = allLogisticsItems.OrderBy(item => item.InstanceGuid.ToString()).ToList();
hashBuilder.Append($"LogisticsCount:{sortedItems.Count}|");
foreach (var item in sortedItems)
{
// 基本标识信息
hashBuilder.Append($"ID:{item.InstanceGuid}|");
hashBuilder.Append($"DisplayName:{item.DisplayName ?? "NULL"}|");
// 几何信息(包围盒)
var bbox = item.BoundingBox();
if (bbox != null)
{
hashBuilder.Append($"BBox:{bbox.Min.X:F3},{bbox.Min.Y:F3},{bbox.Min.Z:F3}-");
hashBuilder.Append($"{bbox.Max.X:F3},{bbox.Max.Y:F3},{bbox.Max.Z:F3}|");
}
// 物流类型属性
var logisticsType = CategoryAttributeManager.GetLogisticsElementType(item);
hashBuilder.Append($"LogType:{logisticsType}|");
// Transform信息(如果有变换)
var transform = item.Transform;
if (transform != null)
{
// 只包含关键的变换信息
hashBuilder.Append($"TX:{transform.Translation.X:F3},{transform.Translation.Y:F3},{transform.Translation.Z:F3}|");
}
}
// 计算最终哈希
var hashInput = hashBuilder.ToString();
var hashBytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(hashInput));
var hexBuilder = new StringBuilder();
foreach (byte b in hashBytes)
{
hexBuilder.Append(b.ToString("x2"));
}
return hexBuilder.ToString();
}
}
catch (Exception ex)
{
LogManager.Warning($"[物流哈希] 计算物流数据哈希失败: {ex.Message},使用时间戳标识");
return $"LOGISTICS_HASH_FAILED_{DateTime.Now.Ticks}";
}
}
///
/// 计算边界范围哈希值
///
/// 边界范围
/// 边界哈希
private static string ComputeBoundsHash(BoundingBox3D bounds)
{
try
{
using (var sha256 = SHA256.Create())
{
var boundsString = $"Bounds:{bounds.Min.X:F6},{bounds.Min.Y:F6},{bounds.Min.Z:F6}-" +
$"{bounds.Max.X:F6},{bounds.Max.Y:F6},{bounds.Max.Z:F6}";
var hashBytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(boundsString));
var hexBuilder = new StringBuilder();
foreach (byte b in hashBytes)
{
hexBuilder.Append(b.ToString("x2"));
}
return hexBuilder.ToString();
}
}
catch (Exception ex)
{
LogManager.Warning($"[边界哈希] 计算边界哈希失败: {ex.Message},使用时间戳标识");
return $"BOUNDS_HASH_FAILED_{DateTime.Now.Ticks}";
}
}
}
}