450 lines
17 KiB
C#
450 lines
17 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using System.Linq;
|
||
using Autodesk.Navisworks.Api;
|
||
using NavisworksTransport.Utils;
|
||
using NavisApplication = Autodesk.Navisworks.Api.Application;
|
||
|
||
namespace NavisworksTransport.Core
|
||
{
|
||
/// <summary>
|
||
/// 楼层属性管理器 - 基于COM API的自定义楼层属性管理
|
||
/// 提供楼层属性的增删改查功能,支持属性继承查询
|
||
/// </summary>
|
||
public class FloorAttributeManager
|
||
{
|
||
#region 常量定义
|
||
|
||
/// <summary>
|
||
/// 分层信息属性分类名称
|
||
/// </summary>
|
||
public const string FLOOR_CATEGORY = "分层信息";
|
||
|
||
/// <summary>
|
||
/// 分层信息属性分类内部名称
|
||
/// </summary>
|
||
public const string FLOOR_CATEGORY_INTERNAL = "Floor_Info_Category";
|
||
|
||
/// <summary>
|
||
/// 楼层属性名称
|
||
/// </summary>
|
||
public const string FLOOR_LEVEL_PROPERTY = "Floor_Level";
|
||
|
||
/// <summary>
|
||
/// 楼层属性显示名称
|
||
/// </summary>
|
||
public const string FLOOR_LEVEL_DISPLAY_NAME = "楼层";
|
||
|
||
/// <summary>
|
||
/// 区域属性名称
|
||
/// </summary>
|
||
public const string ZONE_PROPERTY = "Zone";
|
||
|
||
/// <summary>
|
||
/// 区域属性显示名称
|
||
/// </summary>
|
||
public const string ZONE_DISPLAY_NAME = "区域";
|
||
|
||
/// <summary>
|
||
/// 子系统属性名称
|
||
/// </summary>
|
||
public const string SUBSYSTEM_PROPERTY = "Sub_System";
|
||
|
||
/// <summary>
|
||
/// 子系统属性显示名称
|
||
/// </summary>
|
||
public const string SUBSYSTEM_DISPLAY_NAME = "子系统";
|
||
|
||
#endregion
|
||
|
||
#region 公共方法
|
||
|
||
/// <summary>
|
||
/// 设置对象的分层属性
|
||
/// </summary>
|
||
/// <param name="item">目标模型项</param>
|
||
/// <param name="floorLevel">楼层标识,如"F1", "F2", "B1"等</param>
|
||
/// <param name="zone">区域标识(可选)</param>
|
||
/// <param name="subSystem">子系统标识(可选)</param>
|
||
/// <returns>设置成功返回true,失败返回false</returns>
|
||
public bool SetFloorAttribute(ModelItem item, string floorLevel, string zone = null, string subSystem = null)
|
||
{
|
||
if (item == null || string.IsNullOrEmpty(floorLevel))
|
||
{
|
||
LogManager.Error("[FloorAttributeManager] 设置楼层属性失败:参数无效");
|
||
return false;
|
||
}
|
||
|
||
try
|
||
{
|
||
LogManager.Info($"[FloorAttributeManager] 开始设置模型 {item.DisplayName} 的楼层属性 {floorLevel}");
|
||
|
||
return ExecuteWithUIThread(() =>
|
||
{
|
||
return NavisworksComPropertyManager.SetFloorProperties(
|
||
item,
|
||
floorLevel,
|
||
zone,
|
||
subSystem,
|
||
FLOOR_CATEGORY,
|
||
FLOOR_CATEGORY_INTERNAL,
|
||
FLOOR_LEVEL_PROPERTY,
|
||
ZONE_PROPERTY,
|
||
SUBSYSTEM_PROPERTY);
|
||
});
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"[FloorAttributeManager] ❌ 设置楼层属性失败,错误: {ex.Message}", ex);
|
||
return false;
|
||
}
|
||
}
|
||
|
||
|
||
/// <summary>
|
||
/// 设置单个分层属性,保留其他现有属性
|
||
/// </summary>
|
||
/// <param name="item">模型项</param>
|
||
/// <param name="attributeType">属性类型:楼层、区域、子系统</param>
|
||
/// <param name="attributeValue">属性值</param>
|
||
/// <returns>操作是否成功</returns>
|
||
public bool SetSingleLayerAttribute(ModelItem item, string attributeType, string attributeValue)
|
||
{
|
||
if (item == null || string.IsNullOrEmpty(attributeType) || string.IsNullOrEmpty(attributeValue))
|
||
{
|
||
LogManager.Error("[FloorAttributeManager] 设置单个分层属性失败:参数无效");
|
||
return false;
|
||
}
|
||
|
||
try
|
||
{
|
||
LogManager.Info($"[FloorAttributeManager] 开始设置模型 {item.DisplayName} 的{attributeType}属性: {attributeValue}");
|
||
|
||
return ExecuteWithUIThread(() =>
|
||
{
|
||
// 获取现有的所有分层属性值
|
||
var existingFloorLevel = NavisworksComPropertyManager.GetFloorPropertyValue(item, FLOOR_CATEGORY, FLOOR_LEVEL_PROPERTY);
|
||
var existingZone = NavisworksComPropertyManager.GetFloorPropertyValue(item, FLOOR_CATEGORY, ZONE_PROPERTY);
|
||
var existingSubSystem = NavisworksComPropertyManager.GetFloorPropertyValue(item, FLOOR_CATEGORY, SUBSYSTEM_PROPERTY);
|
||
|
||
// 根据属性类型更新对应的值
|
||
string finalFloorLevel = existingFloorLevel;
|
||
string finalZone = existingZone;
|
||
string finalSubSystem = existingSubSystem;
|
||
|
||
switch (attributeType)
|
||
{
|
||
case "楼层":
|
||
finalFloorLevel = attributeValue;
|
||
break;
|
||
case "区域":
|
||
finalZone = attributeValue;
|
||
break;
|
||
case "子系统":
|
||
finalSubSystem = attributeValue;
|
||
break;
|
||
default:
|
||
LogManager.Error($"[FloorAttributeManager] 不支持的属性类型: {attributeType}");
|
||
return false;
|
||
}
|
||
|
||
// 使用静态方法设置完整的楼层属性
|
||
bool success = NavisworksComPropertyManager.SetFloorProperties(
|
||
item,
|
||
finalFloorLevel,
|
||
finalZone,
|
||
finalSubSystem,
|
||
FLOOR_CATEGORY,
|
||
FLOOR_CATEGORY_INTERNAL,
|
||
FLOOR_LEVEL_PROPERTY,
|
||
ZONE_PROPERTY,
|
||
SUBSYSTEM_PROPERTY);
|
||
|
||
if (success)
|
||
{
|
||
LogManager.Info($"[FloorAttributeManager] ✅ 成功设置{attributeType}属性");
|
||
|
||
// 属性修改成功,清除分层缓存确保下次预览使用最新数据
|
||
try
|
||
{
|
||
ModelSplitterManager.Instance?.ClearCache();
|
||
LogManager.Info("[FloorAttributeManager] 属性修改成功,已清除分层缓存");
|
||
}
|
||
catch (Exception cacheEx)
|
||
{
|
||
LogManager.Warning($"[FloorAttributeManager] 清除缓存时出错: {cacheEx.Message}");
|
||
}
|
||
}
|
||
|
||
return success;
|
||
});
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"[FloorAttributeManager] ❌ 设置{attributeType}属性失败,错误: {ex.Message}", ex);
|
||
return false;
|
||
}
|
||
}
|
||
|
||
|
||
|
||
|
||
/// <summary>
|
||
/// 获取楼层属性值(使用 Native API,性能最优)
|
||
/// </summary>
|
||
/// <param name="item">模型项</param>
|
||
/// <param name="propertyName">属性显示名称,如 "楼层"、"区域"、"子系统"</param>
|
||
/// <returns>属性值,不存在返回 null</returns>
|
||
public string GetFloorProperty(ModelItem item, string propertyName)
|
||
{
|
||
if (item == null) return null;
|
||
|
||
try
|
||
{
|
||
foreach (PropertyCategory category in item.PropertyCategories)
|
||
{
|
||
if (category.DisplayName == FLOOR_CATEGORY)
|
||
{
|
||
foreach (DataProperty property in category.Properties)
|
||
{
|
||
if (property.DisplayName == propertyName)
|
||
{
|
||
return property.Value.ToDisplayString();
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Debug($"[FloorAttributeManager] 获取楼层属性 '{propertyName}' 失败: {ex.Message}");
|
||
}
|
||
return null;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 检查模型项是否有楼层属性(性能优化版本)
|
||
/// </summary>
|
||
public bool HasFloorAttributes(ModelItem item)
|
||
{
|
||
if (item == null) return false;
|
||
|
||
try
|
||
{
|
||
foreach (PropertyCategory category in item.PropertyCategories)
|
||
{
|
||
if (category.DisplayName == FLOOR_CATEGORY)
|
||
return true;
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Debug($"[楼层管理器] 检查类别失败: {ex.Message}");
|
||
}
|
||
return false;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 通过 COM API 获取楼层属性值(特殊场景使用)
|
||
/// 仅在以下情况使用:
|
||
/// 1. 刚通过 COM API 更新属性后需要立即读取
|
||
/// 2. 遇到 Native API 缓存不同步问题时
|
||
/// 注意:性能较差,需要 UI 线程同步
|
||
/// </summary>
|
||
public string GetFloorPropertyViaCom(ModelItem item, string propertyName)
|
||
{
|
||
if (item == null) return null;
|
||
|
||
// 将显示名称转换为内部名称
|
||
string internalName = ConvertToInternalName(propertyName);
|
||
|
||
return ExecuteWithUIThread(() =>
|
||
{
|
||
return NavisworksComPropertyManager.GetFloorPropertyValue(
|
||
item, FLOOR_CATEGORY, internalName);
|
||
});
|
||
}
|
||
|
||
/// <summary>
|
||
/// 将显示名称转换为内部名称
|
||
/// </summary>
|
||
private string ConvertToInternalName(string displayName)
|
||
{
|
||
switch (displayName)
|
||
{
|
||
case "楼层": return FLOOR_LEVEL_PROPERTY;
|
||
case "区域": return ZONE_PROPERTY;
|
||
case "子系统": return SUBSYSTEM_PROPERTY;
|
||
default: return displayName + "_Internal";
|
||
}
|
||
}
|
||
|
||
|
||
|
||
/// <summary>
|
||
/// 批量设置楼层属性
|
||
/// </summary>
|
||
/// <param name="floorMappings">楼层映射字典,键为ModelItem,值为楼层标识</param>
|
||
/// <returns>设置成功的数量</returns>
|
||
public int SetFloorAttributeBatch(Dictionary<ModelItem, string> floorMappings)
|
||
{
|
||
if (floorMappings == null || floorMappings.Count == 0)
|
||
{
|
||
LogManager.Warning("[FloorAttributeManager] 批量设置楼层属性:输入为空");
|
||
return 0;
|
||
}
|
||
|
||
int successCount = 0;
|
||
LogManager.Info($"[FloorAttributeManager] 开始批量设置楼层属性,共 {floorMappings.Count} 个对象");
|
||
|
||
foreach (var mapping in floorMappings)
|
||
{
|
||
try
|
||
{
|
||
if (SetFloorAttribute(mapping.Key, mapping.Value))
|
||
{
|
||
successCount++;
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"[FloorAttributeManager] 批量设置楼层属性时出错:{mapping.Key?.DisplayName} -> {mapping.Value}, 错误: {ex.Message}");
|
||
}
|
||
}
|
||
|
||
// 批量操作完成后执行缓存刷新
|
||
if (successCount > 0)
|
||
{
|
||
NavisworksApiHelper.SafeCacheRefresh("FloorAttributeManager");
|
||
}
|
||
|
||
LogManager.Info($"[FloorAttributeManager] 批量设置完成,成功 {successCount}/{floorMappings.Count} 个对象");
|
||
return successCount;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取所有楼层分组
|
||
/// </summary>
|
||
/// <returns>楼层分组字典,键为楼层标识,值为该楼层的ModelItem列表</returns>
|
||
public Dictionary<string, List<ModelItem>> GetFloorGroups()
|
||
{
|
||
var floorGroups = new Dictionary<string, List<ModelItem>>();
|
||
|
||
try
|
||
{
|
||
LogManager.Info("[FloorAttributeManager] 开始分析楼层分组");
|
||
|
||
// 获取所有模型项
|
||
var allItems = NavisApplication.ActiveDocument.Models.RootItemDescendantsAndSelf
|
||
.Where(item => item.HasGeometry)
|
||
.ToList();
|
||
|
||
LogManager.Info($"[FloorAttributeManager] 共找到 {allItems.Count} 个几何体对象");
|
||
|
||
foreach (var item in allItems)
|
||
{
|
||
try
|
||
{
|
||
string floorLevel = GetFloorProperty(item, "楼层");
|
||
if (!string.IsNullOrEmpty(floorLevel))
|
||
{
|
||
if (!floorGroups.ContainsKey(floorLevel))
|
||
{
|
||
floorGroups[floorLevel] = new List<ModelItem>();
|
||
}
|
||
floorGroups[floorLevel].Add(item);
|
||
}
|
||
else
|
||
{
|
||
// 未分层对象归类到"未分层"
|
||
const string unclassified = "未分层";
|
||
if (!floorGroups.ContainsKey(unclassified))
|
||
{
|
||
floorGroups[unclassified] = new List<ModelItem>();
|
||
}
|
||
floorGroups[unclassified].Add(item);
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"[FloorAttributeManager] 处理对象 {item.DisplayName} 时出错:{ex.Message}");
|
||
}
|
||
}
|
||
|
||
LogManager.Info($"[FloorAttributeManager] 楼层分组完成,共 {floorGroups.Count} 个分组");
|
||
foreach (var group in floorGroups)
|
||
{
|
||
LogManager.Info($" - {group.Key}: {group.Value.Count} 个对象");
|
||
}
|
||
|
||
return floorGroups;
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"[FloorAttributeManager] 获取楼层分组失败:{ex.Message}", ex);
|
||
return new Dictionary<string, List<ModelItem>>();
|
||
}
|
||
}
|
||
|
||
|
||
/// <summary>
|
||
/// 清除对象的楼层属性
|
||
/// </summary>
|
||
/// <param name="item">目标模型项</param>
|
||
/// <returns>清除成功返回true</returns>
|
||
public bool ClearFloorAttribute(ModelItem item)
|
||
{
|
||
if (item == null) return false;
|
||
|
||
try
|
||
{
|
||
LogManager.Info($"[FloorAttributeManager] 开始清除模型 {item.DisplayName} 的楼层属性");
|
||
|
||
bool result = ExecuteWithUIThread(() =>
|
||
{
|
||
var items = new ModelItemCollection { item };
|
||
int removedCount = NavisworksComPropertyManager.RemoveUserDefinedCategory(items, FLOOR_CATEGORY);
|
||
return removedCount > 0;
|
||
});
|
||
|
||
// 执行安全的缓存刷新
|
||
if (result)
|
||
{
|
||
NavisworksApiHelper.SafeCacheRefresh("FloorAttributeManager");
|
||
|
||
// 属性清除成功,清除分层缓存确保下次预览使用最新数据
|
||
try
|
||
{
|
||
ModelSplitterManager.Instance?.ClearCache();
|
||
LogManager.Info("[FloorAttributeManager] 属性清除成功,已清除分层缓存");
|
||
}
|
||
catch (Exception cacheEx)
|
||
{
|
||
LogManager.Warning($"[FloorAttributeManager] 清除缓存时出错: {cacheEx.Message}");
|
||
}
|
||
}
|
||
|
||
return result;
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.Error($"[FloorAttributeManager] ❌ 清除楼层属性失败:{ex.Message}", ex);
|
||
return false;
|
||
}
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 私有方法
|
||
|
||
/// <summary>
|
||
/// 在UI线程中执行操作,确保线程安全
|
||
/// </summary>
|
||
private T ExecuteWithUIThread<T>(Func<T> operation)
|
||
{
|
||
return NavisworksApiHelper.ExecuteOnUIThread(operation);
|
||
}
|
||
|
||
#endregion
|
||
}
|
||
} |