2015-04-06 5 views
1

Я работаю над методом python, который должен вернуть координаты перехвата (точки столкновения) для двух касающихся кругов. Метод работает так, как ожидалось, но он кажется слишком дорогостоящим для своей цели.Как бы оптимизировать этот метод для обнаружения столкновений точек?

Должна быть только одна точка перехвата, и размеры этих кругов могут различаться.

def getPointOfContact(self, body): 
    a1 = min(self.pos.x, body.pos.x) # The x value of the centre of the left-most circle 
    b1 = min(self.pos.y, body.pos.y) # The y value of the up-most circle 
    a2 = max(self.pos.x, body.pos.x) # The x value of the right-most circle 
    b2 = max(self.pos.y, body.pos.y) # The y value of the down-most circle 
    dx = a2-a1 # (Delta x) The difference in x positions 
    dy = b2-b1 # (Delta y) The difference in y positions 
    if dy == 0: # In case of no difference in y, 
     m = 0 # Gradient is "zero" 
    elif dx == 0: # In case of no difference in x, 
     m = float("inf") # Gradient is "infinity" 
    else: 
     m = dy/dx # Gradient 
    if a1 == self.pos.x: # Such that left-most circle's radius is used 
     r1 = (self.size.x)/2 
    else: 
     r1 = (body.size.x)/2 
    # Calculates the x position of intersection using trig 
    x = a1+(r1*math.cos(math.atan(m))) 
    if b1 == self.pos.y: # Such that up-most circle's radius is used 
     r1 = (self.size.x)/2 
    else: 
     r1 = (body.size.x)/2 
    # Calculates the y position of intersection using trig 
    y = b1+(r1*math.sin(math.atan(m))) 
    return (int(x), int(y)) # Returns the coordinates as a tuple of integers 

Фактический расчет на самом деле довольно прямолинейный. Он просто добавляет x и y компоненты смещения радиусов к координате центра круга.

Проблема заключается в том, что для того, чтобы расчет был действительным, должно быть много места, т. Е. Используемый круг должен иметь наименьший компонент, а радиус (r1) сильно соответствует кругу.

Будет ли способ упрощения метода или даже более дешевой техники вообще?

Заранее спасибо.

+0

Возможно, лучшее место, как есть в [Обзор кода] (http://codereview.stackexchange.com/) –

+0

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

+0

@Phrancis, был бы способ передвинуть его туда, не удаляя? –

ответ

1

Я не уверен, что получаю. У вас есть радиус первого круга, и вы предполагаете, что они точно касаются, верно? Тогда просто избавиться от cos, sin и atan:

d = sqrt(d1**2 + d2**2) 
x = a1 + dx * r1/d 
y = b1 + dy * r1/d 

Посмотрите на этот треугольник, где + являются центрами и * пересечение:

0<-dx->|  
0 + 
^ \ r1 
| \ 
| * d = r1+r2 = sqrt(dx**2 + dy**2) 
dy \ 
|  \ r2 
v  \ 
-  + 

Примечание 1: если m=dy/dx и вы пытаетесь вычислите atan(m), тогда вам лучше использовать только atan2(dy, dx), который позаботится о раздражающих нулях и бесконечности.

Примечание 2: cos(atan(dy/dx))==dx/R с R=sqrt(dx**2+dy**2) и то же самое с sin и dy, поскольку atan(dy/dx) угол таким образом, что dx = R*cos(theta) и dy = R*sin(theta).

Примечание 3: вы делаете вещи в int, чтобы ваши круги и перекрестки могли быть немного выключены.

+0

Спасибо за предложения. Использование расстояния между центрами окружностей работало хорошо, как и изменение atan2 (y, x). Я не понимаю, что вы имеете в виду с запиской 2. Не могли бы вы повторить? –

+0

Ahh! Ваш рисунок ASCII треугольника действительно объясняет, как все это работает. Я, вероятно, буду использовать r1 + r2, поскольку r2 также известен, просто исключается для простоты. Спасибо за помощь! –

Смежные вопросы