Function to delete the rotation of geometry does not work in Python

Viewed 64

I have a function which delete the rotation of the geometry. That means, function aligns the principal axes of the geometry such that geometry's principal axes align parallel to the reference axes (X and Y).

I want my code in such a way that, if I give input (X and Y coordinate) of geometry, my function delete the rotation of geometry only if there is a rotation. If there is not a rotation, my function should do nothing.

I have a image before process as below,

enter image description here

For this image, sets coordinates are as

X = [2, 4, 4, 2, 3, 2, 4, 3, 1, 3, 4, 3, 1, 2, 0, 3, 4, 2, 0]
Y = [3, 4, 2, 1, 3, 2, 1, 0, 0, 2, 3, 4, 1, 4, 0, 1, 0, 0, 1]

My Code is as below,

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)


coordinates1 = list(zip(X, Y))

points1 = [Point(*coors) for coors in coordinates1]
point_pairs1 = [(points1[i], points1[i + 1]) for i in range(len(points1) - 1)] + \
              [(points1[-1], points1[0])]

angles1 = [abs(math.atan2((p1.y - p2.y), (p1.x - p2.x))) for p1, p2 in point_pairs1]

angle_amounts1 = {}
for a in set(angles1):
    angle_amounts1[a] = angles1.count(a)

final_rotation_angle1 = max(angle_amounts1, key=angle_amounts1.get)

new_points1 = [rotate(Point(0, 0), p2, final_rotation_angle1) for p2 in points1]

log(new_points1)

X1_coordinate_aligned, Y1_coordinate_aligned = zip(*new_points1)

X1_coordinate_aligned = [round(num,1) for num in X1_coordinate_aligned] 
Y1_coordinate_aligned = [round(num,1) for num in Y1_coordinate_aligned] 

df_1['X1_coordinate_aligned'] = X1_coordinate_aligned
df_1['Y1_coordinate_aligned'] = Y1_coordinate_aligned

plt.scatter(X1_coordinate_aligned, Y1_coordinate_aligned)
plt.show()

If the above mentioned coordinates are passed in the code given above, I got the plot of geometry like this,

enter image description here

My expected Output: I am expecting a geometry as it was before. Basically my aim is to delete the rotation of geometry if there is any. If there is no rotation, then I should get the similar geometry as it was before passing into the code given above.

Kindly let me know where I am doing wrong. If there is a better function to delete the rotation of geometry, the please provide that.

1 Answers

There's a crucial fact in your data: All points lay in a rotated grid.

To transform the data so all vertices still lay in a grid, but in a horizontal+vertical aligned grid, the only thing you must calculate is the angle that "unrotates" the grid.

This as simple as get the two proper points an apply the atan2() maths:

angleRotated = math.atan2((p2.y - p1.y), (p2.x - p1.x)))

Which two "proper" points? The two first points in an sorted list.

Build an array of tuples [x1,y1, x2,y2, x3,y3...] and sort it by its x component and also by the second one (y). See Note_A below.

With those first vertex (p1x,p1y)(p2x,p2y) calculate angleRotated.

Finally use your rotate function with origin = first point:

if angleRotated > 0
     angleRotated = -angleRotated
new_points1 = [rotate(Point(p1x, p1y), p2, angleRotated) for p2 in points1]

Notice I changed the sign for the rotation angle. This is needed in some cases, you may find what cases (points layout) need it.

Note_A: If you sort only by the first component x it may happen that the next positions has two points p2 and p3 with the same x but different y being the p3.y<p2.y. This case will give you a false angle of rotation.

Play with this idea, change origin points and angle. Just to see what happens.

Related