Tuesday, April 28, 2009

FINAL VERSION

Well here's my final version! I managed to reach just over 2000 words by summarizing what I had described and justifying the use of 2D arrays (and indeed, arrays in general!) in graphics applications. Hopefully this, when combined with the other chunks, will introduce a seamless and coherent concept.



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 four rows and four 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:

1. Define display area width and height

2. Declare array screenArray[][] to represent the pixels in the display area

3. Generate random colours

4. Begin drawing horizontal and vertical pixel lines in screenArray[][]

5. Continue drawing horizontal and vertical pixel lines in screenArray[][]

a. test current x, y coordinates to determine which coloured square is being processed

b. set current element of screenArray[][] to appropriate colour accordingly

6. Repeat step 5 until all nine squares have been drawn in screenArray[][]

7. 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:

a) 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.
b) 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.
c) 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. When processing a 2D array, we need to move horizontally accross the columns as well as vertically down the rows. This is done by using an outer loop to control the vertical, top-to-bottom processing and a nested loop contained inside the outer loop to control the horizontal, left-to-right processing. For each value of the outer loop, the nested loop does its full range in its entirety. Below is a simple piece of code showing a nested for loop:

for (int x=0; x <=100; x++){
for (int y=0; y <=100; y++){
// do processing here...
}
}

The processing inside the nested loop could be anything from mathematical calculations to graphical manipulation, which will be the case in the programs we develop below for Processing. An easy way to describe what happens in the above code is as follows. When the outer loop sets x to 0, the nested loop runs from 0 to 100. When the outer loop subsequently moves on to 1, the nested loop again runs from 0 to 100. When the outer loop moves on to 2, the nested loop once again runs from 0 to 100. This process of the nested loop running repeatedly through its full range continues until the outer loop reaches the end of its range.

We will now go straight into the programming and show how each of the steps in our program specification above 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]). Figure 4 illustrates the direction of movement through an array as the code runs.


Fig. 4: Order in which 2D array elements are processed when using nested loops

/** 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
}
}


We hope this example illustrates the point that an array is essentially a data structure in memory that holds data for reuse and has no interface in itself. Putting data into an array and retrieving data from an array is a process that takes place in the program. The point being made about 2D arrays is that they are very useful for storing image data corresponding to areas of the screen (in our case, pixels) and have many wide and varied uses in graphics applications. Another point to note is that Processing can easily be programmed to draw directly to the screen without the use of a 2D array at all. So what is the advantage of storing the screen data in an array first and then drawing it out to the screen later on?

Firstly, it creates a faster and cleaner appearance of the image(s) on the display; as the step by step generation of the data is masked from the user until it is completed – then drawn out to the display with two very fast nested loops.

Secondly, it allows for unpredictable processing where a particular point in the image may need to be altered from within the program if a certain condition becomes true. For example, suppose we have an image bitmap loaded into our screen array using Processing’s loadImage() syntax. We then set up an outer and nested loop to scan through each row of pixels as you have seen. If we come to an area of the image that has a colour that is darker than some threshold, we may want to darken the other image areas – perhaps to reduce contrast. If we are using an array, we can do this quite easily by re-initialising our nested loops and applying a formula to darken each of the lighter pixels; but if we had originally started out by drawing each pixel from the image directly to the display, it would then be too late to go back and process any of the previously drawn pixels.

We hope that this section on 2D (two dimensional) arrays helps you to understand an important construct in computer programming in general, as well as inspire you to apply the concept in a graphical context.

Monday, April 27, 2009

Near-final version

Still a bit shy of 2000 words when program code is removed! Hopefully I'll be able to add a bit more tonight and tomorrow night and have it ready to submit before long. Program described in text works fine as does the standalone one.







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 four rows and four 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:

1. Define display area width and height

2. Declare array screenArray[][] to represent the pixels in the display area

3. Generate random colours

4. Begin drawing horizontal and vertical pixel lines in screenArray[][]

5. Continue drawing horizontal and vertical pixel lines in screenArray[][]

a. test current x, y coordinates to determine which coloured square is being processed

b. set current element of screenArray[][] to appropriate colour accordingly

6. Repeat step 5 until all nine squares have been drawn in screenArray[][]

7. 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:

a) 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.
b) 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.
c) 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. When processing a 2D array, we need to move horizontally accross the columns as well as vertically down the rows. This is done by using an outer loop to control the vertical, top-to-bottom processing and a nested loop contained inside the outer loop to control the horizontal, left-to-right processing. For each value of the outer loop, the nested loop does its full range in its entirety. Below is a simple piece of code showing a nested for loop:

for (int x=0; x <=100; x++){ for (int y=0; y <=100; y++){ // do processing here... } } The processing inside the nested loop could be anything from mathematical calculations to graphical manipulation, which will be the case in the programs we develop below for Processing. An easy way to describe what happens in the above code is as follows. When the outer loop sets x to 0, the nested loop runs from 0 to 100. When the outer loop subsequently moves on to 1, the nested loop again runs from 0 to 100. When the outer loop moves on to 2, the nested loop once again runs from 0 to 100. This process of the nested loop running repeatedly through its full range continues until the outer loop reaches the end of its range. We will now go straight into the programming and show how each of the steps in our program specification above 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]). Figure 4 illustrates the direction of movement through an array as the code runs.








Fig. 4: Order in which 2D array elements are processed when using nested loops




/** 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
}
}

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



}



}

Tuesday, April 21, 2009

Less ambitious

Well following on from my last entry, I got the cross-fading script to work but I feel that to present this as an example of 2D arrays is a little too superfluous for a beginner. Certainly, to include any kind of warping algorithm would be taking away too much from the main point of my chunk, i.e. to demonstrate the use of 2D arrays.

I'm now keeping the main example as a simple script that manipulates randomly coloured squares in the display area. More to follow...

Thursday, March 26, 2009

More work...

Unfortunately, I've been a bit busy over the past few weeks and haven't had the opportunity to work much on the project. However, I plan to put aside this weekend for working on Mass Writing and hope to have an updated script by Sunday.

I also hope to have a good program completed properly as the requirement is for us to have a stand alone program separate from the one developed in the main text. I was thinking of a morphing program (one that takes two images and allows one to be transformed into the other through a seamless transition) although I fear that this may be too ambitious!

I need to experiment and develop a system for cross-fading, possibly using Processing's bitwise operations as described in Chapter 10 of Greenberg. The other requirement for a morphing program is warping, i.e. stretching areas of the first image to meet logically similar areas of the second image - synchronised with the cross-fading effect to give a smooth transition.

A fun weekend lies ahead...!

Tuesday, January 20, 2009

Easiest Syntax?

Just wondering if I should show the syntax for declaring arrays as:

float[][] myArray;
myArray = new float[200][200];

or as:

float[][] myArray = new float[200][200];

I wonder what new students would find easier? Perhaps both?

Sunday, January 11, 2009

Incomplete sketchy attempt...

OK, here's a sketchy attempt at my little bit of writing. By no means is this complete.. nowhere NEAR 2500 words! But at least its a start...


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.

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 useful 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.


More to follow... I'll hopefully be able to post some code soon too.