ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [퍼즐:04] 퍼즐 모서리 정규화
    개발 2023. 8. 8. 00:32

     

    정규화

    모든 모서리를 x축에 딱 붙이는 작업을 한다.

    이렇게 해야 다른 모서리와 비교하기 쉽기 때문이다.

     

    그런데, 뭔가 각도 계산이 잘 못 된 것 같다.

    대충 chat gpt와 copilot이 하라는대로 했더니 이렇게 되었음.

    숫자의 의미를 잘 이해하고, 이 화면은 좌표평면을 뒤집어 놓은 상태라는 것을 잘 생각하면 해결 할 수 있을 듯

     

    그냥 각도 계산을 잘못 했었음.

    모서리의 각도를 θ라고 했을 때 -θ 로 돌리면 정규화가 잘 됨.

    위에 잘못된 정규화는 θ인 각을 θ 만큼 돌려서 문제였음. (단순한 문제였음)

     

    단, 여기에서 중요한 점이 있는데 각을 잘 구해야 한다는 점.

    그렇지 않으면 '홀'과 '헤드'가 바뀌어서 나온다는 점이다.

    처음에 코너를 찾을 때 찾은 코너를 시계방향이던, 시계반대방향이던 통일시켜서 정렬한 후 모서리를 구해야 한다.

    (나도 아무생각없이 했다가 각 조각 별 홀, 헤드 구분이 이상해서 알게되었음)

    갑자기 C# 코드로 바뀌었는데, 이 때부터 python에서 C#으로 옮겨왔다.

    (사실 python은 처음써봐서 문법도 잘 몰라서 힘들었음..)

     

    var baseCorner = corners.OrderBy(c => c.Point.Y).First();
    var otherCorners = corners.OrderBy(c => c.Point.Y).Skip(1).ToArray();
    var ordered = otherCorners
        .Select(c => new
        {
            Corner = c,
            Angle = CalculateAngleBetweenPoints(baseCorner.Point, c.Point)
        })
        .OrderBy(c => c.Angle)
        .Select(x => x.Corner);
    
    // 한 쪽 방향으로 정렬된 점들
    var orderedCorners = new[] { baseCorner }.Concat(ordered).ToArray();

     

    // 두 점 사이의 각을 계산 (출처 chatgpt)
    static double CalculateAngleBetweenPoints(PointF point1, PointF point2)
    {
        double deltaX = point2.X - point1.X;
        double deltaY = point2.Y - point1.Y;
    
        // 아크탄젠트 함수를 사용하여 각도를 계산합니다.
        double angleInRadians = Math.Atan2(deltaY, deltaX);
        
        return angleInRadians;
    }
    
    // 점을 (0, 0)을 중심으로 angle만큼 회전 시킴
    static PointF RotatePointAroundOrigin(PointF point, double angleRad)
    {
        var x = point.X;
        var y = point.Y;
        
        var rotatedX = x * Math.Cos(angleRad) - y * Math.Sin(angleRad);
        var rotatedY = x * Math.Sin(angleRad) + y * Math.Cos(angleRad);
        
        return new PointF((float)rotatedX, (float)rotatedY);
    }
    
    var angle = CalculateAngleBetweenPoints(cornerSet.Item1.Point, cornerSet.Item2.Point);
    foreach (var point in edge)
    {
        float x = point.X;
        float y = point.Y;
        // 0, 0으로 평행 이동
        x -= cornerSet.Item1.Point.X;
        y -= cornerSet.Item1.Point.Y;
    
        // 회전 시킴. rotatedPoint를 모으면 edge를 정규화한 결과를 얻을 수 있다.
        var rotatedPoint = RotatePointAroundOrigin(new PointF(x, y), -angle);
    }
Designed by Tistory.