960 lines
42 KiB
C#
960 lines
42 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using System.Linq;
|
||
using Autodesk.Navisworks.Api;
|
||
using ComApi = Autodesk.Navisworks.Api.Interop.ComApi;
|
||
using ComApiBridge = Autodesk.Navisworks.Api.ComApi.ComApiBridge;
|
||
|
||
namespace NavisworksTransport
|
||
{
|
||
/// <summary>
|
||
/// 类别属性管理器 - 负责为模型元素添加和管理物流相关的自定义属性
|
||
/// </summary>
|
||
public class CategoryAttributeManager
|
||
{
|
||
/// <summary>
|
||
/// 物流类别定义
|
||
/// </summary>
|
||
public static class LogisticsCategories
|
||
{
|
||
public const string LOGISTICS = "物流属性";
|
||
public const string CATEGORY_INTERNAL_NAME = "物流属性_Internal";
|
||
}
|
||
|
||
/// <summary>
|
||
/// 物流属性定义
|
||
/// </summary>
|
||
public static class LogisticsProperties
|
||
{
|
||
public const string TYPE = "类型";
|
||
public const string TRAVERSABLE = "可通行";
|
||
public const string PRIORITY = "优先级";
|
||
public const string VEHICLE_SIZE = "适用车辆尺寸";
|
||
public const string SPEED_LIMIT = "速度限制";
|
||
}
|
||
|
||
/// <summary>
|
||
/// 物流元素类型
|
||
/// </summary>
|
||
public enum LogisticsElementType
|
||
{
|
||
门,
|
||
电梯,
|
||
楼梯,
|
||
通道,
|
||
障碍物,
|
||
装卸区,
|
||
停车位,
|
||
检查点
|
||
}
|
||
|
||
/// <summary>
|
||
/// 为选定的模型项添加物流属性
|
||
/// </summary>
|
||
/// <param name="items">要处理的模型项集合</param>
|
||
/// <param name="elementType">物流元素类型</param>
|
||
/// <param name="isTraversable">是否可通行</param>
|
||
/// <param name="priority">优先级(1-10)</param>
|
||
/// <param name="vehicleSize">适用车辆尺寸</param>
|
||
/// <param name="speedLimit">速度限制(km/h)</param>
|
||
/// <returns>成功处理的项目数量</returns>
|
||
public static int AddLogisticsAttributes(
|
||
ModelItemCollection items,
|
||
LogisticsElementType elementType,
|
||
bool isTraversable = true,
|
||
int priority = 5,
|
||
string vehicleSize = "标准",
|
||
double speedLimit = 10.0)
|
||
{
|
||
if (items == null || items.Count == 0)
|
||
{
|
||
return 0;
|
||
}
|
||
|
||
int successCount = 0;
|
||
|
||
try
|
||
{
|
||
// 获取COM API状态对象
|
||
ComApi.InwOpState10 state = ComApiBridge.State;
|
||
|
||
// 转换选择集合为COM对象
|
||
ComApi.InwOpSelection comSelection = ComApiBridge.ToInwOpSelection(items);
|
||
|
||
// 遍历每个路径对象
|
||
foreach (ComApi.InwOaPath3 path in comSelection.Paths())
|
||
{
|
||
try
|
||
{
|
||
// 获取属性节点
|
||
ComApi.InwGUIPropertyNode2 propertyNode =
|
||
(ComApi.InwGUIPropertyNode2)state.GetGUIPropertyNode(path, false);
|
||
|
||
// 查找现有属性类别的索引
|
||
int existingIndex = GetLogisticsAttributeIndex(propertyNode);
|
||
|
||
// 创建新的属性类别
|
||
ComApi.InwOaPropertyVec propertyCategory =
|
||
(ComApi.InwOaPropertyVec)state.ObjectFactory(
|
||
ComApi.nwEObjectType.eObjectType_nwOaPropertyVec, null, null);
|
||
|
||
// 创建并添加类型属性
|
||
AddProperty(state, propertyCategory, LogisticsProperties.TYPE,
|
||
elementType.ToString(), elementType.ToString() + "_Internal");
|
||
|
||
// 创建并添加可通行属性
|
||
AddProperty(state, propertyCategory, LogisticsProperties.TRAVERSABLE,
|
||
isTraversable ? "是" : "否", "Traversable_Internal");
|
||
|
||
// 创建并添加优先级属性
|
||
AddProperty(state, propertyCategory, LogisticsProperties.PRIORITY,
|
||
priority.ToString(), "Priority_Internal");
|
||
|
||
// 创建并添加车辆尺寸属性
|
||
AddProperty(state, propertyCategory, LogisticsProperties.VEHICLE_SIZE,
|
||
vehicleSize, "VehicleSize_Internal");
|
||
|
||
// 创建并添加速度限制属性
|
||
AddProperty(state, propertyCategory, LogisticsProperties.SPEED_LIMIT,
|
||
speedLimit.ToString("F1") + " km/h", "SpeedLimit_Internal");
|
||
|
||
if (existingIndex >= 0)
|
||
{
|
||
// 如果存在现有属性,使用覆盖模式 (参数1)
|
||
LogManager.WriteLog($"[属性添加] 发现现有物流属性,使用覆盖模式更新");
|
||
LogPropertyNodeState(propertyNode, "属性添加-覆盖前");
|
||
|
||
try
|
||
{
|
||
// 使用参数1表示覆盖现有PropertyCategory
|
||
propertyNode.SetUserDefined(1, LogisticsCategories.LOGISTICS,
|
||
LogisticsCategories.CATEGORY_INTERNAL_NAME, propertyCategory);
|
||
LogManager.WriteLog($"[属性添加] ✅ 成功覆盖现有属性类别");
|
||
|
||
// 立即刷新并验证结果
|
||
propertyNode = RefreshPropertyNode(state, path, "属性添加-覆盖验证");
|
||
LogPropertyNodeState(propertyNode, "属性添加-覆盖后");
|
||
}
|
||
catch (Exception setEx)
|
||
{
|
||
LogManager.WriteLog($"[属性添加] ❌ 覆盖属性失败,错误: {setEx.Message}");
|
||
throw;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// 如果不存在,创建新的属性类别,使用创建模式 (参数0)
|
||
LogManager.WriteLog("[属性添加] 未发现现有物流属性,使用创建模式");
|
||
LogPropertyNodeState(propertyNode, "属性添加-创建前");
|
||
|
||
try
|
||
{
|
||
// 使用参数0表示创建新的PropertyCategory
|
||
propertyNode.SetUserDefined(0, LogisticsCategories.LOGISTICS,
|
||
LogisticsCategories.CATEGORY_INTERNAL_NAME, propertyCategory);
|
||
LogManager.WriteLog("[属性添加] ✅ 成功创建新的属性类别");
|
||
|
||
// 立即刷新并验证结果
|
||
propertyNode = RefreshPropertyNode(state, path, "属性添加-创建验证");
|
||
LogPropertyNodeState(propertyNode, "属性添加-创建后");
|
||
}
|
||
catch (Exception setEx)
|
||
{
|
||
LogManager.WriteLog($"[属性添加] ❌ 创建属性失败,错误: {setEx.Message}");
|
||
throw;
|
||
}
|
||
}
|
||
|
||
successCount++;
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
System.Diagnostics.Debug.WriteLine($"处理单个模型项时发生错误: {ex.Message}");
|
||
}
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
System.Diagnostics.Debug.WriteLine($"添加物流属性时发生错误: {ex.Message}");
|
||
}
|
||
|
||
return successCount;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 创建并添加单个属性到属性类别
|
||
/// </summary>
|
||
/// <param name="state">COM API状态对象</param>
|
||
/// <param name="propertyCategory">属性类别对象</param>
|
||
/// <param name="displayName">显示名称</param>
|
||
/// <param name="value">属性值</param>
|
||
/// <param name="internalName">内部名称</param>
|
||
private static void AddProperty(ComApi.InwOpState10 state,
|
||
ComApi.InwOaPropertyVec propertyCategory,
|
||
string displayName,
|
||
string value,
|
||
string internalName)
|
||
{
|
||
// 创建新属性
|
||
ComApi.InwOaProperty property = (ComApi.InwOaProperty)state.ObjectFactory(
|
||
ComApi.nwEObjectType.eObjectType_nwOaProperty, null, null);
|
||
|
||
// 设置属性信息
|
||
property.name = internalName; // 内部名称
|
||
property.UserName = displayName; // 显示名称
|
||
property.value = value; // 属性值
|
||
|
||
// 添加到属性类别
|
||
propertyCategory.Properties().Add(property);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 检查模型项是否已有物流属性
|
||
/// </summary>
|
||
/// <param name="item">要检查的模型项</param>
|
||
/// <returns>如果已有物流属性返回true</returns>
|
||
public static bool HasLogisticsAttributes(ModelItem item)
|
||
{
|
||
try
|
||
{
|
||
// 检查自定义属性
|
||
foreach (PropertyCategory category in item.PropertyCategories)
|
||
{
|
||
if (category.DisplayName == LogisticsCategories.LOGISTICS)
|
||
{
|
||
return true;
|
||
}
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
System.Diagnostics.Debug.WriteLine($"检查物流属性时发生错误: {ex.Message}");
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取模型项的物流属性值
|
||
/// </summary>
|
||
/// <param name="item">模型项</param>
|
||
/// <param name="propertyName">属性名称</param>
|
||
/// <returns>属性值,如果不存在返回空字符串</returns>
|
||
public static string GetLogisticsPropertyValue(ModelItem item, string propertyName)
|
||
{
|
||
try
|
||
{
|
||
foreach (PropertyCategory category in item.PropertyCategories)
|
||
{
|
||
if (category.DisplayName == LogisticsCategories.LOGISTICS)
|
||
{
|
||
foreach (DataProperty property in category.Properties)
|
||
{
|
||
if (property.DisplayName == propertyName)
|
||
{
|
||
return property.Value.ToDisplayString();
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
System.Diagnostics.Debug.WriteLine($"获取物流属性值时发生错误: {ex.Message}");
|
||
}
|
||
|
||
return string.Empty;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 根据物流属性筛选模型项
|
||
/// </summary>
|
||
/// <param name="items">要筛选的模型项集合</param>
|
||
/// <param name="elementType">要筛选的元素类型</param>
|
||
/// <returns>匹配条件的模型项集合</returns>
|
||
public static ModelItemCollection FilterByLogisticsType(ModelItemCollection items, LogisticsElementType elementType)
|
||
{
|
||
ModelItemCollection filteredItems = new ModelItemCollection();
|
||
|
||
foreach (ModelItem item in items)
|
||
{
|
||
string typeValue = GetLogisticsPropertyValue(item, LogisticsProperties.TYPE);
|
||
if (typeValue == elementType.ToString())
|
||
{
|
||
filteredItems.Add(item);
|
||
}
|
||
}
|
||
|
||
return filteredItems;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 筛选可通行的模型项
|
||
/// </summary>
|
||
/// <param name="items">要筛选的模型项集合</param>
|
||
/// <returns>可通行的模型项集合</returns>
|
||
public static ModelItemCollection FilterTraversableItems(ModelItemCollection items)
|
||
{
|
||
ModelItemCollection filteredItems = new ModelItemCollection();
|
||
|
||
foreach (ModelItem item in items)
|
||
{
|
||
string traversableValue = GetLogisticsPropertyValue(item, LogisticsProperties.TRAVERSABLE);
|
||
if (traversableValue == "是")
|
||
{
|
||
filteredItems.Add(item);
|
||
}
|
||
}
|
||
|
||
return filteredItems;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 根据车辆尺寸筛选适用的通道
|
||
/// </summary>
|
||
/// <param name="items">要筛选的模型项集合</param>
|
||
/// <param name="vehicleSize">车辆尺寸</param>
|
||
/// <returns>适用的通道集合</returns>
|
||
public static ModelItemCollection FilterByVehicleSize(ModelItemCollection items, string vehicleSize)
|
||
{
|
||
ModelItemCollection filteredItems = new ModelItemCollection();
|
||
|
||
foreach (ModelItem item in items)
|
||
{
|
||
string sizeValue = GetLogisticsPropertyValue(item, LogisticsProperties.VEHICLE_SIZE);
|
||
if (sizeValue == vehicleSize || sizeValue == "标准" || string.IsNullOrEmpty(sizeValue))
|
||
{
|
||
filteredItems.Add(item);
|
||
}
|
||
}
|
||
|
||
return filteredItems;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 删除选定模型项的物流属性
|
||
/// </summary>
|
||
/// <param name="items">要删除属性的模型项集合</param>
|
||
/// <returns>成功删除属性的项目数量</returns>
|
||
public static int RemoveLogisticsAttributes(ModelItemCollection items)
|
||
{
|
||
if (items == null || items.Count == 0)
|
||
{
|
||
LogManager.WriteLog("[属性删除] 输入参数为空或无模型项");
|
||
return 0;
|
||
}
|
||
|
||
int successCount = 0;
|
||
LogManager.WriteLog($"[属性删除] 开始删除 {items.Count} 个模型的物流属性");
|
||
|
||
try
|
||
{
|
||
// 获取COM API状态对象
|
||
ComApi.InwOpState10 state = ComApiBridge.State;
|
||
LogManager.WriteLog("[属性删除] 已获取COM API状态对象");
|
||
|
||
// 转换选择集合为COM对象
|
||
ComApi.InwOpSelection comSelection = ComApiBridge.ToInwOpSelection(items);
|
||
LogManager.WriteLog($"[属性删除] 已转换为COM选择集合,路径数: {comSelection.Paths().Count}");
|
||
|
||
// 遍历每个路径对象
|
||
foreach (ComApi.InwOaPath3 path in comSelection.Paths())
|
||
{
|
||
try
|
||
{
|
||
LogManager.WriteLog("[属性删除] 开始处理路径对象");
|
||
|
||
// 获取属性节点
|
||
ComApi.InwGUIPropertyNode2 propertyNode =
|
||
(ComApi.InwGUIPropertyNode2)state.GetGUIPropertyNode(path, false);
|
||
LogManager.WriteLog("[属性删除] 已获取属性节点");
|
||
|
||
// 记录操作前的属性状态
|
||
LogPropertyNodeState(propertyNode, "属性删除-操作前");
|
||
|
||
// 查找现有属性类别的索引
|
||
int existingIndex = GetLogisticsAttributeIndex(propertyNode);
|
||
|
||
if (existingIndex < 0)
|
||
{
|
||
LogManager.WriteLog("[属性删除] 该模型没有物流属性类别,跳过");
|
||
continue;
|
||
}
|
||
|
||
// 使用RemoveUserDefined方法完全删除属性类别
|
||
LogManager.WriteLog($"[属性删除] 发现现有物流属性,使用RemoveUserDefined方法删除");
|
||
LogPropertyNodeState(propertyNode, "属性删除-删除前");
|
||
|
||
try
|
||
{
|
||
// 计算用户定义属性的相对索引(从1开始)
|
||
int relativeIndex = GetLogisticsAttributeRelativeIndex(propertyNode);
|
||
if (relativeIndex >= 0)
|
||
{
|
||
// 用户定义属性索引从1开始,所以需要+1
|
||
int userDefinedIndex = relativeIndex + 1;
|
||
LogManager.WriteLog($"[属性删除] 使用用户定义属性索引: {userDefinedIndex}(相对索引: {relativeIndex})");
|
||
|
||
// 使用RemoveUserDefined方法完全删除属性类别
|
||
propertyNode.RemoveUserDefined(userDefinedIndex);
|
||
LogManager.WriteLog($"[属性删除] ✅ 成功使用RemoveUserDefined删除属性类别");
|
||
}
|
||
else
|
||
{
|
||
LogManager.WriteLog($"[属性删除] ❌ 无法找到物流属性的相对索引");
|
||
throw new InvalidOperationException("无法找到物流属性的相对索引");
|
||
}
|
||
|
||
LogPropertyNodeState(propertyNode, "属性删除-删除后");
|
||
}
|
||
catch (Exception setEx)
|
||
{
|
||
LogManager.WriteLog($"[属性删除] ❌ 删除属性失败,错误: {setEx.Message}");
|
||
throw;
|
||
}
|
||
|
||
successCount++;
|
||
LogManager.WriteLog($"[属性删除] 成功删除一个模型的属性,当前成功数: {successCount}");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.WriteLog($"[属性删除] 删除单个模型项属性时发生错误: {ex.Message}");
|
||
LogManager.WriteLog($"[属性删除] 异常详细信息: {ex}");
|
||
System.Diagnostics.Debug.WriteLine($"删除单个模型项属性时发生错误: {ex.Message}");
|
||
}
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.WriteLog($"[属性删除] 删除物流属性时发生错误: {ex.Message}");
|
||
LogManager.WriteLog($"[属性删除] 异常详细信息: {ex}");
|
||
System.Diagnostics.Debug.WriteLine($"删除物流属性时发生错误: {ex.Message}");
|
||
}
|
||
|
||
LogManager.WriteLog($"[属性删除] 删除操作完成,成功删除 {successCount} 个模型的属性");
|
||
return successCount;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 验证索引是否有效
|
||
/// </summary>
|
||
/// <param name="propertyNode">属性节点</param>
|
||
/// <param name="index">要验证的索引</param>
|
||
/// <param name="operation">操作名称</param>
|
||
/// <returns>索引是否有效</returns>
|
||
private static bool ValidateIndex(ComApi.InwGUIPropertyNode2 propertyNode, int index, string operation)
|
||
{
|
||
try
|
||
{
|
||
int totalCount = 0;
|
||
foreach (ComApi.InwGUIAttribute2 attribute in propertyNode.GUIAttributes())
|
||
{
|
||
totalCount++;
|
||
}
|
||
|
||
bool isValid = index >= 0 && index < totalCount;
|
||
LogManager.WriteLog($"[{operation}] 索引验证: index={index}, totalCount={totalCount}, valid={isValid}");
|
||
return isValid;
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.WriteLog($"[{operation}] 索引验证失败: {ex.Message}");
|
||
return false;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 强制刷新属性节点(尝试清理缓存)
|
||
/// </summary>
|
||
/// <param name="state">COM API状态对象</param>
|
||
/// <param name="path">路径对象</param>
|
||
/// <param name="operation">操作名称</param>
|
||
/// <returns>刷新后的属性节点</returns>
|
||
private static ComApi.InwGUIPropertyNode2 RefreshPropertyNode(ComApi.InwOpState10 state, ComApi.InwOaPath3 path, string operation)
|
||
{
|
||
try
|
||
{
|
||
LogManager.WriteLog($"[{operation}] 强制刷新属性节点");
|
||
|
||
// 尝试多种方式获取属性节点以清理缓存
|
||
ComApi.InwGUIPropertyNode2 propertyNode1 = (ComApi.InwGUIPropertyNode2)state.GetGUIPropertyNode(path, false);
|
||
ComApi.InwGUIPropertyNode2 propertyNode2 = (ComApi.InwGUIPropertyNode2)state.GetGUIPropertyNode(path, true);
|
||
ComApi.InwGUIPropertyNode2 propertyNode3 = (ComApi.InwGUIPropertyNode2)state.GetGUIPropertyNode(path, false);
|
||
|
||
LogManager.WriteLog($"[{operation}] 属性节点刷新完成");
|
||
return propertyNode3;
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.WriteLog($"[{operation}] 属性节点刷新失败: {ex.Message}");
|
||
return (ComApi.InwGUIPropertyNode2)state.GetGUIPropertyNode(path, false);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 记录属性节点的完整状态(用于调试)
|
||
/// </summary>
|
||
/// <param name="propertyNode">属性节点</param>
|
||
/// <param name="operation">操作名称</param>
|
||
private static void LogPropertyNodeState(ComApi.InwGUIPropertyNode2 propertyNode, string operation)
|
||
{
|
||
try
|
||
{
|
||
LogManager.WriteLog($"[{operation}] 开始记录属性节点状态");
|
||
|
||
// 强制重新枚举属性
|
||
var attributesList = new List<ComApi.InwGUIAttribute2>();
|
||
foreach (ComApi.InwGUIAttribute2 attribute in propertyNode.GUIAttributes())
|
||
{
|
||
attributesList.Add(attribute);
|
||
}
|
||
|
||
LogManager.WriteLog($"[{operation}] 重新枚举完成,共发现 {attributesList.Count} 个属性");
|
||
|
||
int index = 0;
|
||
int userDefinedCount = 0;
|
||
int totalCount = attributesList.Count;
|
||
|
||
foreach (var attribute in attributesList)
|
||
{
|
||
try
|
||
{
|
||
string userDefined = attribute.UserDefined ? "用户定义" : "系统属性";
|
||
string className = attribute.ClassUserName ?? "无名称";
|
||
|
||
LogManager.WriteLog($"[{operation}] 属性 {index}: {userDefined}, 类别名称='{className}'");
|
||
|
||
if (attribute.UserDefined)
|
||
{
|
||
userDefinedCount++;
|
||
if (className == LogisticsCategories.LOGISTICS)
|
||
{
|
||
LogManager.WriteLog($"[{operation}] ⭐ 这是物流属性类别,索引: {index}");
|
||
|
||
// 尝试读取属性内容以验证
|
||
try
|
||
{
|
||
var properties = attribute.Properties();
|
||
int propCount = 0;
|
||
foreach (ComApi.InwOaProperty prop in properties)
|
||
{
|
||
propCount++;
|
||
}
|
||
LogManager.WriteLog($"[{operation}] 物流属性类别包含 {propCount} 个子属性");
|
||
}
|
||
catch (Exception propEx)
|
||
{
|
||
LogManager.WriteLog($"[{operation}] 读取物流属性子属性失败: {propEx.Message}");
|
||
}
|
||
}
|
||
}
|
||
}
|
||
catch (Exception attrEx)
|
||
{
|
||
LogManager.WriteLog($"[{operation}] 读取属性 {index} 信息失败: {attrEx.Message}");
|
||
}
|
||
index++;
|
||
}
|
||
|
||
LogManager.WriteLog($"[{operation}] 属性节点状态总结: 总属性数={totalCount}, 用户定义属性数={userDefinedCount}");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.WriteLog($"[{operation}] 记录属性节点状态时发生错误: {ex.Message}");
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 查找现有物流属性类别的绝对索引(用于日志记录)
|
||
/// </summary>
|
||
/// <param name="propertyNode">属性节点</param>
|
||
/// <returns>找到的绝对索引,如果不存在返回-1</returns>
|
||
private static int GetLogisticsAttributeAbsoluteIndex(ComApi.InwGUIPropertyNode2 propertyNode)
|
||
{
|
||
try
|
||
{
|
||
int index = 0;
|
||
int userDefinedCount = 0;
|
||
|
||
foreach (ComApi.InwGUIAttribute2 attribute in propertyNode.GUIAttributes())
|
||
{
|
||
string className = attribute.ClassUserName ?? "无名称";
|
||
|
||
if (attribute.UserDefined)
|
||
{
|
||
userDefinedCount++;
|
||
if (className == LogisticsCategories.LOGISTICS)
|
||
{
|
||
return index;
|
||
}
|
||
}
|
||
index++;
|
||
}
|
||
|
||
return -1;
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.WriteLog($"[绝对索引查找] 查找属性绝对索引时发生错误: {ex.Message}");
|
||
return -1;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 查找现有物流属性类别的相对索引(在用户定义属性中的位置)
|
||
/// </summary>
|
||
/// <param name="propertyNode">属性节点</param>
|
||
/// <returns>找到的相对索引,如果不存在返回-1</returns>
|
||
private static int GetLogisticsAttributeRelativeIndex(ComApi.InwGUIPropertyNode2 propertyNode)
|
||
{
|
||
try
|
||
{
|
||
int userDefinedIndex = 0;
|
||
|
||
foreach (ComApi.InwGUIAttribute2 attribute in propertyNode.GUIAttributes())
|
||
{
|
||
string className = attribute.ClassUserName ?? "无名称";
|
||
|
||
if (attribute.UserDefined)
|
||
{
|
||
if (className == LogisticsCategories.LOGISTICS)
|
||
{
|
||
LogManager.WriteLog($"[相对索引查找] ✅ 找到物流属性类别,相对索引: {userDefinedIndex}");
|
||
return userDefinedIndex;
|
||
}
|
||
userDefinedIndex++;
|
||
}
|
||
}
|
||
|
||
LogManager.WriteLog($"[相对索引查找] ❌ 未找到物流属性类别");
|
||
return -1;
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.WriteLog($"[相对索引查找] 查找属性相对索引时发生错误: {ex.Message}");
|
||
return -1;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 查找现有物流属性类别的索引
|
||
/// </summary>
|
||
/// <param name="propertyNode">属性节点</param>
|
||
/// <returns>找到的索引,如果不存在返回-1</returns>
|
||
private static int GetLogisticsAttributeIndex(ComApi.InwGUIPropertyNode2 propertyNode)
|
||
{
|
||
try
|
||
{
|
||
LogManager.WriteLog("[索引查找] 开始查找物流属性类别索引");
|
||
|
||
int index = 0;
|
||
int totalAttributes = 0;
|
||
int userDefinedCount = 0;
|
||
|
||
foreach (ComApi.InwGUIAttribute2 attribute in propertyNode.GUIAttributes())
|
||
{
|
||
totalAttributes++;
|
||
string className = attribute.ClassUserName ?? "无名称";
|
||
|
||
LogManager.WriteLog($"[索引查找] 检查属性 {index}: UserDefined={attribute.UserDefined}, ClassUserName='{className}'");
|
||
|
||
if (attribute.UserDefined)
|
||
{
|
||
userDefinedCount++;
|
||
if (className == LogisticsCategories.LOGISTICS)
|
||
{
|
||
LogManager.WriteLog($"[索引查找] ✅ 找到物流属性类别,绝对索引: {index}, 在第{userDefinedCount}个用户定义属性中");
|
||
|
||
// 获取相对索引
|
||
int relativeIndex = GetLogisticsAttributeRelativeIndex(propertyNode);
|
||
LogManager.WriteLog($"[索引查找] 物流属性相对索引: {relativeIndex}");
|
||
|
||
return index; // 仍然返回绝对索引用于兼容性
|
||
}
|
||
}
|
||
index++;
|
||
}
|
||
|
||
LogManager.WriteLog($"[索引查找] ❌ 未找到物流属性类别,总共检查了 {totalAttributes} 个属性(其中 {userDefinedCount} 个用户定义属性)");
|
||
return -1;
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.WriteLog($"[索引查找] 查找属性索引时发生错误: {ex.Message}");
|
||
return -1;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 更新选定模型项的物流属性
|
||
/// </summary>
|
||
/// <param name="items">要更新属性的模型项集合</param>
|
||
/// <param name="elementType">新的物流元素类型</param>
|
||
/// <param name="isTraversable">是否可通行</param>
|
||
/// <param name="priority">优先级(1-10)</param>
|
||
/// <param name="vehicleSize">适用车辆尺寸</param>
|
||
/// <param name="speedLimit">速度限制(km/h)</param>
|
||
/// <returns>成功更新的项目数量</returns>
|
||
public static int UpdateLogisticsAttributes(
|
||
ModelItemCollection items,
|
||
LogisticsElementType elementType,
|
||
bool isTraversable = true,
|
||
int priority = 5,
|
||
string vehicleSize = "标准",
|
||
double speedLimit = 10.0)
|
||
{
|
||
if (items == null || items.Count == 0)
|
||
{
|
||
return 0;
|
||
}
|
||
|
||
int successCount = 0;
|
||
|
||
try
|
||
{
|
||
// 获取COM API状态对象
|
||
ComApi.InwOpState10 state = ComApiBridge.State;
|
||
|
||
// 转换选择集合为COM对象
|
||
ComApi.InwOpSelection comSelection = ComApiBridge.ToInwOpSelection(items);
|
||
|
||
// 遍历每个路径对象
|
||
foreach (ComApi.InwOaPath3 path in comSelection.Paths())
|
||
{
|
||
try
|
||
{
|
||
// 获取属性节点
|
||
ComApi.InwGUIPropertyNode2 propertyNode =
|
||
(ComApi.InwGUIPropertyNode2)state.GetGUIPropertyNode(path, false);
|
||
|
||
// 查找现有属性类别的索引
|
||
int existingIndex = GetLogisticsAttributeIndex(propertyNode);
|
||
|
||
// 创建新的属性类别
|
||
ComApi.InwOaPropertyVec propertyCategory =
|
||
(ComApi.InwOaPropertyVec)state.ObjectFactory(
|
||
ComApi.nwEObjectType.eObjectType_nwOaPropertyVec, null, null);
|
||
|
||
// 创建并添加各个属性
|
||
AddProperty(state, propertyCategory, LogisticsProperties.TYPE,
|
||
elementType.ToString(), elementType.ToString() + "_Internal");
|
||
AddProperty(state, propertyCategory, LogisticsProperties.TRAVERSABLE,
|
||
isTraversable ? "是" : "否", "Traversable_Internal");
|
||
AddProperty(state, propertyCategory, LogisticsProperties.PRIORITY,
|
||
priority.ToString(), "Priority_Internal");
|
||
AddProperty(state, propertyCategory, LogisticsProperties.VEHICLE_SIZE,
|
||
vehicleSize, "VehicleSize_Internal");
|
||
AddProperty(state, propertyCategory, LogisticsProperties.SPEED_LIMIT,
|
||
speedLimit.ToString("F1") + " km/h", "SpeedLimit_Internal");
|
||
|
||
// 记录操作前的属性状态
|
||
LogPropertyNodeState(propertyNode, "属性更新-操作前");
|
||
|
||
if (existingIndex >= 0)
|
||
{
|
||
// 如果存在现有属性,使用覆盖模式 (参数1)
|
||
LogManager.WriteLog($"[属性更新] 发现现有物流属性,使用覆盖模式更新");
|
||
LogPropertyNodeState(propertyNode, "属性更新-覆盖前");
|
||
|
||
try
|
||
{
|
||
// 使用参数1表示覆盖现有PropertyCategory
|
||
propertyNode.SetUserDefined(1, LogisticsCategories.LOGISTICS,
|
||
LogisticsCategories.CATEGORY_INTERNAL_NAME, propertyCategory);
|
||
LogManager.WriteLog($"[属性更新] ✅ 成功覆盖现有属性类别");
|
||
|
||
// 立即刷新并验证结果
|
||
propertyNode = RefreshPropertyNode(state, path, "属性更新-覆盖验证");
|
||
LogPropertyNodeState(propertyNode, "属性更新-覆盖后");
|
||
}
|
||
catch (Exception setEx)
|
||
{
|
||
LogManager.WriteLog($"[属性更新] ❌ 覆盖属性失败,错误: {setEx.Message}");
|
||
throw;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// 如果不存在,创建新的属性类别,使用创建模式 (参数0)
|
||
LogManager.WriteLog("[属性更新] 未发现现有物流属性,使用创建模式");
|
||
LogPropertyNodeState(propertyNode, "属性更新-创建前");
|
||
|
||
try
|
||
{
|
||
// 使用参数0表示创建新的PropertyCategory
|
||
propertyNode.SetUserDefined(0, LogisticsCategories.LOGISTICS,
|
||
LogisticsCategories.CATEGORY_INTERNAL_NAME, propertyCategory);
|
||
LogManager.WriteLog("[属性更新] ✅ 成功创建新的属性类别");
|
||
|
||
// 立即刷新并验证结果
|
||
propertyNode = RefreshPropertyNode(state, path, "属性更新-创建验证");
|
||
LogPropertyNodeState(propertyNode, "属性更新-创建后");
|
||
}
|
||
catch (Exception setEx)
|
||
{
|
||
LogManager.WriteLog($"[属性更新] ❌ 创建属性失败,错误: {setEx.Message}");
|
||
throw;
|
||
}
|
||
}
|
||
|
||
successCount++;
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.WriteLog($"[属性更新] 更新单个模型项时发生错误: {ex.Message}");
|
||
}
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.WriteLog($"[属性更新] 更新物流属性时发生错误: {ex.Message}");
|
||
}
|
||
|
||
LogManager.WriteLog($"[属性更新] 更新操作完成,成功更新 {successCount} 个模型的属性");
|
||
return successCount;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 通过COM API获取物流属性值(解决缓存同步问题)
|
||
/// </summary>
|
||
/// <param name="item">模型项</param>
|
||
/// <param name="propertyName">属性名称</param>
|
||
/// <returns>属性值,如果不存在返回空字符串</returns>
|
||
public static string GetLogisticsPropertyValueViaCom(ModelItem item, string propertyName)
|
||
{
|
||
try
|
||
{
|
||
// 获取COM API状态对象
|
||
ComApi.InwOpState10 state = ComApiBridge.State;
|
||
|
||
// 转换ModelItem为COM路径
|
||
ComApi.InwOaPath comPath = ComApiBridge.ToInwOaPath(item);
|
||
|
||
// 获取属性节点
|
||
ComApi.InwGUIPropertyNode2 propertyNode =
|
||
(ComApi.InwGUIPropertyNode2)state.GetGUIPropertyNode(comPath, false);
|
||
|
||
// 遍历所有属性类别
|
||
foreach (ComApi.InwGUIAttribute2 attribute in propertyNode.GUIAttributes())
|
||
{
|
||
if (attribute.UserDefined && attribute.ClassUserName == LogisticsCategories.LOGISTICS)
|
||
{
|
||
// 获取属性集合
|
||
ComApi.InwOaPropertyColl propertyColl = attribute.Properties();
|
||
|
||
// 遍历属性
|
||
foreach (ComApi.InwOaProperty property in propertyColl)
|
||
{
|
||
if (property.UserName == propertyName)
|
||
{
|
||
string value = property.value.ToString();
|
||
LogManager.WriteLog($"[COM API读取] 模型: {item.DisplayName}, 属性: {propertyName}, 值: {value}");
|
||
return value;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
LogManager.WriteLog($"[COM API读取] 模型: {item.DisplayName}, 属性: {propertyName} - 未找到");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogManager.WriteLog($"通过COM API获取物流属性值时发生错误: {ex.Message}");
|
||
System.Diagnostics.Debug.WriteLine($"通过COM API获取物流属性值时发生错误: {ex.Message}");
|
||
}
|
||
|
||
return string.Empty;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取模型项的完整物流属性信息
|
||
/// </summary>
|
||
/// <param name="item">模型项</param>
|
||
/// <returns>物流属性信息,如果不存在返回null</returns>
|
||
public static LogisticsAttributeInfo GetLogisticsAttributeInfo(ModelItem item)
|
||
{
|
||
if (!HasLogisticsAttributes(item))
|
||
{
|
||
return null;
|
||
}
|
||
|
||
try
|
||
{
|
||
var info = new LogisticsAttributeInfo();
|
||
|
||
// 使用COM API获取各个属性值以确保数据一致性
|
||
info.ElementType = GetLogisticsPropertyValueViaCom(item, LogisticsProperties.TYPE);
|
||
info.IsTraversable = GetLogisticsPropertyValueViaCom(item, LogisticsProperties.TRAVERSABLE) == "是";
|
||
|
||
string priorityStr = GetLogisticsPropertyValueViaCom(item, LogisticsProperties.PRIORITY);
|
||
if (int.TryParse(priorityStr, out int priority))
|
||
{
|
||
info.Priority = priority;
|
||
}
|
||
|
||
info.VehicleSize = GetLogisticsPropertyValueViaCom(item, LogisticsProperties.VEHICLE_SIZE);
|
||
|
||
string speedStr = GetLogisticsPropertyValueViaCom(item, LogisticsProperties.SPEED_LIMIT);
|
||
if (speedStr.Contains("km/h"))
|
||
{
|
||
speedStr = speedStr.Replace("km/h", "").Trim();
|
||
if (double.TryParse(speedStr, out double speed))
|
||
{
|
||
info.SpeedLimit = speed;
|
||
}
|
||
}
|
||
|
||
return info;
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
System.Diagnostics.Debug.WriteLine($"获取物流属性信息时发生错误: {ex.Message}");
|
||
return null;
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 物流属性信息类
|
||
/// </summary>
|
||
public class LogisticsAttributeInfo
|
||
{
|
||
/// <summary>
|
||
/// 元素类型
|
||
/// </summary>
|
||
public string ElementType { get; set; } = "";
|
||
|
||
/// <summary>
|
||
/// 是否可通行
|
||
/// </summary>
|
||
public bool IsTraversable { get; set; } = true;
|
||
|
||
/// <summary>
|
||
/// 优先级
|
||
/// </summary>
|
||
public int Priority { get; set; } = 5;
|
||
|
||
/// <summary>
|
||
/// 适用车辆尺寸
|
||
/// </summary>
|
||
public string VehicleSize { get; set; } = "标准";
|
||
|
||
/// <summary>
|
||
/// 速度限制
|
||
/// </summary>
|
||
public double SpeedLimit { get; set; } = 10.0;
|
||
|
||
/// <summary>
|
||
/// 尝试解析元素类型为枚举
|
||
/// </summary>
|
||
/// <returns>解析成功的枚举值,失败返回通道</returns>
|
||
public CategoryAttributeManager.LogisticsElementType GetElementTypeEnum()
|
||
{
|
||
if (Enum.TryParse<CategoryAttributeManager.LogisticsElementType>(ElementType, out var result))
|
||
{
|
||
return result;
|
||
}
|
||
return CategoryAttributeManager.LogisticsElementType.通道;
|
||
}
|
||
}
|
||
} |