219 lines
7.1 KiB
C#
219 lines
7.1 KiB
C#
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;
|
||
}
|
||
}
|
||
}
|