Деление окружности на равные части и возврат координат

#python #geometry

Вопрос:

Я создал несколько кругов с разным происхождением с помощью Python и пытаюсь реализовать функцию, которая разделит каждый круг на n количество равных частей по окружности. Я пытаюсь заполнить массив, содержащий начальную [x,y] координату для каждой части на окружности.

Мой код выглядит следующим образом:

 def fnCalculateArcCoordinates(self,intButtonCount,radius,center):
        lstButtonCoord = []

        #for degrees in range(0,360,intAngle):
        for arc in range(1,intButtonCount   1):
            degrees = arc * 360 / intButtonCount
            xDegreesCoord = int(center[0]   radius * math.cos(math.radians(degrees)))
            yDegreesCoord = int(center[1]   radius * math.sin(math.radians(degrees)))

            lstButtonCoord.append([xDegreesCoord,yDegreesCoord])
        
        return lstButtonCoord
 

Когда я запускаю код для 3 частей, примером возвращаемого набора координат являются:

 [[157, 214], [157, 85], [270, 149]]
 

Это означает, что сегменты имеют разные размеры. Не мог бы кто-нибудь, пожалуйста, помочь мне определить, в чем моя ошибка?

Комментарии:

1. Какова мотивация перехода на градусы только для того, чтобы вернуться к радианам? Конечно, вы можете разделить 2*math.pi на равные части и пропустить преобразования. Обратите внимание, что что бы вы ни делали, определенная ошибка округления неизбежна (особенно при окончательном преобразовании в int). 3 пункта, которые у вас есть, на самом деле кажутся достаточно разумными. Если вы построите их, они будут выглядеть как равносторонний треугольник. Какие 3 балла были бы лучше?

2. Если вы действительно хотите максимально приблизиться к целочисленным координатам, это становится нетривиальной задачей нелинейного целочисленного программирования. В качестве эвристики вы можете начать с вашего текущего решения, а затем изучить его настройку, изменив каждую точку на пиксель. Используйте itertoools для перебора всех возможных комбинаций возмущений в 1 пиксель и посмотрите, не приведут ли они к меньшей общей ошибке.

Ответ №1:

Точные результаты таких тригонометрических вычислений редко бывают точными целыми числами. Укладывая их на пол int , вы, конечно, теряете некоторую точность. Приблизительные (пифагорейские) проверки расстояний показывают, что ваша математика верна:

 (270-157)**2   (149-85)**2
# 16865
(270-157)**2   (214-149)**2
# 16994
(157-157)**2   (214-85)**2
# 16641
 

Кроме того, вы можете использовать встроенный complex тип номера и cmath модуль. В частности cmath.rect , преобразует полярные координаты (радиус и угол) в прямоугольные координаты:

 import cmath

def calc(count, radius, center):
    x, y = center
    for i in range(count):
        r = cmath.rect(radius, (2*cmath.pi)*(i/count))
        yield [round(x r.real, 2), round(y r.imag, 2)]

list(calc(4, 2, [0, 0]))
# [[2.0, 0.0], [0.0, 2.0], [-2.0, 0.0], [-0.0, -2.0]]
list(calc(6, 1, [0, 0]))
# [[1.0, 0.0], [0.5, 0.87], [-0.5, 0.87], [-1.0, 0.0], [-0.5, -0.87], [0.5, -0.87]]
 

Вы хотите изменить округление по своему усмотрению.

Комментарии:

1. Хотя это более элегантно, чем код OP ( 1), вряд ли удастся избежать проблемы, о которой они, похоже, беспокоятся (отсутствие точности при приближении к точкам на целочисленной решетке).

2. @JohnColeman Правда. Добавил некоторые пояснения с этой целью.