노트별 분리
This commit is contained in:
@@ -5,12 +5,13 @@ using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using Teigha.DatabaseServices;
|
||||
using Teigha.Geometry;
|
||||
using Teigha.Runtime;
|
||||
|
||||
namespace DwgExtractorManual.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// DWG <20><><EFBFBD>Ͽ<EFBFBD><CFBF><EFBFBD> <20>ؽ<EFBFBD>Ʈ <20><>ƼƼ<C6BC><C6BC> <20><><EFBFBD><EFBFBD><EFBFBD>ϴ<EFBFBD> Ŭ<><C5AC><EFBFBD><EFBFBD>
|
||||
/// DWG <20><><EFBFBD>Ͽ<EFBFBD><CFBF><EFBFBD> <20>ؽ<EFBFBD>Ʈ <20><>ƼƼ<C6BC><C6BC> <20><><EFBFBD><EFBFBD><EFBFBD>ϴ<EFBFBD> Ŭ<><C5AC><EFBFBD><EFBFBD>
|
||||
/// </summary>
|
||||
internal class DwgDataExtractor
|
||||
{
|
||||
@@ -22,7 +23,7 @@ namespace DwgExtractorManual.Models
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// DWG <20><><EFBFBD>Ͽ<EFBFBD><CFBF><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>Ͽ<EFBFBD> ExcelRowData <20><><EFBFBD><EFBFBD>Ʈ<EFBFBD><C6AE> <20><>ȯ
|
||||
/// DWG <20><><EFBFBD>Ͽ<EFBFBD><CFBF><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>Ͽ<EFBFBD> ExcelRowData <20><><EFBFBD><EFBFBD>Ʈ<EFBFBD><C6AE> <20><>ȯ
|
||||
/// </summary>
|
||||
public DwgExtractionResult ExtractFromDwgFile(string filePath, IProgress<double>? progress = null, CancellationToken cancellationToken = default)
|
||||
{
|
||||
@@ -30,7 +31,7 @@ namespace DwgExtractorManual.Models
|
||||
|
||||
if (!File.Exists(filePath))
|
||||
{
|
||||
Debug.WriteLine($"? <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>ʽ<EFBFBD><CABD>ϴ<EFBFBD>: {filePath}");
|
||||
Debug.WriteLine($"? <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>ʽ<EFBFBD><CABD>ϴ<EFBFBD>: {filePath}");
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -84,26 +85,26 @@ namespace DwgExtractorManual.Models
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
Debug.WriteLine("? <20>۾<EFBFBD><DBBE><EFBFBD> <20><><EFBFBD>ҵǾ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ϴ<EFBFBD>.");
|
||||
Debug.WriteLine("? <20>۾<EFBFBD><DBBE><EFBFBD> <20><>ҵǾ<D2B5><C7BE><EFBFBD><EFBFBD>ϴ<EFBFBD>.");
|
||||
progress?.Report(0);
|
||||
return result;
|
||||
}
|
||||
catch (Teigha.Runtime.Exception ex)
|
||||
{
|
||||
progress?.Report(0);
|
||||
Debug.WriteLine($"? DWG <20><><EFBFBD><EFBFBD> ó<><C3B3> <20><> Teigha <20><><EFBFBD><EFBFBD> <20><EFBFBD>: {ex.Message}");
|
||||
Debug.WriteLine($"? DWG <20><><EFBFBD><EFBFBD> ó<><C3B3> <20><> Teigha <20><><EFBFBD><EFBFBD> <20><EFBFBD>: {ex.Message}");
|
||||
return result;
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
progress?.Report(0);
|
||||
Debug.WriteLine($"? <20>Ϲ<EFBFBD> <20><><EFBFBD><EFBFBD> <20><EFBFBD>: {ex.Message}");
|
||||
Debug.WriteLine($"? <20>Ϲ<EFBFBD> <20><><EFBFBD><EFBFBD> <20><EFBFBD>: {ex.Message}");
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// DWG <20><><EFBFBD>Ͽ<EFBFBD><CFBF><EFBFBD> <20>ؽ<EFBFBD>Ʈ <20><>ƼƼ<C6BC><C6BC><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>Ͽ<EFBFBD> Height <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>Բ<EFBFBD> <20><>ȯ<EFBFBD>մϴ<D5B4>.
|
||||
/// DWG <20><><EFBFBD>Ͽ<EFBFBD><CFBF><EFBFBD> <20>ؽ<EFBFBD>Ʈ <20><>ƼƼ<C6BC><C6BC><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>Ͽ<EFBFBD> Height <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>Բ<EFBFBD> <20><>ȯ<EFBFBD>մϴ<D5B4>.
|
||||
/// </summary>
|
||||
public List<TextEntityInfo> ExtractTextEntitiesWithHeight(string filePath)
|
||||
{
|
||||
@@ -127,7 +128,7 @@ namespace DwgExtractorManual.Models
|
||||
{
|
||||
string layerName = GetLayerName(ent.LayerId, tran, database);
|
||||
|
||||
// AttributeReference ó<><C3B3>
|
||||
// AttributeReference ó<><C3B3>
|
||||
if (ent is BlockReference blr)
|
||||
{
|
||||
foreach (ObjectId attId in blr.AttributeCollection)
|
||||
@@ -149,7 +150,7 @@ namespace DwgExtractorManual.Models
|
||||
}
|
||||
}
|
||||
}
|
||||
// DBText ó<><C3B3>
|
||||
// DBText ó<><C3B3>
|
||||
else if (ent is DBText dbText)
|
||||
{
|
||||
otherTextEntities.Add(new TextEntityInfo
|
||||
@@ -161,7 +162,7 @@ namespace DwgExtractorManual.Models
|
||||
Text = dbText.TextString
|
||||
});
|
||||
}
|
||||
// MText ó<><C3B3>
|
||||
// MText ó<><C3B3>
|
||||
else if (ent is MText mText)
|
||||
{
|
||||
otherTextEntities.Add(new TextEntityInfo
|
||||
@@ -183,7 +184,7 @@ namespace DwgExtractorManual.Models
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
Debug.WriteLine($"? <20>ؽ<EFBFBD>Ʈ <20><>ƼƼ <20><><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD> ({Path.GetFileName(filePath)}): {ex.Message}");
|
||||
Debug.WriteLine($"? <20>ؽ<EFBFBD>Ʈ <20><>ƼƼ <20><><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD> ({Path.GetFileName(filePath)}): {ex.Message}");
|
||||
}
|
||||
|
||||
var sortedAttRefEntities = attRefEntities.OrderByDescending(e => e.Height).ToList();
|
||||
@@ -195,7 +196,7 @@ namespace DwgExtractorManual.Models
|
||||
|
||||
private void ProcessEntity(Entity ent, Transaction tran, Database database, string layerName, string fileName, DwgExtractionResult result)
|
||||
{
|
||||
// AttributeDefinition <20><><EFBFBD><EFBFBD>
|
||||
// AttributeDefinition <20><><EFBFBD><EFBFBD>
|
||||
if (ent is AttributeDefinition attDef)
|
||||
{
|
||||
var titleBlockRow = new TitleBlockRowData
|
||||
@@ -211,10 +212,10 @@ namespace DwgExtractorManual.Models
|
||||
|
||||
result.TitleBlockRows.Add(titleBlockRow);
|
||||
|
||||
// <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>
|
||||
// <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>
|
||||
AddMappingData(fileName, attDef.Tag, attDef.TextString, result);
|
||||
}
|
||||
// BlockReference <20><> <20><> <20><><EFBFBD><EFBFBD> AttributeReference <20><><EFBFBD><EFBFBD>
|
||||
// BlockReference <20><> <20><> <20><><EFBFBD><EFBFBD> AttributeReference <20><><EFBFBD><EFBFBD>
|
||||
else if (ent is BlockReference blr)
|
||||
{
|
||||
foreach (ObjectId attId in blr.AttributeCollection)
|
||||
@@ -236,7 +237,7 @@ namespace DwgExtractorManual.Models
|
||||
|
||||
result.TitleBlockRows.Add(titleBlockRow);
|
||||
|
||||
// <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>
|
||||
// <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>
|
||||
var aiLabel = fieldMapper.ExpresswayToAilabel(attRef.Tag);
|
||||
if (aiLabel != null)
|
||||
{
|
||||
@@ -246,7 +247,7 @@ namespace DwgExtractorManual.Models
|
||||
}
|
||||
}
|
||||
}
|
||||
// DBText <20><>ƼƼ <20><><EFBFBD><EFBFBD> (<28><><EFBFBD><EFBFBD> <20><>Ʈ)
|
||||
// DBText <20><>ƼƼ <20><><EFBFBD><EFBFBD> (<28><><EFBFBD><EFBFBD> <20><>Ʈ)
|
||||
else if (ent is DBText dbText)
|
||||
{
|
||||
var textEntityRow = new TextEntityRowData
|
||||
@@ -260,7 +261,7 @@ namespace DwgExtractorManual.Models
|
||||
|
||||
result.TextEntityRows.Add(textEntityRow);
|
||||
}
|
||||
// MText <20><>ƼƼ <20><><EFBFBD><EFBFBD> (<28><><EFBFBD><EFBFBD> <20><>Ʈ)
|
||||
// MText <20><>ƼƼ <20><><EFBFBD><EFBFBD> (<28><><EFBFBD><EFBFBD> <20><>Ʈ)
|
||||
else if (ent is MText mText)
|
||||
{
|
||||
var textEntityRow = new TextEntityRowData
|
||||
@@ -330,14 +331,607 @@ namespace DwgExtractorManual.Models
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
Debug.WriteLine($"Layer <20≯<EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>: {ex.Message}");
|
||||
Debug.WriteLine($"Layer <20≯<EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>: {ex.Message}");
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 도면에서 Note와 관련된 텍스트들을 추출합니다.
|
||||
/// </summary>
|
||||
public List<NoteEntityInfo> ExtractNotesFromDrawing(string filePath)
|
||||
{
|
||||
var noteEntities = new List<NoteEntityInfo>();
|
||||
|
||||
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)
|
||||
{
|
||||
var allEntities = btr.Cast<ObjectId>().ToList();
|
||||
var dbTextIds = new List<ObjectId>();
|
||||
var polylineIds = new List<ObjectId>();
|
||||
var lineIds = new List<ObjectId>();
|
||||
|
||||
// 먼저 모든 관련 엔터티들의 ObjectId를 수집
|
||||
foreach (ObjectId entId in allEntities)
|
||||
{
|
||||
using (var ent = tran.GetObject(entId, OpenMode.ForRead) as Entity)
|
||||
{
|
||||
if (ent is DBText)
|
||||
{
|
||||
dbTextIds.Add(entId);
|
||||
}
|
||||
else if (ent is Polyline)
|
||||
{
|
||||
polylineIds.Add(entId);
|
||||
}
|
||||
else if (ent is Line)
|
||||
{
|
||||
lineIds.Add(entId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Debug.WriteLine($"[DEBUG] 수집된 엔터티: DBText={dbTextIds.Count}, Polyline={polylineIds.Count}, Line={lineIds.Count}");
|
||||
|
||||
// Note 텍스트들을 찾기
|
||||
var noteTextIds = FindNoteTexts(tran, dbTextIds);
|
||||
Debug.WriteLine($"[DEBUG] 발견된 Note 텍스트: {noteTextIds.Count}개");
|
||||
|
||||
// Note 그룹들을 저장할 리스트 (각 그룹은 NOTE 헤더 + 내용들)
|
||||
var noteGroups = new List<List<NoteEntityInfo>>();
|
||||
|
||||
// 이미 사용된 박스들을 추적 (중복 할당 방지)
|
||||
var usedBoxes = new HashSet<(Point3d minPoint, Point3d maxPoint)>();
|
||||
|
||||
// 각 Note에 대해 처리
|
||||
foreach (var noteTextId in noteTextIds)
|
||||
{
|
||||
using (var noteText = tran.GetObject(noteTextId, OpenMode.ForRead) as DBText)
|
||||
{
|
||||
Debug.WriteLine($"[DEBUG] Note 처리 중: '{noteText.TextString}' at {noteText.Position}");
|
||||
|
||||
// 이 Note에 대한 그룹 생성
|
||||
var currentNoteGroup = new List<NoteEntityInfo>();
|
||||
|
||||
// Note 우측아래에 있는 박스 찾기 (이미 사용된 박스 제외)
|
||||
var noteBox = FindNoteBox(tran, noteText, polylineIds, lineIds, usedBoxes);
|
||||
|
||||
if (noteBox.HasValue)
|
||||
{
|
||||
Debug.WriteLine($"[DEBUG] Note 박스 발견: {noteBox.Value.minPoint} to {noteBox.Value.maxPoint}");
|
||||
|
||||
// 사용된 박스로 등록
|
||||
usedBoxes.Add(noteBox.Value);
|
||||
|
||||
// 박스 내부의 텍스트들 찾기
|
||||
var boxTextIds = FindTextsInNoteBox(tran, noteText, noteBox.Value, dbTextIds);
|
||||
Debug.WriteLine($"[DEBUG] 박스 내 텍스트: {boxTextIds.Count}개");
|
||||
|
||||
// Note 자체를 그룹의 첫 번째로 추가
|
||||
currentNoteGroup.Add(new NoteEntityInfo
|
||||
{
|
||||
Type = "Note",
|
||||
Layer = GetLayerName(noteText.LayerId, tran, database),
|
||||
Text = noteText.TextString,
|
||||
Path = database.Filename,
|
||||
FileName = Path.GetFileName(database.Filename),
|
||||
X = noteText.Position.X,
|
||||
Y = noteText.Position.Y,
|
||||
SortOrder = 0 // Note는 항상 먼저
|
||||
});
|
||||
|
||||
// 박스 내 텍스트들을 좌표별로 정렬하여 그룹에 추가
|
||||
var sortedBoxTexts = GetSortedNoteContents(tran, boxTextIds, database);
|
||||
currentNoteGroup.AddRange(sortedBoxTexts);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.WriteLine($"[DEBUG] Note '{noteText.TextString}'에 대한 박스를 찾을 수 없음");
|
||||
|
||||
// 박스가 없어도 Note 헤더는 추가
|
||||
currentNoteGroup.Add(new NoteEntityInfo
|
||||
{
|
||||
Type = "Note",
|
||||
Layer = GetLayerName(noteText.LayerId, tran, database),
|
||||
Text = noteText.TextString,
|
||||
Path = database.Filename,
|
||||
FileName = Path.GetFileName(database.Filename),
|
||||
X = noteText.Position.X,
|
||||
Y = noteText.Position.Y,
|
||||
SortOrder = 0
|
||||
});
|
||||
}
|
||||
|
||||
noteGroups.Add(currentNoteGroup);
|
||||
}
|
||||
}
|
||||
|
||||
// Note 그룹들을 Y 좌표별로 정렬 (위에서 아래로)
|
||||
var sortedNoteGroups = noteGroups
|
||||
.OrderByDescending(group => group[0].Y) // 각 그룹의 첫 번째 항목(NOTE 헤더)의 Y 좌표로 정렬
|
||||
.ToList();
|
||||
|
||||
// 정렬된 그룹들을 하나의 리스트로 합치기
|
||||
foreach (var group in sortedNoteGroups)
|
||||
{
|
||||
noteEntities.AddRange(group);
|
||||
}
|
||||
}
|
||||
tran.Commit();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
Debug.WriteLine($"❌ Note 추출 중 오류: {ex.Message}");
|
||||
}
|
||||
|
||||
Debug.WriteLine($"[DEBUG] 최종 Note 엔티티 정렬 완료: {noteEntities.Count}개");
|
||||
|
||||
return noteEntities;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// DBText 중에서 "Note"가 포함된 텍스트들을 찾습니다.
|
||||
/// </summary>
|
||||
private List<ObjectId> FindNoteTexts(Transaction tran, List<ObjectId> dbTextIds)
|
||||
{
|
||||
var noteTextIds = new List<ObjectId>();
|
||||
|
||||
foreach (var textId in dbTextIds)
|
||||
{
|
||||
using (var dbText = tran.GetObject(textId, OpenMode.ForRead) as DBText)
|
||||
{
|
||||
if (dbText == null) continue;
|
||||
|
||||
string textContent = dbText.TextString?.Trim() ?? "";
|
||||
|
||||
// 대소문자 구분없이 "Note"가 포함되어 있는지 확인
|
||||
if (textContent.IndexOf("Note", StringComparison.OrdinalIgnoreCase) >= 0)
|
||||
{
|
||||
noteTextIds.Add(textId);
|
||||
Debug.WriteLine($"[DEBUG] Note 텍스트 발견: '{textContent}' at {dbText.Position}, Color: {dbText.Color}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return noteTextIds;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Note 우측아래에 있는 박스를 찾습니다 (교차선 기반 알고리즘).
|
||||
/// Note position에서 height*2 만큼 아래로 수평선을 그어서 교차하는 Line/Polyline을 찾습니다.
|
||||
/// </summary>
|
||||
private (Point3d minPoint, Point3d maxPoint)? FindNoteBox(
|
||||
Transaction tran, DBText noteText, List<ObjectId> polylineIds, List<ObjectId> lineIds, HashSet<(Point3d minPoint, Point3d maxPoint)> usedBoxes)
|
||||
{
|
||||
var notePos = noteText.Position;
|
||||
var noteHeight = noteText.Height;
|
||||
|
||||
// Note position에서 height * 2 만큼 아래로 수평선 정의 (더 넓은 범위로 검색)
|
||||
double searchY = notePos.Y - (noteHeight * 2);
|
||||
var searchLineStart = new Point3d(notePos.X - noteHeight * 20, searchY, 0);
|
||||
var searchLineEnd = new Point3d(notePos.X + noteHeight * 100, searchY, 0);
|
||||
|
||||
Debug.WriteLine($"[DEBUG] 교차 검색선: ({searchLineStart.X}, {searchLineStart.Y}) to ({searchLineEnd.X}, {searchLineEnd.Y})");
|
||||
|
||||
// 1. Polyline과 교차하는지 확인
|
||||
foreach (var polylineId in polylineIds)
|
||||
{
|
||||
using (var polyline = tran.GetObject(polylineId, OpenMode.ForRead) as Polyline)
|
||||
{
|
||||
if (polyline == null) continue;
|
||||
|
||||
// 교차점이 있는지 확인
|
||||
if (DoesLineIntersectPolyline(searchLineStart, searchLineEnd, polyline))
|
||||
{
|
||||
var box = GetPolylineBounds(polyline);
|
||||
if (box.HasValue && IsValidNoteBox(box.Value, notePos, noteHeight) && !usedBoxes.Contains(box.Value))
|
||||
{
|
||||
Debug.WriteLine($"[DEBUG] 교차하는 Polyline 박스 발견: {box.Value.minPoint} to {box.Value.maxPoint}");
|
||||
return box;
|
||||
}
|
||||
else if (box.HasValue && usedBoxes.Contains(box.Value))
|
||||
{
|
||||
Debug.WriteLine($"[DEBUG] 박스가 이미 사용됨: {box.Value.minPoint} to {box.Value.maxPoint}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Line들과 교차하여 닫힌 사각형 찾기
|
||||
var intersectingLines = FindIntersectingLines(tran, lineIds, searchLineStart, searchLineEnd);
|
||||
Debug.WriteLine($"[DEBUG] 교차하는 Line 수: {intersectingLines.Count}");
|
||||
|
||||
foreach (var startLineId in intersectingLines)
|
||||
{
|
||||
var rectangle = TraceRectangleFromLine(tran, lineIds, startLineId, notePos, noteHeight);
|
||||
if (rectangle.HasValue && !usedBoxes.Contains(rectangle.Value))
|
||||
{
|
||||
Debug.WriteLine($"[DEBUG] 교차하는 Line 사각형 발견: {rectangle.Value.minPoint} to {rectangle.Value.maxPoint}");
|
||||
return rectangle;
|
||||
}
|
||||
else if (rectangle.HasValue && usedBoxes.Contains(rectangle.Value))
|
||||
{
|
||||
Debug.WriteLine($"[DEBUG] Line 사각형이 이미 사용됨: {rectangle.Value.minPoint} to {rectangle.Value.maxPoint}");
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 수평선이 Polyline과 교차하는지 확인합니다.
|
||||
/// </summary>
|
||||
private bool DoesLineIntersectPolyline(Point3d lineStart, Point3d lineEnd, Polyline polyline)
|
||||
{
|
||||
try
|
||||
{
|
||||
for (int i = 0; i < polyline.NumberOfVertices; i++)
|
||||
{
|
||||
int nextIndex = (i + 1) % polyline.NumberOfVertices;
|
||||
var segStart = polyline.GetPoint3dAt(i);
|
||||
var segEnd = polyline.GetPoint3dAt(nextIndex);
|
||||
|
||||
// 수평선과 폴리라인 세그먼트의 교차점 확인
|
||||
if (DoLinesIntersect(lineStart, lineEnd, segStart, segEnd))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 두 선분이 교차하는지 확인합니다.
|
||||
/// </summary>
|
||||
private bool DoLinesIntersect(Point3d line1Start, Point3d line1End, Point3d line2Start, Point3d line2End)
|
||||
{
|
||||
try
|
||||
{
|
||||
double x1 = line1Start.X, y1 = line1Start.Y;
|
||||
double x2 = line1End.X, y2 = line1End.Y;
|
||||
double x3 = line2Start.X, y3 = line2Start.Y;
|
||||
double x4 = line2End.X, y4 = line2End.Y;
|
||||
|
||||
double denom = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4);
|
||||
if (Math.Abs(denom) < 1e-10) return false; // 평행선
|
||||
|
||||
double t = ((x1 - x3) * (y3 - y4) - (y1 - y3) * (x3 - x4)) / denom;
|
||||
double u = -((x1 - x2) * (y1 - y3) - (y1 - y2) * (x1 - x3)) / denom;
|
||||
|
||||
return t >= 0 && t <= 1 && u >= 0 && u <= 1;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Polyline의 경계 상자를 계산합니다.
|
||||
/// </summary>
|
||||
private (Point3d minPoint, Point3d maxPoint)? GetPolylineBounds(Polyline polyline)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (polyline.NumberOfVertices < 3) return null;
|
||||
|
||||
var vertices = new List<Point3d>();
|
||||
for (int i = 0; i < polyline.NumberOfVertices; i++)
|
||||
{
|
||||
vertices.Add(polyline.GetPoint3dAt(i));
|
||||
}
|
||||
|
||||
double minX = vertices.Min(v => v.X);
|
||||
double maxX = vertices.Max(v => v.X);
|
||||
double minY = vertices.Min(v => v.Y);
|
||||
double maxY = vertices.Max(v => v.Y);
|
||||
|
||||
return (new Point3d(minX, minY, 0), new Point3d(maxX, maxY, 0));
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 박스가 유효한 Note 박스인지 확인합니다.
|
||||
/// </summary>
|
||||
private bool IsValidNoteBox((Point3d minPoint, Point3d maxPoint) box, Point3d notePos, double noteHeight)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 박스가 Note 아래쪽에 있는지 확인
|
||||
if (box.maxPoint.Y >= notePos.Y) return false;
|
||||
|
||||
// 박스 크기가 적절한지 확인
|
||||
double boxWidth = box.maxPoint.X - box.minPoint.X;
|
||||
double boxHeight = box.maxPoint.Y - box.minPoint.Y;
|
||||
|
||||
// 너무 작거나 큰 박스는 제외
|
||||
if (boxWidth < noteHeight || boxHeight < noteHeight) return false;
|
||||
if (boxWidth > noteHeight * 100 || boxHeight > noteHeight * 100) return false;
|
||||
|
||||
// Note 위치와 적절한 거리에 있는지 확인 (더 유연한 검증)
|
||||
double distanceY = Math.Abs(box.maxPoint.Y - notePos.Y);
|
||||
|
||||
// Y 거리만 확인 (X 거리는 제거 - 오른쪽에 있는 note box도 허용)
|
||||
if (distanceY > noteHeight * 15) return false;
|
||||
|
||||
// Note가 박스의 일정 범위 내에 있는지 확인 (X 범위를 더 넓게)
|
||||
bool isWithinXRange = (notePos.X >= box.minPoint.X - noteHeight * 100) &&
|
||||
(notePos.X <= box.maxPoint.X + noteHeight * 20);
|
||||
if (!isWithinXRange) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 수평선과 교차하는 Line들을 찾습니다.
|
||||
/// </summary>
|
||||
private List<ObjectId> FindIntersectingLines(Transaction tran, List<ObjectId> lineIds, Point3d searchLineStart, Point3d searchLineEnd)
|
||||
{
|
||||
var intersectingLines = new List<ObjectId>();
|
||||
|
||||
foreach (var lineId in lineIds)
|
||||
{
|
||||
using (var line = tran.GetObject(lineId, OpenMode.ForRead) as Line)
|
||||
{
|
||||
if (line == null) continue;
|
||||
|
||||
if (DoLinesIntersect(searchLineStart, searchLineEnd, line.StartPoint, line.EndPoint))
|
||||
{
|
||||
intersectingLines.Add(lineId);
|
||||
Debug.WriteLine($"[DEBUG] 교차 Line 발견: ({line.StartPoint.X}, {line.StartPoint.Y}) to ({line.EndPoint.X}, {line.EndPoint.Y})");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return intersectingLines;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Line에서 시작하여 반시계방향으로 사각형을 추적합니다.
|
||||
/// </summary>
|
||||
private (Point3d minPoint, Point3d maxPoint)? TraceRectangleFromLine(Transaction tran, List<ObjectId> lineIds, ObjectId startLineId, Point3d notePos, double noteHeight)
|
||||
{
|
||||
try
|
||||
{
|
||||
const double tolerance = 2.0; // 좌표 오차 허용 범위
|
||||
var visitedLines = new HashSet<ObjectId>();
|
||||
var rectanglePoints = new List<Point3d>();
|
||||
|
||||
using (var startLine = tran.GetObject(startLineId, OpenMode.ForRead) as Line)
|
||||
{
|
||||
if (startLine == null) return null;
|
||||
|
||||
var currentPoint = startLine.StartPoint;
|
||||
var nextPoint = startLine.EndPoint;
|
||||
rectanglePoints.Add(currentPoint);
|
||||
rectanglePoints.Add(nextPoint);
|
||||
visitedLines.Add(startLineId);
|
||||
|
||||
Debug.WriteLine($"[DEBUG] 사각형 추적 시작: ({currentPoint.X}, {currentPoint.Y}) -> ({nextPoint.X}, {nextPoint.Y})");
|
||||
|
||||
// 최대 4개의 Line으로 사각형 완성 시도
|
||||
for (int step = 0; step < 3; step++) // 시작 Line 제외하고 3개 더 찾기
|
||||
{
|
||||
var nextLineId = FindNextConnectedLine(tran, lineIds, nextPoint, visitedLines, tolerance);
|
||||
if (nextLineId == ObjectId.Null) break;
|
||||
|
||||
using (var nextLine = tran.GetObject(nextLineId, OpenMode.ForRead) as Line)
|
||||
{
|
||||
if (nextLine == null) break;
|
||||
|
||||
// 현재 점과 가까운 쪽을 시작점으로 설정
|
||||
Point3d lineStart, lineEnd;
|
||||
if (nextPoint.DistanceTo(nextLine.StartPoint) < nextPoint.DistanceTo(nextLine.EndPoint))
|
||||
{
|
||||
lineStart = nextLine.StartPoint;
|
||||
lineEnd = nextLine.EndPoint;
|
||||
}
|
||||
else
|
||||
{
|
||||
lineStart = nextLine.EndPoint;
|
||||
lineEnd = nextLine.StartPoint;
|
||||
}
|
||||
|
||||
rectanglePoints.Add(lineEnd);
|
||||
visitedLines.Add(nextLineId);
|
||||
nextPoint = lineEnd;
|
||||
|
||||
Debug.WriteLine($"[DEBUG] 다음 Line 추가: ({lineStart.X}, {lineStart.Y}) -> ({lineEnd.X}, {lineEnd.Y})");
|
||||
|
||||
// 시작점으로 돌아왔는지 확인 (사각형 완성)
|
||||
if (nextPoint.DistanceTo(currentPoint) < tolerance)
|
||||
{
|
||||
Debug.WriteLine("[DEBUG] 사각형 완성됨");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 4개 이상의 점이 있고 닫힌 형태인지 확인
|
||||
if (rectanglePoints.Count >= 4)
|
||||
{
|
||||
var bounds = CalculateBounds(rectanglePoints);
|
||||
if (bounds.HasValue && IsValidNoteBox(bounds.Value, notePos, noteHeight))
|
||||
{
|
||||
return bounds;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
Debug.WriteLine($"[DEBUG] 사각형 추적 중 오류: {ex.Message}");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 현재 점에서 연결된 다음 Line을 찾습니다.
|
||||
/// </summary>
|
||||
private ObjectId FindNextConnectedLine(Transaction tran, List<ObjectId> lineIds, Point3d currentPoint, HashSet<ObjectId> visitedLines, double tolerance)
|
||||
{
|
||||
foreach (var lineId in lineIds)
|
||||
{
|
||||
if (visitedLines.Contains(lineId)) continue;
|
||||
|
||||
using (var line = tran.GetObject(lineId, OpenMode.ForRead) as Line)
|
||||
{
|
||||
if (line == null) continue;
|
||||
|
||||
// 현재 점과 연결되어 있는지 확인
|
||||
if (currentPoint.DistanceTo(line.StartPoint) < tolerance ||
|
||||
currentPoint.DistanceTo(line.EndPoint) < tolerance)
|
||||
{
|
||||
return lineId;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ObjectId.Null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 점들의 경계 상자를 계산합니다.
|
||||
/// </summary>
|
||||
private (Point3d minPoint, Point3d maxPoint)? CalculateBounds(List<Point3d> points)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (points.Count < 3) return null;
|
||||
|
||||
double minX = points.Min(p => p.X);
|
||||
double maxX = points.Max(p => p.X);
|
||||
double minY = points.Min(p => p.Y);
|
||||
double maxY = points.Max(p => p.Y);
|
||||
|
||||
return (new Point3d(minX, minY, 0), new Point3d(maxX, maxY, 0));
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Note 박스 내부의 텍스트들을 찾습니다.
|
||||
/// </summary>
|
||||
private List<ObjectId> FindTextsInNoteBox(
|
||||
Transaction tran, DBText noteText, (Point3d minPoint, Point3d maxPoint) noteBox, List<ObjectId> allTextIds)
|
||||
{
|
||||
var boxTextIds = new List<ObjectId>();
|
||||
var noteHeight = noteText.Height;
|
||||
|
||||
foreach (var textId in allTextIds)
|
||||
{
|
||||
// Note 자신은 제외
|
||||
if (textId == noteText.ObjectId) continue;
|
||||
|
||||
using (var dbText = tran.GetObject(textId, OpenMode.ForRead) as DBText)
|
||||
{
|
||||
if (dbText == null) continue;
|
||||
|
||||
var textPos = dbText.Position;
|
||||
|
||||
// 박스 내부에 있는지 확인
|
||||
if (textPos.X >= noteBox.minPoint.X && textPos.X <= noteBox.maxPoint.X &&
|
||||
textPos.Y >= noteBox.minPoint.Y && textPos.Y <= noteBox.maxPoint.Y)
|
||||
{
|
||||
// Note의 height보다 작거나 같은지 확인
|
||||
if (dbText.Height <= noteHeight)
|
||||
{
|
||||
boxTextIds.Add(textId);
|
||||
Debug.WriteLine($"[DEBUG] 박스 내 텍스트 발견: '{dbText.TextString}' at {textPos}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return boxTextIds;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Note 박스 내의 텍스트들을 좌표에 따라 정렬합니다 (위에서 아래로, 왼쪽에서 오른쪽으로).
|
||||
/// </summary>
|
||||
private List<NoteEntityInfo> GetSortedNoteContents(Transaction tran, List<ObjectId> boxTextIds, Database database)
|
||||
{
|
||||
var noteContents = new List<NoteEntityInfo>();
|
||||
|
||||
// 먼저 모든 텍스트와 좌표 정보를 수집
|
||||
var textInfoList = new List<(ObjectId id, double x, double y, string text, string layer)>();
|
||||
|
||||
foreach (var boxTextId in boxTextIds)
|
||||
{
|
||||
using (var boxText = tran.GetObject(boxTextId, OpenMode.ForRead) as DBText)
|
||||
{
|
||||
if (boxText != null)
|
||||
{
|
||||
var pos = boxText.Position;
|
||||
textInfoList.Add((boxTextId, pos.X, pos.Y, boxText.TextString, GetLayerName(boxText.LayerId, tran, database)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Y 좌표로 먼저 정렬 (위에서 아래로 = Y 큰 값부터), 그다음 X 좌표로 정렬 (왼쪽에서 오른쪽으로 = X 작은 값부터)
|
||||
// CAD에서는 Y축이 위로 갈수록 커지므로, 텍스트를 위에서 아래로 읽으려면 Y가 큰 것부터 처리 (큰 Y = 위쪽)
|
||||
var sortedTexts = textInfoList
|
||||
.OrderByDescending(t => Math.Round(t.y, 1)) // Y 좌표로 내림차순 (위에서 아래로: 큰 Y부터)
|
||||
.ThenBy(t => Math.Round(t.x, 1)) // X 좌표로 오름차순 (왼쪽에서 오른쪽으로: 작은 X부터)
|
||||
.ToList();
|
||||
|
||||
Debug.WriteLine($"[DEBUG] Note 내용 정렬 결과:");
|
||||
int sortOrder = 1; // Note 자체는 0이므로 내용은 1부터 시작
|
||||
|
||||
foreach (var textInfo in sortedTexts)
|
||||
{
|
||||
Debug.WriteLine($"[DEBUG] 순서 {sortOrder}: '{textInfo.text}' at ({textInfo.x:F1}, {textInfo.y:F1})");
|
||||
|
||||
noteContents.Add(new NoteEntityInfo
|
||||
{
|
||||
Type = "NoteContent",
|
||||
Layer = textInfo.layer,
|
||||
Text = textInfo.text,
|
||||
Path = database.Filename,
|
||||
FileName = Path.GetFileName(database.Filename),
|
||||
X = textInfo.x,
|
||||
Y = textInfo.y,
|
||||
SortOrder = sortOrder
|
||||
});
|
||||
|
||||
sortOrder++;
|
||||
}
|
||||
|
||||
return noteContents;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// DWG <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><EFBFBD><EFBFBD><EFBFBD> Ŭ<><C5AC><EFBFBD><EFBFBD>
|
||||
/// DWG <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <EFBFBD><EFBFBD><EFBFBD> Ŭ<><C5AC><EFBFBD><EFBFBD>
|
||||
/// </summary>
|
||||
public class DwgExtractionResult
|
||||
{
|
||||
@@ -358,7 +952,7 @@ namespace DwgExtractorManual.Models
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Title Block <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
/// Title Block <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
/// </summary>
|
||||
public class TitleBlockRowData
|
||||
{
|
||||
@@ -372,7 +966,7 @@ namespace DwgExtractorManual.Models
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Text Entity <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
/// Text Entity <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
/// </summary>
|
||||
public class TextEntityRowData
|
||||
{
|
||||
@@ -384,7 +978,7 @@ namespace DwgExtractorManual.Models
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <20>ؽ<EFBFBD>Ʈ <20><>ƼƼ <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> Ŭ<><C5AC><EFBFBD><EFBFBD>
|
||||
/// <20>ؽ<EFBFBD>Ʈ <20><>ƼƼ <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD> Ŭ<><C5AC><EFBFBD><EFBFBD>
|
||||
/// </summary>
|
||||
public class TextEntityInfo
|
||||
{
|
||||
@@ -394,4 +988,19 @@ namespace DwgExtractorManual.Models
|
||||
public string Tag { get; set; } = "";
|
||||
public string Text { get; set; } = "";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Note 엔티티 정보 클래스
|
||||
/// </summary>
|
||||
public class NoteEntityInfo
|
||||
{
|
||||
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; } = "";
|
||||
public double X { get; set; } = 0; // X 좌표
|
||||
public double Y { get; set; } = 0; // Y 좌표
|
||||
public int SortOrder { get; set; } = 0; // 정렬 순서 (Note=0, NoteContent=1,2,3...)
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,7 @@ using Excel = Microsoft.Office.Interop.Excel;
|
||||
namespace DwgExtractorManual.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// Excel <20><>Ʈ<EFBFBD><C6AE> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20>۾<EFBFBD><DBBE><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>ϴ<EFBFBD> Ŭ<><C5AC><EFBFBD><EFBFBD>
|
||||
/// Excel <20><>Ʈ<EFBFBD><C6AE> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20>۾<EFBFBD><DBBE><EFBFBD> <20><><EFBFBD><EFBFBD>ϴ<EFBFBD> Ŭ<><C5AC><EFBFBD><EFBFBD>
|
||||
/// </summary>
|
||||
internal class ExcelDataWriter
|
||||
{
|
||||
@@ -19,14 +19,14 @@ namespace DwgExtractorManual.Models
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Title Block <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> Excel <20><>Ʈ<EFBFBD><C6AE> <20><><EFBFBD><EFBFBD>
|
||||
/// Title Block <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> Excel <20><>Ʈ<EFBFBD><C6AE> <20><><EFBFBD>
|
||||
/// </summary>
|
||||
public void WriteTitleBlockData(List<TitleBlockRowData> titleBlockRows)
|
||||
{
|
||||
if (excelManager.TitleBlockSheet == null || titleBlockRows == null || titleBlockRows.Count == 0)
|
||||
return;
|
||||
|
||||
int currentRow = 2; // <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>
|
||||
int currentRow = 2; // <20><><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>
|
||||
|
||||
foreach (var row in titleBlockRows)
|
||||
{
|
||||
@@ -42,14 +42,14 @@ namespace DwgExtractorManual.Models
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Text Entity <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> Excel <20><>Ʈ<EFBFBD><C6AE> <20><><EFBFBD><EFBFBD>
|
||||
/// Text Entity <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> Excel <20><>Ʈ<EFBFBD><C6AE> <20><><EFBFBD>
|
||||
/// </summary>
|
||||
public void WriteTextEntityData(List<TextEntityRowData> textEntityRows)
|
||||
{
|
||||
if (excelManager.TextEntitiesSheet == null || textEntityRows == null || textEntityRows.Count == 0)
|
||||
return;
|
||||
|
||||
int currentRow = 2; // <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>
|
||||
int currentRow = 2; // <20><><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>
|
||||
|
||||
foreach (var row in textEntityRows)
|
||||
{
|
||||
@@ -63,7 +63,7 @@ namespace DwgExtractorManual.Models
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> Excel <20><>Ʈ<EFBFBD><C6AE> <20><><EFBFBD><EFBFBD>
|
||||
/// <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> Excel <20><>Ʈ<EFBFBD><C6AE> <20><><EFBFBD>
|
||||
/// </summary>
|
||||
public void WriteMappingDataToExcel(Dictionary<string, Dictionary<string, (string, string, string, string)>> mappingData)
|
||||
{
|
||||
@@ -72,7 +72,7 @@ namespace DwgExtractorManual.Models
|
||||
if (excelManager.MappingSheet == null || mappingData == null)
|
||||
return;
|
||||
|
||||
int currentRow = 2; // <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>
|
||||
int currentRow = 2; // <20><><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>
|
||||
|
||||
Debug.WriteLine($"[DEBUG] Writing mapping data to Excel. Total files: {mappingData.Count}");
|
||||
|
||||
@@ -95,7 +95,7 @@ namespace DwgExtractorManual.Models
|
||||
|
||||
try
|
||||
{
|
||||
// <20><>ġ <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ʈ<EFBFBD><C6AE> <20><><EFBFBD><EFBFBD> <20>迭 <20><><EFBFBD><EFBFBD>
|
||||
// <20><>ġ <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ʈ<EFBFBD><C6AE> <20><><EFBFBD><EFBFBD> <20>迭 <20><><EFBFBD>
|
||||
object[,] rowData = new object[1, 6];
|
||||
rowData[0, 0] = fileName;
|
||||
rowData[0, 1] = mapKey;
|
||||
@@ -122,13 +122,13 @@ namespace DwgExtractorManual.Models
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
Debug.WriteLine($"? <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> Excel <20><><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD>: {ex.Message}");
|
||||
Debug.WriteLine($"? <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> Excel <20><><EFBFBD> <20><> <20><><EFBFBD><EFBFBD>: {ex.Message}");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Excel <20><><EFBFBD><EFBFBD> <20><>Ʈ<EFBFBD><C6AE><EFBFBD><EFBFBD> FileName<6D><65> AILabel<65><6C> <20><>Ī<EFBFBD>Ǵ<EFBFBD> <20><><EFBFBD><EFBFBD> ã<><C3A3> Pdf_value<75><65> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ʈ
|
||||
/// Excel <20><><EFBFBD><EFBFBD> <20><>Ʈ<EFBFBD><C6AE><EFBFBD><EFBFBD> FileName<6D><65> AILabel<65><6C> <20><>Ī<EFBFBD>Ǵ<EFBFBD> <20><><EFBFBD><EFBFBD> ã<><C3A3> Pdf_value<75><65> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ʈ
|
||||
/// </summary>
|
||||
public bool UpdateExcelRow(string fileName, string aiLabel, string pdfValue)
|
||||
{
|
||||
@@ -159,13 +159,13 @@ namespace DwgExtractorManual.Models
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
Debug.WriteLine($"? Excel <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ʈ <20><> <20><><EFBFBD><EFBFBD>: {ex.Message}");
|
||||
Debug.WriteLine($"? Excel <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ʈ <20><> <20><><EFBFBD><EFBFBD>: {ex.Message}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// DWG <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><>ũ<EFBFBD><C5A9><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>ϰ<EFBFBD> <20><><EFBFBD><EFBFBD> (PDF <20>÷<EFBFBD> <20><><EFBFBD><EFBFBD>)
|
||||
/// DWG <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><>ũ<EFBFBD><C5A9><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>ϰ<EFBFBD> <20><><EFBFBD><EFBFBD> (PDF <20>÷<EFBFBD> <20><><EFBFBD><EFBFBD>)
|
||||
/// </summary>
|
||||
public void SaveDwgOnlyMappingWorkbook(Dictionary<string, Dictionary<string, (string, string, string, string)>> mappingData, string resultFolderPath)
|
||||
{
|
||||
@@ -174,26 +174,26 @@ namespace DwgExtractorManual.Models
|
||||
string timestamp = DateTime.Now.ToString("yyyyMMdd_HHmmss");
|
||||
string savePath = System.IO.Path.Combine(resultFolderPath, $"{timestamp}_DwgOnly_Mapping.xlsx");
|
||||
|
||||
Debug.WriteLine($"[DEBUG] DWG <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><>ũ<EFBFBD><C5A9> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>: {savePath}");
|
||||
Debug.WriteLine($"[DEBUG] DWG <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><>ũ<EFBFBD><C5A9> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>: {savePath}");
|
||||
|
||||
var dwgOnlyWorkbook = excelManager.CreateNewWorkbook();
|
||||
var dwgOnlyWorksheet = (Excel.Worksheet)dwgOnlyWorkbook.Worksheets[1];
|
||||
dwgOnlyWorksheet.Name = "DWG Mapping Data";
|
||||
|
||||
// <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> (PDF Value <20>÷<EFBFBD> <20><><EFBFBD><EFBFBD>)
|
||||
dwgOnlyWorksheet.Cells[1, 1] = "<22><><EFBFBD>ϸ<EFBFBD>";
|
||||
// <20><><EFBFBD> <20><><EFBFBD><EFBFBD> (PDF Value <20>÷<EFBFBD> <20><><EFBFBD><EFBFBD>)
|
||||
dwgOnlyWorksheet.Cells[1, 1] = "<22><><EFBFBD>ϸ<EFBFBD>";
|
||||
dwgOnlyWorksheet.Cells[1, 2] = "Map Key";
|
||||
dwgOnlyWorksheet.Cells[1, 3] = "AI Label";
|
||||
dwgOnlyWorksheet.Cells[1, 4] = "DWG Tag";
|
||||
dwgOnlyWorksheet.Cells[1, 5] = "DWG Value";
|
||||
|
||||
// <20><><EFBFBD><EFBFBD> <20><>Ÿ<EFBFBD><C5B8> <20><><EFBFBD><EFBFBD>
|
||||
// <20><><EFBFBD> <20><>Ÿ<EFBFBD><C5B8> <20><><EFBFBD><EFBFBD>
|
||||
var headerRange = dwgOnlyWorksheet.Range["A1:E1"];
|
||||
headerRange.Font.Bold = true;
|
||||
headerRange.Interior.Color = System.Drawing.ColorTranslator.ToOle(System.Drawing.Color.LightGray);
|
||||
headerRange.Borders.LineStyle = Excel.XlLineStyle.xlContinuous;
|
||||
|
||||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>Է<EFBFBD>
|
||||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>Է<EFBFBD>
|
||||
int totalRows = mappingData.Sum(f => f.Value.Count);
|
||||
if (totalRows > 0)
|
||||
{
|
||||
@@ -227,7 +227,7 @@ namespace DwgExtractorManual.Models
|
||||
dwgOnlyWorksheet.Columns.AutoFit();
|
||||
excelManager.SaveWorkbookAs(dwgOnlyWorkbook, savePath);
|
||||
|
||||
Debug.WriteLine($"? DWG <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><>ũ<EFBFBD><C5A9> <20><><EFBFBD><EFBFBD> <20>Ϸ<EFBFBD>: {System.IO.Path.GetFileName(savePath)}");
|
||||
Debug.WriteLine($"? DWG <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><>ũ<EFBFBD><C5A9> <20><><EFBFBD><EFBFBD> <20>Ϸ<EFBFBD>: {System.IO.Path.GetFileName(savePath)}");
|
||||
|
||||
dwgOnlyWorkbook.Close(false);
|
||||
System.GC.Collect();
|
||||
@@ -235,17 +235,17 @@ namespace DwgExtractorManual.Models
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
Debug.WriteLine($"? DWG <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><>ũ<EFBFBD><C5A9> <20><><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD>: {ex.Message}");
|
||||
Debug.WriteLine($"? DWG <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><>ũ<EFBFBD><C5A9> <20><><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD>: {ex.Message}");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Height <20><><EFBFBD>ĵ<EFBFBD> Excel <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>
|
||||
/// Height <20><><EFBFBD>ĵ<EFBFBD> Excel <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>
|
||||
/// </summary>
|
||||
public void WriteHeightSortedData(List<TextEntityInfo> textEntities, Excel.Worksheet worksheet, string fileName)
|
||||
{
|
||||
// <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>
|
||||
// <20><><EFBFBD> <20><><EFBFBD><EFBFBD>
|
||||
worksheet.Cells[1, 1] = "Height";
|
||||
worksheet.Cells[1, 2] = "Type";
|
||||
worksheet.Cells[1, 3] = "Layer";
|
||||
@@ -253,16 +253,16 @@ namespace DwgExtractorManual.Models
|
||||
worksheet.Cells[1, 5] = "FileName";
|
||||
worksheet.Cells[1, 6] = "Text";
|
||||
|
||||
// <20><><EFBFBD><EFBFBD> <20><>Ÿ<EFBFBD><C5B8> <20><><EFBFBD><EFBFBD>
|
||||
// <20><><EFBFBD> <20><>Ÿ<EFBFBD><C5B8> <20><><EFBFBD><EFBFBD>
|
||||
var headerRange = worksheet.Range["A1:F1"];
|
||||
headerRange.Font.Bold = true;
|
||||
headerRange.Interior.Color = System.Drawing.ColorTranslator.ToOle(System.Drawing.Color.LightBlue);
|
||||
|
||||
// <20><><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD> ExtractTextEntitiesWithHeight<68><74><EFBFBD><EFBFBD> <20>̹<EFBFBD> <20><><EFBFBD>ĵǾ<C4B5><C7BE><EFBFBD><EFBFBD>Ƿ<EFBFBD> <20>ٽ<EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>ʽ<EFBFBD><CABD>ϴ<EFBFBD>.
|
||||
// <20><><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD> ExtractTextEntitiesWithHeight<68><74><EFBFBD><EFBFBD> <20>̹<EFBFBD> <20><><EFBFBD>ĵǾ<C4B5><C7BE><EFBFBD><EFBFBD>Ƿ<EFBFBD> <20>ٽ<EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>ʽ<EFBFBD><CABD>ϴ<EFBFBD>.
|
||||
|
||||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>Է<EFBFBD>
|
||||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>Է<EFBFBD>
|
||||
int row = 2;
|
||||
foreach (var entity in textEntities) // sortedEntities<65><73> textEntities<65><73> <20><><EFBFBD><EFBFBD>
|
||||
foreach (var entity in textEntities) // sortedEntities<65><73> textEntities<65><73> <20><><EFBFBD><EFBFBD>
|
||||
{
|
||||
worksheet.Cells[row, 1] = entity.Height;
|
||||
worksheet.Cells[row, 2] = entity.Type;
|
||||
@@ -275,5 +275,99 @@ namespace DwgExtractorManual.Models
|
||||
|
||||
worksheet.Columns.AutoFit();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Note 엔티티들을 Excel 워크시트에 기록합니다 (기존 데이터 아래에 추가).
|
||||
/// </summary>
|
||||
public void WriteNoteEntities(List<NoteEntityInfo> noteEntities, Excel.Worksheet worksheet, string fileName)
|
||||
{
|
||||
if (noteEntities == null || noteEntities.Count == 0)
|
||||
{
|
||||
Debug.WriteLine("[DEBUG] Note 엔티티가 없습니다.");
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// 현재 워크시트의 마지막 사용된 행 찾기
|
||||
Excel.Range usedRange = null;
|
||||
int lastRow = 1;
|
||||
|
||||
try
|
||||
{
|
||||
usedRange = worksheet.UsedRange;
|
||||
lastRow = usedRange?.Rows.Count ?? 1;
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
Debug.WriteLine($"[DEBUG] UsedRange 접근 오류, 기본값 사용: {ex.Message}");
|
||||
lastRow = 1;
|
||||
}
|
||||
|
||||
int startRow = lastRow + 2; // 한 줄 띄우고 시작
|
||||
Debug.WriteLine($"[DEBUG] Note 데이터 기록 시작: {startRow}행부터 {noteEntities.Count}개 항목");
|
||||
|
||||
// Note 섹션 헤더 추가 (간단한 방식으로 변경)
|
||||
try
|
||||
{
|
||||
worksheet.Cells[startRow - 1, 1] = "=== Notes ===";
|
||||
worksheet.Cells[startRow - 1, 2] = "";
|
||||
worksheet.Cells[startRow - 1, 3] = "";
|
||||
worksheet.Cells[startRow - 1, 4] = "";
|
||||
worksheet.Cells[startRow - 1, 5] = "";
|
||||
worksheet.Cells[startRow - 1, 6] = "";
|
||||
|
||||
// 헤더 스타일 적용 (개별 셀로 처리)
|
||||
var headerCell = worksheet.Cells[startRow - 1, 1];
|
||||
headerCell.Font.Bold = true;
|
||||
headerCell.Interior.Color = System.Drawing.ColorTranslator.ToOle(System.Drawing.Color.LightYellow);
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
Debug.WriteLine($"[DEBUG] Note 헤더 작성 오류: {ex.Message}");
|
||||
}
|
||||
|
||||
// Note 데이터 입력 (배치 방식으로 성능 향상)
|
||||
int row = startRow;
|
||||
try
|
||||
{
|
||||
foreach (var noteEntity in noteEntities)
|
||||
{
|
||||
worksheet.Cells[row, 1] = 0; // Height는 0으로 설정
|
||||
worksheet.Cells[row, 2] = noteEntity.Type ?? "";
|
||||
worksheet.Cells[row, 3] = noteEntity.Layer ?? "";
|
||||
worksheet.Cells[row, 4] = ""; // Tag는 빈 값
|
||||
worksheet.Cells[row, 5] = fileName ?? "";
|
||||
worksheet.Cells[row, 6] = noteEntity.Text ?? "";
|
||||
|
||||
Debug.WriteLine($"[DEBUG] Excel 기록: Row {row}, Order {noteEntity.SortOrder}, Type {noteEntity.Type}, Pos({noteEntity.X:F1},{noteEntity.Y:F1}), Text: '{noteEntity.Text}'");
|
||||
row++;
|
||||
}
|
||||
|
||||
Debug.WriteLine($"[DEBUG] Note 데이터 기록 완료: {row - startRow}개 항목");
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
Debug.WriteLine($"[DEBUG] Note 데이터 입력 오류: {ex.Message}");
|
||||
Debug.WriteLine($"[DEBUG] 처리된 행: {row - startRow}개");
|
||||
}
|
||||
|
||||
// AutoFit 시도 (오류 발생시 무시)
|
||||
try
|
||||
{
|
||||
worksheet.Columns.AutoFit();
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
Debug.WriteLine($"[DEBUG] AutoFit 오류 (무시됨): {ex.Message}");
|
||||
}
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
Debug.WriteLine($"❌ WriteNoteEntities 전체 오류: {ex.Message}");
|
||||
Debug.WriteLine($" 스택 트레이스: {ex.StackTrace}");
|
||||
throw; // 상위로 예외 전파
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -262,6 +262,14 @@ namespace DwgExtractorManual.Models
|
||||
var textEntities = dwgExtractor.ExtractTextEntitiesWithHeight(filePath);
|
||||
excelWriter.WriteHeightSortedData(textEntities, worksheet, fileName);
|
||||
|
||||
// Note 엔티티 추출 및 기록
|
||||
var noteEntities = dwgExtractor.ExtractNotesFromDrawing(filePath);
|
||||
if (noteEntities.Count > 0)
|
||||
{
|
||||
excelWriter.WriteNoteEntities(noteEntities, worksheet, fileName);
|
||||
Debug.WriteLine($"[DEBUG] {fileName}: {noteEntities.Count}개 Note 엔티티 추가됨");
|
||||
}
|
||||
|
||||
Debug.WriteLine($"[DEBUG] {fileName} 시트 완료: {textEntities.Count}개 엔티티");
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
|
||||
Reference in New Issue
Block a user