1차 완료

This commit is contained in:
horu2day
2025-08-13 13:57:46 +09:00
parent f114b8b642
commit 52fbc1c967
3 changed files with 167 additions and 73 deletions

View File

@@ -107,6 +107,14 @@ namespace DwgExtractorManual.Models
/// 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)
{
return ExtractTextEntitiesWithHeightExcluding(filePath, new HashSet<ObjectId>());
}
/// <summary>
/// DWG 파일에서 텍스트 엔터티들을 추출하되, 지정된 ObjectId들은 제외합니다.
/// </summary>
public List<TextEntityInfo> ExtractTextEntitiesWithHeightExcluding(string filePath, HashSet<ObjectId> excludeIds)
{
var attRefEntities = new List<TextEntityInfo>();
var otherTextEntities = new List<TextEntityInfo>();
@@ -137,15 +145,19 @@ namespace DwgExtractorManual.Models
{
if (attRef != null)
{
var textString = attRef.TextString == null ? "" : attRef.TextString;
attRefEntities.Add(new TextEntityInfo
// 일반 텍스트 추출시 height 3 이하 제외
if (attRef.Height > 3)
{
Height = attRef.Height,
Type = "AttRef",
Layer = layerName,
Tag = attRef.Tag,
Text = textString,
});
var textString = attRef.TextString == null ? "" : attRef.TextString;
attRefEntities.Add(new TextEntityInfo
{
Height = attRef.Height,
Type = "AttRef",
Layer = layerName,
Tag = attRef.Tag,
Text = textString,
});
}
}
}
}
@@ -153,26 +165,42 @@ namespace DwgExtractorManual.Models
// DBText ó<><C3B3>
else if (ent is DBText dbText)
{
otherTextEntities.Add(new TextEntityInfo
// <20>Ϲ<EFBFBD> <20>ؽ<EFBFBD>Ʈ <20><><EFBFBD><EFBFBD><EFBFBD> height 3 <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>
// Note에서 사용된 텍스트 제외
if (!excludeIds.Contains(entId))
{
Height = dbText.Height,
Type = "DBText",
Layer = layerName,
Tag = "",
Text = dbText.TextString
});
if (dbText.Height > 3)
{
otherTextEntities.Add(new TextEntityInfo
{
Height = dbText.Height,
Type = "DBText",
Layer = layerName,
Tag = "",
Text = dbText.TextString
});
}
}
}
// MText ó<><C3B3>
else if (ent is MText mText)
{
otherTextEntities.Add(new TextEntityInfo
// <20>Ϲ<EFBFBD> <20>ؽ<EFBFBD>Ʈ <20><><EFBFBD><EFBFBD><EFBFBD> height 3 <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>
// Note에서 사용된 텍스트 제외
if (!excludeIds.Contains(entId))
{
Height = mText.Height,
Type = "MText",
Layer = layerName,
Tag = "",
Text = mText.Contents
});
if (mText.Height > 3)
{
otherTextEntities.Add(new TextEntityInfo
{
Height = mText.Height,
Type = "MText",
Layer = layerName,
Tag = "",
Text = mText.Contents
});
}
}
}
}
}
@@ -404,6 +432,9 @@ namespace DwgExtractorManual.Models
Debug.WriteLine($"[DEBUG] Skipping null noteText for ObjectId: {noteTextId}");
continue;
}
// Note 헤더 텍스트를 사용된 텍스트 ID에 추가
result.UsedTextIds.Add(noteTextId);
// 특정 노트만 테스트하기 위한 필터 (디버깅용)
// if (noteText == null || !noteText.TextString.Contains("도로용지경계 기준 노트"))
// {
@@ -460,6 +491,12 @@ namespace DwgExtractorManual.Models
// 테이블 외부의 일반 텍스트들을 좌표별로 정렬하여 그룹에 추가
var sortedNonTableTexts = GetSortedNoteContents(tran, nonTableTextIds, database);
currentNoteGroup.AddRange(sortedNonTableTexts);
// 박스 내부 텍스트들을 사용된 텍스트 ID에 추가
foreach (var textId in nonTableTextIds)
{
result.UsedTextIds.Add(textId);
}
}
else
{
@@ -509,6 +546,7 @@ namespace DwgExtractorManual.Models
}
Debug.WriteLine($"[DEBUG] 최종 Note 엔티티 정렬 완료: {noteEntities.Count}개");
Debug.WriteLine($"[DEBUG] Note에서 사용된 텍스트 ID 개수: {result.UsedTextIds.Count}개");
result.NoteEntities = noteEntities;
result.IntersectionPoints = LastIntersectionPoints.Select(ip => new IntersectionPoint { Position = ip.Position, DirectionBits = ip.DirectionBits, Row = ip.Row, Column = ip.Column }).ToList();
@@ -2146,7 +2184,7 @@ namespace DwgExtractorManual.Models
foreach (var cellBoundary in cellBoundaries)
{
var textsInCell = new List<string>();
var textsInCell = new List<(string text, double y)>();
foreach (var textId in allTextIds)
{
@@ -2177,14 +2215,15 @@ namespace DwgExtractorManual.Models
{
if (!string.IsNullOrWhiteSpace(textContent))
{
textsInCell.Add(textContent.Trim());
Debug.WriteLine($"[CELL_TEXT] ✅ {cellBoundary.Label}에 텍스트 추가: '{textContent.Trim()}'");
textsInCell.Add((textContent.Trim(), textPosition.Y));
Debug.WriteLine($"[CELL_TEXT] ✅ {cellBoundary.Label}에 텍스트 추가: '{textContent.Trim()}' at Y={textPosition.Y:F1}");
}
}
}
// 셀 경계에 찾은 텍스트들을 콤마로 연결하여 저장
cellBoundary.CellText = string.Join(", ", textsInCell);
// Y값이 큰 것부터 정렬 (위에서 아래로)하여 콤마로 연결
var sortedTexts = textsInCell.OrderByDescending(t => t.y).Select(t => t.text);
cellBoundary.CellText = string.Join(", ", sortedTexts);
Debug.WriteLine($"[CELL_TEXT] {cellBoundary.Label} 최종 텍스트: '{cellBoundary.CellText}'");
}
@@ -2731,7 +2770,7 @@ namespace DwgExtractorManual.Models
foreach (var cell in cells)
{
var textsInCell = new List<string>();
var textsInCell = new List<(string text, double y)>();
foreach (var textId in textIds)
{
if (assignedIds.Contains(textId)) continue;
@@ -2743,16 +2782,19 @@ namespace DwgExtractorManual.Models
// Check if the text's alignment point is inside the cell
if (IsPointInCell(dbText.Position, cell))
{
textsInCell.Add(dbText.TextString);
cell.CellText = string.Join("\n", textsInCell);
textsInCell.Add((dbText.TextString, dbText.Position.Y));
assignedIds.Add(textId);
}
}
}
}
if(textsInCell.Any())
// Y값이 큰 것부터 정렬 (위에서 아래로)하여 텍스트 설정
if (textsInCell.Any())
{
assignedTexts[cell] = textsInCell;
var sortedTexts = textsInCell.OrderByDescending(t => t.y).Select(t => t.text);
cell.CellText = string.Join("\n", sortedTexts);
assignedTexts[cell] = textsInCell.Select(t => t.text).ToList();
}
}
@@ -2824,6 +2866,7 @@ namespace DwgExtractorManual.Models
public List<IntersectionPoint> IntersectionPoints { get; set; } = new List<IntersectionPoint>();
public List<(Teigha.Geometry.Point3d topLeft, Teigha.Geometry.Point3d bottomRight, string label)> DiagonalLines { get; set; } = new List<(Teigha.Geometry.Point3d, Teigha.Geometry.Point3d, string)>();
public List<SegmentInfo> TableSegments { get; set; } = new List<SegmentInfo>();
public HashSet<ObjectId> UsedTextIds { get; set; } = new HashSet<ObjectId>(); // Note에서 사용된 텍스트 ID들
}
/// <summary>

View File

@@ -422,39 +422,53 @@ namespace DwgExtractorManual.Models
int maxTableRow = 0;
foreach (var cellBoundary in noteEntity.CellBoundaries)
{
var (cellRow, cellCol) = ParseRowColFromLabel(cellBoundary.Label);
Debug.WriteLine($"[DEBUG] CellBoundary 처리: {cellBoundary.Label} → Row={cellRow}, Col={cellCol}, Text='{cellBoundary.CellText}'");
var (sRow, sCol, eRow, eCol) = ParseCellRangeFromLabel(cellBoundary.Label);
Debug.WriteLine($"[DEBUG] CellBoundary 처리: {cellBoundary.Label} → Range=R{sRow}C{sCol}:R{eRow}C{eCol}, Text='{cellBoundary.CellText}'");
if (cellRow > 0 && cellCol > 0)
if (sRow > 0 && sCol > 0 && eRow > 0 && eCol > 0)
{
// Excel에서 테이블 위치 계산:
// R1 → Note의 현재 행 (currentRow)
// R2 → Note의 다음 행 (currentRow + 1)
// C1 → G열(7), C2 → H열(8)
int excelRow = currentRow + (cellRow - 1); // R1=currentRow, R2=currentRow+1, ...
int excelCol = 7 + (cellCol - 1); // C1=G열(7), C2=H열(8), ...
// 병합된 영역의 셀 개수 계산: (eRow - sRow) × (eCol - sCol)
int rowCount = eRow - sRow; // 행 개수 (bottomRight - topLeft)
int colCount = eCol - sCol; // 열 개수 (bottomRight - topLeft)
Debug.WriteLine($"[DEBUG] Excel 위치: {cellBoundary.Label} → Excel[{excelRow},{excelCol}]");
Debug.WriteLine($"[DEBUG] 병합 영역 크기: {rowCount+1}행 × {colCount+1}열");
// Excel 범위 체크 (최대 20개 컬럼까지)
if (excelCol <= 26) // Z열까지
// 병합된 영역의 모든 셀에 텍스트 복사 (topLeft부터 bottomRight-1까지)
for (int r = sRow; r < eRow; r++) // < eRow (bottomRight 제외)
{
// CellText가 비어있어도 일단 배치해보기 (디버그용)
var cellValue = string.IsNullOrEmpty(cellBoundary.CellText) ? "[빈셀]" : cellBoundary.CellText;
worksheet.Cells[excelRow, excelCol] = cellValue;
Debug.WriteLine($"[DEBUG] ✅ 셀 배치 완료: {cellBoundary.Label} → Excel[{excelRow},{excelCol}] = '{cellValue}'");
for (int c = sCol; c < eCol; c++) // < eCol (bottomRight 제외)
{
// Excel에서 테이블 위치 계산:
// R1 → Note의 현재 행 (currentRow)
// R2 → Note의 다음 행 (currentRow + 1)
// C1 → G열(7), C2 → H열(8)
int excelRow = currentRow + (r - 1); // R1=currentRow, R2=currentRow+1, ...
int excelCol = 7 + (c - 1); // C1=G열(7), C2=H열(8), ...
// Excel 범위 체크 (최대 20개 컬럼까지)
if (excelCol <= 26) // Z열까지
{
// CellText가 비어있어도 일단 배치해보기 (디버그용)
var cellValue = string.IsNullOrEmpty(cellBoundary.CellText) ? "[빈셀]" : cellBoundary.CellText;
// 텍스트 형식으로 설정하여 "0:0" 같은 값이 시간으로 포맷되지 않도록 함
var cell = (Excel.Range)worksheet.Cells[excelRow, excelCol];
cell.NumberFormat = "@"; // 텍스트 형식
cell.Value = cellValue;
Debug.WriteLine($"[DEBUG] ✅ 셀 복사: R{r}C{c} → Excel[{excelRow},{excelCol}] = '{cellValue}'");
}
else
{
Debug.WriteLine($"[DEBUG] ❌ Excel 컬럼 범위 초과: {excelCol} > 26");
}
// 테이블이 차지하는 최대 행 수 추적
maxTableRow = Math.Max(maxTableRow, r);
}
}
else
{
Debug.WriteLine($"[DEBUG] ❌ Excel 컬럼 범위 초과: {excelCol} > 26");
}
// 테이블이 차지하는 최대 행 수 추적
maxTableRow = Math.Max(maxTableRow, cellRow);
}
else
{
Debug.WriteLine($"[DEBUG] ❌ 잘못된 Row/Col: {cellBoundary.Label} → Row={cellRow}, Col={cellCol}");
Debug.WriteLine($"[DEBUG] ❌ 잘못된 Range: {cellBoundary.Label} → R{sRow}C{sCol}:R{eRow}C{eCol}");
}
}
@@ -479,7 +493,10 @@ namespace DwgExtractorManual.Models
for (int cellIndex = 0; cellIndex < Math.Min(tableCells.Length, 15); cellIndex++)
{
var cellValue = tableCells[cellIndex].Trim().Trim('"'); // 따옴표 제거
worksheet.Cells[currentRow, 7 + cellIndex] = cellValue; // G열(7)부터 시작
// 텍스트 형식으로 설정하여 "0:0" 같은 값이 시간으로 포맷되지 않도록 함
var cell = (Excel.Range)worksheet.Cells[currentRow, 7 + cellIndex];
cell.NumberFormat = "@"; // 텍스트 형식
cell.Value = cellValue; // G열(7)부터 시작
}
// 표의 첫 번째 행이 아니면 새로운 Excel 행 추가
@@ -551,30 +568,59 @@ namespace DwgExtractorManual.Models
/// <summary>
/// 라벨에서 Row, Col 정보를 파싱합니다.
/// 예: "R1C2" → (1, 2) 또는 "R2C2→R3C4" → (2, 2) (시작 위치 사용)
/// 라벨에서 셀 범위 정보를 파싱합니다.
/// 예: "R1C2" → (1, 2, 1, 2) 또는 "R2C2→R3C4" → (2, 2, 3, 4)
/// </summary>
private (int row, int col) ParseRowColFromLabel(string label)
private (int sRow, int sCol, int eRow, int eCol) ParseCellRangeFromLabel(string label)
{
try
{
if (string.IsNullOrEmpty(label))
return (0, 0);
return (0, 0, 0, 0);
// "R2C2→R3C4" 형태인 경우 시작 부분만 사용
var startPart = label;
if (label.Contains("→"))
{
startPart = label.Split('→')[0];
// "R2C2→R3C4" 형태 - 범위 파싱
var parts = label.Split('→');
if (parts.Length == 2)
{
var (sRow, sCol) = ParseSingleCell(parts[0]);
var (eRow, eCol) = ParseSingleCell(parts[1]);
return (sRow, sCol, eRow, eCol);
}
}
else
{
// "R1C2" 형태 - 단일 셀
var (row, col) = ParseSingleCell(label);
return (row, col, row, col);
}
return (0, 0, 0, 0);
}
catch
{
return (0, 0, 0, 0);
}
}
var rIndex = startPart.IndexOf('R');
var cIndex = startPart.IndexOf('C');
/// <summary>
/// 단일 셀 위치를 파싱합니다. (예: "R2C3" → (2, 3))
/// </summary>
private (int row, int col) ParseSingleCell(string cellStr)
{
try
{
if (string.IsNullOrEmpty(cellStr))
return (0, 0);
var rIndex = cellStr.IndexOf('R');
var cIndex = cellStr.IndexOf('C');
if (rIndex >= 0 && cIndex > rIndex)
{
var rowStr = startPart.Substring(rIndex + 1, cIndex - rIndex - 1);
var colStr = startPart.Substring(cIndex + 1);
var rowStr = cellStr.Substring(rIndex + 1, cIndex - rIndex - 1);
var colStr = cellStr.Substring(cIndex + 1);
if (int.TryParse(rowStr, out int row) && int.TryParse(colStr, out int col))
{

View File

@@ -198,7 +198,11 @@ namespace DwgExtractorManual.Models
worksheet.Name = excelManager.GetValidSheetName(fileName);
firstSheetProcessed = true;
var textEntities = DwgExtractor.ExtractTextEntitiesWithHeight(dwgFile);
// Note 엔티티 먼저 추출
var noteEntities = DwgExtractor.ExtractNotesFromDrawing(dwgFile);
// Note에서 사용된 텍스트 제외하고 일반 텍스트 추출
var textEntities = DwgExtractor.ExtractTextEntitiesWithHeightExcluding(dwgFile, noteEntities.UsedTextIds);
excelWriter.WriteHeightSortedData(textEntities, worksheet, fileName);
Debug.WriteLine($"[DEBUG] {fileName} 시트 완료: {textEntities.Count}개 엔티티");
@@ -263,11 +267,12 @@ namespace DwgExtractorManual.Models
worksheet.Name = excelManager.GetValidSheetName(fileName);
firstSheetProcessed = true;
var textEntities = DwgExtractor.ExtractTextEntitiesWithHeight(filePath);
excelWriter.WriteHeightSortedData(textEntities, worksheet, fileName);
// Note 엔티티 추출 및 기록
// Note 엔티티 먼저 추출
var noteEntities = DwgExtractor.ExtractNotesFromDrawing(filePath);
// Note에서 사용된 텍스트 제외하고 일반 텍스트 추출
var textEntities = DwgExtractor.ExtractTextEntitiesWithHeightExcluding(filePath, noteEntities.UsedTextIds);
excelWriter.WriteHeightSortedData(textEntities, worksheet, fileName);
if (noteEntities.NoteEntities.Count > 0)
{
excelWriter.WriteNoteEntities(noteEntities.NoteEntities, worksheet, fileName);