NavisworksTransport/src/Core/FloorAttributeManager.cs

450 lines
17 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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
}
}