2014 dxdy logo

Научный форум dxdy

Математика, Физика, Computer Science, Machine Learning, LaTeX, Механика и Техника, Химия,
Биология и Медицина, Экономика и Финансовая Математика, Гуманитарные науки




Начать новую тему Ответить на тему На страницу 1, 2  След.
 
 Вращение точки вокруг другой точки [Delphi]
Сообщение11.02.2013, 00:20 
Аватара пользователя


15/01/12
87
г. Москва
Всем доброго времени суток.

Возникла у меня задача реализовать функцию, которая бы реализовывала расчёт координат точки после её поворота на заданный угол вокруг другой точки. Немного поискав в сети решения данной задачи я пришёл к такому решению:
Используется синтаксис Delphi
function RotatePoint(point, axis: TPoint; alpha: real): TPoint;
var rotated: TPoint;
begin
  rotated.x := Round( cos(alpha)*(point.x - axis.x) + sin(alpha)*(point.y - axis.y) ) + axis.x;
  rotated.y := Round( cos(alpha)*(point.y - axis.y) - sin(alpha)*(point.x - axis.x) ) + axis.y;
  Result := rotated;
end;
 


Здесь point - сама точка, axis - ось вращения, alpha - поворота, положителен для поворота против часовой.
TPoint - стандартный тип "запись с двумя полями: x и y типа integer".
Также прошу обратить внимание, что система координат используется левая.

Собственно сами формулы представляют собой формулы из статьи "Матрица поворота" на Википедии, с поправкой на то, что сначала координаты точки преобразуются из исходной системы координат в систему координат, началом которой является ось поворота, а потом происходит обратное преобразование.

Увы, функция работает неправильно, как вы уже могли догадаться.
Вместо того, чтобы перемещать точку по окружности, функция перемещает её по вот эдакому восьмиугольнику:
Рисунок со временем перестал грузиться/ GAA
(На рисунке след отрезка, который поворачивался вокруг одного из своих концов с помощью вышеприведённой функции.)

Уважаемые форумчане, помогите, пожалуйста, найти проблему.

 Профиль  
                  
 
 Re: Вращение точки вокруг другой точки
Сообщение11.02.2013, 01:50 


12/06/12
34
А что за светлые точки на рисунке?

 Профиль  
                  
 
 Re: Вращение точки вокруг другой точки
Сообщение11.02.2013, 02:25 
Аватара пользователя


15/01/12
87
г. Москва
Ну я же говорю, что это след вращения отрезка.
Видимо, в этих местах координата вращающейся точки изменялась быстрее, нежели в других местах, из-за чего многочисленные изображения отрезка накладывались неплотно.

-- 11.02.2013, 03:38 --

Решил сейчас поиграться со значением угловой скорости, чтобы получить более "гладкое" изображение и обнаружил, что фигура, по которой движется точка с помощью моей функции меняется в зависимости от угловой скорости.
При относительно больших значениях получается визуально почти окружность, при уменьшении значения получается многоугольник, количество сторон которого уменьшается с уменьшением значения угловой скорости.
Более того, при определённых значениях наблюдается явное "спиральное" движение, т.е. точка описывает некую фигуру и с каждым оборотом всё более удаляется от центра.

Очень надеюсь, что здесь найдётся кто-нибудь, кто сможет объяснить причину такой странной работы функции.

 Профиль  
                  
 
 Re: Вращение точки вокруг другой точки
Сообщение11.02.2013, 02:48 
Заслуженный участник


04/05/09
4584
Округлять не надо после каждого маленького поворота. Из-за округления точка сначала идёт вдоль одной оси, потом по диагонали, а потом вдоль другой оси. Вполне может получиться и спираль, если после полного оборота радиус изменится.
Короче, либо считайте всё с плавающей точкой (при этом тоже может получиться спираль, правда с очень маленким шагом), либо поворачивайте исходную точку на постепенно увеличивающийся угол.

 Профиль  
                  
 
 Re: Вращение точки вокруг другой точки
Сообщение11.02.2013, 05:40 


12/06/12
34
Можно вращать точку в полярных координатах, тогда радиус будет равен начальному.

 Профиль  
                  
 
 Re: Вращение точки вокруг другой точки
Сообщение11.02.2013, 09:49 
Аватара пользователя


31/10/08
1244
Проблема в округлении. Если выполнять процесс интерациононо ошибка может накапливается.

Код:
procedure FixAngle;
var point, axis: TPoint;
i:integer;
begin
axis.X:=250;
axis.y:=250;
point.x:=250-50;
point.y:=250;
for i:=0 to 360 do
  begin
  point:=RotatePoint(point,axis,Pi/180);
  Form1.Image1.Canvas.MoveTo(axis.X,axis.Y);
  Form1.Image1.Canvas.LineTo(point.X,point.Y);
  end;
end;


У Вас и есть тот лучай, когда она накапливается.

Из решений менять алгоритм. Делать его неустойчевым к ошибкам.

Самое просто что приходит на ум использоваь числа с плавающей точкой.
Но это полумера, числа в компьюторе иеют ограниченное число знаков. И при операциях с плавающей точкой они тоже округляются.
И ошибка также и иначе будет вылазить. Просто они бдут появляться реже! Так все создатели игр и делают.
Цитата:
Короче, либо считайте всё с плавающей точкой (при этом тоже может получиться спираль, правда с очень маленким шагом)

Даже небольшое округление может приводить к большим ошибкам. К примеру выполните деление $1/x$.

Поэтому надо искать алгоритм на которого ошибки окргуления не будут влиять. К примеру тут можно изменять угол.
Код:
procedure VarAngle;
var r,point, axis: TPoint;
angle:Real;
i:integer;
begin
axis.X:=250;
axis.y:=250;
point.x:=250-50;
point.y:=250;
angle:=0;
for i:=0 to 360 do
  begin
  r:=RotatePoint(point,axis,angle);
  angle:=angle+Pi/180;
  Form1.Image2.Canvas.MoveTo(axis.X,axis.Y);
  Form1.Image2.Canvas.LineTo(r.X,r.Y);
  end;
end;

 Профиль  
                  
 
 Re: Вращение точки вокруг другой точки
Сообщение11.02.2013, 10:28 
Аватара пользователя


15/01/12
87
г. Москва
Всем спасибо, судя по всему, проблема действительно была в округлении.
Переделал алгоритм для расчёта новых координат каждый раз поворотом исходных на возрастающий угол - работает прекрасно.
Забавно, никогда бы не подумал, что погрешности компьютерной математики могут иметь столь заметные последствия.

Позволю себе задать вопрос, несколько отличающийся от исходной проблемы, но тесно связанный с нею.
При изменении алгоритма у меня возникла проблема переполнения переменной, хранящей угол.
Т.к. мне необходимо "вечное" вращение, то очевидно надо как-то предотвращать переполнение.
Насколько корректным является код, подобный этому:
Используется синтаксис Delphi
function NextAngle(alpha, d: real): real;
begin
  if (alpha + d - 2*pi) < eps then Result := 0
  else Reslut := alpha + d;
end;
 

Где eps - константа порядка $ 10^5 $?

 Профиль  
                  
 
 Re: Вращение точки вокруг другой точки
Сообщение11.02.2013, 12:44 
Аватара пользователя


31/10/08
1244
Цитата:
Насколько корректным является код, подобный этому:

Ни насколько.
1) alpha, d могут быть меньше нуля, могут быть больше 10*Pi, а также их сумма может быть меньше 0 и больше 10*Pi.
2) Фаза, при превешении 2*Pi у вас не сохраняется.
3) Сравниваете неправильно сделано.

Так по лучше будет, хотя и тут есть недостатки.
Код:
function NextAngle(alpha, d: real): real;
const
_1_2PI=1/(2*pi);

var
dd:Int64;
begin
Result:=alpha + d;
dd:=Round(Result*_1_2PI);
result:=result-dd*2*Pi;
end;

 Профиль  
                  
 
 Re: Вращение точки вокруг другой точки
Сообщение11.02.2013, 15:45 


12/06/12
34
Pavia в сообщении #682449 писал(а):
Цитата:

Так по лучше будет, хотя и тут есть недостатки.


Мне кажется округление здесь не подходит.

 Профиль  
                  
 
 Re: Вращение точки вокруг другой точки
Сообщение11.02.2013, 20:11 
Аватара пользователя


15/01/12
87
г. Москва
Pavia, эмм, Вы не объясните, как это работает?... :oops:

 Профиль  
                  
 
 Re: Вращение точки вокруг другой точки
Сообщение11.02.2013, 20:37 
Заслуженный участник


27/04/09
28128
Округлять до целого, а потом переводить из целого в плавающее — зачем это, когда есть в Math функция Floor? (Хотя, вроде бы, Round тоже не возвращает целое, а делает это Trunc (по крайней мере, в D7 и D2005 так было).)

Вообще, разве так плохо каждый раз проверять, не стал ли угол больше $2\pi$, а потом, если так, вычитать это самое $2\pi$?

 Профиль  
                  
 
 Re: Вращение точки вокруг другой точки
Сообщение11.02.2013, 23:54 


12/06/12
34
arseniiv в сообщении #682600 писал(а):

Вообще, разве так плохо каждый раз проверять, не стал ли угол больше $2\pi$, а потом, если так, вычитать это самое $2\pi$?


А если измение угла очень большое (больше $2\pi$)?

 Профиль  
                  
 
 Re: Вращение точки вокруг другой точки
Сообщение12.02.2013, 13:15 


05/09/12
2587
В суть темы не вникал, но последние посты напомнили о том, с чем я сталкивался когда писал драйвер шагового двигателя. Задача - повернуть вал на некоторый угол (в общем случае составляющий много-много оборотов) с точностью до долей микрошага (тысячных одного оборота). Если текущий угол хранить в одной переменной с плавающей точкой, то при достижении определенного значения она уже не будет меняться при прибавлении к ней малого приращения, вследствие ухудшения точности данного формата при увеличении абсолютного значения. Пара возможных решений - хранить в фиксированной точке достаточной длины или помнить отдельно целые обороты и дробную часть оборотов в микрошагах.

 Профиль  
                  
 
 Re: Вращение точки вокруг другой точки
Сообщение12.02.2013, 14:21 
Заслуженный участник


27/04/09
28128
ilkos в сообщении #682693 писал(а):
А если измение угла очень большое (больше $2\pi$)?
В общем случае и низ на меньшесть нуля проверять нужно, но мне кажется, что я правильно протелепатировал, что shau-kote прибавляет только меньшие полного оборота положительные углы.

 Профиль  
                  
 
 Re: Вращение точки вокруг другой точки
Сообщение12.02.2013, 16:18 
Аватара пользователя


15/01/12
87
г. Москва
_Ivana, нет, Вы не совсем в тему. (:

Итого я пришёл к следующему решению, которое кажется мне наиболее простым, надёжным и универсальным:
Используется синтаксис Delphi
function NextAngle(alpha, d: real): real;
begin
  alpha := alpha + d;
  while alpha > 2*pi do alpha := alpha - 2*pi;
  while alpha < 0 do alpha := alpha + 2*pi;
end;
 

Таким образом, как и советовал тов. arseniiv, я просто изменяю значение угла и, если необходимо, нормализую его, сохраняя его значение в $[0, 2\pi]$.

Если кто-то видит в данном варианте недочёты, рад буду узнать и постараться исправить их.

 Профиль  
                  
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 18 ]  На страницу 1, 2  След.

Модераторы: Karan, Toucan, PAV, maxal, Супермодераторы



Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group