Files
manual_wpf/Models/DwgDataExtractor.cs

397 lines
16 KiB
C#

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading;
using Teigha.DatabaseServices;
using Teigha.Runtime;
namespace DwgExtractorManual.Models
{
/// <summary>
/// DWG 파일에서 텍스트 엔티티를 추출하는 클래스
/// </summary>
internal class DwgDataExtractor
{
private readonly FieldMapper fieldMapper;
public DwgDataExtractor(FieldMapper fieldMapper)
{
this.fieldMapper = fieldMapper ?? throw new ArgumentNullException(nameof(fieldMapper));
}
/// <summary>
/// DWG 파일에서 데이터를 추출하여 ExcelRowData 리스트로 반환
/// </summary>
public DwgExtractionResult ExtractFromDwgFile(string filePath, IProgress<double>? progress = null, CancellationToken cancellationToken = default)
{
var result = new DwgExtractionResult();
if (!File.Exists(filePath))
{
Debug.WriteLine($"? 파일이 존재하지 않습니다: {filePath}");
return result;
}
try
{
progress?.Report(0);
cancellationToken.ThrowIfCancellationRequested();
using (var database = new Database(false, true))
{
database.ReadDwgFile(filePath, FileOpenMode.OpenForReadAndWriteNoShare, false, null);
progress?.Report(10);
using (var tran = database.TransactionManager.StartTransaction())
{
var bt = tran.GetObject(database.BlockTableId, OpenMode.ForRead) as BlockTable;
using (var btr = tran.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForRead) as BlockTableRecord)
{
int totalEntities = btr.Cast<ObjectId>().Count();
int processedCount = 0;
var fileName = Path.GetFileNameWithoutExtension(database.Filename);
if (string.IsNullOrEmpty(fileName))
{
fileName = "Unknown_File";
}
foreach (ObjectId entId in btr)
{
cancellationToken.ThrowIfCancellationRequested();
using (var ent = tran.GetObject(entId, OpenMode.ForRead) as Entity)
{
string layerName = GetLayerName(ent.LayerId, tran, database);
ProcessEntity(ent, tran, database, layerName, fileName, result);
}
processedCount++;
double currentProgress = 10.0 + (double)processedCount / totalEntities * 80.0;
progress?.Report(Math.Min(currentProgress, 90.0));
}
}
tran.Commit();
}
}
progress?.Report(100);
return result;
}
catch (OperationCanceledException)
{
Debug.WriteLine("? 작업이 취소되었습니다.");
progress?.Report(0);
return result;
}
catch (Teigha.Runtime.Exception ex)
{
progress?.Report(0);
Debug.WriteLine($"? DWG 파일 처리 중 Teigha 오류 발생: {ex.Message}");
return result;
}
catch (System.Exception ex)
{
progress?.Report(0);
Debug.WriteLine($"? 일반 오류 발생: {ex.Message}");
return result;
}
}
/// <summary>
/// DWG 파일에서 텍스트 엔티티들을 추출하여 Height 정보와 함께 반환합니다.
/// </summary>
public List<TextEntityInfo> ExtractTextEntitiesWithHeight(string filePath)
{
var attRefEntities = new List<TextEntityInfo>();
var otherTextEntities = new List<TextEntityInfo>();
try
{
using (var database = new Database(false, true))
{
database.ReadDwgFile(filePath, FileOpenMode.OpenForReadAndWriteNoShare, false, null);
using (var tran = database.TransactionManager.StartTransaction())
{
var bt = tran.GetObject(database.BlockTableId, OpenMode.ForRead) as BlockTable;
using (var btr = tran.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForRead) as BlockTableRecord)
{
foreach (ObjectId entId in btr)
{
using (var ent = tran.GetObject(entId, OpenMode.ForRead) as Entity)
{
string layerName = GetLayerName(ent.LayerId, tran, database);
// AttributeReference 처리
if (ent is BlockReference blr)
{
foreach (ObjectId attId in blr.AttributeCollection)
{
using (var attRef = tran.GetObject(attId, OpenMode.ForRead) as AttributeReference)
{
if (attRef != null)
{
var textString = attRef.TextString == null ? "" : attRef.TextString;
attRefEntities.Add(new TextEntityInfo
{
Height = attRef.Height,
Type = "AttRef",
Layer = layerName,
Tag = attRef.Tag,
Text = textString,
});
}
}
}
}
// DBText 처리
else if (ent is DBText dbText)
{
otherTextEntities.Add(new TextEntityInfo
{
Height = dbText.Height,
Type = "DBText",
Layer = layerName,
Tag = "",
Text = dbText.TextString
});
}
// MText 처리
else if (ent is MText mText)
{
otherTextEntities.Add(new TextEntityInfo
{
Height = mText.Height,
Type = "MText",
Layer = layerName,
Tag = "",
Text = mText.Contents
});
}
}
}
}
tran.Commit();
}
}
}
catch (System.Exception ex)
{
Debug.WriteLine($"? 텍스트 엔티티 추출 중 오류 ({Path.GetFileName(filePath)}): {ex.Message}");
}
var sortedAttRefEntities = attRefEntities.OrderByDescending(e => e.Height).ToList();
var sortedOtherTextEntities = otherTextEntities.OrderByDescending(e => e.Height).ToList();
sortedAttRefEntities.AddRange(sortedOtherTextEntities);
return sortedAttRefEntities;
}
private void ProcessEntity(Entity ent, Transaction tran, Database database, string layerName, string fileName, DwgExtractionResult result)
{
// AttributeDefinition 추출
if (ent is AttributeDefinition attDef)
{
var titleBlockRow = new TitleBlockRowData
{
Type = attDef.GetType().Name,
Name = attDef.BlockName,
Tag = attDef.Tag,
Prompt = attDef.Prompt,
Value = attDef.TextString,
Path = database.Filename,
FileName = Path.GetFileName(database.Filename)
};
result.TitleBlockRows.Add(titleBlockRow);
// 매핑 데이터 저장
AddMappingData(fileName, attDef.Tag, attDef.TextString, result);
}
// BlockReference 및 그 안의 AttributeReference 추출
else if (ent is BlockReference blr)
{
foreach (ObjectId attId in blr.AttributeCollection)
{
using (var attRef = tran.GetObject(attId, OpenMode.ForRead) as AttributeReference)
{
if (attRef != null && attRef.TextString.Trim() != "")
{
var titleBlockRow = new TitleBlockRowData
{
Type = attRef.GetType().Name,
Name = blr.Name,
Tag = attRef.Tag,
Prompt = GetPromptFromAttributeReference(tran, blr, attRef.Tag),
Value = attRef.TextString,
Path = database.Filename,
FileName = Path.GetFileName(database.Filename)
};
result.TitleBlockRows.Add(titleBlockRow);
// 매핑 데이터 저장
var aiLabel = fieldMapper.ExpresswayToAilabel(attRef.Tag);
if (aiLabel != null)
{
AddMappingData(fileName, attRef.Tag, attRef.TextString, result);
}
}
}
}
}
// DBText 엔티티 추출 (별도 시트)
else if (ent is DBText dbText)
{
var textEntityRow = new TextEntityRowData
{
Type = "DBText",
Layer = layerName,
Text = dbText.TextString,
Path = database.Filename,
FileName = Path.GetFileName(database.Filename)
};
result.TextEntityRows.Add(textEntityRow);
}
// MText 엔티티 추출 (별도 시트)
else if (ent is MText mText)
{
var textEntityRow = new TextEntityRowData
{
Type = "MText",
Layer = layerName,
Text = mText.Contents,
Path = database.Filename,
FileName = Path.GetFileName(database.Filename)
};
result.TextEntityRows.Add(textEntityRow);
}
}
private void AddMappingData(string fileName, string tag, string attValue, DwgExtractionResult result)
{
var aiLabel = fieldMapper.ExpresswayToAilabel(tag);
var mapKey = fieldMapper.AilabelToDocAiKey(aiLabel);
if (!string.IsNullOrEmpty(aiLabel))
{
var finalMapKey = mapKey ?? aiLabel;
result.AddMappingData(fileName, finalMapKey, aiLabel, tag, attValue, "");
}
else
{
var finalMapKey = mapKey ?? tag;
if (!string.IsNullOrEmpty(finalMapKey))
{
result.AddMappingData(fileName, finalMapKey, tag, tag, attValue, "");
}
}
}
private string? GetPromptFromAttributeReference(Transaction tr, BlockReference blockref, string tag)
{
string? prompt = null;
BlockTableRecord? blockDef = tr.GetObject(blockref.BlockTableRecord, OpenMode.ForRead) as BlockTableRecord;
if (blockDef == null) return null;
foreach (ObjectId objId in blockDef)
{
AttributeDefinition? attDef = tr.GetObject(objId, OpenMode.ForRead) as AttributeDefinition;
if (attDef != null)
{
if (attDef.Tag.Equals(tag, System.StringComparison.OrdinalIgnoreCase))
{
prompt = attDef.Prompt;
break;
}
}
}
return prompt;
}
private string GetLayerName(ObjectId layerId, Transaction transaction, Database database)
{
try
{
using (var layerTableRecord = transaction.GetObject(layerId, OpenMode.ForRead) as LayerTableRecord)
{
return layerTableRecord?.Name ?? "";
}
}
catch (System.Exception ex)
{
Debug.WriteLine($"Layer 이름 가져오기 오류: {ex.Message}");
return "";
}
}
}
/// <summary>
/// DWG 추출 결과를 담는 클래스
/// </summary>
public class DwgExtractionResult
{
public List<TitleBlockRowData> TitleBlockRows { get; set; } = new List<TitleBlockRowData>();
public List<TextEntityRowData> TextEntityRows { get; set; } = new List<TextEntityRowData>();
public Dictionary<string, Dictionary<string, (string, string, string, string)>> FileToMapkeyToLabelTagValuePdf { get; set; }
= new Dictionary<string, Dictionary<string, (string, string, string, string)>>();
public void AddMappingData(string fileName, string mapKey, string aiLabel, string dwgTag, string dwgValue, string pdfValue)
{
if (!FileToMapkeyToLabelTagValuePdf.ContainsKey(fileName))
{
FileToMapkeyToLabelTagValuePdf[fileName] = new Dictionary<string, (string, string, string, string)>();
}
FileToMapkeyToLabelTagValuePdf[fileName][mapKey] = (aiLabel, dwgTag, dwgValue, pdfValue);
}
}
/// <summary>
/// Title Block 행 데이터
/// </summary>
public class TitleBlockRowData
{
public string Type { get; set; } = "";
public string Name { get; set; } = "";
public string Tag { get; set; } = "";
public string Prompt { get; set; } = "";
public string Value { get; set; } = "";
public string Path { get; set; } = "";
public string FileName { get; set; } = "";
}
/// <summary>
/// Text Entity 행 데이터
/// </summary>
public class TextEntityRowData
{
public string Type { get; set; } = "";
public string Layer { get; set; } = "";
public string Text { get; set; } = "";
public string Path { get; set; } = "";
public string FileName { get; set; } = "";
}
/// <summary>
/// 텍스트 엔티티 정보를 담는 클래스
/// </summary>
public class TextEntityInfo
{
public double Height { get; set; }
public string Type { get; set; } = "";
public string Layer { get; set; } = "";
public string Tag { get; set; } = "";
public string Text { get; set; } = "";
}
}