实现模型轻量化接口,支持保留外壳删除内部元件

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
This commit is contained in:
sladro 2025-11-28 14:42:08 +08:00
parent 69f32020fa
commit bf35d98365
5 changed files with 460 additions and 0 deletions

View File

@ -0,0 +1,40 @@
using System;
using TellmePdmsPluging.Core;
using TellmePdmsPluging.Models;
namespace TellmePdmsPluging.Commands
{
public class SimplifyModelCommand : ICommand
{
public SimplifyModelCommand(SimplifyModelRequest request)
{
Request = request ?? new SimplifyModelRequest();
CommandId = Guid.NewGuid().ToString("N");
}
public string CommandId { get; }
public string CommandType
{
get { return "SimplifyModel"; }
}
public bool CanCancel
{
get { return false; }
}
public SimplifyModelRequest Request { get; }
public object Execute()
{
Request.ApplyDefaults();
return PdmsManager.Instance.SimplifyModel(Request);
}
public void Cancel()
{
throw new NotSupportedException("SimplifyModelCommand 不支持取消");
}
}
}

View File

@ -3,6 +3,7 @@ using System.Collections.Generic;
using TellmePdmsPluging.Models;
using Aveva.ApplicationFramework;
using Aveva.Pdms.Database;
using System.Linq;
namespace TellmePdmsPluging.Core
{
@ -31,6 +32,94 @@ namespace TellmePdmsPluging.Core
{
}
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 ModelStatusResponse GetModelStatus()
{
try
@ -321,8 +410,162 @@ namespace TellmePdmsPluging.Core
};
}
}
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})");
}
}
}
}
}

View File

@ -0,0 +1,121 @@
using System;
using System.Collections.Generic;
namespace TellmePdmsPluging.Models
{
public class SimplifyModelRequest
{
public bool DryRun { get; set; } = true;
public List<string> ZoneFilters
{
get { return _zoneFilters; }
set { _zoneFilters = NormalizeList(value); }
}
public List<string> KeepTypes
{
get { return _keepTypes; }
set { _keepTypes = NormalizeList(value); }
}
public List<string> RemoveTypes
{
get { return _removeTypes; }
set { _removeTypes = NormalizeList(value); }
}
public ShellPaddingOptions BoundingShell { get; set; } = new ShellPaddingOptions();
private List<string> _zoneFilters;
private List<string> _keepTypes;
private List<string> _removeTypes;
public void ApplyDefaults()
{
if (_keepTypes == null || _keepTypes.Count == 0)
{
_keepTypes = new List<string> { "SITE", "ZONE", "STRU", "FRAME", "SHELL", "PLAT", "WALL" };
}
if (_removeTypes == null || _removeTypes.Count == 0)
{
_removeTypes = new List<string> { "PIPE", "BRAN", "ELBO", "VALV", "FITT", "NOZZ", "EQUI" };
}
if (_zoneFilters == null)
{
_zoneFilters = new List<string>();
}
if (BoundingShell == null)
{
BoundingShell = new ShellPaddingOptions();
}
}
private static List<string> NormalizeList(IEnumerable<string> source)
{
if (source == null)
{
return null;
}
var normalized = new List<string>();
foreach (var item in source)
{
if (IsNullOrWhiteSpace(item))
{
continue;
}
var formatted = item.Trim().ToUpperInvariant();
if (!normalized.Contains(formatted))
{
normalized.Add(formatted);
}
}
return normalized;
}
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;
}
public class ShellPaddingOptions
{
public double Padding { get; set; } = 0d;
}
}
public class SimplifyModelResult
{
public bool Success { get; set; }
public bool DryRun { get; set; }
public int TotalVisited { get; set; }
public int RemovedCount { get; set; }
public int KeptCount { get; set; }
public List<string> RemovedElements { get; set; } = new List<string>();
public List<string> Errors { get; set; } = new List<string>();
public DateTime StartedAt { get; set; }
public DateTime CompletedAt { get; set; }
public string Message { get; set; }
public List<string> ZoneSummaries { get; set; } = new List<string>();
}
}

View File

@ -3,6 +3,8 @@ using System.Net;
using System.Text;
using System.IO;
using System.Collections.Generic;
using System.Web.Script.Serialization;
using TellmePdmsPluging.Commands;
using TellmePdmsPluging.Core;
using TellmePdmsPluging.Models;
@ -121,6 +123,9 @@ namespace TellmePdmsPluging.Network
case "/api/status/model":
responseJson = HandleModelStatus();
break;
case "/api/model/simplify":
responseJson = HandleModelSimplify(request);
break;
default:
response.StatusCode = 404;
responseJson = CreateErrorResponse(404, "接口不存在");
@ -211,6 +216,54 @@ namespace TellmePdmsPluging.Network
}
}
private string HandleModelSimplify(HttpListenerRequest request)
{
try
{
var payload = ReadRequestBody(request);
if (string.IsNullOrEmpty(payload))
{
return CreateErrorResponse(400, "请求体不能为空");
}
var serializer = new JavaScriptSerializer();
var simplifyRequest = serializer.Deserialize<SimplifyModelRequest>(payload) ?? new SimplifyModelRequest();
var command = new SimplifyModelCommand(simplifyRequest);
var result = command.Execute() as SimplifyModelResult;
if (result == null)
{
return CreateErrorResponse(500, "模型轻量化结果为空");
}
if (!result.Success)
{
var message = string.IsNullOrEmpty(result.Message) ? "模型轻量化失败" : result.Message;
return CreateErrorResponse(500, message);
}
return CreateSuccessResponse(result);
}
catch (Exception ex)
{
return CreateErrorResponse(500, $"模型轻量化失败: {ex.Message}");
}
}
private string ReadRequestBody(HttpListenerRequest request)
{
if (request == null || request.InputStream == null)
{
return string.Empty;
}
using (var reader = new StreamReader(request.InputStream, request.ContentEncoding ?? Encoding.UTF8))
{
return reader.ReadToEnd();
}
}
private bool CheckPdmsStatus()
{
try

View File

@ -69,13 +69,16 @@
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
<Reference Include="System.Web.Extensions" />
</ItemGroup>
<ItemGroup>
<Compile Include="Class1.cs" />
<Compile Include="Commands\SimplifyModelCommand.cs" />
<Compile Include="Core\ICommand.cs" />
<Compile Include="Core\ApiResponse.cs" />
<Compile Include="Core\PdmsManager.cs" />
<Compile Include="Models\ModelStatusResponse.cs" />
<Compile Include="Models\SimplifyModelRequest.cs" />
<Compile Include="Network\HttpServer.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>