Иногда возникает потребность построить график какой-нибудь функции (даже не важно, написана она самим пользователем или же стандартная функция языка программирования), и вот тогда возникают некоторые сомнения и трудности. Такая задача легко разрешима в Icon.
Для построения графиков в Icon сначала определим окно размерами 500×500 пикселей:
link graphics
procedure main()
local W
W:=WOpen("label=graph","size=500,500")
WDone()
endКак известно, в Icon начало координат – левый верхний угол (точка с координатами (0, 0) пикселей), координата Х растет по направлению к правому верхнему углу, а координата Y – по направлению к нижнему левому углу (т.е. представляете себе, как не совсем удобно расположены координатные оси). Увы, нам такое расположение осей очень неудобно.
Однако, есть способ как решить проблему – для этого необходимо переместить точку начала координат в какое-нибудь другое место и считать координаты относительно этого места. В качестве такого места лучше всего использовать центр окна, который в нашем случае имеет координаты (250,250), от него мы и будем отсчитывать координаты.
Для следующего шага нам потребуется координатная сетка с неким дискретным шагом, поскольку размеры окна в пикселях достаточно велики, то удобнее всего брать шаг сетки, соизмеримый с одним из делителей 500 (ну или лучше всего 250).
Я взял шаг сетки равный 10 пикселям и получил следующую процедуру построения координатной сетки:
procedure grid_coord()
local i
Fg("lightgray")
every i:=0 to 500 by 10 do {
DrawLine(i,0,i,500)
DrawLine(0,i,500,i)
}
Fg("black")
DrawLine(0,250,500,250)
DrawLine(250,0,250,500)
endВ результате получим сетку светло-серого цвета, при этом оси идущие из начала координат (не забываем, что оно теперь имеет координаты [250,250] ) будут черного цвета:
Теперь необходимо сделать процедуру для построения самого графика, да и с учетом нового начала координат.
Разумнее всего, строить график по точкам (т.е. используя процедуру DrawPoint), используя для этого цикл внутри которого помещается команда вычисления функции, используя счетчик цикла как меняющийся параметр, и команда построения точки, которая принимает два аргумента – координата X точки (с учетом нового начала координат) и координата Y (вычисленное значение функции с учетом нового начала координат).
Однако, как сделать так, чтобы можно было подставлять практически любую из описанных функций, не описывая в цикле саму схему ее вычисления ? Да очень просто – нужно объявить функцию, график которой мы будем строить как invocable и дополнить процедуру построения графика функции еще одним параметром – строкой с именем функции!
В итоге получаем следующую процедуру:
procedure func_plot(a,b,func,n,col)
local i
/n:=0.01
/col:="black"
i:=a
while i <= b {
Fg(col)
DrawPoint(i+250,250-100*func(i/20.0))
i+:=n
}
end
где a – начальная точка для построения (по координате Х), b – конечная точка построения (по координате Х), func – имя функции для построения, n – “разрешающая способность” (шаг приращения по координате Х), col – цвет графика (строковая переменная, описывающая цвет).
Но и это не всё – само выражение 250-100*func(i/20.0) содержит еще 2 параметра (но не в явном виде, разумеется), в частности в выражении 100*func(i/20.0) и присутствуют оба параметра: число 100 перед функцией (обозначает во сколько раз увеличен масштаб по оси Y) и число 20.0 внутри самой функции (обозначает во сколько раз увеличен (растянут) масштаб по оси X), разумеется, параметры можно менять под свои нужды.
И ещё одно – если вы думаете, что процедура func_plot принимает 5 аргументов, то вы ошибаетесь! Применяя эту процедуру, вы можете опустить аргументы n и сol, тогда процедура примет значения для этих аргументов по умолчанию (n = 0.01 и col= “black”, т.е. приращение по Х 0.01 и черный цвет графика), например:
func_plot(0,100,"sin")
(при условии,что sin объявлен как invocable)
или так:
func_plot(0,100,"sin",,"red")
Ну, а теперь пара интересных функций.
sinc(x) – синус кардинальный:
procedure sinc(x)
if x=0 then return 1 else return sin(&pi*x)/(&pi*x)
end
График:
func_plot(-250,250,"sinc",,"green")
si(x) – синус интегральный (потребуется библиотека factors):
procedure si(x)
local i,g,s,k,v
i:=0
s:=0
while i<20 do {
k:=(2*i)+1
g:=(-1)^i
v:=(g*(x^k))/(factorial(k)*k)
s+:=v
i+:=1
}
return s
end
График:
func_plot(-250,250,"si",,"orange")
сi(x) – косинус интегральный (тоже нужна factors):
procedure ci(x)
local i,g,s,k
g:=0.5772156649
s:=g+log(x,&e)
i:=1
while i<20 do {
k:=(((-1.0)^i)*(x^(2.0*i)))/(factorial(2.0*i)*2.0*i)
s+:=k
i+:=1
}
return s
end
График:
func_plot(2,250,"ci",,"blue")
Также графики можно совмещать:
func_plot(-250,250,"sinc",,"green")
func_plot(2,250,"ci",,"blue")
func_plot(1,250,"log",,"violet")
func_plot(0,250,"cos",,"cyan")
В общем, большой простор для экспериментов…






