Как повернуть одну линию так, чтобы она была параллельна другой?

#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. Спасибо! Ваше решение отлично сработало для меня.