#!/usr/bin/perl -w
##############################################
# Create a png image a user defined function
# on the fly with the GD.pm module.
#############################################
use strict;
use CGI;
my $func = CGI->new->param("f");
unless ($func) {
# --- send user a form asking for the function ---
print "Content-type: text/html\n\n";
print "
Enter a function
";
return;
}
else {
# -- create and output png image of the function --
my $img = PlotFunction::makeImage($func);
print "Content-type: image/png\n\n";
print $img->png;
}
# =====================================
{
package PlotFunction;
use GD;
use constant XPixBorder => 10;
use constant YPixBorder => 10;
use constant Epsilon => 1e-6;
use constant XMax => 8.0 + Epsilon;
use constant XMin => -8.0;
use constant YMax => 1.5 + Epsilon;
use constant YMin => -1.5;
use constant XPixSize => 384;
use constant YPixSize => 256;
use constant DX => (XMax - XMin)/(XPixSize/2);
use constant XConvert => XPixSize/(XMax - XMmin);
use constant YConvert => YPixSize/(YMax - YMin);
# allocate new GD.pm Image.
our $im = GD::Image->new(XPixSize+2*XPixBorder, YPixSize+2*YPixBorder);
# allocate some colors. First allocated is background.
use constant White => $im->colorAllocate(255,255,255);
use constant Black => $im->colorAllocate( 0, 0, 0);
use constant Grey => $im->colorAllocate(172,172,172);
use constant DarkBlue => $im->colorAllocate( 0, 0,128);
our $xpixpen; # current pen x coord
our $ypixpen; # current pen y coord
our $pencolor; # current pen color
our $f; # function to be plotted.
# make the background transparent and the image interlaced.
$im->transparent(White);
$im->interlaced('true');
# input: function f(x) to be plotted as a string, i.e. "sin(x)".
sub makeImage {
($f) = @_;
# convert function in form "exp(x)" to "exp($x)".
for ($f) {
s/exp/~~~/g;
s/x/\$x/g;
s/~~~/exp/g;
}
# draw axes
$pencolor = Grey;
pendown(XMin,0); lineto(XMax,0);
pendown(0,YMin); lineto(0,YMax);
# draw function
$pencolor = Black;
my $x = XMin;
my $y = f($x);
my ($lastx, $lasty);
pendown($x,$y);
while ($xstring(gdLargeFont, XPixBorder*2, YPixBorder*2,
"f(x) = $func", DarkBlue);
return $im;
}
# function to be plotted
sub f {
my ($x) = @_;
return eval $f;
}
# convert x coords to pix
sub xx {
my ($x) = @_;
return XPixBorder + ($x-XMin)*XConvert;
}
# convert x coords to pix
sub yy {
my ($y) = @_;
return YPixborder + (YMax-$y)*YConvert;
}
# input: (x,y) coords to place pen
sub pendown {
my ($x,$y) = @_;
$xpixpen = xx($x);
$ypixpen = yy($y);
return;
}
# input: (x,y) coords
# draw line from last pendown position to (x,y)
sub lineto {
my ($x, $y) = @_;
my ($xpixnew, $ypixnew) = ( xx($x), yy($y) );
$im->line($xpixpen, $ypixpen, $xpixnew, $ypixnew, $pencolor);
($xpixpen, $ypixpen) = ($xpixnew, $ypixnew);
return;
}
} # end PlotFunction package