CadParamPluging/Cad/TemplateAnnotationOptionsExtractor.cs

219 lines
7.1 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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<string> 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<string>();
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<string>();
}
private static IEnumerable<string> SplitLines(string text)
{
if (string.IsNullOrWhiteSpace(text))
{
return Enumerable.Empty<string>();
}
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<string> SplitValues(string raw)
{
if (string.IsNullOrWhiteSpace(raw))
{
return new List<string>();
}
var parts = Regex.Split(raw, @"\s*[;,\|、/]+\s*")
.Select(s => (s ?? string.Empty).Trim())
.Where(s => s.Length > 0)
.ToList();
return parts;
}
}
}