from math import atan2
def argsort(seq):
#http://stackoverflow.com/questions/3382352/equivalent-of-numpy-argsort-in-basic-python/3382369#3382369
#by unutbu
#https://stackoverflow.com/questions/3382352/equivalent-of-numpy-argsort-in-basic-python
# from Boris Gorelik
return sorted(range(len(seq)), key=seq.__getitem__)
def rotational_sort(list_of_xy_coords, centre_of_rotation_xy_coord, clockwise=True):
cx,cy=centre_of_rotation_xy_coord
angles = [atan2(x-cx, y-cy) for x,y in list_of_xy_coords]
indices = argsort(angles)
if clockwise:
return [list_of_xy_coords[i] for i in indices]
else:
return [list_of_xy_coords[i] for i in indices[::-1]]
points=[[0.,0.],[0.,1.],[1.,0.],[1.,1.],[1.,2.],[1.,3.],[2.,0.]]
rotational_sort(points, (0,0),True)
[[0.0, 0.0],
[0.0, 1.0],
[1.0, 3.0],
[1.0, 2.0],
[1.0, 1.0],
[1.0, 0.0],
[2.0, 0.0]]
Notice the last two points have the same angle from the centre, so it's a toss up to say which one should come first.
If you wanted to force closer points to be first, or last in this situation, you could include a secondary metric (say distance) to be included in the thing to be sorted.
e.g. augment the angles
list with something that includes a distance value - maybe something like:
polar_coords = [(atan2(x-cx, y-cy), ((x-cx)**2)+((y-cy)**2)) for x,y in list_of_xy_coords]
Which returns the polar coordinates (angle,distance) of the points, which if you then sorted, should resolve these magnitude-tie-breaks in a consistent fashion.
P.S. Credit where it's due - @Diego Palacios's atan2
is precisely the thing to convert from cartesian pairs to angles, there's probably a more tidy way to do the magnitude part of my second calculation along those lines too. I've also "borrowed" a useful argsort
function here from an answer to this helpful discussion: Equivalent of Numpy.argsort() in basic python? courtesy of @Boris Gorelik