#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 Правда. Добавил некоторые пояснения с этой целью.