То, что мы хотим отсортировать, это угол от начальной координаты. Здесь я использовал numpy для интерпретации каждого вектора из начальной координаты как комплексного числа, для которого есть простой способ вычисления угла (против часовой стрелки вдоль единичной сферы)
def angle_with_start(coord, start):
vec = coord - start
return np.angle(np.complex(vec[0], vec[1]))
Полный код:
import itertools
import numpy as np
def angle_with_start(coord, start):
vec = coord - start
return np.angle(np.complex(vec[0], vec[1]))
def sort_clockwise(points):
# convert into a coordinate system
# (1, 1, 1, 2) -> (1, 1), (1, 2)
coords = [np.array([points[i], points[i+4]]) for i in range(len(points) // 2)]
# find the point closest to the origin,
# this becomes our starting point
coords = sorted(coords, key=lambda coord: np.linalg.norm(coord))
start = coords[0]
rest = coords[1:]
# sort the remaining coordinates by angle
# with reverse=True because we want to sort by clockwise angle
rest = sorted(rest, key=lambda coord: angle_with_start(coord, start), reverse=True)
# our first coordinate should be our starting point
rest.insert(0, start)
# convert into the proper coordinate format
# (1, 1), (1, 2) -> (1, 1, 1, 2)
return list(itertools.chain.from_iterable(zip(*rest)))
Поведение на некоторых типовых входах:
In [1]: a
Out[1]: [1, 1, 2, 2, 1, 2, 1, 2]
In [2]: sort_clockwise(a)
Out[2]: [1, 1, 2, 2, 1, 2, 2, 1]
In [3]: b
Out[3]: [1, 2, 0, 2, 1, 2, 3, 1]
In [4]: sort_clockwise(b)
Out[4]: [1, 0, 2, 2, 1, 3, 2, 1]