Files

504 lines
19 KiB
C#
Raw Permalink Normal View History

2025-09-16 16:06:41 +08:00
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace Szmedi.RevitToolkit.Approval.Assists;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text.RegularExpressions;
using System.Windows.Markup;
using Autodesk.Revit.DB.ExtensibleStorage;
using Newtonsoft.Json;
using Szmedi.RevitToolkit.Approval.Models;
using static Dapper.SqlMapper;
/// <summary>
/// 用于保存从MVDLite文本中解析出的结构化数据的类。
/// </summary>
public class MvdData
{
/// <summary>
/// 文件头部的元数据。
/// 例如:# MVDLite_Version = '2.5.0.0'
/// </summary>
public Dictionary<string, string> Metadata { get; set; } = [];
/// <summary>
/// 路径别名定义列表。
/// 例如: "hasAssignments as (IfcObjectDefinition)->HasAssignments->RelatedObjectsType"
/// </summary>
public List<Alias> Aliases { get; set; } = new List<Alias>();
/// <summary>
/// 实体定义列表。
/// </summary>
public List<EntityDefinition> EntityDefinitions { get; set; } = [];
}
/// <summary>
/// 代表一个规则定义
/// </summary>
public class Alias
{
public string Name { get; set; }
public string SourceType { get; set; }
public string Path { get; set; }
public override string ToString() => $"{Name} as ({SourceType}){Path}";
}
/// <summary>
/// 代表一个在 "定义" 块中定义的实体。
/// </summary>
public class EntityDefinition
{
/// <summary>
/// 继承那一行的名称
/// </summary>
public string Name { get; set; }
/// <summary>
/// 定义后的第一行描述
/// </summary>
public string Description { get; set; }
/// <summary>
/// 继承自的名称
/// </summary>
public string InheritsFrom { get; set; }
/// <summary>
/// 新增:专门存放“类型标签”的值列表
/// </summary>
public List<string> TypeLabels { get; set; } = [];
/// <summary>
/// 类型判断
/// </summary>
public List<string> Conditions { get; set; } = [];
/// <summary>
/// 约束,每个约束就是一个属性条目
/// </summary>
public List<Constraint> Constraints { get; set; } = [];
public string IfcMap { get; set; } // 来自 "# IFC_MAP = 'IfcElement'" 这样的注释
public override string ToString() => $"Entity: {Name}" + (string.IsNullOrEmpty(InheritsFrom) ? "" : $" inherits {InheritsFrom}");
}
/// <summary>
/// 代表一个在 "约束" 块中定义的规则,即一个属性条目
/// </summary>
public class Constraint
{
/// <summary>
/// 描述约束规则,如:'预制剪力墙 的属性 \"编号\" 应满足值类型约束规则'
/// </summary>
public string Description { get; set; }
/// <summary>
/// 表达式,如:预制剪力墙->任意属性集->任意属性('编号')->属性值[Type]>='STRING'
/// </summary>
public string Expression { get; set; }
/// <summary>
///用于解析注释中的额外信息,例如: # PropName = '型号规格'keyPropNameDefaultValue型号规格KeyRangeDefaultValue>=0
/// 固定只有两个,一个是属性名,一个取值范围
/// </summary>
public Dictionary<string, string> PropertyDictionary { get; set; } = [];
/// <summary>
/// 参数值类型
/// </summary>
public string ParameterType
{
get
{
if (ValueRange.Contains("实数值"))
{
return "Number";
}
return "Text";
}
}
/// <summary>
/// 参数的取值范围
/// </summary>
public string[] Values
{
get
{
var range = ValueRange.Replace(" ", "");
if (range.Contains("实数值") || range.Contains(">=0"))
{
return ["0"];
}
else if (range.Contains(">0"))
{
if (range.Contains("<=1"))
{
return ["1"];
}
return ["100"];
}
else if (range.Contains("字符串值"))
{
return [""];
}
return [.. Regex.Matches(range, @"\\""([^""]*)\\""").OfType<Match>().Select(m => m.Groups[1].Value)];
}
}
/// <summary>
/// 属性名
/// </summary>
public string PropName => PropertyDictionary.ContainsKey("PropName") ? PropertyDictionary["PropName"] : string.Empty;
/// <summary>
/// 取值范围
/// </summary>
public string ValueRange => PropertyDictionary.ContainsKey("Range") ? PropertyDictionary["Range"] : string.Empty;
public override string ToString() => $"Constraint: {PropName} => {ValueRange}";
}
/// <summary>
/// 一个静态工具类用于将MVDLite格式的文本数据解析为结构化的C#对象。
/// </summary>
public class MvdLiteAssist
{
public static List<string> GetSigns(Major major, string entityName, string inheritsFrom)
{
var archi = IOAssists.GetMvdLiteContent(major);
var archiData = MvdLiteAssist.Parse(archi);
var archiDefinition = MvdLiteAssist.GetDefinitionByName(archiData, entityName, inheritsFrom);
var archiExpression = archiDefinition.Constraints.FirstOrDefault().Expression;
var archiSigns = Regex.Matches(archiExpression, @"'([^']*)'").OfType<Match>().Select(m => m.Groups[1].Value);
return [.. archiSigns];
}
public static List<string> GetSigns(string majorName, string entityName, string inheritsFrom)
{
var archi = IOAssists.GetMvdLiteContent(majorName);
var archiData = MvdLiteAssist.Parse(archi);
var archiDefinition = MvdLiteAssist.GetDefinitionByName(archiData, entityName, inheritsFrom);
var archiExpression = archiDefinition.Constraints.FirstOrDefault().Expression;
var archiSigns = Regex.Matches(archiExpression, @"'([^']*)'").OfType<Match>().Select(m => m.Groups[1].Value);
return [.. archiSigns];
}
private enum ParserState
{
Idle, // 用于解析元数据和别名
InDefinition,
InConstraint
}
/// <summary>
/// 获取所有直接包含属性的集合(不包含子类继承父类的属性)
/// </summary>
/// <param name="mvdData"></param>
/// <returns></returns>
public static List<AfcaArchiProperty> GetProperties(MvdData mvdData)
{
List<AfcaArchiProperty> properties = [];
List<EntityDefinition> definitions = mvdData.EntityDefinitions;
foreach (var entity in definitions)
{
var constraints = entity.Constraints;
foreach (var cons in constraints)
{
if (string.IsNullOrEmpty(cons.PropName) || string.IsNullOrEmpty(cons.Description))
{
continue;
}
var property = new AfcaArchiProperty
{
DefinitionName = entity.Name,
Name = cons.PropName,
ValueConstraints = cons.Values,
ValueRange = cons.ValueRange,
};
properties.Add(property);
//sb.AppendLine($"Entity: {entity.Name}, Property: {cons.PropName}, DefaultValue: {cons.ValueRange}");
}
}
return properties;
}
/// <summary>
/// 获取所有构件标识列表
/// </summary>
/// <param name="mvdData"></param>
/// <returns></returns>
public static HashSet<string> GetElementSigns(MvdData mvdData, string ifcClass = "IfcElement")
{
HashSet<string> signs = [];
List<EntityDefinition> definitions = mvdData.EntityDefinitions;
foreach (var entity in definitions)
{
if (!string.IsNullOrEmpty(entity.Description) && entity.IfcMap == ifcClass)
{
foreach (var label in entity.TypeLabels)
{
signs.Add(label);
}
}
}
return signs;
}
/// <summary>
/// 解析包含MVDLite数据的文本字符串。
/// </summary>
/// <param name="textContent">要解析的文本内容。</param>
/// <returns>一个包含所有解析后数据的 MvdData 对象。</returns>
public static MvdData Parse(string textContent)
{
var mvdData = new MvdData();
if (string.IsNullOrWhiteSpace(textContent)) return mvdData;
var lines = textContent.Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.None);
ParserState state = ParserState.Idle;
EntityDefinition currentEntity = null;
Constraint currentConstraint = null;
// 用于匹配不同类型行的正则表达式
var metaRegex = new Regex(@"^#\s*([^=]+?)\s*=\s*'(.*)'");
var aliasRegex = new Regex(@"^(\S+)\s+as\s+\((.*?)\)(.*)");
var entityInheritRegex = new Regex(@"^(\S+)\s+继承\s+(\S+)");
var descriptionCommentRegex = new Regex(@"^#\s*'(.*)'");
var ifcMapCommentRegex = new Regex(@"^#\s*IFC_MAP\s*=\s*'(.*)'");
var propCommentRegex = new Regex(@"^#\s*(\w+)\s*=\s*'(.*)'");
// 新增:专门用于匹配“类型标签”的正则表达式
var typeLabelRegex = new Regex(@"^(\S+)->类型标签\s*=\s*(.*)$");
foreach (var line in lines)
{
var trimmedLine = line.Trim();
if (trimmedLine.StartsWith("定义"))
{
state = ParserState.InDefinition;
currentEntity = new EntityDefinition();
mvdData.EntityDefinitions.Add(currentEntity);
continue;
}
if (trimmedLine.StartsWith("约束"))
{
state = ParserState.InConstraint;
currentConstraint = null;
continue;
}
if (trimmedLine.StartsWith("#BLOCK") || string.IsNullOrWhiteSpace(trimmedLine))
{
if (state == ParserState.InConstraint && currentEntity != null && currentConstraint != null && !string.IsNullOrEmpty(currentConstraint.Expression))
{
currentEntity.Constraints.Add(currentConstraint);
}
currentConstraint = null;
if (string.IsNullOrWhiteSpace(trimmedLine)) continue;
if (trimmedLine.StartsWith("#BLOCK"))
{
state = ParserState.Idle;
currentEntity = null;
continue;
}
}
switch (state)
{
case ParserState.Idle:
Match metaMatch = metaRegex.Match(trimmedLine);
if (metaMatch.Success)
{
mvdData.Metadata[metaMatch.Groups[1].Value.Trim()] = metaMatch.Groups[2].Value;
break;
}
Match aliasMatch = aliasRegex.Match(trimmedLine);
if (aliasMatch.Success)
{
mvdData.Aliases.Add(new Alias
{
Name = aliasMatch.Groups[1].Value,
SourceType = aliasMatch.Groups[2].Value,
Path = aliasMatch.Groups[3].Value.Trim()
});
}
break;
case ParserState.InDefinition:
Match descMatch = descriptionCommentRegex.Match(trimmedLine);
if (descMatch.Success)
{
currentEntity.Description = descMatch.Groups[1].Value;
break;
}
Match ifcMapMatch = ifcMapCommentRegex.Match(trimmedLine);
if (ifcMapMatch.Success)
{
currentEntity.IfcMap = ifcMapMatch.Groups[1].Value;
break;
}
// --- 新增逻辑:优先处理类型标签 ---
Match typeLabelMatch = typeLabelRegex.Match(trimmedLine);
if (typeLabelMatch.Success)
{
string allLabelsRaw = typeLabelMatch.Groups[2].Value;
// 使用正则表达式从长字符串中提取所有被单引号包裹的值
var labelMatches = Regex.Matches(allLabelsRaw, @"'([^']*)'");
var labels = labelMatches.Cast<Match>()
.Select(m => m.Groups[1].Value)
.ToList();
currentEntity.TypeLabels.AddRange(labels);
break; // 处理完毕,跳过此行后续逻辑
}
// --- 结束新增逻辑 ---
Match entityInheritMatch = entityInheritRegex.Match(trimmedLine);
if (entityInheritMatch.Success)
{
currentEntity.Name = entityInheritMatch.Groups[1].Value;
currentEntity.InheritsFrom = entityInheritMatch.Groups[2].Value;
}
else if (!trimmedLine.StartsWith("#"))
{
// 其他非注释行、非类型标签行,被视为普通条件
currentEntity.Conditions.Add(trimmedLine);
}
break;
case ParserState.InConstraint:
if (trimmedLine.StartsWith("#"))
{
Match constraintDescMatch = descriptionCommentRegex.Match(trimmedLine);
if (constraintDescMatch.Success)
{
if (currentEntity != null && currentConstraint != null && !string.IsNullOrEmpty(currentConstraint.Expression))
{
currentEntity.Constraints.Add(currentConstraint);
}
currentConstraint = new Constraint { Description = constraintDescMatch.Groups[1].Value };
}
else
{
Match propMatch = propCommentRegex.Match(trimmedLine);
if (propMatch.Success)
{
if (currentConstraint == null) currentConstraint = new Constraint();
currentConstraint.PropertyDictionary[propMatch.Groups[1].Value] = propMatch.Groups[2].Value;
}
}
}
else
{
if (currentConstraint == null)
{
currentConstraint = new Constraint();
}
currentConstraint.Expression = trimmedLine;
if (currentEntity != null)
{
currentEntity.Constraints.Add(currentConstraint);
}
currentConstraint = null;
}
break;
}
}
if (currentEntity != null && currentConstraint != null && !string.IsNullOrEmpty(currentConstraint.Expression))
{
currentEntity.Constraints.Add(currentConstraint);
}
return mvdData;
}
/// <summary>
/// 获取任意标识需要的所有属性
/// </summary>
/// <param name="data"></param>
/// <param name="labelName"></param>
/// <returns></returns>
public static List<Constraint> GetConstraintsByLabel(MvdData data, string labelName)
{
var result = new List<Constraint>();
var definitions = FindDefinitionsByTypeLabel(data, labelName);
foreach (var entity in definitions)
{
var constraints = entity.Constraints;
foreach (var cons in constraints)
{
if (string.IsNullOrEmpty(cons.PropName) || string.IsNullOrEmpty(cons.Description))
{
continue;
}
result.Add(cons);
//sb.AppendLine($"Entity: {entity.Name}, Property: {cons.PropName}, DefaultValue: {cons.ValueRange}");
}
}
return result;
}
/// <summary>
/// 按定义名称查找定义
/// </summary>
/// <param name="mvdData"></param>
/// <param name="name"></param>
/// <returns></returns>
public static EntityDefinition GetDefinitionByName(MvdData mvdData, string name)
{
if (mvdData == null || mvdData.EntityDefinitions == null || string.IsNullOrEmpty(name))
{
return null;
}
return mvdData.EntityDefinitions.FirstOrDefault(def => def.Name.Equals(name, StringComparison.OrdinalIgnoreCase));
}
/// <summary>
/// 按定义名称查找定义
/// </summary>
/// <param name="mvdData"></param>
/// <param name="name"></param>
/// <returns></returns>
public static EntityDefinition GetDefinitionByName(MvdData mvdData, string name, string inheritsFrom)
{
if (mvdData == null || mvdData.EntityDefinitions == null || string.IsNullOrEmpty(name))
{
return null;
}
return mvdData.EntityDefinitions.FirstOrDefault(def => def.Name.Equals(name, StringComparison.OrdinalIgnoreCase) && def.InheritsFrom.ToLower() == inheritsFrom.ToLower());
}
/// <summary>
/// 查找所有在其类型标签列表中包含指定名称的实体定义。
/// </summary>
/// <param name="mvdData">要搜索的数据源。</param>
/// <param name="labelToFind">要查找的类型标签名称。</param>
/// <param name="comparisonType">一个枚举值,指定比较字符串时是否区分大小写。默认为区分大小写。</param>
/// <returns>一个包含所有匹配的实体定义的列表。</returns>
public static List<EntityDefinition> FindDefinitionsByTypeLabel(
MvdData mvdData,
string labelToFind,
StringComparison comparisonType = StringComparison.Ordinal)
{
var allDefinitions = mvdData.EntityDefinitions;
// 如果输入为空,则返回一个空列表
if (allDefinitions == null || string.IsNullOrEmpty(labelToFind) || mvdData.EntityDefinitions.Count == 0)
{
return [];
}
// 使用 LINQ 进行高效查询:
// 遍历所有实体定义def
// 并在每个实体的 TypeLabels 列表中查找Any是否存在一个标签label
// 与要查找的标签labelToFind相等。
return [.. allDefinitions.Where(
def => def.TypeLabels.Any(label => label.Equals(labelToFind, comparisonType)))];
}
}