С немного тригонометрии это не так уж трудно. Возможно, вы знаете, но угол между двумя (нормализованными) векторами равен acos(vec1 * vec2)
. Однако это вычисляет только проецируемый угол, но можно использовать atan2
для расчета угла направления.
Чтобы это означает функцию вычисления его, а затем использовать его в качестве key
для сортировки было бы хорошим способом:
import math
pts = [[2,3], [5,2],[4,1],[3.5,1],[1,2],[2,1],[3,1],[3,3],[4,3]]
origin = [2, 3]
refvec = [0, 1]
def clockwiseangle_and_distance(point):
# Vector between point and the origin: v = p - o
vector = [point[0]-origin[0], point[1]-origin[1]]
# Length of vector: ||v||
lenvector = math.hypot(vector[0], vector[1])
# If length is zero there is no angle
if lenvector == 0:
return -math.pi, 0
# Normalize vector: v/||v||
normalized = [vector[0]/lenvector, vector[1]/lenvector]
dotprod = normalized[0]*refvec[0] + normalized[1]*refvec[1] # x1*x2 + y1*y2
diffprod = refvec[1]*normalized[0] - refvec[0]*normalized[1] # x1*y2 - y1*x2
angle = math.atan2(diffprod, dotprod)
# Negative angles represent counter-clockwise angles so we need to subtract them
# from 2*pi (360 degrees)
if angle < 0:
return 2*math.pi+angle, lenvector
# I return first the angle because that's the primary sorting criterium
# but if two vectors have the same angle then the shorter distance should come first.
return angle, lenvector
sorted
пробег:
>>> sorted(pts, key=clockwiseangle_and_distance)
[[2, 3], [3, 3], [4, 3], [5, 2], [4, 1], [3.5, 1], [3, 1], [2, 1], [1, 2]]
и с прямоугольной сетке вокруг происхождение это также работает как ожидалось:
>>> origin = [2,3]
>>> refvec = [0, 1]
>>> pts = [[1,4],[2,4],[3,4],[1,3],[2,3],[3,3],[1,2],[2,2],[3,2]]
>>> sorted(pts, key=clockwiseangle_and_distance)
[[2, 3], [2, 4], [3, 4], [3, 3], [3, 2], [2, 2], [1, 2], [1, 3], [1, 4]]
, даже если вы измените эталонный вектор:
>>> origin = [2,3]
>>> refvec = [1,0] # to the right instead of pointing up
>>> pts = [[1,4],[2,4],[3,4],[1,3],[2,3],[3,3],[1,2],[2,2],[3,2]]
>>> sorted(pts, key=clockwiseangle_and_distance)
[[2, 3], [3, 3], [3, 2], [2, 2], [1, 2], [1, 3], [1, 4], [2, 4], [3, 4]]
Спасибо @Scott Mermelstein
для лучшего названия функции и @f5r5e5d
для atan2
предложения.
Это проблема плохо поставлена. Для произвольного множества точек ваше описание того, как сортировать точки, не определено. – hvwaldow
что-то вроде: для каждой точки и обновленного начала pt, убедитесь, что единичный вектор остается неизменным из последнего цикла и что величина является минимальной для всех параметров ... пока не закончится точка, которая поддерживает этот начальный единичный вектор, затем перейдите к следующему ... т.е.вектор справа, затем вниз, затем влево – ldgorman
Ну, у вас есть заданные r и тета. Просто сортируйте по r, а затем отрицательной тета. Конечно, вы скажете: «У меня нет r и тета. У меня есть x и y». Не будь таким прямоугольным ... –