Compare commits
2 Commits
0278688b28
...
107eab90fa
| Author | SHA1 | Date | |
|---|---|---|---|
| 107eab90fa | |||
| 9c76b624bf |
@@ -513,56 +513,189 @@ namespace DwgExtractorManual.Models
|
|||||||
private (Point3d minPoint, Point3d maxPoint)? FindNoteBox(
|
private (Point3d minPoint, Point3d maxPoint)? FindNoteBox(
|
||||||
Transaction tran, DBText noteText, List<ObjectId> polylineIds, List<ObjectId> lineIds, HashSet<(Point3d minPoint, Point3d maxPoint)> usedBoxes)
|
Transaction tran, DBText noteText, List<ObjectId> polylineIds, List<ObjectId> lineIds, HashSet<(Point3d minPoint, Point3d maxPoint)> usedBoxes)
|
||||||
{
|
{
|
||||||
var notePos = noteText.Position;
|
var allLineSegments = new List<Line>();
|
||||||
var noteHeight = noteText.Height;
|
try
|
||||||
|
|
||||||
double stableX;
|
|
||||||
if (noteText.HorizontalMode == TextHorizontalMode.TextLeft)
|
|
||||||
{
|
{
|
||||||
stableX = noteText.Position.X;
|
var notePos = noteText.Position;
|
||||||
}
|
var noteHeight = noteText.Height;
|
||||||
else
|
|
||||||
{
|
|
||||||
stableX = noteText.AlignmentPoint.X;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 검색 라인 정의: 안정적인 X좌표를 기준으로 하되, 약간의 오차를 허용하는 너비
|
// Polylines를 Line 세그먼트로 분해하여 추가
|
||||||
double searchY = notePos.Y - (noteHeight * 2);
|
foreach (var polylineId in polylineIds)
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
if (polyline == null) continue;
|
using (var polyline = tran.GetObject(polylineId, OpenMode.ForRead) as Polyline)
|
||||||
|
|
||||||
if (DoesLineIntersectPolyline(searchLineStart, searchLineEnd, polyline))
|
|
||||||
{
|
{
|
||||||
var box = GetPolylineBounds(polyline);
|
if (polyline == null) continue;
|
||||||
if (box.HasValue && IsValidNoteBox(box.Value, notePos, noteHeight) && !usedBoxes.Contains(box.Value))
|
var explodedEntities = new DBObjectCollection();
|
||||||
|
try
|
||||||
{
|
{
|
||||||
Debug.WriteLine($"[DEBUG] 교차하는 Polyline 박스 발견: {box.Value.minPoint} to {box.Value.maxPoint}");
|
polyline.Explode(explodedEntities);
|
||||||
return box;
|
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<Line> FindIntersectingLineSegments(List<Line> allLineSegments, Point3d searchLineStart, Point3d searchLineEnd)
|
||||||
|
{
|
||||||
|
var intersectingLines = new List<Line>();
|
||||||
|
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<Line> allLineSegments, Line startLine, Point3d notePos, double noteHeight, HashSet<(Point3d minPoint, Point3d maxPoint)> usedBoxes)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
double tolerance = noteHeight * 2.0;
|
||||||
|
var visitedLines = new HashSet<Line>();
|
||||||
|
var rectanglePoints = new List<Point3d>();
|
||||||
|
|
||||||
|
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<Line> allLineSegments, Point3d currentPoint, HashSet<Line> 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들과 교차하여 사각형 찾기
|
if (bestMatch != null)
|
||||||
var intersectingLines = FindIntersectingLines(tran, lineIds, searchLineStart, searchLineEnd);
|
|
||||||
foreach (var startLineId in intersectingLines)
|
|
||||||
{
|
{
|
||||||
var rectangle = TraceRectangleFromLine(tran, lineIds, startLineId, notePos, noteHeight);
|
return (bestMatch, bestConnectionType);
|
||||||
if (rectangle.HasValue && !usedBoxes.Contains(rectangle.Value))
|
|
||||||
{
|
|
||||||
Debug.WriteLine($"[DEBUG] 교차하는 Line 사각형 발견: {rectangle.Value.minPoint} to {rectangle.Value.maxPoint}");
|
|
||||||
return rectangle;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
@@ -682,150 +815,7 @@ namespace DwgExtractorManual.Models
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 수평선과 교차하는 Line들을 찾습니다.
|
|
||||||
/// </summary>
|
|
||||||
private List<ObjectId> FindIntersectingLines(Transaction tran, List<ObjectId> lineIds, Point3d searchLineStart, Point3d searchLineEnd)
|
|
||||||
{
|
|
||||||
var intersectingLines = new List<ObjectId>();
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Line에서 시작하여 반시계방향으로 사각형을 추적합니다. (갭 허용)
|
|
||||||
/// </summary>
|
|
||||||
private (Point3d minPoint, Point3d maxPoint)? TraceRectangleFromLine(Transaction tran, List<ObjectId> lineIds, ObjectId startLineId, Point3d notePos, double noteHeight)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
double tolerance = noteHeight * 2.0; // 갭 허용 오차를 Note 높이에 비례하여 설정
|
|
||||||
var visitedLines = new HashSet<ObjectId>();
|
|
||||||
var rectanglePoints = new List<Point3d>();
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 현재 점에서 가장 가까운 연결된 다음 Line을 찾습니다. (갭 허용)
|
|
||||||
/// </summary>
|
|
||||||
private (ObjectId lineId, string connectionType)? FindNextConnectedLine(Transaction tran, List<ObjectId> lineIds, Point3d currentPoint, HashSet<ObjectId> 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 점들의 경계 상자를 계산합니다.
|
/// 점들의 경계 상자를 계산합니다.
|
||||||
|
|||||||
@@ -340,6 +340,14 @@ namespace DwgExtractorManual.Models
|
|||||||
worksheet.Cells[row, 5] = fileName ?? "";
|
worksheet.Cells[row, 5] = fileName ?? "";
|
||||||
worksheet.Cells[row, 6] = noteEntity.Text ?? "";
|
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}'");
|
Debug.WriteLine($"[DEBUG] Excel 기록: Row {row}, Order {noteEntity.SortOrder}, Type {noteEntity.Type}, Pos({noteEntity.X:F1},{noteEntity.Y:F1}), Text: '{noteEntity.Text}'");
|
||||||
row++;
|
row++;
|
||||||
}
|
}
|
||||||
|
|||||||
48
NoteDetectionRefactor.md
Normal file
48
NoteDetectionRefactor.md
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
Project: Refactor the NOTE Content Box Detection Algorithm
|
||||||
|
|
||||||
|
1. High-Level Goal:
|
||||||
|
The primary objective is to replace the current, fragile "horizontal search line" algorithm in
|
||||||
|
Models/DwgDataExtractor.cs with a more robust and accurate method that reliably finds the content box for
|
||||||
|
any "NOTE" text, regardless of its position or the composition of its bounding box.
|
||||||
|
|
||||||
|
2. Core Strategy: "Vertical Ray-Casting"
|
||||||
|
We will implement a new algorithm that emulates how a human would visually locate the content. This
|
||||||
|
involves a "gradual downward scan" (or vertical ray-cast) from the NOTE's position.
|
||||||
|
|
||||||
|
3. Implementation Plan (TODO List):
|
||||||
|
|
||||||
|
* Step 1: Unify All Geometry into Line Segments
|
||||||
|
* Create a single helper method, GetAllLineSegments, that processes all Line and Polyline entities from
|
||||||
|
the drawing.
|
||||||
|
* This method will decompose every Polyline into its constituent Line segments.
|
||||||
|
* It will return a single, unified List<Line> containing every potential boundary segment in the
|
||||||
|
drawing.
|
||||||
|
* Crucially: This method must ensure all temporary Line objects created during the process are properly
|
||||||
|
disposed of to prevent memory leaks.
|
||||||
|
|
||||||
|
* Step 2: Implement the Ray-Casting Logic in `FindNoteBox`
|
||||||
|
* The FindNoteBox method will be completely rewritten.
|
||||||
|
* It will first call GetAllLineSegments to get the unified geometry list.
|
||||||
|
* It will then perform the vertical ray-cast starting from the NOTE's X-coordinate and scanning
|
||||||
|
downwards.
|
||||||
|
* It will find all horizontal lines that intersect the ray and sort them by their Y-coordinate (from
|
||||||
|
top to bottom).
|
||||||
|
* It will identify the second line in this sorted list as the top edge of the content box (the first is
|
||||||
|
assumed to be the NOTE's own bounding box).
|
||||||
|
|
||||||
|
* Step 3: Implement Smart Box Tracing
|
||||||
|
* Create a new helper method, TraceBoxFromTopLine.
|
||||||
|
* This method will take the identified top line segment as its starting point.
|
||||||
|
* It will intelligently trace the remaining three sides of the rectangle by searching the unified list
|
||||||
|
of line segments for the nearest connecting corners.
|
||||||
|
* This tracing logic must be tolerant of small gaps between the endpoints of the lines forming the box.
|
||||||
|
|
||||||
|
* Step 4: Final Cleanup
|
||||||
|
* Once the new ray-casting algorithm is fully implemented and validated, all of the old, obsolete
|
||||||
|
methods related to the previous search-line approach must be deleted to keep the code clean. This
|
||||||
|
includes:
|
||||||
|
* FindIntersectingLineSegments
|
||||||
|
* TraceRectangleFromLineSegments
|
||||||
|
* FindNextConnectedLineSegment
|
||||||
|
* DoesLineIntersectPolyline
|
||||||
|
* GetPolylineBounds
|
||||||
Reference in New Issue
Block a user