diff --git a/Models/DwgDataExtractor.cs b/Models/DwgDataExtractor.cs index a8a42b9..2492fbb 100644 --- a/Models/DwgDataExtractor.cs +++ b/Models/DwgDataExtractor.cs @@ -507,30 +507,40 @@ namespace DwgExtractorManual.Models } /// - /// Note 우측아래에 있는 박스를 찾습니다 (교차선 기반 알고리즘). - /// Note position에서 height*2 만큼 아래로 수평선을 그어서 교차하는 Line/Polyline을 찾습니다. + /// Note 텍스트 아래에 있는 콘텐츠 박스를 찾습니다. + /// Note의 정렬점을 기준으로 안정적인 검색 라인을 사용합니다. /// 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) + { + stableX = noteText.Position.X; + } + else + { + stableX = noteText.AlignmentPoint.X; + } - // Note position에서 height * 2 만큼 아래로 수평선 정의 + // 검색 라인 정의: 안정적인 X좌표를 기준으로 하되, 약간의 오차를 허용하는 너비 double searchY = notePos.Y - (noteHeight * 2); - var searchLineStart = new Point3d(notePos.X - noteHeight * 10, searchY, 0); - var searchLineEnd = new Point3d(notePos.X + noteHeight * 50, searchY, 0); + 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}, {searchLineStart.Y}) to ({searchLineEnd.X}, {searchLineEnd.Y})"); + 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과 교차하는지 확인 + // 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); @@ -539,18 +549,12 @@ namespace DwgExtractorManual.Models 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들과 교차하여 닫힌 사각형 찾기 + // 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); @@ -559,10 +563,6 @@ namespace DwgExtractorManual.Models 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; @@ -707,13 +707,13 @@ namespace DwgExtractorManual.Models } /// - /// Line에서 시작하여 반시계방향으로 사각형을 추적합니다. + /// Line에서 시작하여 반시계방향으로 사각형을 추적합니다. (갭 허용) /// private (Point3d minPoint, Point3d maxPoint)? TraceRectangleFromLine(Transaction tran, List lineIds, ObjectId startLineId, Point3d notePos, double noteHeight) { try { - const double tolerance = 2.0; // 좌표 오차 허용 범위 + double tolerance = noteHeight * 2.0; // 갭 허용 오차를 Note 높이에 비례하여 설정 var visitedLines = new HashSet(); var rectanglePoints = new List(); @@ -727,47 +727,44 @@ namespace DwgExtractorManual.Models rectanglePoints.Add(nextPoint); visitedLines.Add(startLineId); - Debug.WriteLine($"[DEBUG] 사각형 추적 시작: ({currentPoint.X}, {currentPoint.Y}) -> ({nextPoint.X}, {nextPoint.Y})"); + Debug.WriteLine($"[DEBUG] 사각형 추적 시작 (갭 허용): ({currentPoint.X:F2}, {currentPoint.Y:F2}) -> ({nextPoint.X:F2}, {nextPoint.Y:F2})"); - // 최대 4개의 Line으로 사각형 완성 시도 - for (int step = 0; step < 3; step++) // 시작 Line 제외하고 3개 더 찾기 + for (int step = 0; step < 5; step++) // 최대 5번의 연결 시도 { - var nextLineId = FindNextConnectedLine(tran, lineIds, nextPoint, visitedLines, tolerance); - if (nextLineId == ObjectId.Null) break; + 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 lineStart, lineEnd; - if (nextPoint.DistanceTo(nextLine.StartPoint) < nextPoint.DistanceTo(nextLine.EndPoint)) + Point3d newNextPoint; + if (connectionType == "Start") { - lineStart = nextLine.StartPoint; - lineEnd = nextLine.EndPoint; + newNextPoint = nextLine.EndPoint; } else { - lineStart = nextLine.EndPoint; - lineEnd = nextLine.StartPoint; + newNextPoint = nextLine.StartPoint; } - rectanglePoints.Add(lineEnd); + rectanglePoints.Add(newNextPoint); visitedLines.Add(nextLineId); - nextPoint = lineEnd; + nextPoint = newNextPoint; - Debug.WriteLine($"[DEBUG] 다음 Line 추가: ({lineStart.X}, {lineStart.Y}) -> ({lineEnd.X}, {lineEnd.Y})"); + Debug.WriteLine($"[DEBUG] 다음 Line 추가 (갭 허용): {nextLine.StartPoint} -> {nextLine.EndPoint}"); - // 시작점으로 돌아왔는지 확인 (사각형 완성) if (nextPoint.DistanceTo(currentPoint) < tolerance) { - Debug.WriteLine("[DEBUG] 사각형 완성됨"); + Debug.WriteLine("[DEBUG] 사각형 완성됨 (갭 허용)"); break; } } } - // 4개 이상의 점이 있고 닫힌 형태인지 확인 if (rectanglePoints.Count >= 4) { var bounds = CalculateBounds(rectanglePoints); @@ -782,16 +779,20 @@ namespace DwgExtractorManual.Models } catch (System.Exception ex) { - Debug.WriteLine($"[DEBUG] 사각형 추적 중 오류: {ex.Message}"); + Debug.WriteLine($"[DEBUG] 사각형 추적 중 오류 (갭 허용): {ex.Message}"); return null; } } /// - /// 현재 점에서 연결된 다음 Line을 찾습니다. + /// 현재 점에서 가장 가까운 연결된 다음 Line을 찾습니다. (갭 허용) /// - private ObjectId FindNextConnectedLine(Transaction tran, List lineIds, Point3d currentPoint, HashSet visitedLines, double tolerance) + 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; @@ -800,16 +801,30 @@ namespace DwgExtractorManual.Models { if (line == null) continue; - // 현재 점과 연결되어 있는지 확인 - if (currentPoint.DistanceTo(line.StartPoint) < tolerance || - currentPoint.DistanceTo(line.EndPoint) < tolerance) + double distToStart = currentPoint.DistanceTo(line.StartPoint); + if (distToStart < minDistance) { - return lineId; + minDistance = distToStart; + bestMatchId = lineId; + bestConnectionType = "Start"; + } + + double distToEnd = currentPoint.DistanceTo(line.EndPoint); + if (distToEnd < minDistance) + { + minDistance = distToEnd; + bestMatchId = lineId; + bestConnectionType = "End"; } } } - return ObjectId.Null; + if (bestMatchId.HasValue) + { + return (bestMatchId.Value, bestConnectionType); + } + + return null; } ///