프로그래밍/C#

[C#] C#에서 사각형 내에 포함된 선 추출하기

흔한티벳여우 2024. 8. 7. 08:33
반응형

안녕하세요, 여러분! 오늘은 C#을 사용하여 주어진 사각형 영역 내에 포함된 선(Line) 데이터를 추출하는 방법에 대해 알아보겠습니다. 또한 사각형 영역에 걸쳐 있는 선을 자르는 방법도 다룰 것입니다.

 

문제 정의

우리는 x, y 좌표계에 다수의 선(Line) 데이터를 가지고 있습니다. 주어진 사각형(Rect) 영역 내에 존재하는 선 데이터를 추출하는 프로그램을 작성해야 합니다. 만약 사각형 영역에 완전히 포함되지 않고 걸쳐 있는 선이 있는 경우, 선을 잘라서 영역 내만 포함되도록 변경하여 추출해야 합니다.

 

단계별 구현

1. 데이터 구조 정의

먼저, 포인트(Point), 라인(Line), 사각형(Rect) 구조체를 정의합니다.

public struct Point
{
    public double X { get; set; }
    public double Y { get; set; }

    public Point(double x, double y)
    {
        X = x;
        Y = y;
    }
}

public struct Line
{
    public Point P0 { get; set; }
    public Point P1 { get; set; }

    public Line(Point p0, Point p1)
    {
        P0 = p0;
        P1 = p1;
    }
}

public struct Rect
{
    public double X { get; set; }
    public double Y { get; set; }
    public double Width { get; set; }
    public double Height { get; set; }

    public Rect(double x, double y, double width, double height)
    {
        X = x;
        Y = y;
        Width = width;
        Height = height;
    }

    public bool Contains(Point p)
    {
        return p.X >= X && p.X <= X + Width && p.Y >= Y && p.Y <= Y + Height;
    }
}

 

2. 선이 사각형에 포함되는지 확인

다음으로, 주어진 선이 사각형에 완전히 포함되는지 확인하는 함수를 작성합니다.

private static bool IsLinePartiallyInRect(Line line, Rect rect)
{
    return rect.Contains(line.P0) || rect.Contains(line.P1) ||
           IsPointInRect(line.P0, rect) || IsPointInRect(line.P1, rect);
}

private static bool IsPointInRect(Point p, Rect rect)
{
    return p.X >= rect.X && p.X <= rect.X + rect.Width && 
           p.Y >= rect.Y && p.Y <= rect.Y + rect.Height;
}

 

3. 선을 사각형 내로 자르기

사각형 영역에 걸쳐 있는 선을 자르는 함수도 작성해야 합니다. 여기서는 Liang-Barsky 알고리즘을 사용합니다.

private static Line? ClipLineToRect(Line line, Rect rect)
{
    Point p0 = line.P0;
    Point p1 = line.P1;

    if (rect.Contains(p0) && rect.Contains(p1))
    {
        return line;
    }

    double xMin = rect.X;
    double yMin = rect.Y;
    double xMax = rect.X + rect.Width;
    double yMax = rect.Y + rect.Height;

    double dx = p1.X - p0.X;
    double dy = p1.Y - p0.Y;

    double[] p = { -dx, dx, -dy, dy };
    double[] q = { p0.X - xMin, xMax - p0.X, p0.Y - yMin, yMax - p0.Y };

    double u1 = 0.0;
    double u2 = 1.0;

    for (int i = 0; i < 4; i++)
    {
        if (p[i] == 0 && q[i] < 0)
        {
            return null;
        }

        double t = q[i] / p[i];
        if (p[i] < 0)
        {
            if (t > u1) u1 = t;
        }
        else if (p[i] > 0)
        {
            if (t < u2) u2 = t;
        }
    }

    if (u1 > u2) return null;

    Point newP0 = new Point(p0.X + u1 * dx, p0.Y + u1 * dy);
    Point newP1 = new Point(p0.X + u2 * dx, p0.Y + u2 * dy);

    return new Line(newP0, newP1);
}

 

4. 사각형 내에 포함된 선 추출

마지막으로, 주어진 모든 선을 검사하여 사각형 내에 포함된 선을 추출하고, 걸쳐 있는 선은 자르는 함수를 작성합니다.

public static List<Line> GetLinesInRect(List<Line> lines, Rect rect)
{
    List<Line> result = new List<Line>();
    
    foreach (var line in lines)
    {
        if (rect.Contains(line.P0) && rect.Contains(line.P1))
        {
            result.Add(line);
        }
        else if (IsLinePartiallyInRect(line, rect))
        {
            var clippedLine = ClipLineToRect(line, rect);
            if (clippedLine.HasValue)
            {
                result.Add(clippedLine.Value);
            }
        }
    }

    return result;
}

 

5. 사용 예제

아래는 이 함수들을 사용하는 예제입니다.

public static void Main(string[] args)
{
    List<Line> lines = new List<Line>
    {
        new Line(new Point(1, 1), new Point(5, 5)),
        new Line(new Point(2, 3), new Point(8, 7)),
        new Line(new Point(0, 0), new Point(10, 10)),
    };

    Rect rect = new Rect(2, 2, 6, 6);

    List<Line> result = GetLinesInRect(lines, rect);

    foreach (var line in result)
    {
        Console.WriteLine($"Line from ({line.P0.X}, {line.P0.Y}) to ({line.P1.X}, {line.P1.Y})");
    }
}

 

위의 예제에서는 여러 개의 선이 주어지고, 사각형 내에 포함되거나 걸쳐 있는 선들을 추출하여 결과를 출력합니다.

반응형