도면에서 표 추출

This commit is contained in:
horu2day
2025-08-12 14:33:18 +09:00
parent 3abb3c07ce
commit f114b8b642
26 changed files with 4877 additions and 2566 deletions

View File

@@ -17,7 +17,7 @@ namespace DwgExtractorManual
{
public partial class MainWindow : Window
{
private DispatcherTimer _timer;
private DispatcherTimer? _timer;
private ExportExcel? _exportExcel;
private SqlDatas? _sqlDatas;
// 자동 처리 모드 플래그
@@ -26,16 +26,76 @@ namespace DwgExtractorManual
public MainWindow()
{
InitializeComponent();
InitializeDefaultPaths();
InitializeTimer();
LoadSettings();
SetBuildTime();
// 앱 종료 시 Teigha 리소스 정리
this.Closed += MainWindow_Closed;
LogMessage("🚀 DWG 정보 추출기가 시작되었습니다.");
}
private void MainWindow_Closed(object sender, EventArgs e)
private void LoadSettings()
{
LogMessage("⚙️ 설정을 불러옵니다...");
var settings = SettingsManager.LoadSettings();
if (settings != null)
{
if (!string.IsNullOrEmpty(settings.SourceFolderPath) && Directory.Exists(settings.SourceFolderPath))
{
txtSourceFolder.Text = settings.SourceFolderPath;
LogMessage($"📂 저장된 소스 폴더: {settings.SourceFolderPath}");
CheckDwgFiles(settings.SourceFolderPath);
}
else
{
LogMessage($"⚠️ 저장된 소스 폴더를 찾을 수 없습니다: {settings.SourceFolderPath}");
}
if (!string.IsNullOrEmpty(settings.DestinationFolderPath) && Directory.Exists(settings.DestinationFolderPath))
{
txtResultFolder.Text = settings.DestinationFolderPath;
LogMessage($"💾 저장된 결과 폴더: {settings.DestinationFolderPath}");
}
else
{
LogMessage($"⚠️ 저장된 결과 폴더를 찾을 수 없습니다: {settings.DestinationFolderPath}");
}
if (!string.IsNullOrEmpty(settings.LastExportType))
{
if (settings.LastExportType == "Excel")
{
rbExcel.IsChecked = true;
}
else if (settings.LastExportType == "Database")
{
rbDatabase.IsChecked = true;
}
LogMessage($"📋 저장된 출력 형식: {settings.LastExportType}");
}
LogMessage("✅ 설정 불러오기 완료.");
}
else
{
LogMessage(" 저장된 설정 파일이 없습니다. 기본값으로 시작합니다.");
InitializeDefaultPaths(); // Fallback
}
}
private void SaveSettings()
{
LogMessage("⚙️ 현재 설정을 저장합니다...");
var settings = new AppSettings
{
SourceFolderPath = txtSourceFolder.Text,
DestinationFolderPath = txtResultFolder.Text,
LastExportType = rbExcel.IsChecked == true ? "Excel" : "Database"
};
SettingsManager.SaveSettings(settings);
LogMessage("✅ 설정 저장 완료.");
}
private void MainWindow_Closed(object? sender, EventArgs e)
{
try
{
@@ -70,7 +130,13 @@ namespace DwgExtractorManual
{
_timer = new DispatcherTimer();
_timer.Interval = TimeSpan.FromSeconds(1);
_timer.Tick += (s, e) => txtTime.Text = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
_timer.Tick += (s, e) =>
{
if (_timer != null)
{
txtTime.Text = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
}
};
_timer.Start();
}
@@ -176,6 +242,9 @@ namespace DwgExtractorManual
private async void BtnExtract_Click(object sender, RoutedEventArgs e)
{
// 설정 저장
SaveSettings();
// 입력 유효성 검사
if (string.IsNullOrEmpty(txtSourceFolder.Text) || !Directory.Exists(txtSourceFolder.Text))
{
@@ -278,7 +347,7 @@ namespace DwgExtractorManual
}
else
{
System.Windows.MessageBox.Show(message, title, button, image);
System.Windows.MessageBox.Show(this, message, title, button, image);
}
}
@@ -294,7 +363,7 @@ namespace DwgExtractorManual
}
else
{
return System.Windows.MessageBox.Show(message, title, MessageBoxButton.YesNo, MessageBoxImage.Question);
return System.Windows.MessageBox.Show(this, message, title, MessageBoxButton.YesNo, MessageBoxImage.Question);
}
}
@@ -395,12 +464,11 @@ namespace DwgExtractorManual
LogMessage("💾 Excel 파일과 매핑 데이터를 저장합니다...");
// 매핑 딕셔너리를 JSON 파일로 저장 (PDF 데이터 병합용)
_exportExcel.SaveMappingDictionary(mappingDataFile);
_exportExcel?.SaveMappingDictionary(mappingDataFile);
LogMessage($"✅ 매핑 데이터 저장 완료: {Path.GetFileName(mappingDataFile)}");
// Excel 파일 저장
_exportExcel.SaveAndCloseExcel(excelFileName);
_exportExcel?.SaveAndCloseExcel(excelFileName);
LogMessage($"✅ Excel 파일 저장 완료: {Path.GetFileName(excelFileName)}");
var elapsed = stopwatch.Elapsed;
@@ -461,7 +529,7 @@ namespace DwgExtractorManual
try
{
// 실제 DWG 처리 로직 (DwgToDB는 실패시 true 반환)
bool failed = _sqlDatas.DwgToDB(file.FullName);
bool failed = _sqlDatas?.DwgToDB(file.FullName) ?? true;
bool success = !failed;
fileStopwatch.Stop();
@@ -777,6 +845,9 @@ namespace DwgExtractorManual
private async void BtnPdfExtract_Click(object sender, RoutedEventArgs e)
{
// 설정 저장
SaveSettings();
// 입력 유효성 검사
if (string.IsNullOrEmpty(txtSourceFolder.Text) || !Directory.Exists(txtSourceFolder.Text))
{
@@ -1092,7 +1163,12 @@ namespace DwgExtractorManual
LogMessage($"📄 JSON 파일 확인됨: {Path.GetFileName(jsonFilePath)}");
// 최신 매핑 데이터 파일 찾기
string resultDir = Path.GetDirectoryName(csvFilePath) ?? txtResultFolder.Text;
string? resultDir = Path.GetDirectoryName(csvFilePath);
if (string.IsNullOrEmpty(resultDir))
{
LogMessage("⚠️ 결과 디렉터리를 찾을 수 없습니다.");
return;
}
var mappingDataFiles = Directory.GetFiles(resultDir, "*_mapping_data.json", SearchOption.TopDirectoryOnly)
.OrderByDescending(f => File.GetCreationTime(f))
.ToArray();
@@ -1168,7 +1244,12 @@ namespace DwgExtractorManual
LogMessage($"📄 JSON 파일 확인됨: {Path.GetFileName(jsonFilePath)}");
// 기존 Excel 매핑 파일 검색 (임시 파일 제외)
string resultDir = Path.GetDirectoryName(csvFilePath) ?? txtResultFolder.Text;
string? resultDir = Path.GetDirectoryName(csvFilePath);
if (string.IsNullOrEmpty(resultDir))
{
LogMessage("⚠️ 결과 디렉터리를 찾을 수 없습니다.");
return;
}
var allExcelFiles = Directory.GetFiles(resultDir, "*_Mapping.xlsx", SearchOption.TopDirectoryOnly);
// 임시 파일(~$로 시작하는 파일) 필터링
@@ -1296,6 +1377,9 @@ namespace DwgExtractorManual
private async void BtnMerge_Click(object sender, RoutedEventArgs e)
{
// 설정 저장
SaveSettings();
// 입력 유효성 검사
if (string.IsNullOrEmpty(txtResultFolder.Text) || !Directory.Exists(txtResultFolder.Text))
{
@@ -1560,6 +1644,9 @@ namespace DwgExtractorManual
/// </summary>
private async void BtnAuto_Click(object sender, RoutedEventArgs e)
{
// 설정 저장
SaveSettings();
try
{
// 입력 검증
@@ -1656,6 +1743,9 @@ namespace DwgExtractorManual
/// </summary>
private async void BtnDwgOnly_Click(object sender, RoutedEventArgs e)
{
// 설정 저장
SaveSettings();
try
{
// 경로 검증
@@ -1738,6 +1828,13 @@ namespace DwgExtractorManual
/// </summary>
private async void BtnDwgHeightSort_Click(object sender, RoutedEventArgs e)
{
// 설정 저장
SaveSettings();
// 시각화 데이터 초기화
ClearVisualizationData();
LogMessage("🧹 시각화 데이터 초기화 완료");
try
{
// 경로 검증
@@ -2057,8 +2154,8 @@ namespace DwgExtractorManual
if (allDwgFiles.Count > 0)
{
// 단일 Excel 파일에 모든 DWG 파일 처리
LogMessage("📏 단일 Height 정렬 Excel 파일 생성 중...");
// Height 정렬 Excel 파일 생성 (Note 데이터 포함)
LogMessage("📏 Height 정렬 Excel 파일 생성 중 (Note 표 데이터 포함)...");
await ProcessAllFilesDwgHeightSort(allDwgFiles, resultBaseFolder);
LogMessage("✅ Height 정렬 Excel 파일 생성 완료");
}
@@ -2109,7 +2206,91 @@ namespace DwgExtractorManual
string savePath = Path.Combine(resultFolder, $"{timestamp}_AllDWG_HeightSorted.xlsx");
exportExcel.ExportAllDwgToExcelHeightSorted(allDwgFiles, savePath);
// 시각화 데이터 캐시 초기화
MainWindow.ClearVisualizationData();
LogMessage("[DEBUG] 시각화 데이터 캐시 초기화 완료.");
foreach (var (filePath, folderName) in allDwgFiles)
{
LogMessage($"[DEBUG] DWG 파일에서 Note 추출 시작: {Path.GetFileName(filePath)}");
var noteExtractionResult = exportExcel.DwgExtractor.ExtractNotesFromDrawing(filePath);
var noteEntities = noteExtractionResult.NoteEntities;
LogMessage($"[DEBUG] 추출된 Note 엔티티 수: {noteEntities.Count}");
LogMessage($"[DEBUG] 추출된 IntersectionPoints 수: {noteExtractionResult.IntersectionPoints.Count}");
LogMessage($"[DEBUG] 추출된 DiagonalLines 수: {noteExtractionResult.DiagonalLines.Count}");
LogMessage($"[DEBUG] 추출된 TableSegments 수: {noteExtractionResult.TableSegments.Count}");
if (noteEntities.Any())
{
// 테이블이 있는 Note만 가시화 데이터 생성 (최소 4개 셀 이상)
var notesWithTables = noteEntities.Where(ne =>
ne.Type == "Note" &&
ne.Cells != null &&
ne.Cells.Count >= 4 && // 최소 4개 셀이 있어야 테이블로 인정
ne.TableSegments != null &&
ne.TableSegments.Count >= 4).ToList(); // 최소 4개 선분이 있어야 함
LogMessage($"[DEBUG] 테이블이 있는 Note: {notesWithTables.Count}개");
foreach (var noteWithTable in notesWithTables)
{
var visualizationData = new TableCellVisualizationData
{
FileName = $"{Path.GetFileName(filePath)} - {noteWithTable.Text}",
NoteText = noteWithTable.Text,
NoteBounds = (
noteWithTable.Cells.Min(c => c.MinPoint.X),
noteWithTable.Cells.Min(c => c.MinPoint.Y),
noteWithTable.Cells.Max(c => c.MaxPoint.X),
noteWithTable.Cells.Max(c => c.MaxPoint.Y)
),
Cells = noteWithTable.Cells.Select(tc => new CellBounds
{
MinX = tc.MinPoint.X, MinY = tc.MinPoint.Y, MaxX = tc.MaxPoint.X, MaxY = tc.MaxPoint.Y,
Row = tc.Row, Column = tc.Column, Text = tc.CellText
}).ToList(),
TableSegments = noteWithTable.TableSegments.Select(ts => new SegmentInfo
{
StartX = ts.StartX, StartY = ts.StartY,
EndX = ts.EndX, EndY = ts.EndY,
IsHorizontal = ts.IsHorizontal
}).ToList(),
IntersectionPoints = noteWithTable.IntersectionPoints,
DiagonalLines = noteWithTable.DiagonalLines ?? new List<DiagonalLine>(),
CellBoundaries = noteWithTable.CellBoundaries?.Select(cb => new CellBoundaryInfo
{
TopLeftX = cb.TopLeft.X, TopLeftY = cb.TopLeft.Y,
TopRightX = cb.TopRight.X, TopRightY = cb.TopRight.Y,
BottomLeftX = cb.BottomLeft.X, BottomLeftY = cb.BottomLeft.Y,
BottomRightX = cb.BottomRight.X, BottomRightY = cb.BottomRight.Y,
Label = cb.Label, Width = cb.Width, Height = cb.Height,
CellText = cb.CellText ?? ""
}).ToList() ?? new List<CellBoundaryInfo>(),
TextEntities = noteEntities.Where(ne => ne.Type == "NoteContent").Select(ne => new TextInfo
{
X = ne.X, Y = ne.Y, Text = ne.Text,
IsInTable = noteWithTable.Cells.Any(cell =>
ne.X >= cell.MinPoint.X && ne.X <= cell.MaxPoint.X &&
ne.Y >= cell.MinPoint.Y && ne.Y <= cell.MaxPoint.Y)
}).ToList()
};
MainWindow.SaveVisualizationData(visualizationData);
LogMessage($"[DEBUG] 테이블 Note 시각화 데이터 추가: {visualizationData.FileName} (셀: {visualizationData.Cells.Count}개)");
}
}
else
{
LogMessage($"[DEBUG] Note 엔티티가 없어 시각화 데이터를 생성하지 않습니다: {Path.GetFileName(filePath)}");
}
}
LogMessage($"[DEBUG] 총 {allDwgFiles.Count}개 파일의 시각화 데이터 저장 완료.");
// 최종 시각화 데이터 확인
var finalVisualizationData = MainWindow.GetVisualizationData();
LogMessage($"[DEBUG] 최종 저장된 시각화 데이터: {finalVisualizationData.Count}개 항목");
LogMessage("✅ Height 정렬 Excel 파일 생성 완료");
LogMessage($"📁 저장된 파일: {Path.GetFileName(savePath)}");
}
@@ -2388,5 +2569,298 @@ namespace DwgExtractorManual
_sqlDatas?.Dispose();
base.OnClosed(e);
}
/// <summary>
/// Note 추출 기능 테스트 메서드
/// </summary>
private async Task TestNoteExtraction()
{
try
{
LogMessage("🧪 === Note 추출 기능 테스트 시작 ===");
string sourceFolder = txtSourceFolder.Text;
string resultFolder = txtResultFolder.Text;
if (string.IsNullOrEmpty(sourceFolder) || !Directory.Exists(sourceFolder))
{
LogMessage("❌ 소스 폴더가 선택되지 않았거나 존재하지 않습니다.");
UpdateStatus("소스 폴더를 선택해주세요.");
return;
}
if (string.IsNullOrEmpty(resultFolder))
{
LogMessage("❌ 결과 폴더가 선택되지 않았습니다.");
UpdateStatus("결과 폴더를 선택해주세요.");
return;
}
// 결과 폴더가 없으면 생성
if (!Directory.Exists(resultFolder))
{
Directory.CreateDirectory(resultFolder);
LogMessage($"📁 결과 폴더 생성: {resultFolder}");
}
// DWG 파일 찾기
var dwgFiles = Directory.GetFiles(sourceFolder, "*.dwg", SearchOption.AllDirectories);
LogMessage($"📊 발견된 DWG 파일 수: {dwgFiles.Length}개");
if (dwgFiles.Length == 0)
{
LogMessage("⚠️ DWG 파일이 없습니다.");
UpdateStatus("DWG 파일이 없습니다.");
return;
}
UpdateStatus("🔧 Note 추출 중...");
progressBar.Maximum = dwgFiles.Length;
progressBar.Value = 0;
// Teigha 서비스 초기화
LogMessage("🔧 Teigha 서비스 초기화 중...");
TeighaServicesManager.Instance.AcquireServices();
// 간단한 빈 매핑 데이터로 FieldMapper 생성 (테스트용)
var mappingData = new MappingTableData();
var fieldMapper = new FieldMapper(mappingData);
var extractor = new DwgDataExtractor(fieldMapper);
var csvWriter = new CsvDataWriter();
int processedCount = 0;
int successCount = 0;
int failureCount = 0;
// 각 DWG 파일에 대해 Note 추출 테스트
foreach (string dwgFile in dwgFiles.Take(3)) // 처음 3개 파일만 테스트
{
try
{
string fileName = Path.GetFileNameWithoutExtension(dwgFile);
LogMessage($"🔍 [{processedCount + 1}/{Math.Min(3, dwgFiles.Length)}] Note 추출 중: {fileName}");
// Note 데이터 추출
var noteExtractionResult = extractor.ExtractNotesFromDrawing(dwgFile);
var noteEntities = noteExtractionResult.NoteEntities;
// 테이블이 있는 Note만 시각화 데이터 저장
if (noteEntities.Any())
{
var notesWithTables = noteEntities.Where(ne =>
ne.Type == "Note" &&
ne.Cells != null &&
ne.Cells.Count >= 4 && // 최소 4개 셀이 있어야 테이블로 인정
ne.TableSegments != null &&
ne.TableSegments.Count >= 4).ToList(); // 최소 4개 선분이 있어야 함
LogMessage($" 테이블이 있는 Note: {notesWithTables.Count}개");
foreach (var noteWithTable in notesWithTables)
{
var visualizationData = new TableCellVisualizationData
{
FileName = $"{Path.GetFileName(dwgFile)} - {noteWithTable.Text}",
NoteText = noteWithTable.Text,
NoteBounds = (
noteWithTable.Cells.Min(c => c.MinPoint.X),
noteWithTable.Cells.Min(c => c.MinPoint.Y),
noteWithTable.Cells.Max(c => c.MaxPoint.X),
noteWithTable.Cells.Max(c => c.MaxPoint.Y)
),
Cells = noteWithTable.Cells.Select(tc => new CellBounds
{
MinX = tc.MinPoint.X, MinY = tc.MinPoint.Y, MaxX = tc.MaxPoint.X, MaxY = tc.MaxPoint.Y,
Row = tc.Row, Column = tc.Column, Text = tc.CellText
}).ToList(),
TableSegments = noteWithTable.TableSegments.Select(ts => new SegmentInfo
{
StartX = ts.StartX, StartY = ts.StartY,
EndX = ts.EndX, EndY = ts.EndY,
IsHorizontal = ts.IsHorizontal
}).ToList(),
IntersectionPoints = noteWithTable.IntersectionPoints,
DiagonalLines = noteExtractionResult.DiagonalLines.Where(dl =>
noteWithTable.Cells.Any(cell =>
(dl.Item1.X >= cell.MinPoint.X && dl.Item1.X <= cell.MaxPoint.X &&
dl.Item1.Y >= cell.MinPoint.Y && dl.Item1.Y <= cell.MaxPoint.Y) ||
(dl.Item2.X >= cell.MinPoint.X && dl.Item2.X <= cell.MaxPoint.X &&
dl.Item2.Y >= cell.MinPoint.Y && dl.Item2.Y <= cell.MaxPoint.Y))).Select(dl => new DiagonalLine
{
StartX = dl.Item1.X, StartY = dl.Item1.Y, EndX = dl.Item2.X, EndY = dl.Item2.Y, Label = dl.Item3
}).ToList(),
CellBoundaries = noteWithTable.CellBoundaries?.Select(cb => new CellBoundaryInfo
{
TopLeftX = cb.TopLeft.X, TopLeftY = cb.TopLeft.Y,
TopRightX = cb.TopRight.X, TopRightY = cb.TopRight.Y,
BottomLeftX = cb.BottomLeft.X, BottomLeftY = cb.BottomLeft.Y,
BottomRightX = cb.BottomRight.X, BottomRightY = cb.BottomRight.Y,
Label = cb.Label, Width = cb.Width, Height = cb.Height,
CellText = cb.CellText ?? ""
}).ToList() ?? new List<CellBoundaryInfo>(),
TextEntities = noteEntities.Where(ne => ne.Type == "NoteContent").Select(ne => new TextInfo
{
X = ne.X, Y = ne.Y, Text = ne.Text,
IsInTable = noteWithTable.Cells.Any(cell =>
ne.X >= cell.MinPoint.X && ne.X <= cell.MaxPoint.X &&
ne.Y >= cell.MinPoint.Y && ne.Y <= cell.MaxPoint.Y)
}).ToList()
};
MainWindow.SaveVisualizationData(visualizationData);
LogMessage($" ✅ 테이블 Note 시각화 데이터 저장: {visualizationData.FileName} (셀: {visualizationData.Cells.Count}개)");
}
}
LogMessage($" 추출된 엔터티: {noteEntities.Count}개");
var noteCount = noteEntities.Count(ne => ne.Type == "Note");
var contentCount = noteEntities.Count(ne => ne.Type == "NoteContent");
var tableCount = noteEntities.Count(ne => ne.Type == "Note" && !string.IsNullOrEmpty(ne.TableCsv));
LogMessage($" - Note 헤더: {noteCount}개");
LogMessage($" - Note 콘텐츠: {contentCount}개");
LogMessage($" - 테이블 포함 Note: {tableCount}개");
// CSV 파일 생성
if (noteEntities.Count > 0)
{
// Note 박스 텍스트 CSV
var noteTextCsvPath = Path.Combine(resultFolder, $"{fileName}_note_texts.csv");
csvWriter.WriteNoteBoxTextToCsv(noteEntities, noteTextCsvPath);
LogMessage($" ✅ Note 텍스트 CSV 저장: {Path.GetFileName(noteTextCsvPath)}");
// Note 테이블 CSV
var noteTableCsvPath = Path.Combine(resultFolder, $"{fileName}_note_tables.csv");
csvWriter.WriteNoteTablesToCsv(noteEntities, noteTableCsvPath);
LogMessage($" ✅ Note 테이블 CSV 저장: {Path.GetFileName(noteTableCsvPath)}");
// 통합 CSV
var combinedCsvPath = Path.Combine(resultFolder, $"{fileName}_note_combined.csv");
csvWriter.WriteNoteDataToCombinedCsv(noteEntities, combinedCsvPath);
LogMessage($" ✅ 통합 CSV 저장: {Path.GetFileName(combinedCsvPath)}");
// 개별 테이블 CSV
if (tableCount > 0)
{
var individualTablesDir = Path.Combine(resultFolder, $"{fileName}_individual_tables");
csvWriter.WriteIndividualNoteTablesCsv(noteEntities, individualTablesDir);
LogMessage($" ✅ 개별 테이블 CSV 저장: {Path.GetFileName(individualTablesDir)}");
}
// 통계 CSV
var statisticsCsvPath = Path.Combine(resultFolder, $"{fileName}_note_statistics.csv");
csvWriter.WriteNoteStatisticsToCsv(noteEntities, statisticsCsvPath);
LogMessage($" ✅ 통계 CSV 저장: {Path.GetFileName(statisticsCsvPath)}");
// 첫 번째 테이블이 있는 Note의 내용 출력 (디버깅용)
var firstTableNote = noteEntities.FirstOrDefault(ne => ne.Type == "Note" && !string.IsNullOrEmpty(ne.TableCsv));
if (firstTableNote != null)
{
LogMessage($" 📋 첫 번째 테이블 Note: '{firstTableNote.Text}'");
var tableLines = firstTableNote.TableCsv.Split(new[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries);
LogMessage($" 📋 테이블 행 수: {tableLines.Length}");
for (int i = 0; i < Math.Min(3, tableLines.Length); i++)
{
var line = tableLines[i];
if (line.Length > 60) line = line.Substring(0, 60) + "...";
LogMessage($" 행 {i + 1}: {line}");
}
}
}
successCount++;
LogMessage($" ✅ 성공");
}
catch (Exception ex)
{
failureCount++;
LogMessage($" ❌ 실패: {ex.Message}");
}
processedCount++;
progressBar.Value = processedCount;
// UI 업데이트를 위한 지연
await Task.Delay(100);
}
LogMessage($"🧪 === Note 추출 테스트 완료 ===");
LogMessage($"📊 처리 결과: 성공 {successCount}개, 실패 {failureCount}개");
LogMessage($"💾 결과 파일들이 저장되었습니다: {resultFolder}");
UpdateStatus($"Note 추출 테스트 완료: 성공 {successCount}개, 실패 {failureCount}개");
// 결과 폴더 열기
if (successCount > 0)
{
try
{
System.Diagnostics.Process.Start("explorer.exe", resultFolder);
}
catch { }
}
}
catch (Exception ex)
{
LogMessage($"❌ Note 추출 테스트 중 오류: {ex.Message}");
UpdateStatus("Note 추출 테스트 중 오류 발생");
throw;
}
finally
{
try
{
TeighaServicesManager.Instance.ForceDisposeServices();
LogMessage("🔄 Teigha 서비스 정리 완료");
}
catch (Exception ex)
{
LogMessage($"⚠️ Teigha 서비스 정리 중 오류: {ex.Message}");
}
}
}
/// <summary>
/// 빌드 시간을 상태바에 표시합니다.
/// </summary>
private void SetBuildTime()
{
try
{
// 현재 실행 파일의 빌드 시간을 가져옵니다
var assembly = System.Reflection.Assembly.GetExecutingAssembly();
var buildDate = System.IO.File.GetLastWriteTime(assembly.Location);
txtBuildTime.Text = $"빌드: {buildDate:yyyy-MM-dd HH:mm}";
}
catch (Exception ex)
{
txtBuildTime.Text = "빌드: 알 수 없음";
LogMessage($"⚠️ 빌드 시간 조회 오류: {ex.Message}");
}
}
/// <summary>
/// 교차점 테스트 버튼 클릭 이벤트
/// </summary>
private void BtnTestIntersection_Click(object sender, RoutedEventArgs e)
{
try
{
LogMessage("🔬 교차점 생성 테스트 시작...");
UpdateStatus("교차점 테스트 중...");
// 테스트 실행
IntersectionTestDebugger.RunIntersectionTest();
LogMessage("✅ 교차점 테스트 완료 - Debug 창을 확인하세요");
UpdateStatus("교차점 테스트 완료");
}
catch (Exception ex)
{
LogMessage($"❌ 교차점 테스트 중 오류: {ex.Message}");
UpdateStatus("교차점 테스트 중 오류 발생");
}
}
}
}