diff --git a/Models/DwgDataExtractor.cs b/Models/DwgDataExtractor.cs index 2492fbb..33d3744 100644 --- a/Models/DwgDataExtractor.cs +++ b/Models/DwgDataExtractor.cs @@ -513,56 +513,189 @@ namespace DwgExtractorManual.Models private (Point3d minPoint, Point3d maxPoint)? FindNoteBox( Transaction tran, DBText noteText, List polylineIds, List lineIds, HashSet<(Point3d minPoint, Point3d maxPoint)> usedBoxes) { - var notePos = noteText.Position; - var noteHeight = noteText.Height; - - double stableX; - if (noteText.HorizontalMode == TextHorizontalMode.TextLeft) + var allLineSegments = new List(); + try { - stableX = noteText.Position.X; - } - else - { - stableX = noteText.AlignmentPoint.X; - } + var notePos = noteText.Position; + var noteHeight = noteText.Height; - // 검색 라인 정의: 안정적인 X좌표를 기준으로 하되, 약간의 오차를 허용하는 너비 - double searchY = notePos.Y - (noteHeight * 2); - double searchWidth = noteHeight * 15; - var searchLineStart = new Point3d(stableX - noteHeight * 2, searchY, 0); - var searchLineEnd = new Point3d(stableX + searchWidth, searchY, 0); - - Debug.WriteLine($"[DEBUG] 안정화된 검색 라인: ({searchLineStart.X:F2}, {searchLineStart.Y:F2}) to ({searchLineEnd.X:F2}, {searchLineEnd.Y:F2}) for NOTE at ({notePos.X:F2}, {notePos.Y:F2}) with stableX={stableX:F2}"); - - // 1. Polyline과 교차 확인 - foreach (var polylineId in polylineIds) - { - using (var polyline = tran.GetObject(polylineId, OpenMode.ForRead) as Polyline) + // Polylines를 Line 세그먼트로 분해하여 추가 + foreach (var polylineId in polylineIds) { - if (polyline == null) continue; - - if (DoesLineIntersectPolyline(searchLineStart, searchLineEnd, polyline)) + using (var polyline = tran.GetObject(polylineId, OpenMode.ForRead) as Polyline) { - var box = GetPolylineBounds(polyline); - if (box.HasValue && IsValidNoteBox(box.Value, notePos, noteHeight) && !usedBoxes.Contains(box.Value)) + if (polyline == null) continue; + var explodedEntities = new DBObjectCollection(); + try { - Debug.WriteLine($"[DEBUG] 교차하는 Polyline 박스 발견: {box.Value.minPoint} to {box.Value.maxPoint}"); - return box; + polyline.Explode(explodedEntities); + foreach (DBObject obj in explodedEntities) + { + if (obj is Line line) + { + allLineSegments.Add(line.Clone() as Line); + } + obj.Dispose(); + } + } + catch (System.Exception ex) + { + Debug.WriteLine($"[DEBUG] Polyline 분해 중 오류: {ex.Message}"); + } + finally + { + explodedEntities.Dispose(); } } } + + // 기존 Line들을 추가 + foreach (var lineId in lineIds) + { + using (var line = tran.GetObject(lineId, OpenMode.ForRead) as Line) + { + if (line != null) + { + allLineSegments.Add(line.Clone() as Line); + } + } + } + + double stableX; + if (noteText.HorizontalMode == TextHorizontalMode.TextLeft) + { + stableX = noteText.Position.X; + } + else + { + stableX = noteText.AlignmentPoint.X; + } + + double searchY = notePos.Y - (noteHeight * 2); + double searchWidth = noteHeight * 15; + var searchLineStart = new Point3d(stableX - noteHeight * 6, searchY, 0); // 왼쪽으로 확장 (중간값) + var searchLineEnd = new Point3d(stableX + searchWidth, searchY, 0); + var searchLineEnd = new Point3d(stableX + searchWidth, searchY, 0); + + Debug.WriteLine($"[DEBUG] 확장된 통합 검색 라인: ({searchLineStart.X:F2}, {searchLineStart.Y:F2}) to ({searchLineEnd.X:F2}, {searchLineEnd.Y:F2}) for NOTE at ({notePos.X:F2}, {notePos.Y:F2})"); + + var intersectingLines = FindIntersectingLineSegments(allLineSegments, searchLineStart, searchLineEnd); + foreach (var startLine in intersectingLines) + { + var rectangle = TraceRectangleFromLineSegments(allLineSegments, startLine, notePos, noteHeight, usedBoxes); + if (rectangle.HasValue) + { + Debug.WriteLine($"[DEBUG] 교차하는 Line/Polyline 조합 사각형 발견: {rectangle.Value.minPoint} to {rectangle.Value.maxPoint}"); + return rectangle; + } + } + + return null; + } + finally + { + // 생성된 모든 Line 객체들을 Dispose + foreach (var line in allLineSegments) + { + line.Dispose(); + } + } + } + + private List FindIntersectingLineSegments(List allLineSegments, Point3d searchLineStart, Point3d searchLineEnd) + { + var intersectingLines = new List(); + foreach (var line in allLineSegments) + { + if (DoLinesIntersect(searchLineStart, searchLineEnd, line.StartPoint, line.EndPoint)) + { + intersectingLines.Add(line); + } + } + return intersectingLines; + } + + private (Point3d minPoint, Point3d maxPoint)? TraceRectangleFromLineSegments(List allLineSegments, Line startLine, Point3d notePos, double noteHeight, HashSet<(Point3d minPoint, Point3d maxPoint)> usedBoxes) + { + try + { + double tolerance = noteHeight * 2.0; + var visitedLines = new HashSet(); + var rectanglePoints = new List(); + + var currentPoint = startLine.StartPoint; + var nextPoint = startLine.EndPoint; + rectanglePoints.Add(currentPoint); + rectanglePoints.Add(nextPoint); + visitedLines.Add(startLine); + + for (int step = 0; step < 5; step++) + { + var findResult = FindNextConnectedLineSegment(allLineSegments, nextPoint, visitedLines, tolerance); + if (findResult == null) break; + + var nextLine = findResult.Value.line; + var connectionType = findResult.Value.connectionType; + + Point3d newNextPoint = (connectionType == "Start") ? nextLine.EndPoint : nextLine.StartPoint; + + rectanglePoints.Add(newNextPoint); + visitedLines.Add(nextLine); + nextPoint = newNextPoint; + + if (nextPoint.DistanceTo(currentPoint) < tolerance) + { + break; + } + } + + if (rectanglePoints.Count >= 4) + { + var bounds = CalculateBounds(rectanglePoints); + if (bounds.HasValue && IsValidNoteBox(bounds.Value, notePos, noteHeight) && !usedBoxes.Contains(bounds.Value)) + { + return bounds; + } + } + return null; + } + catch (System.Exception ex) + { + Debug.WriteLine($"[DEBUG] 통합 사각형 추적 중 오류: {ex.Message}"); + return null; + } + } + + private (Line line, string connectionType)? FindNextConnectedLineSegment(List allLineSegments, Point3d currentPoint, HashSet visitedLines, double tolerance) + { + Line bestMatch = null; + string bestConnectionType = null; + double minDistance = tolerance; + + foreach (var line in allLineSegments) + { + if (visitedLines.Contains(line)) continue; + + double distToStart = currentPoint.DistanceTo(line.StartPoint); + if (distToStart < minDistance) + { + minDistance = distToStart; + bestMatch = line; + bestConnectionType = "Start"; + } + + double distToEnd = currentPoint.DistanceTo(line.EndPoint); + if (distToEnd < minDistance) + { + minDistance = distToEnd; + bestMatch = line; + bestConnectionType = "End"; + } } - // 2. Line들과 교차하여 사각형 찾기 - var intersectingLines = FindIntersectingLines(tran, lineIds, searchLineStart, searchLineEnd); - foreach (var startLineId in intersectingLines) + if (bestMatch != null) { - 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; - } + return (bestMatch, bestConnectionType); } return null; @@ -682,150 +815,7 @@ namespace DwgExtractorManual.Models } } - /// - /// 수평선과 교차하는 Line들을 찾습니다. - /// - private List FindIntersectingLines(Transaction tran, List lineIds, Point3d searchLineStart, Point3d searchLineEnd) - { - var intersectingLines = new List(); - - 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; - } - - /// - /// Line에서 시작하여 반시계방향으로 사각형을 추적합니다. (갭 허용) - /// - private (Point3d minPoint, Point3d maxPoint)? TraceRectangleFromLine(Transaction tran, List lineIds, ObjectId startLineId, Point3d notePos, double noteHeight) - { - try - { - double tolerance = noteHeight * 2.0; // 갭 허용 오차를 Note 높이에 비례하여 설정 - var visitedLines = new HashSet(); - var rectanglePoints = new List(); - - 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:F2}, {currentPoint.Y:F2}) -> ({nextPoint.X:F2}, {nextPoint.Y:F2})"); - - for (int step = 0; step < 5; step++) // 최대 5번의 연결 시도 - { - var findResult = FindNextConnectedLine(tran, lineIds, nextPoint, visitedLines, tolerance); - if (findResult == null) break; - - var nextLineId = findResult.Value.lineId; - var connectionType = findResult.Value.connectionType; - - using (var nextLine = tran.GetObject(nextLineId, OpenMode.ForRead) as Line) - { - if (nextLine == null) break; - - Point3d newNextPoint; - if (connectionType == "Start") - { - newNextPoint = nextLine.EndPoint; - } - else - { - newNextPoint = nextLine.StartPoint; - } - - rectanglePoints.Add(newNextPoint); - visitedLines.Add(nextLineId); - nextPoint = newNextPoint; - - Debug.WriteLine($"[DEBUG] 다음 Line 추가 (갭 허용): {nextLine.StartPoint} -> {nextLine.EndPoint}"); - - if (nextPoint.DistanceTo(currentPoint) < tolerance) - { - Debug.WriteLine("[DEBUG] 사각형 완성됨 (갭 허용)"); - break; - } - } - } - - 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; - } - } - - /// - /// 현재 점에서 가장 가까운 연결된 다음 Line을 찾습니다. (갭 허용) - /// - private (ObjectId lineId, string connectionType)? FindNextConnectedLine(Transaction tran, List lineIds, Point3d currentPoint, HashSet visitedLines, double tolerance) - { - ObjectId? bestMatchId = null; - string? bestConnectionType = null; - double minDistance = 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; - - double distToStart = currentPoint.DistanceTo(line.StartPoint); - if (distToStart < minDistance) - { - minDistance = distToStart; - bestMatchId = lineId; - bestConnectionType = "Start"; - } - - double distToEnd = currentPoint.DistanceTo(line.EndPoint); - if (distToEnd < minDistance) - { - minDistance = distToEnd; - bestMatchId = lineId; - bestConnectionType = "End"; - } - } - } - - if (bestMatchId.HasValue) - { - return (bestMatchId.Value, bestConnectionType); - } - - return null; - } + /// /// 점들의 경계 상자를 계산합니다. diff --git a/Models/ExcelDataWriter.cs b/Models/ExcelDataWriter.cs index dbe5356..f1183df 100644 --- a/Models/ExcelDataWriter.cs +++ b/Models/ExcelDataWriter.cs @@ -340,6 +340,14 @@ namespace DwgExtractorManual.Models worksheet.Cells[row, 5] = fileName ?? ""; worksheet.Cells[row, 6] = noteEntity.Text ?? ""; + // "NOTE" 타입인 경우 행 배경색 변경 + if (noteEntity.Type == "Note") + { + Excel.Range noteRowRange = worksheet.Range[worksheet.Cells[row, 1], worksheet.Cells[row, 6]]; + noteRowRange.Interior.Color = System.Drawing.ColorTranslator.ToOle(System.Drawing.Color.LightYellow); + noteRowRange.Font.Bold = true; + } + Debug.WriteLine($"[DEBUG] Excel 기록: Row {row}, Order {noteEntity.SortOrder}, Type {noteEntity.Type}, Pos({noteEntity.X:F1},{noteEntity.Y:F1}), Text: '{noteEntity.Text}'"); row++; }