Monday 27 April 2009

Chunk 54 sine in action

I'm writing chunk 54 Sine in action. I've not really kept up with posting regular updates, but thought I'd post the program that I will be writing about.

This program plots a sine function, by creating an image and then colouring the pixels of the image based on their distance from the plotted function.

The sine function is adjusted using different functions to produce varied output, depending on the parameters selected.

The output looks something like this




The full write up will follow shortly, but for the moment here is the program:






/*
// Chunk 54 - Sine in Action
// Plots a sine function by colouring surrounding pixels
// in relation to their proximity to the sine wave
*/

float theta0 ; //Start angle
float dTheta0; // Increment start angle 'angular velocity'
float dTheta; // Value for incrementing theta, a function of period

float amplitude; // maximum height of wave
float amplitude0; //intial undamped amplitude
float damping; //decrase in height over period of wave
float frequency; //repetitions of wave within 2Pi radians

int count = 1;//use to reverse gradient
int range; //range for vertical movement of function
int colorChoice; //colour type to plot
int adjustmentChoice; // choice of funtion to adjust postion of sine wave

PImage img;
void setup() {
size(500, 500);
frameRate(20);
img = createImage(250,250,RGB);

noSmooth();
setOptions();
}

void draw() {
background(255);
amplitude = amplitude0;
theta0 += dTheta0; //increment initial angle

if ( frameCount % range == 0){
count = -count;
}

//set colours of image
float theta = theta0; //set initial angle for calculating sin wave
int intColor; // value of colour to plot at x,y
color c; //colour of plotted point x,y based on intColor
float adjSinWave; // y value to plot colour around

//plot sin function by colouring surrounding points
for (int x = 0; x < img.width; x++) {
adjSinWave = adjustment(x, adjustmentChoice) + plotSinWave(theta);

for ( int y= 0; y < img.height; y++){
intColor = getColorValue(adjSinWave, y);
c= getColor(intColor,colorChoice);
img.set(x,y,c);
}
theta += dTheta;
}

// display the results
image(img,0,0,width,height);
}

void setOptions(){
float period = 450.0; // How many pixels before the wave repeats
//values for plotting sine wave
theta0 = 0;
dTheta0 = 0.01;
dTheta = TWO_PI / period; //change in angle plotted between x and x+1
amplitude0 = img.height/2; //amplitude looks best close to height/2
damping = 0.987; //keep close to 1, or sine function becomes quickly flat
frequency = 6;
range = img.height;
colorChoice = 2; // 1- grayscale, 2 - colour shift,
adjustmentChoice = 3; //1 - constant, 2 - linear, 3 - sin & linear
}

float plotSinWave(float angle){ //main sine wave to plot everything else round
// float result = 0; //for testing colour distibution
float result = amplitude * sin (frequency * angle);
amplitude = amplitude * damping;
return result;
}

float adjustment(float xPos, int choice){ //adjustment to position of sine wave
float result = 0;

if (choice == 1){ //constant

result = img.height/2;

}
else if (choice ==2) { //simple linear function

int intersect = 0;
float gradient ;
float gradientChange =0;

if (count > 0 ){ //count switches from positive to negative when framecount % range is reached
//increase intersect up to range
gradientChange = frameCount % (range);
}
else {//decrease intersect from range to zero
gradientChange = range - frameCount % (range);
}

gradient = (img.height - gradientChange) / img.width;
result = intersect + gradient * xPos ;

}
else if (choice == 3){//combination of sin and linear functions

float amp1 = 0.25;
int freq1 = 1;
int period1 = img.width;
float amp2 = 5;
int freq2= 2;
int period2 = img.width/3;
int intersect = 0;
float gradient;

gradient = amp1 * sin(freq1 * (xPos * TWO_PI/period1));
if (count > 0 ){ //count switches from positive to negative when framecount % range is reached
//increase intersect up to range
intersect = frameCount % (range);
}
else {//decrease intersect from range to zero
intersect = range - frameCount % (range);
}

//linear function with variable intersect and gradient
float result1 = intersect + gradient * xPos;
float result2 = amp2 * sin(freq2 * (xPos * TWO_PI/period2));

result = result1 + result2;

}
return result;

}

int getColorValue(float maxValue, float value){
//colors plotted around sine wave
// returns int value between 0 & 255 based on distance from maxValue

float h = img.height;
float temp = 0;
int result;
float minValue;
float rangeColor;

// if maxValue > h/2 then minValue is 0 else minValue 2 * maxValue - h
minValue = min(0, 2* maxValue - h);
//color increasing to maxValue
if ( value <= maxValue){
temp = value - minValue ;
}
else { //color decreasing from maxValue
temp = 2 * maxValue - (value + minValue );
}

rangeColor = max(maxValue, h - maxValue); //range over which colour varies between 0 and 255
temp = scaleValue(temp, 0, rangeColor); //scale value to be between 0 and 255
result = round(temp); //convert scaled value to int

return result;
}

float scaleValue(float z, float minVal, float maxVal){

//adjust values to ensure minimum equals 0
float adjZ = z - minVal;
//Scale values to ensure new max equals 255
float adjMaxZ = maxVal - minVal;
float scaledZ = adjZ * (255/adjMaxZ);

return scaledZ;
}

color getColor(int colorVal, int choice){

int tempColor;
int redVal = 0;
int greenVal =0;
int blueVal =0;

if (choice == 1){ //grayscale

redVal = greenVal = blueVal = colorVal;

}
else if (choice == 2 ){// Smooth transition of color from blue to green to yellow to red
//subdivide colour selection based on range of values

if ( colorVal >= 0 && colorVal <= 63){
tempColor = 4 * colorVal;
redVal = 0;
greenVal = tempColor;
blueVal = 255;
}
else if ( colorVal > 63 && colorVal <= 127){
tempColor = 4 * (colorVal - 64);
redVal = 0;
greenVal = 255;
blueVal = 255 - tempColor;
}
else if ( colorVal > 127 && colorVal <= 191){
tempColor = 4 * (colorVal - 128);
redVal = tempColor;
greenVal = 255;
blueVal = 0;
}
else if ( colorVal > 191 && colorVal <= 255){
tempColor = 4 * (colorVal - 192);
redVal = 255;
greenVal = 255 - tempColor;
blueVal = 0;
}
}

return color(redVal,greenVal,blueVal);

}


Java2html