Wednesday, April 22, 2009

Chunk update

Thought I'd better post what I've done of my chunk. Fortunately, this is nearly finished. Hoping to have everything completed and ready to go by the end of the month at the latest. I've given up on inserting the images / tables here. It dosn't work!


We saw on page xx the various uses of one-dimensional (1D) arrays. Now we are going to take this concept further and show how two-dimensional (2D) arrays can be used for computer graphics.

Firstly, let us describe what a 2D array is. Where a 1D array is basically a list of items of a similar type, a 2D array is best described as a table of items of a similar type. In terms of geometry, a 2D array can be thought of as a flat plane with an X and Y axis.

Figure 1 shows a 1D array with which you should already be familiar. This array has five elements, numbered 0 to 4. Figure 2 shows a 2D array. This array has five rows and three columns. The first number in each subscript refers to the row and the second number refers to the column.









Fig. 1: 1D Array Fig. 2: 2D Array





The uses of this in computing are quite wide and varied. Employing 2D arrays in computer graphics can be quite useful as a table can be used for storing values and data relating to pixels on screen. The use of programming constructs such as loops allows for each element of the array to be processed individually as seen previously for 1D arrays on page xx. The difference for a 2D array is that access to the elements needs to move in both directions, i.e. horizontally as well as vertically. The way that this is done is described later.





Now we will look at the syntax for declaring arrays. We know that a 1D array is declared as follows:



int[] myArray = new int[size];



Similarly, a 2D array is declared as follows:



int[][] myArray = new int[sizeX][sizeY];



The difference here is that the 2D array has two subscripts, i.e. one to control the X coordinate and one to control the Y coordinate. In theory, it dosn’t really matter whether the first or second subscript is considered to be the X or Y coordinate but what is important is that any reference to the subscripts in the code should remain consistent throughout the program.





The example we will develop in this chapter will involve manipulating each element of the 2D array which will then be drawn to the screen using Processing’s point(x,y) syntax. Writing such a program involves thinking of the elements of the array as pixels on the screen. Therefore, it might help to firstly explain what a pixel actually is.







A pixel (picture element) is a small piece of data in an image on a television or computer display. It is not a small square with one colour; rather is is composed of three or four smaller parts for each of the primary colours: cyan, magenta, yellow and black. Any image displayed on a pixellated screen will involve many of these pixels (sample points) glowing at different intensities in order to produce the larger image that we see when we are at a reasonable distance.





Fig. 3: Graphic representation of a coloured pixel





In our program, we are going to consider any point on the display area as a single coloured point and not go into the complexities of different colours within each point. The Processing language’s point(x,y) function treats the display area as such anyway. The technicalities of how intensely particular colours are displayed within a pixel is dealt with at some lower level in the system, below Processing’s syntax, so we need worry about this no more. However, we will employ the use of Processing’s stroke() function to control the general colour of our points.



So now to move on to developing our program! Here’s the specification:

Write a Processing program that displays a large square containing nine different randomly coloured squares within it.

This program sounds quite simple but when we break it down into stages, we can see how much processing is involved:


  • Define display area width and height
  • Declare array screenArray[][] to represent the pixels in the display area
  • Generate random colours
  • Begin drawing horizontal and vertical pixel lines in screenArray[][]
  • Continue drawing horizontal and vertical pixel lines in screenArray[][]
    • test current x, y coordinates to determine which coloured square is being processed
    • set current element of screenArray[][] to appropriate colour accordingly
  • Repeat step 5 until all nine squares have been drawn in screenArray[][]
  • Loop through screenArray[][] and draw each element to its corresponding pixel on the display





These steps can be broken down into further substeps that get closer to Processing’s syntax. A couple of things to note about the above algorithm follow:


  • Firstly, screenArray[][] is the 2D array that holds values representing the pixels in the display area. The contents of screenArray[][] are not the pixels themselves.

  • Secondly, step 5 is a loop. We will know in advance what the width and height of the display area will be, thus we know the terminating condition for the loop. Therefore, a for loop as seen on page xx will be suitable here.

  • In order to loop successfully through all rows and columns of the array and display area, we need to employ the concept of nested loops. Doing this will allow us to access each array element distinctly, as you will see.



Before we develop the code for our program, we need to describe the concept of outer and nested loops. Looping or iterating through code should be familiar to you from page xx. A loop can be used to populate or process the elements in a one dimensional (1D) array as you will have already seen.

We will now go straight into the programming and show how each of the above steps can be implemented, one by one.



Step 1 states that we define the display area width and height. The Processing code for this should be very familiar to you at this stage:

// set up display area 200 by 200 pixels

size(200, 200);



Step 2 involves creating the array with the arbitrary name screenArray[][] to hold the values representing the pixels on the screen:



// create an array called screenArray[][] to hold coloured pixel points representing the display area

color[][] screenArray = new color[200][200];

Step 3 states that we generate random colours. We have chosen to do this using a one dimensional (1D) array with nine elements, one for each randomly coloured square:



// create 1D array to hold random colour for each of the nine squares

color[] colour = new color[9];





// populate colour[] array with nine random colours, one for each square

for (int i=0; i<9; i++){

colour[i] = color(random(255), random(255), random(255));

}





The color function is used here to generate a colour with a random amount of red, green and blue; thus generating any colour in the spectrum. The first parameter taken by color() is the red value, the second is the green and the third is blue. Each parameter is set to a random number between 0 and 255 (where 0 is black and 255 is white).



Step 4 is implemented by setting up control variables to track our current x and y positions in the 2D array:

// declare variables vertical and horizontal to control outer and nested loops



int vertical = 0;

int horizontal = 0;





We then set up our outer and nested loops to allow us to distinctly access each element of the array in turn. For each value of the outer loop, the nested loop runs through all of its values. In other words, each time the outer loop changes to its next value, the nested loop runs through its entire range. So we are effectively moving through the array one row at a time, where the nested loop is controlling the horizontal movement from beginning to end, each time the outer loop changes vertically downwards to the next row; where the nested loop subsequently starts over. This process continues until the end of the array is reached (bottom-right element or screenArray[200][200]).





/** loop through screenArray[][] and fill it with the appropriate values to produce coloured squares **/

// outer loop to process vertical direction, y axis, top-to-bottom column in the 2D array



for (vertical=0; vertical<200; vertical++){



// nested loop to process horizontal direction, x axis, left-to-right row in the 2D array



for (horizontal=0; horizontal<200; horizontal++){



Step 5 is the most complex part of our program and involves testing (using if() conditions) which of the nine square areas we are currently processing the pixels for. So, we need to choose a random colour from our pre-defined 1D colour[] array when we know that the pixel we are processing is in the area of a particular square. We need to set up range tests for each of the nine squares and select the appropriate colour from colour[0] to colour[8]:

if ((vertical <= 200) && (horizontal <= 200))

pixelColour = colour[8];

if ((vertical <= 200) && (horizontal <= 133))

pixelColour = colour[7];

if ((vertical <= 200) && (horizontal <= 66))

pixelColour = colour[6];

if ((vertical <= 133) && (horizontal <= 200))

pixelColour = colour[5];

if ((vertical <= 133) && (horizontal <= 133))

pixelColour = colour[4];

if ((vertical <= 133) && (horizontal <= 66))

pixelColour = colour[3];

if ((vertical <= 66) && (horizontal <= 200))

pixelColour = colour[2];

if ((vertical <= 66) && (horizontal <= 133))

pixelColour = colour[1];

if ((vertical <= 66) && (horizontal <= 66))

pixelColour = colour[0];



// store previously set pixelColour variable in the current element of our array

screenArray[vertical][horizontal] = pixelColour;





Note that the values 200, 133 and 66 are not arbitrary; they define the boundaries between the edges of our nine squares based on a 200 X 200 display area.

Step 6 is nothing more than a statement that says the code of Step 5 is within the loop set up in Step 4.



Step 7 draws the contents of the array screenArray[][] to the display area:

// use nested loops again to draw coloured squares to the display pixel by pixel

// note how this processing is separate from the array processing above. We can

// effectively manipulate an array in the computer's memory before displaying our

// results on the screen



for (vertical=0; vertical<200; vertical++){

for (horizontal=0; horizontal<200; horizontal++){

stroke(screenArray[vertical][horizontal]); //set colour from current element in our 2D array

point(vertical, horizontal); //draw pixel point at same position on the display area

}

}

Nested loops are used here again; this time to read the values into Processing’s stroke() function that sets the current colour being used. The point() function then draws the coloured point to the current pixel on the display area. The result seen on the screen is the nine coloured squares, which proves that screenArray[][] itself contains a set of correctly coloured elements where each element corresponds to a pixel on the display.

So, our completed program (with a few code optimizations added in) looks like this:





/*

Coloured Squares

This program displays nine coloured squares on the display

It employs a 1D array to hold the list of nine random colours

and a 2D array of the color datatype to represent the screen output

*/





// set up display area 200 by 200 pixels



size(200, 200);





// create an array called screenArray[][] to hold coloured pixel points representing the display area



color[][] screenArray = new color[200][200];





// create 1D array to hold random colour for each of the nine squares



color[] colour = new color[9];





// populate colour[] array with nine random colours, one for each square



for (int i=0; i<9; i++){



colour[i] = color(random(255), random(255), random(255));



}





// declare variable pixelColour to hold current element / pixel colour



// initialise to first random colour value



color pixelColour = colour[0];





// declare variables vertical and horizontal to control outer and nested loops



int vertical = 0;



int horizontal = 0;





/** loop through screenArray[][] and fill it with the appropriate values to produce coloured squares **/





// outer loop to process vertical direction, y axis, top-to-bottom column in the 2D array



for (vertical=0; vertical<200; vertical++){



// nested loop to process horizontal direction, x axis, left-to-right row in the 2D array



for (horizontal=0; horizontal<200; horizontal++){



if ((vertical <= 200) && (horizontal <= 200))



pixelColour = colour[8];



if ((vertical <= 200) && (horizontal <= 133))



pixelColour = colour[7];



if ((vertical <= 200) && (horizontal <= 66))



pixelColour = colour[6];



if ((vertical <= 133) && (horizontal <= 200))



pixelColour = colour[5];



if ((vertical <= 133) && (horizontal <= 133))



pixelColour = colour[4];



if ((vertical <= 133) && (horizontal <= 66))



pixelColour = colour[3];



if ((vertical <= 66) && (horizontal <= 200))



pixelColour = colour[2];



if ((vertical <= 66) && (horizontal <= 133))



pixelColour = colour[1];



if ((vertical <= 66) && (horizontal <= 66))



pixelColour = colour[0];



// store previously set pixelColour variable in the current element of our array



screenArray[vertical][horizontal] = pixelColour;



}



}





// use nested loops again to draw coloured squares to the display pixel by pixel



// note how this processing is separate from the array processing above. We can



// effectively manipulate an array in the computer's memory before displaying our



// results on the screen



for (vertical=0; vertical<200; vertical++){



for (horizontal=0; horizontal<200; horizontal++){



stroke(screenArray[vertical][horizontal]); //set colour from current element in our 2D array



point(vertical, horizontal); //draw pixel point at same position on the display area



}



}

No comments: