397 lines
16 KiB
C#
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; } = "";
|
|
}
|
|
} |