Keeping it Small and Simple

2007.05.30

Ruby, meet SDL

Filed under: Graphics Programming, Ruby Programming — Lorenzo E. Danielsson @ 22:21

Just today somebody asked me why I am doing a pygame tutorial, since I am “a ruby guy”, whatever that’s supposed to mean. I never claimed to be “a ruby guy”. I program in Pascal as well. Go ahead and call me a “Pascal guy”. Or a “C guy”.

Anyways, such minor issues apart. There are Ruby bindings for SDL called (amazingly enough) Ruby/SDL. Now this is not “pygame in Ruby”. Ruby/SDL is a Ruby wrapper for SDL. As such, its API looks like the original SDL API. Pygame, is not a wrapper. It is a python library for developing multimedia applications that uses SDL internally. Confused? I hope not. Ruby/SDL is probably comparable to PySDL which seems to be a Python wrapper for SDL.

I started writing the pygame tutorial because a few people asked me to. Pygame is more popular than Ruby/SDL. (Note: I said more popular, not better. I have no opinion on which is better. I’m only interested in being able to use both). I’m not going to do a Ruby/SDL tutorial, at least not now, but I can at least give you something to get started. First of all, you need to get Ruby/SDL installed. On Debian that translates to:


# aptitude install libsdl-ruby1.8

at least if you are using Etch. If you are not on Debian or one of its derivates.

Once it is installed you can start off by going to /usr/share/doc/libsdl-ruby1.8/examples and studying the examples there. They show you just about everything you need to know. I will also add a small example of my own, adapted from my pygame tutorial.

 1 #! /usr/bin/ruby -w
 2 
 3 require 'sdl'
 4 
 5 SDL.init SDL::INIT_VIDEO
 6 screen = SDL::set_video_mode 640, 480, 24, SDL::SWSURFACE
 7 x = y = 0
 8 
 9 BGCOLOR = screen.format.mapRGB 0, 0, 0
10 LINECOLOR = screen.format.mapRGB 255, 255, 255
11 
12 running = true
13 
14 while running
15   while event = SDL::Event2.poll
16     case event
17     when SDL::Event2::Quit
18       running = false
19     when SDL::Event2::MouseMotion
20       x = event.x
21       y = event.y
22       end
23   end
24 
25   screen.fill_rect 0, 0, 640, 480, BGCOLOR
26   screen.draw_line x, 0, x, 479, LINECOLOR
27   screen.draw_line 0, y, 639, y, LINECOLOR
28   screen.flip
29 end

That’s it! Have fun..

Advertisements

Pygame tutorial #3: mouse events

Filed under: Graphics Programming, Pygame Tutorial, Python Programming — Lorenzo E. Danielsson @ 10:17

In the last tutorial, you learned how to draw lines. This time we will deal with mouse events. As usual we will keep it simple.

Already in the first tutorial you learned about the QUIT event. Now let’s add a little bit of code to track the position of the mouse on our window. This is done by the MOUSEMOTION event. The code looks as follows:

 1 #! /usr/bin/env python
 2 
 3 import pygame
 4 
 5 x = y = 0
 6 running = 1
 7 screen = pygame.display.set_mode((640, 400))
 8 
 9 while running:
10     event = pygame.event.poll()
11     if event.type == pygame.QUIT:
12         running = 0
13     elif event.type == pygame.MOUSEMOTION:
14         print "mouse at (%d, %d)" % event.pos
15 
16     screen.fill((0, 0, 0))
17     pygame.display.flip()

Most of the code should look familiar by now. What is new is the check to see if we have an event of the type MOUSEMOTION (line 13). Also notice that if the event is a mouse motion event we can get a little bit more information out of the Event object. In the next line (14), we use call event.pos to get the current coordinates of the mouse pointer. This method returns a pair of values representing the x-position and y-position of the mouse pointer.

Note that the values returned by event.pos are relative to the top left-hand corner of the window, not the entire screen (unless, of course, the window covers the entire screen). You probably already know that the top-left hand corner is (0, 0) in screen coordinates.

Exercises

  1. Write a program that prints the position of the mouse pointer using Cartesian coordinates. To begin with assume that the x-axis is at half the height of the window and the the y-axis is located at half the width of the window. You already know how to draw lines, so you might as well draw the axes. Take care with the difference in direction along the y-axis between screen coordinates and Cartesian coordinates.
  2. Replace MOUSEMOTION in the example above with MOUSEBUTTONDOWN. Run the program. Move the mouse over the window and press any mouse button. What happens?
  3. Imagine that your window consists of tiles, each one 32×32 pixels. Write a program that detects the current mouse position, translates the screen coordinates into tile coordinates and prints this.
  4. Write a program that calculates the distance of the mouse pointer from the center of the window. Remember that there is an imaginary straight line from the center point to the point where the mouse pointer is located. Just calculate the length of the straight line.

Seeing screen coordinates dumped onto you terminal window is exciting for just about 0.02 seconds. Let’s do something else. Since what we have learned so far is drawing lines we will stick to that. Here is a program that draws lines that cut the mouse pointer’s coordinates.

 1 #! /usr/bin/env python
 2 
 3 import pygame
 4 
 5 bgcolor = 0, 0, 0
 6 linecolor = 255, 255, 255
 7 x = y = 0
 8 running = 1
 9 screen = pygame.display.set_mode((640, 400))
10 
11 while running:
12     event = pygame.event.poll()
13     if event.type == pygame.QUIT:
14         running = 0
15     elif event.type == pygame.MOUSEMOTION:
16         x, y = event.pos
17 
18     screen.fill(bgcolor)
19     pygame.draw.line(screen, linecolor, (x, 0), (x, 399))
20     pygame.draw.line(screen, linecolor, (0, y), (639, y))
21     pygame.display.flip()

There is really nothing new in this code so I don’t think you will have any difficult understanding it. We have already learned how to set the color of the line we are drawing, so let’s extend the program slightly:

 1 #! /usr/bin/env python
 2 
 3 import pygame
 4 
 5 bgcolor = 0, 0, 0
 6 blueval = 0
 7 bluedir = 1
 8 x = y = 0
 9 running = 1
10 screen = pygame.display.set_mode((640, 400))
11 
12 while running:
13     event = pygame.event.poll()
14     if event.type == pygame.QUIT:
15         running = 0
16     elif event.type == pygame.MOUSEMOTION:
17         x, y = event.pos
18 
19     screen.fill(bgcolor)
20     pygame.draw.line(screen, (0, 0, blueval), (x, 0), (x, 399))
21     pygame.draw.line(screen, (0, 0, blueval), (0, y), (639, y))
22     blueval += bluedir
23     if blueval == 255 or blueval == 0: bluedir *= -1
24     pygame.display.flip()

Exercises

  1. In the examples above, the program draws lines that extend the full width and the height of the window. Create a program that draws a much smaller ‘+’, say from 10 pixels to the left/top of the mouse pointer to 10 pixels to the right/below the pointer.
  2. Write a program that draws a horizontal line at the y-coordinate of the mouse pointer. The color of the line should vary according to the following: divide the window into four quadrants. Check which of the quadrants the pointer is in and set the line color to red if it is in the first quadrant, green if it is in the second quadrant, blue if in the third quadrant or white if the mouse pointer is in the last quadrant.
  3. Write a program that tracks the positon of the mouse pointer and draws one line from the bottom right right-hand corner of the window to the current mouse position as well as one line from the bottom left-hand corner of the window to the position of the mouse pointer.

Mouse buttons

If you have been doing the exercises so far then you already know how to deal with a mouse button being pressed. Let’s look at an example.

 1 #! /usr/bin/env python
 2 
 3 import pygame
 4 
 5 LEFT = 1
 6 
 7 running = 1
 8 screen = pygame.display.set_mode((320, 200))
 9 
10 while running:
11     event = pygame.event.poll()
12     if event.type == pygame.QUIT:
13         running = 0
14     elif event.type == pygame.MOUSEBUTTONDOWN and event.button == LEFT:
15         print "You pressed the left mouse button at (%d, %d)" % event.pos
16     elif event.type == pygame.MOUSEBUTTONUP and event.button == LEFT:
17         print "You released the left mouse button at (%d, %d)" % event.pos
18 
19     screen.fill((0, 0, 0))
20     pygame.display.flip()

In this example we handle the two events MOUSEBUTTONDOWN and MOUSEBUTTONUP. Run the program and try this. Press the left mouse button down. While holding the button down, move it to a different position, the release the mouse button. Good, now you know how that works.

Exercises

  1. Write a program that draws a horizontal line and a vertical line that both intersect the position of the mouse pointer. The color of the lines should change every time the left button is clicked. The vertical line should be set to a new random color. After generating a random color value, make sure that it is different from the current color. The horizontal line should be set to the previous color of the vertical line.
  2. Write a program that draws a ‘+’ surrounding the mouse pointer when it is pressed down. The size of the cross should be 20 pixels in each direction. When the mouse button is released the cross should disappear.

Conclusion

In this tutorial you have learned how to deal with mouse motion and mouse button state. I think you are now comfortable enough with what events that we can look into them into some detail. Up to now we have been using poll() to get an event off the event queue, for the sake of simplicity. In the next tutorial you will see why that is not really a good idea and what you should do instead. Don’t worry, it won’t really become more complicated.

We will also learn a few more drawing methods.

2007.05.27

Pygame tutorial #2: drawing lines

Filed under: Graphics Programming, Pygame, Pygame Tutorial, Python Programming — Lorenzo E. Danielsson @ 02:46

Welcome to part 2 in my pygame tutorial. This time we will build upon what you learned last time as we start drawing onto surfaces. We will continue to move very slowly so that everybody gets a chance to learn.

Drawing a line

You draw a line by using pygame.draw.line. You can also use pygame.draw.aaline which draws an anti-aliased line. Using anti-aliasing can make the line appear less jagged in some cases at the expense of the function call being much slower.

To draw a blue line from (0, 0) to (200, 100) (note: we are measuring in pixels) onto the surface screen you do:


pygame.draw.line(screen, (0, 0, 255), (0, 0), (200, 100))

You could also do this:


blue = 0, 0, 255
point1 = 0, 0
point2 = 200, 100
pygame.draw.line(screen, blue, point1, point2)

This is will do exactly the same thing as the previous example, but is (possibly) more readable. Let’s try to put this together to a little program. We will draw two diagonal lines: one going from the top left-hand corner to the bottom right-hand corner and one from the top right-hand corner to the bottom left-hand corner. We will use pygame.draw.line for one of the lines and pygame.draw.aaline for the other.

 1 #! /usr/bin/env python
 2 
 3 import pygame
 4 
 5 screen = pygame.display.set_mode((640, 480))
 6 running = 1
 7 
 8 while running:
 9     event = pygame.event.poll()
10     if event.type == pygame.QUIT:
11         running = 0
12 
13     screen.fill((0, 0, 0))
14     pygame.draw.line(screen, (0, 0, 255), (0, 0), (639, 479))
15     pygame.draw.aaline(screen, (0, 0, 255), (639, 0), (0, 479))
16     pygame.display.flip()

I hope you recognize most of the code from the first tutorial. If you run the program you should see a big blue ‘x’ across the window.

Exercises

  1. Improve the program by getting rid of “magic numbers”. Declare two variables width and height and initialize them to the width and the height of the window. Then modify the rest of the program to use these variables instead of actual numbers. To verify that you have made all the required changes, try setting width and height to different values and confirm that you still get two diagonal lines and that each line’s end points are at one of the corners of the window.
  2. Improve the program further by declaring variables called linecolor, topleft, bottomright and so on. Modify the program to make use of the variables.
  3. Modify the program to draw the two lines in different colors.
  4. Write a program that instead draws one horizontal and one vertical line. The lines should both be centered.
  5. Write a program that draws four lines: the diagonal lines as in the example as well has the horizontal and vertical lines as in the last exercise. Each line should be in a different color. The program should take the height and width of the window as command-line arguments.
  6. Write a program that draws the following pattern:
    fishnet.png
    Once you have solved it for the upper left hand corner, repeat it so that the same pattern is drawn in all four corners of the screen. You should be able to draw all in all corners with a single loop and four calls to pygame.draw.line.

Moving things around

Now that we know how to draw lines on the screen with pygame, let’s start moving them around. Moving lines around is simple. we store the line coordinates in variables. Inside the event loop we modify the values of those variables. Let’s draw a line that jumps up and down.

 1 #! /usr/bin/env python
 2 
 3 import pygame
 4 
 5 y = 0
 6 dir = 1
 7 running = 1
 8 width = 800
 9 height = 600
10 screen = pygame.display.set_mode((width, height))
11 linecolor = 255, 0, 0
12 bgcolor = 0, 0, 0
13 
14 while running:
15     event = pygame.event.poll()
16     if event.type == pygame.QUIT:
17         running = 0
18 
19     screen.fill(bgcolor)
20     pygame.draw.line(screen, linecolor, (0, y), (width-1, y))
21 
22     y += dir
23     if y == 0 or y == height-1: dir *= -1
24 
25     pygame.display.flip()

There we go. The y-position of the line is determined by the variable y which increased by dir in each iteration of the event loop. The value of dir is 1 when the line is moving downwards, or -1 when the line is moving upwards. Simple, isn’t it?

Exercises

  1. Comment out the line screen.fill(bgcolor) and run the program. What happens?
  2. Extend the program to also include a vertical line that moves across the screen.

Drawing a color bar

Our final example for today will draw a single color bar (“copper bar” if you’ve ever owned an Amiga). Just like our last example, this one will also jump.

 1 #! /usr/bin/env python
 2 
 3 import pygame
 4 
 5 y = 0
 6 dir = 1
 7 running = 1
 8 barheight = 124
 9 screen = pygame.display.set_mode((800, 600));
10 
11 barcolor = []
12 for i in range(1, 63):
13     barcolor.append((0, 0, i*4))
14 for i in range(1, 63):
15     barcolor.append((0, 0, 255 - i*4))
16 
17 while running:
18     event = pygame.event.poll()
19     if event.type == pygame.QUIT:
20         running = 0
21 
22     screen.fill((0, 0, 0))
23     for i in range(0, barheight):
24         pygame.draw.line(screen, barcolor[i], (0, y+i), (799, y+i))
25 
26     y += dir
27     if y + barheight > 599 or y < 0:
28         dir *= -1
29 
30     pygame.display.flip()

In this example I create an array called colorbar (for the lack of a better name). This will hold values for the colorbar as it shifts from black to bright blue and back to black. Keep in mind that a color is composed of red, green and blue. Each one of these can be a value between 0 and 255.

If I change the blue value by one for each new line, I would get a really smooth gradient bar. But, the height would be 256 pixels from black to blue and another 256 pixels from blue back to black = 512 pixels, which is too high. There would hardly be enough space in our window to see the bar moving up and down.

So I have to decide on a bar height that I find acceptable. I settled on 124, which means I have 62 pixels from the black to blue gradient and another 62 for the blue to black gradient. This also means that I have to move from a blue value of 1 to a blue value of 255 in 62 pixels. The change in blue per line must be 4 per line.

I use two for loops to populate the barcolor array. The first loop pushes increasing values of blue to the array and the second one decreasing values of blue. It is important to notice that this array is nothing other than a lookup. It doesn’t contain the bar as you see it on the screen. It just contains color values.

Run it and see what it looks like. Once you’ve seen it run, analyze the code and make sure you understand exactly how it works. Then start experimenting with it.

Exercises

  1. The color bar example code is horrible. Full of “magic numbers” everywhere! Fix it.
  2. Try using pygame.draw.aaline for drawing the lines. Run the program. Do you notice any difference in speed?
  3. Change the color of the color bar.
  4. Write a program that draws three color bars in different colors. Take note of the height per bar, so that all three can fit and have some space for movement.

Conclusion

In this tutorial you have learned to draw lines. We will be staying with methods of drawing to the screen a little while longer, before we move on to other interesting things like loading and displaying images. In the next tutorial you will also learn a bit about mouse events.


2007.12.11:Added explanation of what the colorbar array does in the last example. Thanks to reader Sergy for pointing out that it needed some explanation.

2007.05.25

Pygame tutorial #1: getting started

Filed under: Game Programming, Graphics Programming, Pygame, Pygame Tutorial, Python Programming — Lorenzo E. Danielsson @ 02:22

This is the first part of my pygame tutorial, aimed at beginners. I will keep it small and simple, meaning I will proceed very slowly. I am not going to go into too much detail. I will explain just about as much as is necessary to get you started. You will need to have the pygame documentation available. Always keep it open while you are going through this tutorial.

One little thing before we begin. I am chronically lazy. It is amazing that I even manage to get out of bed every day. So please don’t expect this to be a regular thing. I will write tutorials as and when my eyes are open.

What you will need

  • Python: I am using Python 2.4 which is the default Python version on Debian Etch. Other versions will work as well.
  • Pygame: There really isn’t much point in programming in pygame unless you have it installed.
  • A text editor: I recommend Vim a powerful editor with an unfortunately bad reputation for being complex. Don’t believe the rumors. They are not true.

If you are on Debian or one of its derivates, try this (as root):

# aptitude install python-pygame

That will install pygame and all dependencies for you. Other distros and operating systems: both Python and pygame are most likely available in your repositories. Figure out how to install them and you are ready to go.

What you should know already

It is a good idea if you at least have some basic knowledge of Python. I guess you could be learning it as you go along, but I will assume that you know how to program in Python already.

Getting started

First of all, let us look at creating a pygame application that does absolutely nothing. Well, nearly absolutely nothing. It actually does display a window. It also does some very rudimentary event handling. You can see this as a template for the next few programs that we will write.

Here is the code:

1 #! /usr/bin/env python
2 
3 import pygame
4 
5 screen = pygame.display.set_mode((640, 400))
6 
7 while 1:
8     pass

First of all, to use pygame we have to import it. Then we create a Surface that is 640 pixels wide and 400 pixels high. There are a lot more things you can do with set_mode, but we will keep it simple at this point.

Next we enter into an infinite loop. We need this because otherwise the window will
If you run this program it should display a 640×400 window. That wasn’t too difficult was it. If you try to close this application by clicking on the window’s close button, you will notice that it does nothing. You will have to go activate the terminal that you started the program from and
hit CTRL+C to stop the program. We will fix that soon.

Exercises

  1. Create a window that is 320 pixels wide and 200 pixels high.
  2. Create a program where the user can specify the width and the height as command line arguments.
  3. Create a program that asks the users for the width and the height and then displays the window.
  4. Write a program that calls pygame.display.set_mode twice with different sizes. What do you expect should happen? Run the program. What actually happens? Can you explain why?

Adding an event loop

Our first example was maybe a little too simple. Staring at a completely blank window soon gets boring. Also, having to go to the terminal and hit CTRL+C to close the window seems a little awkward. Let’s add a bit of code!

Here is an updated version of the first program:

 1 #! /usr/bin/env python
 2 
 3 import pygame
 4 
 5 screen = pygame.display.set_mode((640, 400))
 6 running = 1
 7 
 8 while running:
 9     event = pygame.event.poll()
10     if event.type == pygame.QUIT:
11         running = 0
12 

What is new is that I have added a simple event loop. The loop is controlled by a flag called running. As long as the flag is set the loop keeps running. Inside the loop we use the poll method to grab the next event from the event queue. There are other ways of doing this, but polling works just fine for now.

There are several different event types that pygame knows about and can respond to. One of these is QUIT, which gets triggered when the user clicks on the window’s close button. All we do if we get an event of this type is clear the running flag, which will exit the loop and cause the program to terminate. Still simple, isn’t it.

Exercises

  1. Adapt each of the programs you wrote for the exercises in the previous section to use an event loop.
  2. Rewrite the program to do away with the running flag. Make sure that the program still jumps out of the event loop on the QUIT event.

Finishing touches to the template

As a final step before we start doing real things, let’s add just a little bit more so that we have a complete template for what follows. We will paint the our Surface and we will learn how to do a bit of screen flipping. First the code:

 1 #! /usr/bin/env python
 2 
 3 import pygame
 4 
 5 screen = pygame.display.set_mode((640, 400))
 6 running = 1
 7 
 8 while running:
 9     event = pygame.event.poll()
10     if event.type == pygame.QUIT:
11         running = 0
12     screen.fill((0, 0, 0))
13     pygame.display.flip()
14 

We have added just two lines of code. The first one sets a background color for the Surface. We have passed in a sequence of three values: red, green and blue. Each one can be a value between 0 and 255. Since we set all to zero, we get a black screen. You should experiment with different values for red, green and blue.

The next thing that is new is that we call pygame.display.flip. Drawing directly to the screen is usually a very bad idea. Instead, we have a invisible buffer that we draw onto. When we have finished drawing we make the buffer visible. That way we get flicker-free animations (when we get to that).

Exercises

  1. Create a window with a white background color.
  2. Create a window with a red background color.
  3. Experiment with setting different background colors. If you are not familiar with RGB values then spend a little extra time to figure out how to get colors like yellow, brown, cyan etc.
  4. Create a program that asks the user to specify the values for red, green and blue. Check that the values are in the valid range (0-255) and then use these for the background color.
  5. Create a program that upon start-up checks the time of the day and sets the brightness of the background color accordingly. Use a blue scale. If it is midnight, the screen should be black. If it is midday, the screen should be bright blue. Any other time the background should be something in between corresponding to the brightness outside.

Conclusion

So what have you learned so far? Not an awful lot, by the looks of it. But in a way you have. You have acquired some basics that you will need to understand the next tutorial, which will come soon. In the meantime, try your hands on a few of the exercises. If you complete all you can make up a few of your own.

2007.05.19

Plotting trigonometrical functions in PHP

Filed under: Graphics Programming, Mathematics, PHP Programming — Lorenzo E. Danielsson @ 02:48

If you’ve ever tried software applications like MRTG or Zabbix you will have seen that these programs are able to generate graphs that are displayed on a web page. If you wonder how it’s done, I hope that this short tutorial will give you an idea.

I’m going to use PHP for this example, but it wouldn’t be difficult to adapt to mod_perl, mod_ruby or possibly mod_pascal (is there such a thing??). To begin with we will need a web server (I’m using Apache2 with PHP support. If you are using Debian or one of its derivates, aptitude install libapache2-mod-php5 should do the trick (you could also use libapache2-mod-php4 if you prefer). You will also need the PHP GD (www.libgd.org library for dynamically creating images. You get that with aptitude install php5-gd.

The GD library allows to create an image, use various functions to draw on the image and finally stream the image to the client (web browser). GD itself is written in C, but there are bindings for several languages available. There are also various utility libraries available that build on top of GD, that make it easier to use GD for specific purposes, but it’s always a good idea to understand how things work at a lower level, so in this tutorial I will look at GD itself.

The procedure is quite simple:

  1. Create an image (either a new blank image or load an existing image)
  2. Perform drawing operations on the image
  3. Stream the image data to the client

In this example, I’m going to plot the two trigonometrical functions sine and cosine. We will create two files. I called the first on trigplot.php (you can call it whatever you want), and it looks like this:

<?php

header("Content-type: image/png");

function draw_axes($image, $width, $height, $color) {
    $xaxis = $height / 2;
    $yaxis = $width / 2;

    imageline($image, $yaxis, 0, $yaxis, $height-1, $color);
    imageline($image, 0, $xaxis, $width-1, $xaxis, $color);
}

function plot_sin($image, $height, $color) {
    for ($x = 0; $x < 360; ++$x) {
        $amplitude = $height/2 - 10;
        $y = $height/2 + $amplitude * sin(deg2rad($x-180));
        imagesetpixel($image, $x, $y, $color);
    }
}

function plot_cos($image, $height, $color) {
    for ($x = 0; $x < 360; ++$x) {
        $amplitude = $height/2 - 10;
        $y = $height/2 + $amplitude * cos(deg2rad($x-180));
        imagesetpixel($image, $x, $y, $color);
    }
}

$width = 360;
$height = 200;
$image = imagecreate($width, $height) or die("Failed to create stream");
$bgcolor = imagecolorallocate($image, 255, 255, 255);
$axiscolor = imagecolorallocate($image, 0, 0, 0);
$curvecolor1 = imagecolorallocate($image, 0, 0, 255);
$curvecolor2 = imagecolorallocate($image, 0, 255, 0);

draw_axes($image, $width, $height, $axiscolor);
plot_sin($image, $height, $curvecolor1);
plot_cos($image, $height, $curvecolor2);
imagepng($image);
imagedestroy($image);

?>

(Sorry for the lack of line numbering, Vim gave me errors when I tried to run :TOhtml with line numbering enabled.)

Notice the header call. This is important. We are sending image data to the web browser, so we must notify it of the content type, so that it will now what to do with the incoming data. The rest should be fairly straightforward I hope (make sure you have you PHP documentation open so that you can read up on the functions that are used). Of course you don’t have separate code this short into functions, but I did it just to show that this is a PHP file like any other and that you can use normal PHP constructs in it.

You could now upload this file to a location where you web server is able to serve it, and you should see a very simple graph containing to curves in different colors. As far as the web browser is concerned, this is an image it is displaying, similar to the way the browser will display any other image. The browser is not at all concerned with the fact that this image is, in fact, dynamically created.

If, instead of seeing an image in your browser, you get something about the image not being displayed because it contains errors then skip down to the section called A little note on debugging.

But how about if you would want to include the graph in an existing web page? That is not a problem at all. Here is a sample, you could call it index.html if you want.

<html>
<head>
<title>Trigonometry plotter</title>
</head>

<body>
<center><b>Trigonometry Functions</b></center>
<img src="trigplot.php">
</body>
</html>

Notice that I am using a normal HTML IMG tag, and pay attention to the SRC attribute. That is really all there is to it (I’m not calling the blog Keeping it Small and Simple for nothing).

A little note on debugging

If a syntax error creeps into your image generation code, then you will just get a blank image if you browse index.html. If you browse trigplot.php, on the other hand, you will get a message that the image cannot be displayed because it contains errors. To get some useful information about the error, browse trigplot.php and get your browser to view the source. It will contain error messages from PHP, along with line numbers. With that your debugging almost becomes trivial.

You will not see any error messages if you try to view the source of index.html. You must browse something like http://localhost/phpsamples/trigplot/trigplot.php to be able to see the error messages that PHP sends you.

Ideas for exercises

For those who feel so inclined I’ve added a few ideas for exercises based on my sample. You can try them if you don’t have anything better to do. Feel free to post your solutions as comments. (No, I’m not going to give you a degree in computer science. 😀 )

  1. Add a border around the graph.
  2. Add labels to the curves (something like y = sin(x) and y = cos(x)). Make sure these get well positioned.
  3. The axes are currently just straight lines. Make them look more like the ones you would find in your average school math book. Add arrows, labels etc.
  4. All drawing in the original is done by GD. Use a drawing program to create an image that contains labeled axes and has a border around it. In your PHP code, use the imagecreatefrompng() function to load the image and then perform you function plotting on it. Make sure you get your positioning right.
  5. Add y = tan(x) to the graph. What special condition do you need to take into consideration when plotting this function?
  6. Add a grid. Choose a light gray color so that it doesn’t dominate the graph.
  7. Create a form that asks the user for information like amplitude, start angle, end angle, wavelength etc, and uses this information to plot the functions.
  8. In the plot functions, highlight the maximum and minimum points of the sine and cosine functions.
  9. Write a Perl program that uses an Inline Asm section to dynamically generate PHP code that dynamically creates graphs of trigonometric functions. 😉

These are just a few examples that I can think of.

Addendum

Spot the error in the code? Hint: think Cartesian vs. screen coordinates. You can fix that by changing $y = $height/2 + ... to $y = $height/2 - ... in the two functions plot_sin and plot_cos.


Update 2007.05.23: Noticed an error in the code.

Blog at WordPress.com.