1차 완료
This commit is contained in:
@@ -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>();
|
||||
@@ -136,6 +144,9 @@ namespace DwgExtractorManual.Models
|
||||
using (var attRef = tran.GetObject(attId, OpenMode.ForRead) as AttributeReference)
|
||||
{
|
||||
if (attRef != null)
|
||||
{
|
||||
// 일반 텍스트 추출시 height 3 이하 제외
|
||||
if (attRef.Height > 3)
|
||||
{
|
||||
var textString = attRef.TextString == null ? "" : attRef.TextString;
|
||||
attRefEntities.Add(new TextEntityInfo
|
||||
@@ -150,8 +161,15 @@ namespace DwgExtractorManual.Models
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// DBText ó<><C3B3>
|
||||
else if (ent is DBText dbText)
|
||||
{
|
||||
// <20>Ϲ<EFBFBD> <20>ؽ<EFBFBD>Ʈ <20><><EFBFBD><EFBFBD><EFBFBD> height 3 <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>
|
||||
// Note에서 사용된 텍스트 제외
|
||||
if (!excludeIds.Contains(entId))
|
||||
{
|
||||
if (dbText.Height > 3)
|
||||
{
|
||||
otherTextEntities.Add(new TextEntityInfo
|
||||
{
|
||||
@@ -162,8 +180,16 @@ namespace DwgExtractorManual.Models
|
||||
Text = dbText.TextString
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
// MText ó<><C3B3>
|
||||
else if (ent is MText mText)
|
||||
{
|
||||
// <20>Ϲ<EFBFBD> <20>ؽ<EFBFBD>Ʈ <20><><EFBFBD><EFBFBD><EFBFBD> height 3 <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>
|
||||
// Note에서 사용된 텍스트 제외
|
||||
if (!excludeIds.Contains(entId))
|
||||
{
|
||||
if (mText.Height > 3)
|
||||
{
|
||||
otherTextEntities.Add(new TextEntityInfo
|
||||
{
|
||||
@@ -177,6 +203,8 @@ namespace DwgExtractorManual.Models
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tran.Commit();
|
||||
}
|
||||
@@ -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>
|
||||
|
||||
@@ -422,27 +422,39 @@ 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)
|
||||
{
|
||||
// 병합된 영역의 셀 개수 계산: (eRow - sRow) × (eCol - sCol)
|
||||
int rowCount = eRow - sRow; // 행 개수 (bottomRight - topLeft)
|
||||
int colCount = eCol - sCol; // 열 개수 (bottomRight - topLeft)
|
||||
|
||||
Debug.WriteLine($"[DEBUG] 병합 영역 크기: {rowCount+1}행 × {colCount+1}열");
|
||||
|
||||
// 병합된 영역의 모든 셀에 텍스트 복사 (topLeft부터 bottomRight-1까지)
|
||||
for (int r = sRow; r < eRow; r++) // < eRow (bottomRight 제외)
|
||||
{
|
||||
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 + (cellRow - 1); // R1=currentRow, R2=currentRow+1, ...
|
||||
int excelCol = 7 + (cellCol - 1); // C1=G열(7), C2=H열(8), ...
|
||||
|
||||
Debug.WriteLine($"[DEBUG] Excel 위치: {cellBoundary.Label} → Excel[{excelRow},{excelCol}]");
|
||||
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;
|
||||
worksheet.Cells[excelRow, excelCol] = cellValue;
|
||||
Debug.WriteLine($"[DEBUG] ✅ 셀 배치 완료: {cellBoundary.Label} → Excel[{excelRow},{excelCol}] = '{cellValue}'");
|
||||
// 텍스트 형식으로 설정하여 "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
|
||||
{
|
||||
@@ -450,11 +462,13 @@ namespace DwgExtractorManual.Models
|
||||
}
|
||||
|
||||
// 테이블이 차지하는 최대 행 수 추적
|
||||
maxTableRow = Math.Max(maxTableRow, cellRow);
|
||||
maxTableRow = Math.Max(maxTableRow, r);
|
||||
}
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
var rIndex = startPart.IndexOf('R');
|
||||
var cIndex = startPart.IndexOf('C');
|
||||
return (0, 0, 0, 0);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return (0, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/// <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))
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user