0

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.

Urvesh
  • 331
  • 4
  • 15
  • I don't understand what you intend. You rotate each point always around (0,0) but each angle is that from p(i) to p(i+1). It will be good if you provide an image before "deleting the rotation" and another for the expected result. – Ripi2 Sep 06 '22 at 19:48
  • Thank you for reply. I have dited my question. Kindly have a look into it. Looking forward to know your suggestions. – Urvesh Sep 06 '22 at 20:04
  • Better, thanks. What do mean by "delete"? What was the initial position (p1,p2) such that after rotation gives (20,20) and you want to delete? Should it be (pp,0)? – Ripi2 Sep 06 '22 at 20:15
  • For 'Delete': I mean, if my geometry's principal axis is ´not parallel to reference coordinate axis, then my code should make principal axis parallel to reference axis. And If I have geometry which already has principal axis parallel to reference axis then my code should not rotate the geometry. This is my goal for this small task. – Urvesh Sep 06 '22 at 20:21
  • I hope, I have explained you my aim for this task. Kindly let me know if you need any more information. – Urvesh Sep 06 '22 at 20:34

1 Answers1

0

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.

Ripi2
  • 7,031
  • 1
  • 17
  • 33
  • Thank you for your answer. Give me some time. I will write you here within 2 hours after trying with your suggestions. – Urvesh Sep 08 '22 at 19:26
  • Hello, I have first sorted the coordinates using 'sorted' function as mentioned: merged_list1 = sorted(zip(X, Y)). Then I found the angle between first two point, which I got 90 in degree. Then according to your suggestion, I rotate the geometry by writing code: new_points1 = [rotate(point(0, 0), p2, angleRotated ) for p2 in points1]. Where (0, 0) is my first point after sorting and 'angleRotated' value is 90 degree. But after running the code, the result is same. Geometry is getting rotation which should not be happened. – Urvesh Sep 08 '22 at 20:30
  • Another option: Can we find the principal axis of the geometry? If yes, could you please explain me the procedure or the direct code available to find the axis? If the we find principal axis and later we can find the angle between principal axis and reference axis. Then we can remove the rotation of geometry by unrotating it. – Urvesh Sep 08 '22 at 20:37
  • If the angle for the two first points in the sorted list is 90 degrees then tthe grid is rotated one these angles: 0, 90, 180, 270. Finding which of them needs more data info (at least one or two points before and after geometriy rotation). – Ripi2 Sep 09 '22 at 17:46
  • Finding the main axis of a group of points is not trivial. Some regression code may help. But if points are lay out in several axis (your example shows two axis) then regression would fail. All generic methods will fail for some cloud of points. – Ripi2 Sep 09 '22 at 17:48
  • For your first comment of today: After sorting the points, if the angle between two points is one of 0, 90, 180, and 270 then my geometry is aligned at X or Y axis. Right? and if the angle between first two points after sorting is not among those four angles, and have angle value for example 23 degree, then should I rotate all points to ß23 degree..Am I right? Or correct me if I am not. – Urvesh Sep 09 '22 at 19:44
  • For 23 degrees, rotate with that angle... or with its negative one (-23), depending on what axis X or Y you wish to align with. – Ripi2 Sep 13 '22 at 17:02