TellmePdmsPluging/Core/PdmsManager.cs

1489 lines
53 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 TellmePdmsPluging.Models;
using Aveva.ApplicationFramework;
using Aveva.Pdms.Database;
using Aveva.ApplicationFramework.Presentation;
using System.Linq;
namespace TellmePdmsPluging.Core
{
public class PdmsManager
{
private static PdmsManager _instance;
private static readonly object _lock = new object();
public static PdmsManager Instance
{
get
{
if (_instance == null)
{
lock (_lock)
{
if (_instance == null)
_instance = new PdmsManager();
}
}
return _instance;
}
}
private PdmsManager()
{
}
public SimplifyModelResult SimplifyModel(SimplifyModelRequest request)
{
var effectiveRequest = request ?? new SimplifyModelRequest();
effectiveRequest.ApplyDefaults();
var result = new SimplifyModelResult
{
DryRun = effectiveRequest.DryRun,
StartedAt = DateTime.Now
};
try
{
if (!IsPdmsConnected())
{
result.Success = false;
result.CompletedAt = DateTime.Now;
result.Message = "PDMS 未连接";
result.Errors.Add("PDMS 未连接");
return result;
}
var currentMdb = MDB.CurrentMDB;
var designDb = currentMdb?.GetFirstDB(DbType.Design);
if (designDb == null || designDb.World == null)
{
result.Success = false;
result.CompletedAt = DateTime.Now;
result.Message = "未找到有效的设计数据库";
result.Errors.Add("未找到有效的设计数据库");
return result;
}
var context = new SimplifyContext(effectiveRequest, result);
var sites = designDb.World.Members();
bool processed = false;
if (sites != null)
{
foreach (var site in sites)
{
if (!IsElementValid(site) || !string.Equals(GetElementTypeName(site), "SITE", StringComparison.OrdinalIgnoreCase))
{
continue;
}
var zones = site.Members();
if (zones == null)
{
continue;
}
foreach (var zone in zones)
{
if (!IsElementValid(zone) || !string.Equals(GetElementTypeName(zone), "ZONE", StringComparison.OrdinalIgnoreCase))
{
continue;
}
if (!context.ShouldProcessZone(zone))
{
continue;
}
processed = true;
context.EnterZone(zone);
context.ProcessChildren(zone);
}
}
}
result.Success = processed && result.Errors.Count == 0;
result.Message = processed
? (result.DryRun ? "模型轻量化干跑完成" : "模型轻量化完成")
: "未找到符合过滤条件的Zone";
result.CompletedAt = DateTime.Now;
return result;
}
catch (Exception ex)
{
result.Success = false;
result.Errors.Add(ex.Message);
result.Message = "模型轻量化失败";
result.CompletedAt = DateTime.Now;
return result;
}
}
public ShrinkwrapModelResult ShrinkwrapModel(ShrinkwrapModelRequest request)
{
var effectiveRequest = request ?? new ShrinkwrapModelRequest();
effectiveRequest.ApplyDefaults();
var result = new ShrinkwrapModelResult
{
DryRun = effectiveRequest.DryRun,
Padding = effectiveRequest.Padding,
StartedAt = DateTime.Now
};
try
{
if (!IsPdmsConnected())
{
result.Success = false;
result.CompletedAt = DateTime.Now;
result.Message = "PDMS 未连接";
result.Errors.Add("PDMS 未连接");
return result;
}
var currentMdb = MDB.CurrentMDB;
var designDb = currentMdb?.GetFirstDB(DbType.Design);
if (designDb == null || designDb.World == null)
{
result.Success = false;
result.CompletedAt = DateTime.Now;
result.Message = "未找到有效的设计数据库";
result.Errors.Add("未找到有效的设计数据库");
return result;
}
var context = new ShrinkwrapContext(effectiveRequest, result);
var sites = designDb.World.Members();
bool processed = false;
if (sites != null)
{
foreach (var site in sites)
{
if (!IsElementValid(site) || !string.Equals(GetElementTypeName(site), "SITE", StringComparison.OrdinalIgnoreCase))
{
continue;
}
var zones = site.Members();
if (zones == null)
{
continue;
}
foreach (var zone in zones)
{
if (!IsElementValid(zone) || !string.Equals(GetElementTypeName(zone), "ZONE", StringComparison.OrdinalIgnoreCase))
{
continue;
}
if (!context.ShouldProcessZone(zone))
{
continue;
}
processed = true;
context.EnterZone(zone);
context.ProcessZone(zone);
}
}
}
result.Success = processed && result.Errors.Count == 0;
result.Message = processed
? (result.DryRun ? "外壳保留干跑完成" : "外壳保留完成")
: "未找到符合过滤条件的Zone";
result.CompletedAt = DateTime.Now;
return result;
}
catch (Exception ex)
{
result.Success = false;
result.Errors.Add(ex.Message);
result.Message = "外壳保留失败";
result.CompletedAt = DateTime.Now;
return result;
}
}
public ModelStatusResponse GetModelStatus()
{
try
{
// 检查PDMS是否连接
if (!IsPdmsConnected())
{
return new ModelStatusResponse
{
ModelLoaded = false
};
}
return new ModelStatusResponse
{
ModelLoaded = true,
ProjectInfo = GetProjectInfo(),
ModelStatistics = GetModelStatistics(),
SessionInfo = GetSessionInfo()
};
}
catch (Exception ex)
{
// 记录错误日志
System.Diagnostics.Debug.WriteLine($"获取PDMS模型状态失败: {ex.Message}");
return new ModelStatusResponse
{
ModelLoaded = false
};
}
}
public OpenProjectResult OpenProject(OpenProjectRequest request)
{
var effectiveRequest = request ?? new OpenProjectRequest();
effectiveRequest.ApplyDefaults();
var result = new OpenProjectResult
{
ProjectName = effectiveRequest.ProjectName,
FileSize = -1,
PolygonCount = -1,
FeatureCount = -1,
CompletedAt = DateTime.Now
};
try
{
var currentProject = Project.CurrentProject;
if (currentProject == null)
{
result.Success = false;
result.Message = "Project.CurrentProject 为空,无法打开项目";
return result;
}
bool alreadyOpen = false;
try
{
alreadyOpen = currentProject.IsOpen();
}
catch
{
alreadyOpen = false;
}
result.WasAlreadyOpen = alreadyOpen;
// 如果已经打开且未指定目标项目名,则直接返回成功
if (alreadyOpen && string.IsNullOrEmpty(effectiveRequest.ProjectName))
{
result.Success = true;
result.Message = "项目已打开";
PopulateOpenProjectMetrics(result);
return result;
}
if (string.IsNullOrEmpty(effectiveRequest.ProjectName))
{
result.Success = false;
result.Message = "ProjectName 不能为空";
return result;
}
bool opened = currentProject.Open(
effectiveRequest.ProjectName,
effectiveRequest.UserName ?? string.Empty,
effectiveRequest.Password ?? string.Empty);
result.Success = opened;
result.Message = opened ? "项目打开成功" : "项目打开失败Open 返回 false";
if (opened)
{
PopulateOpenProjectMetrics(result);
}
result.CompletedAt = DateTime.Now;
return result;
}
catch (Exception ex)
{
result.Success = false;
result.Message = "项目打开异常: " + ex.Message;
result.CompletedAt = DateTime.Now;
return result;
}
}
public CloseProjectResult CloseProject(CloseProjectRequest request)
{
var effectiveRequest = request ?? new CloseProjectRequest();
effectiveRequest.ApplyDefaults();
var result = new CloseProjectResult
{
CompletedAt = DateTime.Now
};
try
{
var currentProject = Project.CurrentProject;
if (currentProject == null)
{
result.Success = false;
result.Message = "Project.CurrentProject 为空,无法关闭项目";
return result;
}
bool isOpen = false;
try
{
isOpen = currentProject.IsOpen();
}
catch
{
isOpen = false;
}
result.WasOpen = isOpen;
result.ProjectName = GetProjectNameSafe(currentProject);
if (!isOpen)
{
result.Success = true;
result.Message = "当前没有已打开项目";
result.CompletedAt = DateTime.Now;
return result;
}
var projectType = currentProject.GetType();
var closeWithForce = projectType.GetMethod("Close", new[] { typeof(bool) });
if (closeWithForce != null)
{
closeWithForce.Invoke(currentProject, new object[] { effectiveRequest.Force });
}
else
{
var closeNoArg = projectType.GetMethod("Close", Type.EmptyTypes);
if (closeNoArg == null)
{
result.Success = false;
result.Message = "未找到可用的 Project.Close 方法";
result.CompletedAt = DateTime.Now;
return result;
}
closeNoArg.Invoke(currentProject, null);
}
result.Success = true;
result.Message = "项目关闭成功";
result.CompletedAt = DateTime.Now;
return result;
}
catch (Exception ex)
{
result.Success = false;
result.Message = "关闭项目异常: " + ex.Message;
result.CompletedAt = DateTime.Now;
return result;
}
}
public ExportIfcResult ExportIfc(ExportIfcRequest request)
{
var effectiveRequest = request ?? new ExportIfcRequest();
effectiveRequest.ApplyDefaults();
var result = new ExportIfcResult
{
StartedAt = DateTime.Now,
ExportPath = effectiveRequest.ExportPath,
FileName = effectiveRequest.FileName,
FullPath = effectiveRequest.GetFullPath()
};
try
{
if (!IsPdmsConnected())
{
result.Success = false;
result.Message = "PDMS 未连接";
result.CompletedAt = DateTime.Now;
result.DurationSeconds = (result.CompletedAt - result.StartedAt).TotalSeconds;
return result;
}
var currentMdb = MDB.CurrentMDB;
var designDb = currentMdb?.GetFirstDB(DbType.Design);
if (designDb == null || designDb.World == null)
{
result.Success = false;
result.Message = "未找到有效的设计数据库";
result.CompletedAt = DateTime.Now;
result.DurationSeconds = (result.CompletedAt - result.StartedAt).TotalSeconds;
return result;
}
// 确保导出目录存在
if (!System.IO.Directory.Exists(effectiveRequest.ExportPath))
{
System.IO.Directory.CreateDirectory(effectiveRequest.ExportPath);
}
// 构建PML导出命令
string pmlCommand = BuildIfcExportCommand(effectiveRequest);
// 执行PML命令 - 通过MacroCommand类型反射构造并执行
var macroType = CommandManager.Instance.MacroCommand;
if (macroType == null)
throw new InvalidOperationException("MacroCommand类型未注册");
var ctors = macroType.GetConstructors(
System.Reflection.BindingFlags.Public |
System.Reflection.BindingFlags.NonPublic |
System.Reflection.BindingFlags.Instance);
var ctorInfo = new System.Text.StringBuilder();
foreach (var c in ctors)
{
ctorInfo.Append(c.ToString()).Append(" | ");
}
throw new InvalidOperationException("MacroCommand类型: " + macroType.FullName + " 构造函数: " + ctorInfo);
// 检查文件是否生成
if (System.IO.File.Exists(result.FullPath))
{
var fileInfo = new System.IO.FileInfo(result.FullPath);
result.FileSizeBytes = fileInfo.Length;
result.Success = true;
result.Message = "IFC导出成功";
}
else
{
result.Success = false;
result.Message = "IFC导出失败未生成文件";
}
result.CompletedAt = DateTime.Now;
result.DurationSeconds = (result.CompletedAt - result.StartedAt).TotalSeconds;
return result;
}
catch (Exception ex)
{
result.Success = false;
result.Message = "IFC导出异常: " + ex.Message;
result.CompletedAt = DateTime.Now;
result.DurationSeconds = (result.CompletedAt - result.StartedAt).TotalSeconds;
return result;
}
}
private string BuildIfcExportCommand(ExportIfcRequest request)
{
// 构建PDMS IFC导出的PML命令
// 根据PDMS版本和配置命令可能有所不同
string fullPath = request.GetFullPath().Replace("\\", "/");
// 基本的IFC导出命令格式
return string.Format("EXPORT IFC FILE '{0}'", fullPath);
}
public OpenMdbResult OpenMdb(OpenMdbRequest request)
{
var effectiveRequest = request ?? new OpenMdbRequest();
effectiveRequest.ApplyDefaults();
var result = new OpenMdbResult
{
MdbName = effectiveRequest.MdbName,
ReadOnly = effectiveRequest.ReadOnly,
DefaultType = effectiveRequest.DefaultType,
FileSize = -1,
PolygonCount = -1,
FeatureCount = -1,
CompletedAt = DateTime.Now
};
try
{
if (string.IsNullOrEmpty(effectiveRequest.MdbName))
{
result.Success = false;
result.Message = "MdbName 不能为空";
return result;
}
// 如果当前MDB已经是目标则直接返回成功
try
{
var current = MDB.CurrentMDB;
if (current != null && string.Equals(current.Name, effectiveRequest.MdbName, StringComparison.OrdinalIgnoreCase))
{
result.Success = true;
result.WasAlreadyOpen = true;
result.Message = "MDB 已经打开";
PopulateOpenMdbMetrics(result);
result.CompletedAt = DateTime.Now;
return result;
}
}
catch
{
// ignore, continue to open
}
var setup = MDBSetup.CreateMDBSetup(effectiveRequest.MdbName);
if (setup == null)
{
result.Success = false;
result.Message = "创建 MDBSetup 失败";
return result;
}
setup.ReadOnly = effectiveRequest.ReadOnly;
if (effectiveRequest.Subtype.HasValue)
{
setup.Subtype = effectiveRequest.Subtype.Value;
}
if (!string.IsNullOrEmpty(effectiveRequest.DefaultType))
{
DbType defaultType;
if (!TryParseDbType(effectiveRequest.DefaultType, out defaultType))
{
result.Success = false;
result.Message = "DefaultType 无效: " + effectiveRequest.DefaultType;
return result;
}
setup.DefaultType = defaultType;
}
if (effectiveRequest.ReadTypes != null && effectiveRequest.ReadTypes.Count > 0)
{
DbType[] readTypes;
string error;
if (!TryParseDbTypes(effectiveRequest.ReadTypes, out readTypes, out error))
{
result.Success = false;
result.Message = "ReadTypes 无效: " + error;
return result;
}
setup.ReadTypes = readTypes;
}
if (effectiveRequest.WriteTypes != null && effectiveRequest.WriteTypes.Count > 0)
{
DbType[] writeTypes;
string error;
if (!TryParseDbTypes(effectiveRequest.WriteTypes, out writeTypes, out error))
{
result.Success = false;
result.Message = "WriteTypes 无效: " + error;
return result;
}
setup.WriteTypes = writeTypes;
}
var openedMdb = Project.OpenMDB(setup);
if (openedMdb == null)
{
result.Success = false;
result.Message = "打开 MDB 失败OpenMDB 返回 null";
result.CompletedAt = DateTime.Now;
return result;
}
result.Success = true;
result.WasAlreadyOpen = false;
result.MdbName = openedMdb.Name;
result.Message = "MDB 打开成功";
PopulateOpenMdbMetrics(result);
result.CompletedAt = DateTime.Now;
return result;
}
catch (Exception ex)
{
result.Success = false;
result.Message = "打开 MDB 异常: " + ex.Message;
result.CompletedAt = DateTime.Now;
return result;
}
}
private static bool TryParseDbTypes(IEnumerable<string> values, out DbType[] types, out string error)
{
var list = new List<DbType>();
var invalid = new List<string>();
foreach (var raw in values)
{
if (string.IsNullOrEmpty(raw))
{
continue;
}
DbType parsed;
if (TryParseDbType(raw, out parsed))
{
if (!list.Contains(parsed))
{
list.Add(parsed);
}
}
else
{
invalid.Add(raw);
}
}
if (invalid.Count > 0)
{
types = null;
error = string.Join(",", invalid.ToArray());
return false;
}
types = list.ToArray();
error = null;
return true;
}
private static bool TryParseDbType(string value, out DbType dbType)
{
dbType = DbType.Design;
if (string.IsNullOrEmpty(value))
{
return false;
}
try
{
dbType = (DbType)Enum.Parse(typeof(DbType), value.Trim(), true);
return true;
}
catch
{
return false;
}
}
private static string GetProjectNameSafe(Project project)
{
if (project == null)
{
return null;
}
try
{
var nameProperty = project.GetType().GetProperty("Name");
if (nameProperty != null)
{
var value = nameProperty.GetValue(project, null) as string;
if (!string.IsNullOrEmpty(value))
{
return value;
}
}
}
catch
{
// ignore and fallback
}
return null;
}
private bool IsPdmsConnected()
{
try
{
// 使用MDB.CurrentMDB检查PDMS连接状态
var currentMdb = MDB.CurrentMDB;
return currentMdb != null;
}
catch
{
return false;
}
}
private ProjectInfo GetProjectInfo()
{
try
{
// 使用MDB.CurrentMDB和Project.CurrentProject获取真实项目信息
var currentMdb = MDB.CurrentMDB;
var currentProject = Project.CurrentProject;
if (currentMdb != null)
{
var designDb = currentMdb.GetFirstDB(DbType.Design);
if (designDb != null)
{
return new ProjectInfo
{
ProjectName = designDb.Name ?? "Unknown",
MdsName = currentMdb.Name ?? "Unknown",
PdmsVersion = "12.1.SP4"
};
}
}
return new ProjectInfo
{
ProjectName = "Unknown",
MdsName = "Unknown",
PdmsVersion = "12.1.SP4"
};
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"获取项目信息失败: {ex.Message}");
return new ProjectInfo
{
ProjectName = "Unknown",
MdsName = "Unknown",
PdmsVersion = "12.1.SP4"
};
}
}
private ModelStatistics GetModelStatistics()
{
try
{
// 使用MDB.CurrentMDB获取真实模型统计信息
var currentMdb = MDB.CurrentMDB;
if (currentMdb != null)
{
var designDb = currentMdb.GetFirstDB(DbType.Design);
if (designDb?.World != null)
{
// 初始化统计计数器
var elementCounts = new Dictionary<string, int>
{
{"SITE", 0}, {"ZONE", 0}, {"PIPE", 0}, {"EQUI", 0},
{"STRU", 0}, {"VALVE", 0}, {"FITT", 0}, {"NOZZ", 0}
};
int totalElements = 0;
var activeZones = new List<string>();
int zoneCount = 0;
// 递归统计所有元素
CountElementsByType(designDb.World, elementCounts, ref totalElements);
// 专门统计Zone信息
CountZones(designDb.World, ref zoneCount, activeZones);
return new ModelStatistics
{
TotalElements = totalElements,
ElementCounts = elementCounts,
ZoneCount = zoneCount,
ActiveZones = activeZones,
FileSize = TryGetCurrentModelFileSize(),
PolygonCount = -1,
FeatureCount = totalElements
};
}
}
return new ModelStatistics
{
TotalElements = 0,
ElementCounts = new Dictionary<string, int>(),
ZoneCount = 0,
ActiveZones = new List<string>(),
FileSize = -1,
PolygonCount = -1,
FeatureCount = 0
};
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"获取模型统计信息失败: {ex.Message}");
return new ModelStatistics
{
TotalElements = 0,
ElementCounts = new Dictionary<string, int>(),
ZoneCount = 0,
ActiveZones = new List<string>(),
FileSize = -1,
PolygonCount = -1,
FeatureCount = 0
};
}
}
private void PopulateOpenProjectMetrics(OpenProjectResult result)
{
var statistics = GetModelStatistics();
if (statistics == null)
{
return;
}
result.FileSize = statistics.FileSize;
result.PolygonCount = statistics.PolygonCount;
result.FeatureCount = statistics.FeatureCount;
}
private void PopulateOpenMdbMetrics(OpenMdbResult result)
{
var statistics = GetModelStatistics();
if (statistics == null)
{
return;
}
result.FileSize = statistics.FileSize;
result.PolygonCount = statistics.PolygonCount;
result.FeatureCount = statistics.FeatureCount;
}
private long TryGetCurrentModelFileSize()
{
try
{
var currentMdb = MDB.CurrentMDB;
if (currentMdb == null)
{
return -1;
}
var designDb = currentMdb.GetFirstDB(DbType.Design);
string path = TryGetCandidatePath(designDb) ?? TryGetCandidatePath(currentMdb);
if (string.IsNullOrEmpty(path) || !System.IO.File.Exists(path))
{
return -1;
}
return new System.IO.FileInfo(path).Length;
}
catch
{
return -1;
}
}
private static string TryGetCandidatePath(object source)
{
if (source == null)
{
return null;
}
var type = source.GetType();
var names = new[] { "FileName", "Filename", "FullName", "Path" };
foreach (var name in names)
{
var prop = type.GetProperty(name);
if (prop != null && prop.PropertyType == typeof(string))
{
var value = prop.GetValue(source, null) as string;
if (LooksLikeFilePath(value))
{
return value;
}
}
var field = type.GetField(name);
if (field != null && field.FieldType == typeof(string))
{
var value = field.GetValue(source) as string;
if (LooksLikeFilePath(value))
{
return value;
}
}
}
return null;
}
private static bool LooksLikeFilePath(string value)
{
if (string.IsNullOrEmpty(value))
{
return false;
}
var trimmed = value.Trim();
if (trimmed.Length < 3)
{
return false;
}
return trimmed.IndexOf('\\') >= 0 || trimmed.IndexOf('/') >= 0;
}
private void CountElementsByType(DbElement parentElement, Dictionary<string, int> elementCounts, ref int totalElements)
{
try
{
if (parentElement == null || parentElement.IsNull || !parentElement.IsValid)
return;
// 获取所有子元素
var members = parentElement.Members();
if (members != null)
{
foreach (var element in members)
{
if (element != null && !element.IsNull && element.IsValid)
{
totalElements++;
// 获取元素的实际类型
var elementType = element.GetActualType();
if (elementType != null)
{
string typeName = elementType.Name;
if (elementCounts.ContainsKey(typeName))
{
elementCounts[typeName]++;
}
}
// 递归统计子元素
CountElementsByType(element, elementCounts, ref totalElements);
}
}
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"统计元素类型时出错: {ex.Message}");
}
}
private void CountZones(DbElement worldElement, ref int zoneCount, List<string> activeZones)
{
try
{
if (worldElement == null || worldElement.IsNull || !worldElement.IsValid)
return;
// 查找SITE元素
var sites = worldElement.Members();
if (sites != null)
{
foreach (var site in sites)
{
if (site != null && !site.IsNull && site.IsValid)
{
var siteType = site.GetActualType();
if (siteType != null && siteType.Name == "SITE")
{
// 在SITE下查找ZONE元素
var zones = site.Members();
if (zones != null)
{
foreach (var zone in zones)
{
if (zone != null && !zone.IsNull && zone.IsValid)
{
var zoneType = zone.GetActualType();
if (zoneType != null && zoneType.Name == "ZONE")
{
zoneCount++;
// 获取Zone名称
try
{
string zoneName = "";
if (zone.GetValidString(DbAttributeInstance.NAME, ref zoneName))
{
if (!string.IsNullOrEmpty(zoneName))
{
activeZones.Add(zoneName);
}
}
}
catch
{
// 如果无法获取名称,跳过
}
}
}
}
}
}
}
}
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"统计Zone信息时出错: {ex.Message}");
}
}
private SessionInfo GetSessionInfo()
{
try
{
// 使用MDB.CurrentMDB获取真实会话信息
var currentMdb = MDB.CurrentMDB;
if (currentMdb != null)
{
var designDb = currentMdb.GetFirstDB(DbType.Design);
if (designDb?.CurrentSession != null)
{
// 从真实的数据库会话获取信息
var session = designDb.CurrentSession;
return new SessionInfo
{
UserName = session.User ?? Environment.UserName, // 从DbSession获取用户名
StartTime = session.Date, // 从DbSession获取会话创建时间
DurationMinutes = (int)(DateTime.Now - session.Date).TotalMinutes // 计算会话持续时间
};
}
}
return new SessionInfo
{
UserName = Environment.UserName,
StartTime = DateTime.Now,
DurationMinutes = 0
};
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"获取会话信息失败: {ex.Message}");
return new SessionInfo
{
UserName = Environment.UserName,
StartTime = DateTime.Now,
DurationMinutes = 0
};
}
}
private static bool IsElementValid(DbElement element)
{
return element != null && !element.IsNull && element.IsValid;
}
private static string GetElementTypeName(DbElement element)
{
try
{
var type = element?.GetActualType();
return type?.Name ?? string.Empty;
}
catch
{
return string.Empty;
}
}
private static string BuildElementPath(DbElement element)
{
var segments = new List<string>();
var current = element;
int guard = 0;
while (IsElementValid(current) && guard < 128)
{
string name = string.Empty;
try
{
if (!current.GetValidString(DbAttributeInstance.NAME, ref name) || string.IsNullOrEmpty(name))
{
name = current.ToString();
}
}
catch
{
name = current.ToString();
}
segments.Add(name.Trim());
current = current.Owner;
guard++;
}
segments.Reverse();
return "/" + string.Join("/", segments.ToArray());
}
private class SimplifyContext
{
private const int MaxRemovedSnapshots = 200;
public SimplifyContext(SimplifyModelRequest request, SimplifyModelResult result)
{
Request = request;
Result = result;
_keepTypes = new HashSet<string>(request.KeepTypes ?? new List<string>());
_removeTypes = new HashSet<string>(request.RemoveTypes ?? new List<string>());
}
public SimplifyModelRequest Request { get; }
public SimplifyModelResult Result { get; }
public string CurrentZoneName { get; private set; }
private readonly HashSet<string> _keepTypes;
private readonly HashSet<string> _removeTypes;
public bool ShouldProcessZone(DbElement zone)
{
if (Request.ZoneFilters == null || Request.ZoneFilters.Count == 0)
{
return true;
}
var zonePath = BuildElementPath(zone).ToUpperInvariant();
return Request.ZoneFilters.Any(filter => zonePath.Contains(filter));
}
public void EnterZone(DbElement zone)
{
CurrentZoneName = BuildElementPath(zone);
if (!Result.ZoneSummaries.Contains(CurrentZoneName))
{
Result.ZoneSummaries.Add(CurrentZoneName);
}
}
public void ProcessChildren(DbElement parent)
{
var members = parent.Members();
if (members == null)
{
return;
}
foreach (var child in members)
{
ProcessElement(child);
}
}
private void ProcessElement(DbElement element)
{
if (!IsElementValid(element))
{
return;
}
Result.TotalVisited++;
var typeName = GetElementTypeName(element);
var normalizedType = string.IsNullOrEmpty(typeName) ? string.Empty : typeName.ToUpperInvariant();
bool keep = _keepTypes.Contains(normalizedType);
bool remove = _removeTypes.Contains(normalizedType) && !keep;
if (remove)
{
RemoveElement(element, normalizedType);
return;
}
Result.KeptCount++;
ProcessChildren(element);
}
private void RemoveElement(DbElement element, string typeName)
{
var elementPath = BuildElementPath(element);
if (Request.DryRun)
{
SnapshotRemoval(elementPath, typeName, true);
return;
}
try
{
element.Delete();
SnapshotRemoval(elementPath, typeName, false);
}
catch (Exception ex)
{
Result.Errors.Add($"删除元素 {elementPath} 失败: {ex.Message}");
}
}
private void SnapshotRemoval(string elementPath, string typeName, bool dryRun)
{
Result.RemovedCount++;
if (Result.RemovedElements.Count < MaxRemovedSnapshots)
{
var marker = dryRun ? "DRY" : "DEL";
Result.RemovedElements.Add($"[{marker}] {elementPath} ({typeName})");
}
}
}
private class ShrinkwrapContext
{
private const int MaxRemovedSnapshots = 200;
public ShrinkwrapContext(ShrinkwrapModelRequest request, ShrinkwrapModelResult result)
{
Request = request;
Result = result;
_keepTypes = new HashSet<string>(request.KeepTypes ?? new List<string>());
}
public ShrinkwrapModelRequest Request { get; }
public ShrinkwrapModelResult Result { get; }
public string CurrentZoneName { get; private set; }
private readonly HashSet<string> _keepTypes;
private float[] _innerBox;
public bool ShouldProcessZone(DbElement zone)
{
if (Request.ZoneFilters == null || Request.ZoneFilters.Count == 0)
{
return true;
}
var zonePath = BuildElementPath(zone).ToUpperInvariant();
return Request.ZoneFilters.Any(filter => zonePath.Contains(filter));
}
public void EnterZone(DbElement zone)
{
CurrentZoneName = BuildElementPath(zone);
if (!Result.ZoneSummaries.Contains(CurrentZoneName))
{
Result.ZoneSummaries.Add(CurrentZoneName);
}
}
public void ProcessZone(DbElement zone)
{
float[] zoneBox;
if (!TryGetLimitsBox(zone, out zoneBox))
{
Result.Errors.Add($"Zone包围盒计算失败: {BuildElementPath(zone)}");
return;
}
_innerBox = BuildInnerBox(zoneBox, (float)Request.Padding);
ProcessChildren(zone);
}
private void ProcessChildren(DbElement parent)
{
var members = parent.Members();
if (members == null)
{
return;
}
foreach (var child in members)
{
ProcessElement(child);
}
}
private void ProcessElement(DbElement element)
{
if (!IsElementValid(element))
{
return;
}
Result.TotalVisited++;
var typeName = GetElementTypeName(element);
var normalizedType = string.IsNullOrEmpty(typeName) ? string.Empty : typeName.ToUpperInvariant();
if (_keepTypes.Contains(normalizedType))
{
Result.KeptCount++;
ProcessChildren(element);
return;
}
float[] box;
if (!TryGetLimitsBox(element, out box))
{
Result.KeptCount++;
return;
}
if (IsInsideInnerBox(box, _innerBox, (float)Request.TouchTolerance))
{
RemoveElement(element, normalizedType);
return;
}
Result.ShellKeptCount++;
Result.KeptCount++;
ProcessChildren(element);
}
private void RemoveElement(DbElement element, string typeName)
{
var elementPath = BuildElementPath(element);
if (Request.DryRun)
{
SnapshotRemoval(elementPath, typeName, true);
return;
}
try
{
element.Delete();
SnapshotRemoval(elementPath, typeName, false);
}
catch (Exception ex)
{
Result.Errors.Add($"删除元素 {elementPath} 失败: {ex.Message}");
}
}
private void SnapshotRemoval(string elementPath, string typeName, bool dryRun)
{
Result.RemovedCount++;
if (Result.RemovedElements.Count < MaxRemovedSnapshots)
{
var marker = dryRun ? "DRY" : "DEL";
Result.RemovedElements.Add($"[{marker}] {elementPath} ({typeName})");
}
}
private static bool TryGetLimitsBox(DbElement element, out float[] box)
{
box = null;
try
{
var spatial = Spatial.Instance;
if (spatial == null)
{
return false;
}
Aveva.Pdms.Geometry.LimitsBox limits;
var ok = spatial.LimitsBox(element, out limits);
if (!ok)
{
return false;
}
box = ConvertLimitsBox(limits);
return box != null && box.Length >= 6;
}
catch
{
return false;
}
}
private static float[] ConvertLimitsBox(Aveva.Pdms.Geometry.LimitsBox limits)
{
// 兼容不同版本 PDMS LimitsBox 字段/属性命名
// 期望输出: [xmin, ymin, zmin, xmax, ymax, zmax]
try
{
var type = typeof(Aveva.Pdms.Geometry.LimitsBox);
var boxed = (object)limits;
float xmin = ReadFloat(boxed, type, new[] { "XMIN", "XMin", "MinX", "Xmin" });
float ymin = ReadFloat(boxed, type, new[] { "YMIN", "YMin", "MinY", "Ymin" });
float zmin = ReadFloat(boxed, type, new[] { "ZMIN", "ZMin", "MinZ", "Zmin" });
float xmax = ReadFloat(boxed, type, new[] { "XMAX", "XMax", "MaxX", "Xmax" });
float ymax = ReadFloat(boxed, type, new[] { "YMAX", "YMax", "MaxY", "Ymax" });
float zmax = ReadFloat(boxed, type, new[] { "ZMAX", "ZMax", "MaxZ", "Zmax" });
return new[] { xmin, ymin, zmin, xmax, ymax, zmax };
}
catch
{
return null;
}
}
private static float ReadFloat(object boxed, System.Type type, string[] names)
{
foreach (var name in names)
{
var prop = type.GetProperty(name);
if (prop != null)
{
var v = prop.GetValue(boxed, null);
if (v != null)
{
return Convert.ToSingle(v);
}
}
var field = type.GetField(name);
if (field != null)
{
var v = field.GetValue(boxed);
if (v != null)
{
return Convert.ToSingle(v);
}
}
}
throw new InvalidOperationException("LimitsBox缺少必要字段/属性");
}
private static float[] BuildInnerBox(float[] outerBox, float padding)
{
var inner = new float[6];
inner[0] = outerBox[0] + padding;
inner[1] = outerBox[1] + padding;
inner[2] = outerBox[2] + padding;
inner[3] = outerBox[3] - padding;
inner[4] = outerBox[4] - padding;
inner[5] = outerBox[5] - padding;
if (inner[3] < inner[0])
{
inner[0] = outerBox[0];
inner[3] = outerBox[3];
}
if (inner[4] < inner[1])
{
inner[1] = outerBox[1];
inner[4] = outerBox[4];
}
if (inner[5] < inner[2])
{
inner[2] = outerBox[2];
inner[5] = outerBox[5];
}
return inner;
}
private static bool IsInsideInnerBox(float[] box, float[] innerBox, float tolerance)
{
if (box == null || innerBox == null || box.Length < 6 || innerBox.Length < 6)
{
return false;
}
// box完全在innerBox内部留tolerance避免贴边误删
return (box[0] > innerBox[0] + tolerance) &&
(box[1] > innerBox[1] + tolerance) &&
(box[2] > innerBox[2] + tolerance) &&
(box[3] < innerBox[3] - tolerance) &&
(box[4] < innerBox[4] - tolerance) &&
(box[5] < innerBox[5] - tolerance);
}
}
}
}