using System.ComponentModel;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows;
using System.Windows.Markup;
using Autodesk.Revit.Attributes;
using Autodesk.Revit.DB;
using Autodesk.Revit.DB.Structure;
using FuzzySharp;
using JiebaNet.Segmenter;
using Microsoft.Win32;
using Nice3point.Revit.Toolkit.External;
using Szmedi.RevitToolkit.Approval.Controls.ProgressWrapper;
using Szmedi.RevitToolkit.Approval.Models;
namespace Szmedi.RevitToolkit.Approval.Commands
{
///
/// 建筑标识预处理
///
[Transaction(TransactionMode.Manual)]
[Regeneration(RegenerationOption.Manual)]
public class ProcessArchiSignCmd : ExternalCommand
{
private Major major;
private string majorName;
public override void Execute()
{
StringBuilder sb = new StringBuilder();
const string signParam = "深圳构件标识";
var dir = Path.Combine(GlobalAssists.DirAssembly, "mvdlite");
major = Document.GetMajor(out majorName);
var result = MessageBox.Show(
$"""
通过各专业专业独有的构件
(建筑-门窗,结构-梁,暖通-风管,电气-桥架,给排水-无风管有水管)
当前专业为:{majorName},
是 - 继续,否 - 手动选择mvdlite文件
""",
"提示",
MessageBoxButton.YesNoCancel,
MessageBoxImage.Question);
string fileContent;
if (result == MessageBoxResult.Yes)
{
fileContent = Directory.GetFiles(dir, "*.mvdlite")
.FirstOrDefault(f => f.Contains(majorName)) switch
{
string file when !string.IsNullOrEmpty(file) => File.ReadAllText(file),
_ => throw new FileNotFoundException("未找到对应的MVDLite文件,请检查目录或文件名。")
};
}
else if (result == MessageBoxResult.No)
{
OpenFileDialog dialog = new OpenFileDialog()
{
Filter = "MVDLite 文件 (*.mvdlite)|*.mvdlite",
Title = "选择 MVDLite 文件",
InitialDirectory = dir,
RestoreDirectory = true
};
if (dialog.ShowDialog() != true)
{
return;
}
fileContent = File.ReadAllText(dialog.FileName);
}
else
{
return;
}
Document.InvokeGroup(
_ =>
{
if (!NeedRemoveParameter(signParam))
{
return;
}
var componentSignSet = UiApplication.Application.Create.NewCategorySet();
var builtInCategories = Enum.GetValues(typeof(BuiltInCategory));
foreach (BuiltInCategory cate in builtInCategories)
{
try
{
var category = Category.GetCategory(Document, cate);
if (category is { CategoryType: CategoryType.Model, AllowsBoundParameters: true })
{
if (cate == BuiltInCategory.OST_Rooms || cate == BuiltInCategory.OST_Areas)
{
continue; //空间和区域不需要标识
}
componentSignSet.Insert(category);
}
}
//有的类别不支持这个方法获取
catch (Exception)
{
//sb.AppendLine($"{ex.Message}:{cate}");
}
}
Document.AddSharedParameter(signParam, componentSignSet, BuiltInParameterGroup.PG_IFC);
var allElements = Document.OfParentModelCollector().ToElements();
try
{
//sb.AppendLine($"标识,优化标识,匹配,比率,");
MvdData data = MvdLiteAssist.Parse(fileContent);
var groups = allElements.GroupBy(e => e.GetTypeId());
Document.Invoke(
_ =>
{
foreach (var g in groups)
{
string mapperName = GetMapperSign(g, data);
//if (elementGroup.Key == ElementId.InvalidElementId)//可能是地形
//{
// string name = string.Empty;
// if (elementGroup.FirstOrDefault().Category != null)
// {
// name = elementGroup.FirstOrDefault().Category.name;
// }
// else
// {
// name = elementGroup.FirstOrDefault().name;
// }
// mapperName = GetMapperSign(name, data);
//}
//else
//{
// mapperName = GetMapperSign(type.name, data);
// if (string.IsNullOrEmpty(mapperName))//如果类型名找不到标识,使用族名称
// {
// mapperName = GetMapperSign(type.FamilyName, data);
// }
//}
foreach (var elem in g)
{
var param = elem.LookupParameter(signParam);
param.SetValue(mapperName);
}
}
}, $"填写标识");
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}, $"填写 {majorName} 构件标识");
MessageBox.Show("处理完成", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
//File.WriteAllText(Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + "\\匹配结果" + ".csv",
// sb.ToString(), Encoding.UTF8);
}
class Mapper(string name, string sign, int ratio)
{
public string Name { get; } = name;
public string Sign { get; } = sign;
public int Ratio { get; } = ratio;
public override string ToString()
{
return $"{Name} - {Sign} ({Ratio})";
}
}
//private StringBuilder sb = new StringBuilder();
//private List Mappers { get; componentSignSet; } = new List();
private string GetMapperSign(IGrouping elementGroup, MvdData data)
{
if (elementGroup.Key == ElementId.InvalidElementId)
{
return string.Empty;
}
var definitions = MvdLiteAssist.GetElementSigns(data);
var categoryName = elementGroup.FirstOrDefault().Category?.Name;
//如果没有匹配到,使用类型名进行匹配
var type = Document.GetElement(elementGroup.Key) as ElementType;
var famName = type.FamilyName;
ConfigManager.ConfigFileBaseDir = Path.Combine(RvApp.AddInDirectory, "configs");
var segmenter = new JiebaSegmenter();
var subText = $"{type.Name} {famName} {categoryName}";
var replaceText = subText.ExtractChinese();
var segments = segmenter.Cut(replaceText).Distinct();
var combinedText = string.Join(" ", segments);
string resultName = string.Empty;
double minRatio = 30;
foreach (var defin in definitions)
{
var defText = defin.Replace(majorName, "");
var segmentsDef = segmenter.Cut(defText);
defText = string.Join(" ", segmentsDef);
var tempRatio = Fuzz.TokenSetRatio(defText, combinedText);
//var tempRatio = Fuzz.Ratio(defin, segment);
if (tempRatio >= minRatio)
{
//sb.AppendLine($"{defin},{defText},{combinedText},{tempRatio},");
minRatio = tempRatio;
resultName = defin;
}
}
return resultName;
}
//private static string ExtractChinese(string text)
//{
// if (string.IsNullOrEmpty(text)) return string.Empty;
// // 方法1:正则(简单常用)
// return Regex.Replace(text, @"[^\u4e00-\u9fa5]", "");
// // 方法2:遍历(可扩展)
// // var sb = new StringBuilder();
// // foreach (char c in text)
// // if (c >= 0x4e00 && c <= 0x9fa5)
// // sb.Append(c);
// // return sb.ToString();
//}
///
/// 清理字符串中的括号、下划线、减号、加号等符号
///
/// 原始字符串
/// 清理后的字符串
public static string CleanSpecialChars(string input, string replacestr = " ")
{
if (string.IsNullOrEmpty(input))
return input;
// 正则模式说明:
// [()\[\]{}<>_-+] 匹配以下符号:
// 圆括号 ()、方括号 []、花括号 {}、尖括号 <>、下划线 _、减号 -、加号 +
// 注意:方括号内的特殊字符(如 [ ] - )需要转义或放在安全位置(如末尾)
string pattern = @"[()\[\]{}<>_+-]";
return Regex.Replace(input, pattern, replacestr);
}
private string GetBestMatchingSign(IGrouping g, HashSet definitions, string categoryName, string famName, ref string resultName)
{
//初步匹配
List strings = [];
if (major == Major.Architecture || major == Major.Structure || major == Major.MasterPlan)
{
int mapperRatio = 30;
foreach (var mapper in definitions)
{
//var sourceIndex = Levenshtein.GetMatchingBlocks(mapper, categoryName).FirstOrDefault().SourcePos;
//var pos = mapper.Length - sourceIndex;
var tempRatio = Fuzz.WeightedRatio(mapper, $"{categoryName}");
if (tempRatio > 30)
{
if (tempRatio > mapperRatio)
{
mapperRatio = tempRatio;
resultName = mapper;
}
strings.Add(mapper);
}
}
}
else
{
strings = [.. definitions];
}
var subText = g.FirstOrDefault().Name;
var replaceText = subText.Replace('-', ' ').Replace('_', ' ').Replace('—', ' ');
var combinedText = $"{famName} {replaceText}";
int minRatio = 20;
foreach (var defin in strings)
{
//var tempRatio = Fuzz.TokenSortRatio(defin, replaceText);
var tempRatio = Fuzz.WeightedRatio(defin, combinedText);
if (tempRatio > minRatio)
{
//Mappers.Add(new(replaceText, defin, tempRatio));
minRatio = tempRatio;
resultName = defin;
}
}
//if (string.IsNullOrEmpty(resultName))
//{
// resultName = "无标识";
//}
return resultName;
}
///
/// 需要移除现有的标识参数
///
///
///
private bool NeedRemoveParameter(string paramName)
{
var dict = SharedParameterAssists.GetParameterElementBindings(Document)
.Where(d => d.Key.Name == paramName);
if (dict.Any())
{
var result = MessageBox.Show(
$"已存在一个或多个{paramName}的参数定义,将全部进行删除,并重新添加,是否继续?",
"警告",
MessageBoxButton.YesNo,
MessageBoxImage.Warning);
if (result == MessageBoxResult.Yes)
{
Document.Invoke(
_ =>
{
Document.Delete(dict.Select(d => d.Key).Select(p => p.Id).ToList());
},
$"删除现有{paramName}参数");
}
else
{
return false;
}
}
return true;
}
}
}