Search code examples
python-3.xgeometryrotation2dcoordinate-transformation

Find an angle of rotation of geometry and make geometry without rotation in Python


I have set of points (X and Y cooridnates) of 2D geometry which is rotated at certain angle. Angle is unknown. I want to make this geometry without rotation. I do not have clue how should I make it without rotation.

Respective coordinates of rotated geometry are as below and image also shows the rotated geometry,

x = [-2.38, -1.68, -0.97, -0.26, -0.97, -0.26, 0.45, 1.15, 1.86, 2.57, 1.86, 1.15, 0.45, -0.26, -0.97, -1.68]
y = [-1.24, -0.53, 0.18, 0.88, 1.59, 2.3, 1.59, 0.88, 0.18, -0.53, -1.24, -0.53, 0.18, -0.53, -1.24, -1.94]

Geometry's centroid is placed at (0, 0).

enter image description here

I want to make my geometry like in the picture below,

enter image description here

My question: I want to rotate my geometry so that parts' principal axes align with the axes of the coordinate system at origin. How can I do that? I could not find any way to make this geometry without rotation. Kindly give some suggestions to me and help me providing a code.


Solution

  • Ok, I worked out some code, this seems to be working out for me, sbNative is just there for logging purpuses, you can install it or delete the affected lines. Btw im rotating it along the center at point 0,0. If you wish to change that do that in the function call of rotate, youll find it.

    EDIT: This code is by no means optimized, it is just written very explicitly so its easy to understand, and i didnt bother speeding it up cuz its not terrible.

    from sbNative.debugtools import log, cleanRepr
    from numpy import arctan, degrees
    import math
    
    
    def rotate(origin, point, angle):
        """
        https://stackoverflow.com/questions/34372480/rotate-point-about-another-point-in-degrees-python
        Rotate a point counterclockwise by a given angle around a given origin.
    
        The angle should be given in radians.
        """
    
        qx = origin.x + math.cos(angle) * (point.x - origin.x) - math.sin(angle) * (point.y - origin.y)
        qy = origin.y + math.sin(angle) * (point.x - origin.x) + math.cos(angle) * (point.y - origin.y)
        return qx, qy
    
    
    @cleanRepr()
    class Point:
        def __init__(self, *pts):
            pt_names = "xyzw"
            for n, v in zip(pt_names[:len(pts)], pts):
                self.__setattr__(n, v)
    
    
    x = [-2.38, -1.68, -0.97, -0.26, -0.97, -0.26, 0.45, 1.15, 1.86, 2.57, 1.86, 1.15, 0.45, -0.26, -0.97, -1.68]
    y = [-1.24, -0.53, 0.18, 0.88, 1.59, 2.3, 1.59, 0.88, 0.18, -0.53, -1.24, -0.53, 0.18, -0.53, -1.24, -1.94]
    
    coordinates = list(zip(x, y))
    
    points = [Point(*coors) for coors in coordinates]
    point_pairs = [(points[i], points[i + 1]) for i in range(len(points) - 1)] + \
                  [(points[-1], points[0])]
    
    angles = [abs(arctan((p1.x - p2.x) / (p1.y - p2.y))) for p1, p2 in point_pairs]
    
    angle_amounts = {}
    for a in set(angles):
        angle_amounts[a] = angles.count(a)
    
    final_rotation_angle = max(angle_amounts, key=angle_amounts.get)
    
    new_points = [rotate(Point(0, 0), p2, final_rotation_angle) for p2 in points]
    
    log(new_points)
    
    new_x_coors, new_y_coors = zip(*new_points)
    
    import matplotlib.pyplot as plt
    
    plt.scatter(new_x_coors, new_y_coors)
    plt.show()
    

    This is the result