using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text.RegularExpressions; using Autodesk.AutoCAD.DatabaseServices; using CadParamPluging.Common; namespace CadParamPluging.Cad { public sealed class TemplateAnnotationExtractionResult { public DropdownOptions Options { get; set; } public TemplateAnnotationExtractionSummary Summary { get; set; } } public sealed class TemplateAnnotationExtractionSummary { public int LayoutCountScanned { get; set; } public int EntityCountScanned { get; set; } public int TextObjectCountScanned { get; set; } public int MatchedLineCount { get; set; } } public static class TemplateAnnotationOptionsExtractor { private static readonly Regex FieldRegex = new Regex( @"^\s*(交付状态|工艺方法|结构特征)\s*[::]\s*(.+?)\s*$", RegexOptions.Compiled); private static readonly Regex MTextFormatRegex = new Regex(@"\\[A-Za-z]+[^;]*;", RegexOptions.Compiled); public static TemplateAnnotationExtractionResult Extract(string templatePath) { if (string.IsNullOrWhiteSpace(templatePath)) { throw new ArgumentNullException(nameof(templatePath)); } var options = new DropdownOptions(); var summary = new TemplateAnnotationExtractionSummary(); using (var db = new Database(false, true)) { ReadTemplateDatabase(db, templatePath); db.CloseInput(true); using (var tr = db.TransactionManager.StartTransaction()) { var layoutDict = (DBDictionary)tr.GetObject(db.LayoutDictionaryId, OpenMode.ForRead); foreach (DBDictionaryEntry entry in layoutDict) { var layout = (Layout)tr.GetObject(entry.Value, OpenMode.ForRead); summary.LayoutCountScanned++; var btr = (BlockTableRecord)tr.GetObject(layout.BlockTableRecordId, OpenMode.ForRead); foreach (ObjectId id in btr) { summary.EntityCountScanned++; var obj = tr.GetObject(id, OpenMode.ForRead); if (obj is Entity ent) { foreach (var line in ExtractLinesFromEntity(ent, tr, summary)) { TryParseLine(line, options, summary); } } } } tr.Commit(); } } options.Normalize(); return new TemplateAnnotationExtractionResult { Options = options, Summary = summary }; } private static void ReadTemplateDatabase(Database db, string templatePath) { // AutoCAD .NET 不同版本 ReadDwgFile 的重载参数略有差异,这里优先使用 FileShare 以允许文件被其它进程占用。 try { db.ReadDwgFile(templatePath, FileShare.ReadWrite, true, string.Empty); } catch (MissingMethodException) { db.ReadDwgFile(templatePath, FileOpenMode.OpenForReadAndAllShare, true, string.Empty); } } private static IEnumerable ExtractLinesFromEntity(Entity ent, Transaction tr, TemplateAnnotationExtractionSummary summary) { if (ent is DBText text) { summary.TextObjectCountScanned++; return SplitLines(text.TextString); } if (ent is MText mt) { summary.TextObjectCountScanned++; var plain = SimplifyMText(mt.Contents); return SplitLines(plain); } if (ent is BlockReference br) { var lines = new List(); foreach (ObjectId attId in br.AttributeCollection) { var att = tr.GetObject(attId, OpenMode.ForRead) as AttributeReference; if (att == null) { continue; } summary.TextObjectCountScanned++; lines.AddRange(SplitLines(att.TextString)); } return lines; } return Enumerable.Empty(); } private static IEnumerable SplitLines(string text) { if (string.IsNullOrWhiteSpace(text)) { return Enumerable.Empty(); } return (text ?? string.Empty) .Replace("\r\n", "\n") .Replace("\r", "\n") .Split(new[] { '\n' }, StringSplitOptions.RemoveEmptyEntries) .Select(s => (s ?? string.Empty).Trim()) .Where(s => s.Length > 0); } private static string SimplifyMText(string contents) { if (string.IsNullOrEmpty(contents)) { return string.Empty; } var s = contents .Replace("\\P", "\n") .Replace("\\p", "\n") .Replace("\\~", " "); s = s.Replace("{", string.Empty).Replace("}", string.Empty); s = MTextFormatRegex.Replace(s, string.Empty); return s; } private static void TryParseLine(string line, DropdownOptions options, TemplateAnnotationExtractionSummary summary) { if (string.IsNullOrWhiteSpace(line)) { return; } var m = FieldRegex.Match(line); if (!m.Success) { return; } var key = m.Groups[1].Value; var rawVal = m.Groups[2].Value; var values = SplitValues(rawVal); if (values.Count == 0) { return; } summary.MatchedLineCount++; switch (key) { case "交付状态": options.DeliveryStatuses.AddRange(values); break; case "工艺方法": options.ProcessMethods.AddRange(values); break; case "结构特征": options.StructuralFeatures.AddRange(values); break; } } private static List SplitValues(string raw) { if (string.IsNullOrWhiteSpace(raw)) { return new List(); } var parts = Regex.Split(raw, @"\s*[;;,,\|、/]+\s*") .Select(s => (s ?? string.Empty).Trim()) .Where(s => s.Length > 0) .ToList(); return parts; } } }