#algorithm #trigonometry #computational-geometry
Вопрос:
Пользователь меняет одну вершину первой строки (текущую строку), и вторая строка мгновенно должна стать параллельной первой строке. Чтобы достичь этого, я пытаюсь найти угол между двумя векторами этих линий, используя формулу:
vec1.x =(x-x2), vec1.y =(y-y2); // coordinates of first vector (x,y) - user-editable point
vec2.x =(x3-x4), vec2.y =(y3-y4); // coordinates of second vector
double angle = acos(
( vec1.x * vec2.x vec1.y * vec2.y )
/
sqrt( ( SQR(vec1.x) SQR(vec1.y) ) * ( SQR(vec2.x) SQR(vec2.y) ) )
);
когда
x > x2
формула даетangle > 90°
когда
x < x2
формула даетangle < 90°
а затем поверните вторую строку на angle
point xAxis = point{cos(angle),sin(angle)};
point yAxis = point{-sin(angle),cos(angle)};
point origin = point{x3,y3};
point p = point{x4-origin.x, y4-origin.y};
x4 = origin.x p.x * xAxis.x p.y * yAxis.x;
y4 = origin.y p.x * xAxis.y p.y * yAxis.y;
когда я вращаю линию против часовой стрелки, все в порядке, вторая линия идет параллельно первой,
но когда я поворачиваю линию по часовой стрелке, вторая линия начинает шоу уродов
Я предполагаю, что в определенных условиях вместо поворота второй строки на angle
я должен повернуть ее на -angle
Комментарии:
1. Вместо того, чтобы вращать вектор, почему бы не спроецировать один вектор на другой? Это должно быть намного чище и быстрее.
Ответ №1:
cos(a) == cos(-a)
, так acos(cos(a))
что может дать вам либо a
или -a
. И то и другое верно.
Если вы хотите получить угол вектора, используйте atan2(y,x)
, который охватывает весь круг. Если вы хотите использовать свое косинусное решение, вы должны сами различать положительный и отрицательный угол и убедиться, что результат находится в правильном квадранте.
Но вашу проблему легче решить вот так:
len1 = sqrt((x2-x)*(x2-x) (y2-y)*(y2-y));
len2 = sqrt((x4-x3)*(x4-x3) (y4-y3)*(y4-y3));
x4 = x3 (x2-x)*len2/len1;
y4 = y3 (y2-y)*len2/len1;
Вы просто делаете новую линию в направлении первой, с длиной второй. Проверьте len1==0.0
, так как в этом случае направление не определено.
Обратите также внимание, что независимо от того, как вы это сделаете, вы будете накапливать ошибки по мере того, как пользователь будет перетаскивать точку. Каждый раз, когда вы меняете строку 2, длина будет немного меняться, и затем вы собираетесь использовать это в качестве основы для следующей. Ошибки небольшие, и вы, вероятно, не заметите, но вам действительно следует помнить len2
об этом в начале и использовать это значение для всех будущих операций.
Комментарии:
1. Спасибо! Ваше решение отлично сработало для меня.