TellmePdmsPluging/Core/PdmsManager.cs

2330 lines
80 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();
private static readonly object _attributeCacheLock = new object();
private static readonly Dictionary<string, DbAttribute> _attributeCache = new Dictionary<string, DbAttribute>(StringComparer.OrdinalIgnoreCase);
private static readonly string[] LinkedAttributeCandidates = new[]
{
"ATCONN", "BRCON", "DEPREF", "ECRFA", "CONNE", "CONNS", "ATTC",
"CTYA", "CTYE", "CTYO", "CTYS", "ENDPOI", "CLNK", "CONN", "DCON", "DPCO"
};
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,
SkipLinkedElements = effectiveRequest.SkipLinkedElements,
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;
}
if (!effectiveRequest.DryRun && IsDbReadOnly(designDb))
{
result.Success = false;
result.CompletedAt = DateTime.Now;
result.Message = "当前Design DB为只读无法执行真实删除";
result.Errors.Add("当前Design DB为只读无法执行真实删除");
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);
}
}
}
if (!effectiveRequest.DryRun && processed && result.RemovedCount > 0)
{
string persistError;
if (!TryPersistCurrentMdbChanges("TellmePdms simplify model", out persistError))
{
result.Errors.Add("删除已执行,但保存更改失败: " + persistError);
}
}
result.Success = processed && result.Errors.Count == 0;
if (!processed)
{
result.Message = "未找到符合过滤条件的Zone";
}
else if (result.Success)
{
result.Message = result.DryRun ? "模型轻量化干跑完成" : "模型轻量化完成";
}
else
{
var topErrors = result.Errors.Take(3).ToArray();
var errorSummary = topErrors.Length == 0 ? "UNKNOWN_ERROR" : string.Join(" | ", topErrors);
result.Message = (result.DryRun ? "模型轻量化干跑完成,但存在错误: " : "模型轻量化完成,但存在错误: ") + errorSummary;
}
if (effectiveRequest.SkipLinkedElements && result.SkippedLinkedCount > 0)
{
result.Message += ";已跳过连接元素 " + result.SkippedLinkedCount + " 个";
}
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,
SkipLinkedElements = effectiveRequest.SkipLinkedElements,
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;
}
if (!effectiveRequest.DryRun && IsDbReadOnly(designDb))
{
result.Success = false;
result.CompletedAt = DateTime.Now;
result.Message = "当前Design DB为只读无法执行真实删除";
result.Errors.Add("当前Design DB为只读无法执行真实删除");
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);
}
}
}
if (!effectiveRequest.DryRun && processed && result.RemovedCount > 0)
{
string persistError;
if (!TryPersistCurrentMdbChanges("TellmePdms shrinkwrap model", out persistError))
{
result.Errors.Add("删除已执行,但保存更改失败: " + persistError);
}
}
result.Success = processed && result.Errors.Count == 0;
if (!processed)
{
result.Message = "未找到符合过滤条件的Zone";
}
else if (result.Success)
{
result.Message = result.DryRun ? "外壳保留干跑完成" : "外壳保留完成";
}
else
{
var topErrors = result.Errors.Take(3).ToArray();
var errorSummary = topErrors.Length == 0 ? "UNKNOWN_ERROR" : string.Join(" | ", topErrors);
result.Message = (result.DryRun ? "外壳保留干跑完成,但存在错误: " : "外壳保留完成,但存在错误: ") + errorSummary;
}
if (effectiveRequest.SkipLinkedElements && result.SkippedLinkedCount > 0)
{
result.Message += ";已跳过连接元素 " + result.SkippedLinkedCount + " 个";
}
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命令 - 通过MacroCommand类型反射构造并执行
var macroType = CommandManager.Instance.MacroCommand;
if (macroType == null)
throw new InvalidOperationException("MacroCommand类型未注册");
var ctor = macroType.GetConstructor(
System.Reflection.BindingFlags.Public |
System.Reflection.BindingFlags.NonPublic |
System.Reflection.BindingFlags.Instance,
null,
new[] { typeof(string), typeof(string), typeof(string) },
null);
if (ctor == null)
{
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未找到(string,string,string)构造函数,类型: " + macroType.FullName + " 构造函数: " + ctorInfo);
}
var exportCommands = BuildExportCommands(effectiveRequest);
for (int i = 0; i < exportCommands.Length; i++)
{
var macroCommand = ctor.Invoke(new object[]
{
"TellmePdmsPluging.ExportIfc." + (i + 1),
exportCommands[i],
string.Empty
}) as Command;
if (macroCommand == null)
{
throw new InvalidOperationException("MacroCommand实例创建失败类型: " + macroType.FullName);
}
macroCommand.Execute();
}
// 检查文件是否生成
if (System.IO.File.Exists(result.FullPath))
{
var fileInfo = new System.IO.FileInfo(result.FullPath);
result.FileSizeBytes = fileInfo.Length;
result.Success = true;
result.Message = "RVM导出成功";
}
else
{
result.Success = false;
result.Message = "RVM导出失败未生成文件";
}
result.CompletedAt = DateTime.Now;
result.DurationSeconds = (result.CompletedAt - result.StartedAt).TotalSeconds;
return result;
}
catch (Exception ex)
{
result.Success = false;
result.Message = "RVM导出异常: " + ex.Message;
result.CompletedAt = DateTime.Now;
result.DurationSeconds = (result.CompletedAt - result.StartedAt).TotalSeconds;
return result;
}
}
private string[] BuildExportCommands(ExportIfcRequest request)
{
// 按文档流程构建命令:
// EXPORT SYSTEM <driver> (可选)
// EXPORT FILE <name> OVERWRITE
// EXPORT <selection>
// EXPORT FINISH
string fullPath = request.GetFullPath().Replace("\\", "/");
var commands = new List<string>();
if (!string.IsNullOrEmpty(request.ExportSystem))
{
commands.Add("EXPORT SYSTEM " + request.ExportSystem);
}
commands.Add(string.Format("EXPORT FILE {0} {1}", fullPath, request.Overwrite.GetValueOrDefault(true) ? "OVERWRITE" : "READ"));
var selections = request.GetEffectiveSelections();
foreach (var selectionCommand in selections)
{
commands.Add(selectionCommand);
}
commands.Add("EXPORT FINISH");
return commands.ToArray();
}
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 static bool IsDbReadOnly(Db db)
{
if (db == null)
{
return true;
}
try
{
var property = db.GetType().GetProperty("IsReadOnly");
if (property == null)
{
return false;
}
var value = property.GetValue(db, null);
if (value is bool)
{
return (bool)value;
}
}
catch
{
// ignore and treat as writable
}
return false;
}
private static bool TryPersistCurrentMdbChanges(string comment, out string error)
{
error = null;
try
{
var mdb = MDB.CurrentMDB;
if (mdb == null)
{
error = "当前MDB为空";
return false;
}
bool saveResult;
if (TryInvokeSaveWorkByComment(mdb, comment, out saveResult))
{
if (saveResult)
{
return true;
}
error = "SaveWork(string) 返回 false";
return false;
}
var designDb = mdb.GetFirstDB(DbType.Design);
if (designDb == null)
{
error = "未找到Design DB";
return false;
}
if (IsDbReadOnly(designDb))
{
error = "Design DB为只读";
return false;
}
if (TryInvokeSaveWorkByDbs(mdb, new[] { designDb }, comment, out saveResult))
{
if (saveResult)
{
return true;
}
error = "SaveWork(Db[], string) 返回 false";
return false;
}
error = "未找到可用的SaveWork重载";
return false;
}
catch (Exception ex)
{
error = ex.Message;
return false;
}
}
private static bool TryInvokeSaveWorkByComment(MDB mdb, string comment, out bool saveResult)
{
saveResult = false;
try
{
var method = mdb.GetType().GetMethod("SaveWork", new[] { typeof(string) });
if (method == null)
{
return false;
}
var result = method.Invoke(mdb, new object[] { comment ?? string.Empty });
saveResult = !(result is bool) || (bool)result;
return true;
}
catch
{
return false;
}
}
private static bool TryInvokeSaveWorkByDbs(MDB mdb, Db[] dbs, string comment, out bool saveResult)
{
saveResult = false;
try
{
var method = mdb.GetType().GetMethod("SaveWork", new[] { typeof(Db[]), typeof(string) });
if (method == null)
{
return false;
}
var result = method.Invoke(mdb, new object[] { dbs, comment ?? string.Empty });
saveResult = !(result is bool) || (bool)result;
return true;
}
catch
{
return false;
}
}
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 static bool ShouldSkipLinkedElement(DbElement element, bool skipLinkedElements, out string reason)
{
reason = null;
if (!skipLinkedElements || !IsElementValid(element))
{
return false;
}
try
{
if (!element.IsDeleteable)
{
reason = "IsDeleteable=false";
return true;
}
}
catch
{
// ignore
}
string attributeName;
string attributeValue;
if (TryFindLinkedAttributeValue(element, out attributeName, out attributeValue))
{
reason = string.IsNullOrEmpty(attributeValue)
? attributeName
: (attributeName + "=" + attributeValue);
return true;
}
return false;
}
private static bool TryFindLinkedAttributeValue(DbElement element, out string attributeName, out string attributeValue)
{
attributeName = null;
attributeValue = null;
if (!IsElementValid(element))
{
return false;
}
foreach (var candidate in LinkedAttributeCandidates)
{
DbAttribute attribute;
if (!TryGetDbAttributeByName(candidate, out attribute) || attribute == null)
{
continue;
}
bool isValid;
try
{
isValid = element.IsAttributeValid(attribute);
}
catch
{
continue;
}
if (!isValid)
{
continue;
}
string textValue = string.Empty;
try
{
if (element.GetValidAsString(attribute, ref textValue) && HasMeaningfulLinkedValue(textValue))
{
attributeName = candidate;
attributeValue = SummarizeValue(textValue);
return true;
}
}
catch
{
// ignore and fallback to array check
}
try
{
var refs = element.GetElementArray(attribute);
if (refs != null)
{
for (int i = 0; i < refs.Length; i++)
{
if (IsElementValid(refs[i]))
{
attributeName = candidate;
attributeValue = "REFS>0";
return true;
}
}
}
}
catch
{
// ignore
}
}
return false;
}
private static bool TryGetDbAttributeByName(string name, out DbAttribute attribute)
{
attribute = null;
if (string.IsNullOrEmpty(name))
{
return false;
}
lock (_attributeCacheLock)
{
if (_attributeCache.TryGetValue(name, out attribute))
{
return attribute != null;
}
}
DbAttribute resolved = null;
try
{
var flags = System.Reflection.BindingFlags.Public |
System.Reflection.BindingFlags.Static |
System.Reflection.BindingFlags.IgnoreCase;
var field = typeof(DbAttributeInstance).GetField(name, flags);
if (field != null)
{
resolved = field.GetValue(null) as DbAttribute;
}
if (resolved == null)
{
var property = typeof(DbAttributeInstance).GetProperty(name, flags);
if (property != null)
{
resolved = property.GetValue(null, null) as DbAttribute;
}
}
}
catch
{
resolved = null;
}
lock (_attributeCacheLock)
{
_attributeCache[name] = resolved;
}
attribute = resolved;
return attribute != null;
}
private static bool HasMeaningfulLinkedValue(string value)
{
if (IsNullOrWhiteSpace(value))
{
return false;
}
var normalized = value.Trim().ToUpperInvariant();
switch (normalized)
{
case "0":
case "FALSE":
case "NONE":
case "NO":
case "NULREF":
case "NULL":
case "UNSET":
case "UNDEFINED":
case "[]":
case "{}":
return false;
}
if (normalized.IndexOf("NULREF", StringComparison.Ordinal) >= 0 ||
normalized.IndexOf("UNSET", StringComparison.Ordinal) >= 0 ||
normalized.IndexOf("UNDEFINED", StringComparison.Ordinal) >= 0)
{
return false;
}
bool hasLetter = false;
bool hasSlash = false;
for (int i = 0; i < normalized.Length; i++)
{
char ch = normalized[i];
if (char.IsLetter(ch))
{
hasLetter = true;
break;
}
if (ch == '/')
{
hasSlash = true;
}
}
if (!hasLetter && !hasSlash)
{
return false;
}
return true;
}
private static string SummarizeValue(string value)
{
if (string.IsNullOrEmpty(value))
{
return value;
}
var trimmed = value.Trim();
const int maxLength = 64;
if (trimmed.Length <= maxLength)
{
return trimmed;
}
return trimmed.Substring(0, maxLength) + "...";
}
private static bool IsNullOrWhiteSpace(string value)
{
if (value == null)
{
return true;
}
for (int i = 0; i < value.Length; i++)
{
if (!char.IsWhiteSpace(value[i]))
{
return false;
}
}
return true;
}
private class SimplifyContext
{
private const int MaxRemovedSnapshots = 200;
private const int MaxSkippedSnapshots = 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);
try
{
string linkedReason;
if (ShouldSkipLinkedElement(element, Request.SkipLinkedElements, out linkedReason))
{
Result.KeptCount++;
SnapshotSkipped(elementPath, typeName, linkedReason);
return;
}
if (Request.DryRun)
{
SnapshotRemoval(elementPath, typeName, true);
return;
}
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)
{
Result.RemovedElements.Add((dryRun ? "[DRYRUN-DEL] " : "[DEL] ") + elementPath + " (" + typeName + ")");
}
}
private void SnapshotSkipped(string elementPath, string typeName, string reason)
{
Result.SkippedLinkedCount++;
if (Result.SkippedLinkedElements.Count < MaxSkippedSnapshots)
{
var suffix = string.IsNullOrEmpty(reason) ? string.Empty : (" [" + reason + "]");
Result.SkippedLinkedElements.Add("[SKIP-LINKED] " + elementPath + " (" + typeName + ")" + suffix);
}
}
}
private class ShrinkwrapContext
{
private const int MaxRemovedSnapshots = 200;
private const int MaxSkippedSnapshots = 200;
private const float MinBoxEdge = 0.001f;
public ShrinkwrapContext(ShrinkwrapModelRequest request, ShrinkwrapModelResult result)
{
Request = request;
Result = result;
_keepTypes = new HashSet<string>(request.KeepTypes ?? new List<string>());
_shellBoxes = new List<float[]>();
}
public ShrinkwrapModelRequest Request { get; }
public ShrinkwrapModelResult Result { get; }
public string CurrentZoneName { get; private set; }
private readonly HashSet<string> _keepTypes;
private float[] _zoneBox;
private float[] _innerBox;
private float[] _innerDeleteBox;
private List<float[]> _shellBoxes;
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)
{
if (!TryGetLimitsBox(zone, out _zoneBox))
{
Result.Errors.Add($"Zone包围盒计算失败: {BuildElementPath(zone)}");
return;
}
_innerBox = BuildInnerBox(_zoneBox, (float)Math.Max(0d, Request.Padding));
_innerDeleteBox = BuildDeleteCoreBox(_innerBox, (float)Math.Max(0d, Request.TouchTolerance));
_shellBoxes = BuildShellBoxes(_zoneBox, _innerDeleteBox);
if (!ProcessZoneWithExactSpatial(zone))
{
ProcessChildren(zone);
}
}
private bool ProcessZoneWithExactSpatial(DbElement zone)
{
if (_shellBoxes == null || _shellBoxes.Count == 0 || _innerDeleteBox == null)
{
return false;
}
var spatial = Spatial.Instance;
if (spatial == null)
{
return false;
}
DbElement[] candidates;
try
{
candidates = spatial.ElementsInElementExact(zone, true);
}
catch
{
return false;
}
if (candidates == null || candidates.Length == 0)
{
return true;
}
Array.Sort(candidates, delegate (DbElement a, DbElement b)
{
return GetOwnerDepth(b).CompareTo(GetOwnerDepth(a));
});
foreach (var element in candidates)
{
ProcessExactCandidate(element);
}
return true;
}
private void ProcessExactCandidate(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++;
return;
}
if (OverlapsAnyShellBox(element))
{
Result.ShellKeptCount++;
Result.KeptCount++;
return;
}
bool overlapsDeleteCore;
if (!TryElementInBox(element, _innerDeleteBox, out overlapsDeleteCore))
{
float[] box;
if (TryGetLimitsBox(element, out box) && IsInsideInnerBox(box, _innerDeleteBox, 0f))
{
RemoveElement(element, normalizedType);
return;
}
Result.KeptCount++;
return;
}
if (overlapsDeleteCore)
{
RemoveElement(element, normalizedType);
return;
}
Result.KeptCount++;
}
private bool OverlapsAnyShellBox(DbElement element)
{
if (_shellBoxes == null || _shellBoxes.Count == 0)
{
return false;
}
foreach (var shellBox in _shellBoxes)
{
bool overlaps;
if (TryElementInBox(element, shellBox, out overlaps) && overlaps)
{
return true;
}
}
return false;
}
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;
}
if (OverlapsAnyShellBox(element))
{
Result.ShellKeptCount++;
Result.KeptCount++;
ProcessChildren(element);
return;
}
float[] box;
if (!TryGetLimitsBox(element, out box))
{
Result.KeptCount++;
return;
}
if (IsInsideInnerBox(box, _innerDeleteBox, 0f))
{
RemoveElement(element, normalizedType);
return;
}
Result.KeptCount++;
ProcessChildren(element);
}
private void RemoveElement(DbElement element, string typeName)
{
var elementPath = BuildElementPath(element);
try
{
string linkedReason;
if (ShouldSkipLinkedElement(element, Request.SkipLinkedElements, out linkedReason))
{
Result.KeptCount++;
SnapshotSkipped(elementPath, typeName, linkedReason);
return;
}
if (Request.DryRun)
{
SnapshotRemoval(elementPath, typeName, true);
return;
}
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)
{
Result.RemovedElements.Add((dryRun ? "[DRYRUN-DEL] " : "[DEL] ") + elementPath + " (" + typeName + ")");
}
}
private void SnapshotSkipped(string elementPath, string typeName, string reason)
{
Result.SkippedLinkedCount++;
if (Result.SkippedLinkedElements.Count < MaxSkippedSnapshots)
{
var suffix = string.IsNullOrEmpty(reason) ? string.Empty : (" [" + reason + "]");
Result.SkippedLinkedElements.Add("[SKIP-LINKED] " + elementPath + " (" + typeName + ")" + suffix);
}
}
private static int GetOwnerDepth(DbElement element)
{
var current = element;
int depth = 0;
int guard = 0;
while (IsElementValid(current) && guard < 512)
{
depth++;
current = current.Owner;
guard++;
}
return depth;
}
private static bool TryElementInBox(DbElement element, float[] box, out bool overlaps)
{
overlaps = false;
if (!IsElementValid(element) || box == null || box.Length < 6)
{
return false;
}
try
{
float[] elementBox;
if (!TryGetLimitsBox(element, out elementBox))
{
return false;
}
overlaps = BoxesOverlap(elementBox, box);
return true;
}
catch
{
return false;
}
}
private static bool TryGetLimitsBox(DbElement element, out float[] box)
{
box = null;
if (!IsElementValid(element))
{
return false;
}
try
{
var spatial = Spatial.Instance;
if (spatial == null)
{
return false;
}
var spatialType = spatial.GetType();
var arrayMethod = spatialType.GetMethod("LimitsBox", new[] { typeof(DbElement), typeof(float[]) });
if (arrayMethod != null)
{
var args = new object[] { element, new float[6] };
var okObj = arrayMethod.Invoke(spatial, args);
if (okObj is bool && (bool)okObj)
{
if (TryNormalizeBox(args[1] as float[], out box))
{
return true;
}
}
}
var methods = spatialType.GetMethods().Where(m => m.Name == "LimitsBox").ToArray();
foreach (var method in methods)
{
var parameters = method.GetParameters();
if (parameters.Length != 2 || parameters[0].ParameterType != typeof(DbElement) || !parameters[1].ParameterType.IsByRef)
{
continue;
}
object boxValue;
try
{
boxValue = Activator.CreateInstance(parameters[1].ParameterType.GetElementType());
}
catch
{
continue;
}
var args = new object[] { element, boxValue };
var okObj = method.Invoke(spatial, args);
if (!(okObj is bool) || !(bool)okObj)
{
continue;
}
var converted = ConvertLimitsBoxObject(args[1]);
if (TryNormalizeBox(converted, out box))
{
return true;
}
}
}
catch
{
// ignore
}
return false;
}
private static float[] ConvertLimitsBoxObject(object limits)
{
if (limits == null)
{
return null;
}
var type = limits.GetType();
try
{
float xmin = ReadFloat(limits, type, new[] { "XMIN", "XMin", "MinX", "Xmin" });
float ymin = ReadFloat(limits, type, new[] { "YMIN", "YMin", "MinY", "Ymin" });
float zmin = ReadFloat(limits, type, new[] { "ZMIN", "ZMin", "MinZ", "Zmin" });
float xmax = ReadFloat(limits, type, new[] { "XMAX", "XMax", "MaxX", "Xmax" });
float ymax = ReadFloat(limits, type, new[] { "YMAX", "YMax", "MaxY", "Ymax" });
float zmax = ReadFloat(limits, type, new[] { "ZMAX", "ZMax", "MaxZ", "Zmax" });
return new[] { xmin, ymin, zmin, xmax, ymax, zmax };
}
catch
{
return null;
}
}
private static float ReadFloat(object boxed, Type type, string[] names)
{
foreach (var name in names)
{
var prop = type.GetProperty(name);
if (prop != null)
{
var value = prop.GetValue(boxed, null);
if (value != null)
{
return Convert.ToSingle(value);
}
}
var field = type.GetField(name);
if (field != null)
{
var value = field.GetValue(boxed);
if (value != null)
{
return Convert.ToSingle(value);
}
}
}
throw new InvalidOperationException("LimitsBox缺少必要字段/属性");
}
private static bool TryNormalizeBox(float[] source, out float[] normalized)
{
normalized = null;
if (source == null || source.Length < 6)
{
return false;
}
float xmin = Math.Min(source[0], source[3]);
float ymin = Math.Min(source[1], source[4]);
float zmin = Math.Min(source[2], source[5]);
float xmax = Math.Max(source[0], source[3]);
float ymax = Math.Max(source[1], source[4]);
float zmax = Math.Max(source[2], source[5]);
if ((xmax - xmin) < MinBoxEdge || (ymax - ymin) < MinBoxEdge || (zmax - zmin) < MinBoxEdge)
{
return false;
}
normalized = new[] { xmin, ymin, zmin, xmax, ymax, zmax };
return true;
}
private static float[] BuildInnerBox(float[] outerBox, float padding)
{
if (outerBox == null || outerBox.Length < 6)
{
return null;
}
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 float[] BuildDeleteCoreBox(float[] innerBox, float tolerance)
{
if (innerBox == null || innerBox.Length < 6)
{
return null;
}
var core = new float[6];
var offset = Math.Max(0f, tolerance);
core[0] = innerBox[0] + offset;
core[1] = innerBox[1] + offset;
core[2] = innerBox[2] + offset;
core[3] = innerBox[3] - offset;
core[4] = innerBox[4] - offset;
core[5] = innerBox[5] - offset;
float[] normalized;
return TryNormalizeBox(core, out normalized) ? normalized : null;
}
private static List<float[]> BuildShellBoxes(float[] outerBox, float[] innerDeleteBox)
{
var boxes = new List<float[]>();
if (outerBox == null || innerDeleteBox == null)
{
return boxes;
}
AddShellBox(boxes, outerBox[0], outerBox[1], outerBox[2], innerDeleteBox[0], outerBox[4], outerBox[5]); // Left
AddShellBox(boxes, innerDeleteBox[3], outerBox[1], outerBox[2], outerBox[3], outerBox[4], outerBox[5]); // Right
AddShellBox(boxes, innerDeleteBox[0], outerBox[1], outerBox[2], innerDeleteBox[3], innerDeleteBox[1], outerBox[5]); // Front
AddShellBox(boxes, innerDeleteBox[0], innerDeleteBox[4], outerBox[2], innerDeleteBox[3], outerBox[4], outerBox[5]); // Back
AddShellBox(boxes, innerDeleteBox[0], innerDeleteBox[1], outerBox[2], innerDeleteBox[3], innerDeleteBox[4], innerDeleteBox[2]); // Bottom
AddShellBox(boxes, innerDeleteBox[0], innerDeleteBox[1], innerDeleteBox[5], innerDeleteBox[3], innerDeleteBox[4], outerBox[5]); // Top
return boxes;
}
private static void AddShellBox(List<float[]> boxes, float xmin, float ymin, float zmin, float xmax, float ymax, float zmax)
{
var candidate = new[] { xmin, ymin, zmin, xmax, ymax, zmax };
float[] normalized;
if (TryNormalizeBox(candidate, out normalized))
{
boxes.Add(normalized);
}
}
private static bool IsInsideInnerBox(float[] box, float[] innerBox, float tolerance)
{
if (box == null || innerBox == null || box.Length < 6 || innerBox.Length < 6)
{
return false;
}
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);
}
private static bool BoxesOverlap(float[] a, float[] b)
{
if (a == null || b == null || a.Length < 6 || b.Length < 6)
{
return false;
}
return (a[0] <= b[3]) && (a[3] >= b[0]) &&
(a[1] <= b[4]) && (a[4] >= b[1]) &&
(a[2] <= b[5]) && (a[5] >= b[2]);
}
}
}
}