В некоторых задачах на построение графики иногда требуется применить иное, нежели в декартовой системе координат соотношение между точками и/или геометрическими объектами, поэтому в таких задачах нередко применяется полярная система координат (см. Полярная система координат), в которой соотношения между объектами плоскости выражаются через радиусы (r) и углы (phi).
Так как недавно пришлось с этим столкнуться (при решении одной из задач), то я решил обобщить некоторый полученный мной опыт в использовании полярных координат.
Сначала для удобства пользования введем две функции, которые нам очень потребуются в дальнейшем — это процедуры polar_point(x,y,r,phi) и polar_line(x,y,r,phi):
procedure polar_line(x,y,r,phi) local xx,yy xx:=r*cos(dtor(phi)) yy:=r*sin(dtor(phi)) DrawLine(x,y,x+xx,y+yy) end procedure polar_point(x,y,r,phi) local xx,yy xx:=r*cos(dtor(phi)) yy:=r*sin(dtor(phi)) DrawPoint(x+xx,y+yy) end
Эти функции требуют четыре параметра: x,y — декартовы координаты точки, которую мы будем использовать в качестве «начала координат» и r,phi — длина радиуса из «начала координат» до точки, которую мы хотим построить, а также угол (phi) между полярным лучом и радиус-вектором (радиусом) в требуемую точку.
Функция polar_point строит точки, а функция polar_line строит линии (от точки «начала координат» до точки координаты которой выражены через радиус и угол). Еще у этих функций есть небольшой нюанс, связанный с их определением, в частности из-за использования в них функции dtor(), преобразующей градусы в радианы (стандартные тригонометрические функции Icon принимают аргумент в радианах) угол phi будет определяться в градусах, причем диапазон значений практически не ограничен.
Однако, что дает применение именно полярной системы координат? Многое, в частности, введение полярных координат позволяет рисовать некоторые интересные кривые и фигуры. Например, с помощью полярных координат можно построить «полярную розу» (которая описывается уравнением r(phi)=2*sin(4*phi):
procedure rose(x,y) local i,r i:=-360 while i<360 do { r:=2*sin(dtor(4*i)) polar_point(x,y,50*r,50+i) i+:=0.01 } end
где x,y — декартовы координаты точки с которой начнет строится «роза», которая выглядит вот так:
А если в процедуре rose заменить polar_point на polar_line (с теми же аргументами), то получится закрашенная роза:
С помощью полярной системы координат можно выводить на экран различные интересные кривые, которые замучаешься программировать в декартовых координатах (вот же раздолье для математиков), например, спираль Архимеда:
procedure spiral_l(x,y,n) local i,r i:=-360*n while i<0 do { r:=0.5+0.08*i polar_point(x,y,r,i) i+:=0.01 } end
где x,y — декартовы координаты «начала координат» (точку (0,0) ставить не советую!), а n — число витков спирали. В данном случае получается левозакрученная спираль, которая выглядит вот так:
Для получения картинки была применена команда spiral_l(250,250,5), а вывод был в окно размером 500*500 пикселей. Чтобы получить правозакрученную спираль, необходимо немного исправить процедуру вычерчивающую спираль (а именно, изменить параметр i) — получаем следующую процедуру:
procedure spiral_r(x,y,n) local i,r i:=0 while i<360*n do { r:=0.5+0.08*i polar_point(x,y,r,i) i+:=0.01 } end
Запущенная с теми же аргументами функция spiral_r дает вот такую спираль:
Еще одна интересная штучка получилась, когда я слегка ошибся в формуле описания конических сечений (эллипса, гиперболы, параболы и т.п.). Вот, собственно, программный код процедуры с ошибкой:
procedure sun(x,y,l,e) local i,r i:=0 while i<360 do { r:=l/(1-e*cos(i)) polar_point(x,y,r*50,i+50) i+:=0.01 } end
А вот результат:
К сожалению, я не знаю, что обозначают в данном случае некоторые параметры (ибо не математик, а полученный график следствие просчета), но одно понятно точно, что здесь нужно качественное исследование (кто хочет займитесь, но результаты опишите в комментариях).
Этот график, кстати, говоря был получен вот такой командой — sun(250,250,2,0.6), но что еще более интересно, что если заменить polar_point в функции sun на polar_line, то получается закрашенное солнце:
Следущее, что я смог реализовать — это конические сечения, процедура построения которых выглядит так:
procedure axial(x,y,l,e) local i,r,kk i:=-360 while i<360 do { kk:=e*cos(dtor(i)) r:=l/(1.0-kk) polar_point(x,y,r*10,i+10) i+:=0.01 } end
где x,y — декартовы координаты точки, которая будет играть роль «начала координат», l — фокальный параметр, e — эксцентрисет (если e>1 получиться гипербола; e=1, то получиться парабола; e=0, получиться окружность с радиусом l, и если e < 1, то получиться эллипс).
Вот так выглядит результат команды axial(250,250,2,0.6):
Также, ради интереса, я написал процедуры для отображение «полярной розы» (но уже с настраиваемыми параметрами), циссоиды, кардиоиды, а также для отображения улитки Паскаля, которые наряду с уже представленными кривыми, можно увидеть тут:
procedure polar_line(x,y,r,phi) local xx,yx xx:=r*cos(dtor(phi)) yy:=r*sin(dtor(phi)) DrawLine(x,y,x+xx,y+yy) end procedure polar_point(x,y,r,phi) local xx,yx xx:=r*cos(dtor(phi)) yy:=r*sin(dtor(phi)) DrawPoint(x+xx,y+yy) end procedure rose(x,y) local i,r i:=-360 while i<360 do { r:=2*sin(dtor(4*i)) polar_point(x,y,50*r,50+i) i+:=0.01 } end procedure rose_l(x,y) local i,r i:=-360 while i<360 do { r:=2*sin(dtor(4*i)) polar_line(x,y,50*r,50+i) i+:=0.01 } end procedure rose_m(x,y,a,b,c) local i,r i:=-360 while i<360 do { r:=a*cos(dtor(b*i+c)) polar_line(x,y,50*r,50+i) i+:=0.1 } end procedure spiral_l(x,y,n) local i,r i:=-360*n while i<0 do { r:=0.5+0.08*i polar_point(x,y,r,i) i+:=0.01 } end procedure spiral_r(x,y,n) local i,r i:=0 while i<360*n do { r:=0.5+0.08*i polar_point(x,y,r,i) i+:=0.01 } end procedure sun(x,y,l,e) local i,r i:=0 while i<360 do { r:=l/(1-e*cos(i)) polar_point(x,y,r*50,i+50) i+:=0.01 } end procedure FillSun(x,y,l,e) local i,r i:=0 while i<360 do { r:=l/(1-e*cos(i)) polar_line(x,y,r*50,i+50) i+:=0.01 } end procedure axial(x,y,l,e) local i,r,kk i:=-360 while i<360 do { kk:=e*cos(dtor(i)) r:=l/(1.0-kk) polar_point(x,y,r*10,i+10) i+:=0.01 } end procedure kardio(x,y,a) local i,r i:=-360 while i<360 do { r:=2*a*(1-cos(dtor(i))) polar_point(x,y,r*50,i+50) i+:=0.01 } end procedure pascal(x,y,l,a) local i,r i:=0 while i<360 do { r:=l-a*sin(dtor(i)) polar_point(x,y,r*50,i+50) i+:=0.01 } end procedure cissoid(x,y,a) local i,r,v i:=-70 while i<70 do { v:=sin(dtor(i))^2 r:=(2*v*a)/(cos(dtor(i))) polar_point(x,y,r*50,i+50) i+:=0.01 } end