using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text.RegularExpressions; using Autodesk.AutoCAD.DatabaseServices; namespace CadParamPluging.Cad { public sealed class LayoutAnnotation { public string LayoutName { get; set; } public List DeliveryStatuses { get; set; } public List ProcessMethods { get; set; } public List StructuralFeatures { get; set; } public List SpecialConditions { get; set; } public LayoutAnnotation() { DeliveryStatuses = new List(); ProcessMethods = new List(); StructuralFeatures = new List(); SpecialConditions = new List(); } } public static class TemplateLayoutAnnotationExtractor { 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 List ExtractPerLayout(string templatePath) { if (string.IsNullOrWhiteSpace(templatePath)) { throw new ArgumentNullException(nameof(templatePath)); } var result = new List(); 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); var layoutName = layout.LayoutName; // 通常图纸在 PaperSpace,Model 不作为候选。 if (string.Equals(layoutName, "Model", StringComparison.OrdinalIgnoreCase)) { continue; } var ann = new LayoutAnnotation { LayoutName = layoutName }; var btr = (BlockTableRecord)tr.GetObject(layout.BlockTableRecordId, OpenMode.ForRead); var visitedBlocks = new HashSet(); foreach (ObjectId id in btr) { var obj = tr.GetObject(id, OpenMode.ForRead); if (obj is Entity ent) { ExtractInto(ent, tr, visitedBlocks, ann); } } Normalize(ann); if (HasAnyValue(ann)) { result.Add(ann); } } tr.Commit(); } } return result; } private static void ReadTemplateDatabase(Database db, string templatePath) { try { db.ReadDwgFile(templatePath, FileShare.ReadWrite, true, string.Empty); } catch (MissingMethodException) { db.ReadDwgFile(templatePath, FileOpenMode.OpenForReadAndAllShare, true, string.Empty); } } private static void ExtractInto(Entity ent, Transaction tr, HashSet visitedBlocks, LayoutAnnotation ann) { if (ent is DBText text) { ParseTextBlock(text.TextString, ann); return; } if (ent is MText mt) { var plain = SimplifyMText(mt.Contents); ParseTextBlock(plain, ann); return; } if (ent is BlockReference br) { foreach (ObjectId attId in br.AttributeCollection) { var att = tr.GetObject(attId, OpenMode.ForRead) as AttributeReference; if (att == null) { continue; } ParseTextBlock(att.TextString, ann); } // 说明文字可能在块定义内部(非属性),需要递归扫描块内容。 var blockId = br.BlockTableRecord; if (blockId.IsNull || visitedBlocks.Contains(blockId)) { return; } visitedBlocks.Add(blockId); var blockBtr = tr.GetObject(blockId, OpenMode.ForRead) as BlockTableRecord; if (blockBtr == null) { return; } foreach (ObjectId childId in blockBtr) { var child = tr.GetObject(childId, OpenMode.ForRead) as Entity; if (child != null) { ExtractInto(child, tr, visitedBlocks, ann); } } } } private static void ParseTextBlock(string text, LayoutAnnotation ann) { if (ann == null) { return; } var lines = SplitLines(text).ToList(); if (lines.Count == 0) { return; } var hasAnyField = false; foreach (var line in lines) { if (TryParseFieldLine(line, ann)) { hasAnyField = true; } } if (!hasAnyField) { return; } foreach (var line in lines) { if (IsSpecialConditionValueLine(line)) { ann.SpecialConditions.Add(NormalizeValue(line)); } } } 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 bool TryParseFieldLine(string line, LayoutAnnotation ann) { if (string.IsNullOrWhiteSpace(line)) { return false; } var m = FieldRegex.Match(line); if (!m.Success) { return false; } var key = m.Groups[1].Value; var val = (m.Groups[2].Value ?? string.Empty).Trim(); if (val.Length == 0) { return false; } val = NormalizeValue(val); switch (key) { case "交付状态": ann.DeliveryStatuses.Add(val); break; case "工艺方法": ann.ProcessMethods.Add(val); break; case "结构特征": ann.StructuralFeatures.Add(val); break; case "特殊条件": ann.SpecialConditions.Add(val); break; } return true; } private static bool IsSpecialConditionValueLine(string line) { if (string.IsNullOrWhiteSpace(line)) { return false; } // 特殊条件“最后一行”为不带冒号的单独值,且必须在同一文本块内已出现过字段行。 if (FieldRegex.IsMatch(line)) { return false; } return line.IndexOf(':') < 0 && line.IndexOf(':') < 0; } private static void Normalize(LayoutAnnotation ann) { ann.DeliveryStatuses = NormalizeList(ann.DeliveryStatuses); ann.ProcessMethods = NormalizeList(ann.ProcessMethods); ann.StructuralFeatures = NormalizeList(ann.StructuralFeatures); ann.SpecialConditions = NormalizeList(ann.SpecialConditions); } private static string NormalizeValue(string s) { if (string.IsNullOrWhiteSpace(s)) { return string.Empty; } var trimmed = s.Trim(); var chars = trimmed.Where(c => !char.IsWhiteSpace(c)).ToArray(); return new string(chars); } private static List NormalizeList(IEnumerable values) { var result = new List(); if (values == null) { return result; } var seen = new HashSet(StringComparer.OrdinalIgnoreCase); foreach (var raw in values) { var v = (raw ?? string.Empty).Trim(); if (v.Length == 0) { continue; } if (seen.Add(v)) { result.Add(v); } } return result; } private static bool HasAnyValue(LayoutAnnotation ann) { return ann != null && ((ann.DeliveryStatuses != null && ann.DeliveryStatuses.Count > 0) || (ann.ProcessMethods != null && ann.ProcessMethods.Count > 0) || (ann.StructuralFeatures != null && ann.StructuralFeatures.Count > 0) || (ann.SpecialConditions != null && ann.SpecialConditions.Count > 0)); } } }