Полярная система координат в Icon

В некоторых задачах на построение графики иногда требуется применить иное, нежели в декартовой системе координат соотношение между точками и/или геометрическими объектами, поэтому в таких задачах нередко применяется полярная система координат (см. Полярная система координат), в которой соотношения между объектами плоскости выражаются через радиусы (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 — декартовы координаты точки с которой начнет строится «роза», которая выглядит вот так:

r(phi)=2*sin(4*phi)

А если в процедуре rose заменить polar_point на polar_line (с теми же аргументами), то получится закрашенная роза:

ig2_0_o

С помощью полярной системы координат можно выводить на экран различные интересные кривые, которые замучаешься программировать в декартовых координатах (вот же раздолье для математиков), например, спираль Архимеда:

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 дает вот такую спираль:

ig4_0_o

Еще одна интересная штучка получилась, когда я слегка ошибся в формуле описания конических сечений (эллипса, гиперболы, параболы и т.п.). Вот, собственно, программный код процедуры с ошибкой:

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

А вот результат:

ig5_0_o

К сожалению, я не знаю, что обозначают в данном случае некоторые параметры (ибо не математик, а полученный график следствие просчета), но одно понятно точно, что здесь нужно качественное исследование (кто хочет займитесь, но результаты опишите в комментариях).

Этот график, кстати, говоря был получен вот такой командой — sun(250,250,2,0.6), но что еще более интересно, что если заменить polar_point в функции sun на polar_line, то получается закрашенное солнце:

ig6_0_o

Следущее, что я смог реализовать — это конические сечения, процедура построения которых выглядит так:

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

Добавить комментарий