Я предполагаю, что вам нужно что-то быстрое в вычислительном отношении, так как вы упоминаете «столкновение», а это переполнение стека. Во-первых, диаграмма:
Мы хотим вычислить компоненты AF , которые мы будем обозначать f = q i + p j . AFD образует треугольник, поэтому мы можем получить длину f из AD , которую мы обозначим d . Давайте пометим длины курсивом и векторами жирным шрифтом:
f = d cos (θ).
Но триг это вычислительно дорого. Итак, давайте использовать тот факт, что векторное произведение точек между b (AB) и d равно:
b · d = b d cos (θ)
Угол один и тот же, потому что AF и AB находятся на одной линии. Подставляя в течение d cos (θ):
b · d = b f
f = ( b · d ) / b
Теперь у нас есть f , но нам нужны его компоненты p и q. Называя угол к горизонтали φ:
q = f cos (φ)
p = f sin (φ)
Но опять же мы избегаем триггера. Мы знаем, что f идет вдоль b , поэтому f = k b и фактически использует единичный вектор в направлении б
f = f ( b / b )
Подставляя наше выражение для f :
f = [( b · d ) / b ] ( b / б )
= [( b / b ) · d ] ( b / b )
= [ b · d ] b / ( b 2 )
Определение коэффициента k, который является общим для обоих компонентов:
k = (b x d x + b y d y ) / b 2
Разделяя b 2 , мы можем избежать операции с квадратным корнем, чтобы получить единичный вектор вдоль b
Наши компоненты, тогда:
q = k b x
p = k b y
Наконец, добавьте обратно в смещение точки A.
Fx = Ax + q
Fy = Ay + p
Итак, псевдокод:
var vbx = Bx - Ax; //vector b x component
var vby = By - Ay; //vector b y component
var dot = vbx*(Dx-Ax) + vby*(Dy-Ay); // dot product of b and d
var k = dot/(vbx*vbx + vby*vby); // inverse of square of vector b length
var fx = Ax + k*vbx
var fy = Ay + k*vby
Без вызовов с квадратным корнем, без триггера, 8 сложений / вычитаний, 6 умножений, 1 деление. Единственные нестабильности, которые я вижу: делить на ноль, когда A и B находятся в одном положении, возможное переполнение вычисляется dot
, если AB большое, а AD большое.