Wednesday 31 December 2008



Added some more animation features to my Bezier Flower Demo - which you can view by clicking on the link below -
View Petal Demo @ http://www.javaimage.co.uk/flower.html

Chapter 58

Chapter 58 Bezier Curves 2


Plan

1 - Recap on some key points from last chapter (keep up to date with philomath’s blog)


Processing uses cubic bezier - 2 Anchor points (AP) and 2 control points (CP)

(Make the point that ‘cubic bezier’ => MAXIMUM number of turning points is 2)

Joining two bezier curves together - HOW to KEEP Joined curve ‘smooth’ by making common anchor point (AP) and last control point (CP) of 1st curve and 1st control point of 2nd curve on a straight line - introduce the term ‘colinear’ - Refer back to chapter 24 equation of a straight line.


Demo program 1

Devise a simple program which allows you to plot 7 points - and uses cubic beziers to draw a curve - allow this curve to remove sharp turns at common anchor point by moving either the common anchor point or the last control point of the 1st curve or first control point of the second curve so all 3 points are colinear - by hitting the ‘S’ (S for Smooth) key.

Explain how we can move one of the CPs or common AP using the equation of a straight line y = mx + c



Demo Program 2


Compare a pair of joined cubic beziers with a complex poly - trace both

MORE HERE


Demo Program 3

Using Bezier Curves for animation - describe a Processing program which plots an animating flower or flowers - using CBC - Describe the maths (O Level) to work out where the Anchor Points and control points are to draw one petal of a flower -


A DIAGRAM IS VERY IMPORTANT HERE -

SHOWING A CIRCLE WITH A SEGMENT - TWO RADIUS LINES AT AN ANGLE WITH THEIR TANGENT LINES GOING OUT IN OPPOSITE DIRECTIONS AND ANOTHER TWO LINES RADIATING FROM THE TANGENT POINTS AT A GIVEN ‘TILT’ ANGLE.



Explain the maths in terms of straight lines - but also give an alternative mathematical method using CROSS product (to work out tangent) and matrices to rotate the tangents to a given tilt angle.

Monday 29 December 2008

Flower Bezier curves

Managed to lose my Bezier demo (Flower/Spiral generator) in November - (damn you 'Time Machine') - Actually, it turned out to be a good thing, as it made me rethink the maths - in terms of Vectors rather than equations of straight lines. The four control points for the cubic bezier are calculated by working out the tangents to lines radiating from the centre of a circle. Using the radius line and its tangent - we work out an orthogonal matrix - applying a 'tilt' (rotation matrix) to squash or expand the petal.
My lost code was horrible - all sorts of case statements to deal with angle quadrants.


The following code - is the very start of my new Demo program




int displayWidth,displayHeight ;
String mode ;
float CX,CY ;


float degreesToRadians(float th)
{
return PI * th /180.0f ;
}



float translateX(float x)
{
return x+CX ;
}


float translateY(float y)
{
return -y+displayHeight-CY ;
}


PVector [] calcControlPoints(float angle,float ro,float radius,float tilt,float petalLength)
{

PVector [] bezControlPoints = new PVector[4] ;

float halfRo = ro / 2.0f ;

PVector[] cPoints = calcPetalPointPair(angle-halfRo,tilt,petalLength) ;
PVector startPt = cPoints[0] ;
PVector fPoint = cPoints[1] ;


bezControlPoints[0] = new PVector(startPt.x * radius,startPt.y * radius) ;
bezControlPoints[1] = new PVector(startPt.x * radius + fPoint.x,startPt.y * radius + fPoint.y) ;



PVector [] cPoints2 = calcPetalPointPair(angle+halfRo,-tilt,petalLength) ;
startPt = cPoints2[0] ;
fPoint = cPoints2[1] ;

bezControlPoints[3] = new PVector(startPt.x * radius,startPt.y * radius) ;
bezControlPoints[2] = new PVector(startPt.x * radius + fPoint.x,startPt.y * radius + fPoint.y) ;


return bezControlPoints ;

}


void drawBezier(PVector [] cps)
{
drawBezier(cps[0].x,cps[0].y,cps[1].x,cps[1].y,cps[2].x,cps[2].y,cps[3].x,cps[3].y) ;
}

void drawBezier(float x1,float y1,float x2,float y2,float x3,float y3,float x4,float y4)
{
noFill() ;
stroke(0,0,0) ;
bezier(translateX(x1),translateY(y1),
translateX(x2),translateY(y2),
translateX(x3),translateY(y3),
translateX(x4),translateY(y4)) ;



}


void drawControlPoints(PVector[] cps)
{
stroke(255,0,0) ;
drawLine(cps[0].x,cps[0].y,cps[1].x,cps[1].y) ;
stroke(0,255,0) ;
drawLine(cps[2].x,cps[2].y,cps[3].x,cps[3].y) ;

}



PVector[] calcPetalPointPair(float angle,float tilt,float petalLength)
{


PVector startPt = new PVector(1.0*sin(degreesToRadians(angle)),1.0*cos(degreesToRadians(angle)));


PVector vert = new PVector(0,0,1.0f) ; // Unit Vector Perp to XY Plane
PVector nCPc = startPt.cross(vert) ; // Calculate Tangent to Circle at startPt.x,startPt.y


PMatrix2D iMat = new PMatrix2D() ;

iMat.rotate(degreesToRadians(tilt < 0 ? 180+tilt : tilt)) ; // Petal Tilt


PMatrix2D cMat = new PMatrix2D(nCPc.x,startPt.x,0f,nCPc.y,startPt.y,0.0f) ;

// Matrix
// | nCPc.x startx |
// | nCPc.y starty |


cMat.preApply(iMat) ; // Apply our orthog axis to the rotation matrix


PVector fPoint = new PVector() ;
PVector sPoint = new PVector(petalLength,0) ; // Petal Length

cMat.mult(sPoint,fPoint) ; // Apply Full transformation to petal Vector

PVector [] points = new PVector[2] ;
points[0] = startPt ;
points[1] = fPoint ;

return points;

}





void setup()
{

mode = JAVA2D ;


displayHeight = screen.height/2 ;
displayWidth = screen.width/2 ;
CX = displayWidth / 2 ;
CY = displayHeight / 2 ;

size(displayWidth, displayHeight,mode);
loop() ;

}

void drawLine(float x,float y,float x2,float y2) {
line(translateX(x),translateY(y),translateX(x2),translateY(y2)) ;
}

void drawCircle(float x,float y,float rad)
{
ellipse(translateX(x), translateY(y), rad,rad) ;
}




void draw() {

background(255);
float dt = 1/frameRate ; // We should calculate dt - time passed since last update-draw

float radius = 20.0f ;
float tilt = 70.0f ;
float petalLength = 250.0f ;
float ro = 15.0f ;
float step = 7.0f ;
float numpetals = 360.0f / step ;

noFill() ;
ellipseMode(RADIUS) ;
stroke(0,0,0) ;
drawCircle(0,0,radius) ;

for (float angle = 0.0f ; angle < step*numpetals ; angle+=step)
{
PVector [] cps = calcControlPoints(angle,ro,radius,tilt,petalLength) ;
drawBezier(cps) ;
}




}

Wednesday 29 October 2008

Bezier 2 - 58 Chunk

Not yet up on the MCT-MWP blog - but I am doing Chunk 58 - 'Bezier 2'. I need to get my thinking cap on, coming up with some cool demo programs.

HTML Guru WANTED!

I've noticed my lovely listings being chopped off! I've prefixed and postfixed my listings with 'PRE' tags - Can any HTML/Blogger.com Guru please advise? Ta.

Saturday 18 October 2008

2D Bezier Curves Demo

I like this demo! Although not graphically very exciting - it does show the potential for Bezier curves in games - Paths for nasties, cars etc. You can see from my variables names within the code, where my inspiration came from!
http://www.javaimage.co.uk/bez.html

View Bez Demo


/*
Demo showing Objects moving over 2D space using Bezier curves -
JW October 18th 2008
http://www.javaimage.co.uk/bez.html

*/

public static final int BEZ_ARCFROMTOPLEFT = 0;
public static final int BEZ_ARCFROMTOPRIGHT = 1;
public static final int BEZ_UTURNFROMTOPLEFT = 2;
public static final int BEZ_UTURNFROMTOPRIGHT = 3;
public static final int BEZ_CENTRALTOPTWIRLRIGHT = 4;
public static final int BEZ_CENTRALTOPTWIRLLEFT = 5;
public static final int BEZ_HELIXFROMTOPLEFT = 6;
public static final int BEZ_HELIXFROMTOPRIGHT = 7;
public static final int BEZ_RBEND = 8;
public static final int BEZ_RBEND_INVERTED = 9;
public static final int BEZ_DOWN_RIGHT = 10;
public static final int BEZ_DOWN_LEFT = 11;
public static final int BEZ_FLAT_LEFT_23 = 12;
public static final int BEZ_FLAT_RIGHT_23 = 13;
public static final int BEZ_FLAT_LEFT_13 = 14;
public static final int BEZ_FLAT_RIGHT_13 = 15;
public static final int BEZ_UP_RIGHT = 16;
public static final int BEZ_UP_LEFT = 17;
public static final int BEZ_S = 18;
public static final int BEZ_S_INVERTED = 19;
public static final int BEZ_FLAT_LEFT_34 = 20;
public static final int BEZ_FLAT_RIGHT_34 = 21;
public static final int BEZ_UTURNFROMBOTTOMLEFT = 22;
public static final int BEZ_UTURNFROMBOTTOMRIGHT = 23;
public static final int BEZ_SWOOPTOPLEFT_TORIGHT = 24;
public static final int BEZ_SWOOPTOPRIGHT_TOLEFT = 25;
public static final int BEZ_REVERSESINEWAVE = 26;
public static final int BEZ_COSINEWAVE = 27;
public static final int BEZ_LEFTNOSE = 28;
public static final int BEZ_RIGHTNOSE = 29;
public static final int BEZ_CSHAPE = 30;
public static final int BEZ_CSHAPE_MIRROR = 31;
public static final int BEZ_DIAGONAL_FROMTOPLEFT = 32;
public static final int BEZ_DIAGONAL_FROMTOPRIGHT = 33;
public static final int BEZ_SHEARED_S = 34;
public static final int BEZ_SHEARED_S_MIRROR = 35;
public static final int BEZ_DOWN_CENTRE = 36;

public static final int NUM_BEZIERS = 37;



int displayWidth,displayHeight ;
String mode ;
BezierCP [] bez = new BezierCP[NUM_BEZIERS] ;

// Curve table

public class BezierCP {
float cx,cy ;
float cx2,cy2 ;
float cx3,cy3 ;
float cx4,cy4 ;
public BezierCP(float cx,float cy,float cx2, float cy2, float cx3, float cy3,float cx4,float cy4)
{
this.cx = cx ; this.cy = cy ;
this.cx2 = cx2 ; this.cy2 = cy2 ;
this.cx3 = cx3 ; this.cy3 = cy3 ;
this.cx4 = cx4 ; this.cy4 = cy4 ;




}

float getX(float t) {
return bezierPoint(cx,cx2,cx3,cx4,t) ;

}

float getY(float t) {
return bezierPoint(cy,cy2,cy3,cy4,t) ;

}

public void draw() {
bezier(cx,cy,cx2,cy2,cx3,cy3,cx4,cy4) ;
}


}


public class Galaxian {

float time, duration ;
BezierCP gbez ; // bezier curve this Galaxian follows
boolean randomchoice = false ;
color col = color(random(255),random(255),random(255),255) ; // random colour

// Default Glaxian contructor

public Galaxian() {
time = 0f ;
duration = 4.0 ;
gbez = bez[0] ;
randomchoice = true ;
}

public Galaxian(BezierCP gbez,float duration) {
this.duration = duration ;
time = 0f ;
this.gbez = gbez ;

}
public Galaxian(int bezidx,float duration) {
this(bez[bezidx],duration) ;
}

public void update(float dt) {


if (time > duration) {
// Galaxian has finished - start again
time = 0f ;
if (randomchoice)
gbez = bez[(int)random(NUM_BEZIERS)] ;

} else {


}

time = time + dt ;

}

public void draw() {

debug() ; // Draw Curve the Galaxian is following.


if (time < duration) {

float t = time/duration ;
float xpos = gbez.getX(t) ;
float ypos = gbez.getY(t) ;
fill(col) ;
rect(xpos,ypos,20,20) ;
}

}

public void debug() {
noFill() ;
stroke(col) ;
gbez.draw() ;
}


}



/*
Create a global Array of Bezier Objects -
This object is just a wrapper for a Processing Bezier Object for storing control points.

*/

void InitBezier(int width,int height)
{


bez[BEZ_ARCFROMTOPLEFT] =
new BezierCP( 0, 100,
width, 0,
width/2, height/2,
width, height);

bez[BEZ_ARCFROMTOPRIGHT] =
new BezierCP( width, 100,
0, 0,
width/2, height/2,
0, height);

bez[BEZ_UTURNFROMTOPLEFT] =
new BezierCP( 100, -100,
100, 100.0f +height/2,
width-100, 100.0f + height/2,
width-100, 0);

bez[BEZ_UTURNFROMTOPRIGHT] =
new BezierCP( width-100, -100,
width-100, +200.0f + height/2,
100, +200.0f + height/2,
100, 0);

bez[BEZ_CENTRALTOPTWIRLRIGHT] =
new BezierCP( width/2, 0,
width, height*0.25f,
0, height*0.75f,
width/2, height);

bez[BEZ_CENTRALTOPTWIRLLEFT] =
new BezierCP( width/2, 0,
0, height*0.25f,
width, height*0.75f,
width/2, height);

bez[BEZ_HELIXFROMTOPLEFT] =
new BezierCP( 0, 0,
0, height/2,
width, height/2,
width, height);

bez[BEZ_HELIXFROMTOPRIGHT] =
new BezierCP( width, 0,
width, height/2,
0, height/2,
0, height);

bez[BEZ_RBEND] =
new BezierCP( width, height*0.25f,
width, height*0.25f,
100, height*0.25f,
100, height);
bez[BEZ_RBEND_INVERTED] =
new BezierCP( 0, height*0.25f,
width, height*0.25f,
width, height*0.25f,
width, height*0.25f);
bez[BEZ_DOWN_RIGHT] =
new BezierCP( width*0.75f, 0,
width*0.75f, 0,
width*0.75f, height,
width*0.75f, height);
bez[BEZ_DOWN_LEFT] =
new BezierCP( width*0.25f, 0,
width*0.25f, 0,
width*0.25f, height,
width*0.25f, height);
bez[BEZ_FLAT_LEFT_23] =
new BezierCP( width, height*0.33f,
width, height*0.33f,
0, height*0.33f,
0, height*0.33f);
bez[BEZ_FLAT_RIGHT_23] =
new BezierCP( 0, height*0.33f,
0, height*0.33f,
width, height*0.33f,
width, height*0.33f);
bez[BEZ_FLAT_LEFT_34] =
new BezierCP( width, height*0.25f,
width, height*0.25f,
0, height*0.25f,
0, height*0.25f);
bez[BEZ_FLAT_RIGHT_34] =
new BezierCP( 0, height*0.25f,
0, height*0.25f,
width, height*0.25f,
width, height*0.25f);
bez[BEZ_FLAT_LEFT_13] =
new BezierCP( width, height*0.66f,
width, height*0.66f,
0, height*0.66f,
0, height*0.66f);
bez[BEZ_FLAT_RIGHT_13] =
new BezierCP( 0, height*0.66f,
0, height*0.66f,
width, height*0.66f,
width, height*0.66f);
bez[BEZ_UP_RIGHT] =
new BezierCP( width*0.75f, height,
width*0.75f, height,
width*0.75f, 0,
width*0.75f, 0);
bez[BEZ_UP_LEFT] =
new BezierCP( width*0.25f, height,
width*0.25f, height,
width*0.25f, 0,
width*0.25f, 0);
bez[BEZ_S] =
new BezierCP( width/2, 0,
0, 0,
width, height*0.66f,
width/2, height);
bez[BEZ_S_INVERTED] =
new BezierCP( width/2, 0,
width, 0,
0, height*0.66f,
width/2, height);

bez[BEZ_UTURNFROMBOTTOMLEFT] =
new BezierCP( 0, height,
0, -100,
width, -100,
width+100, height+100);

bez[BEZ_UTURNFROMBOTTOMRIGHT] =
new BezierCP( width, height+100,
width, -100,
0, -100,
-100, height+100);

bez[BEZ_SWOOPTOPLEFT_TORIGHT] =
new BezierCP( 100, -100,
200, height-400,
200, height-400,
width+100, height-200);

bez[BEZ_SWOOPTOPRIGHT_TOLEFT] =
new BezierCP( width-100, -100,
width-200, height-400,
width-200, height-400,
-100, height-200);

bez[BEZ_REVERSESINEWAVE] =
new BezierCP( width+100, 100,
200, 100,
width+100, height-200,
-100, height-200);

bez[BEZ_COSINEWAVE] =
new BezierCP( -100, 100,
width+100, 100,
200, height-200,
width+100, height-200);

bez[BEZ_LEFTNOSE] =
new BezierCP( width/2 - 100, -100,
width/2 + 200, 200,
-800, 400,
width+100, height-200);

bez[BEZ_RIGHTNOSE] =
new BezierCP( width/2 + 100, -100,
width/2 - 200, 200,
width+800, 400,
-100, height-200);

bez[BEZ_CSHAPE] =
new BezierCP( width + 100, 0,
-200, 0,
-200, height-100,
width+100, height-100);

bez[BEZ_CSHAPE_MIRROR] =
new BezierCP( -100, 0,
width+200, 0,
width+200, height-100,
-100, height-100);

bez[BEZ_DIAGONAL_FROMTOPLEFT] =
new BezierCP( -100, 0,
-100, 0,
width/2, height+100,
width/2, height+100);

bez[BEZ_DIAGONAL_FROMTOPRIGHT] =
new BezierCP( width+100, 0,
width+100, 0,
width/2, height+100,
width/2, height+100);

bez[BEZ_SHEARED_S_MIRROR] =
new BezierCP( -100, 50,
width+600, 180,
-1000, 360,
width+100, height-50);

bez[BEZ_SHEARED_S] =
new BezierCP( width+100, 50,
-600, 180,
width+1000, 360,
-100, height-50);

bez[BEZ_DOWN_CENTRE] =
new BezierCP( width/2, -100,
width/2, -100,
width/2, height+100,
width/2, height+100);


}



/*
Define some Galaxians
*/

int MAX_GALAXIANS = 20 ;

Galaxian [] galaxians = new Galaxian[MAX_GALAXIANS] ;

void setup() {

mode = JAVA2D ;

displayHeight = screen.height/2 ;
displayWidth = screen.width/2 ;
InitBezier(displayWidth,displayHeight) ;

for (int i = 0 ; i < galaxians.length ; i++) {
galaxians[i] = new Galaxian((int)random(NUM_BEZIERS),2.0f + random(4.0f)) ; // pick a random Bezier 'curve' and a random duration between 2 and 6 seconds

}


size(displayWidth, displayHeight,mode);
loop() ;

}




void draw() {
background(255);
float dt = 1/frameRate ; // We should calculate dt - time passed since last update-draw
// but this should be approx equal to 1 / frameRate

// Update the Galaxians
for (int i = 0 ; i < galaxians.length ; i++) {
galaxians[i].update(dt) ;
}


// Draw Galaxians

for (int i = 0 ; i < galaxians.length ; i++) {
galaxians[i].draw() ;
}


}

Simple Processing Script - Contour Heat Map


Ok - I've got my Processing Environment up and running - I've even compiled my own 1st Java PApplet using JDK, ANT and core.jar.  If I can find out how to embedd Applets on this blog - I will put it up at some time.  Anyone who wants to know more about my setup - please get in touch!

Anyhow, here is my first attempt at using the PDE which simulates some American Lake heating up during the day (Lake Errie? - I lifted the depth data a few years ago for some fishing game I was developing)




//  This is a crude simulation of the temperature of a lake
// at some point in time. 

float wmaxtemp = -32000f;
float wmintemp = 32000f;        // min and max water temperatures

float scalef = 0.03125 ;        // Scale factor for ploting 1 square unit of the lake.

int screenWidth = 672 ;        // Screen Width in Pixels
int screenHeight = 540 ;       // Screen Height in Pixels


// Colour table used to plot Lake map temperatures - (Probably should be reversed - or un-comment line 238)

static int colTabs[][] = {
         {0,0,255},{32,0,196},{64,0,160},{96,0,128},{128,0,96},{160,0,64},{192,0,32},{255,0,0}

  } ;


int time = 0 ;        // time of day - updated in draw loop


// Depth Map Of some famous American Lake - I lifted off the internet (units not important - they were Fixed point)


static int depthmap[][] = {

        { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},

        { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},

        { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},

        { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},

        { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},

        { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1280, 1792, 0, 0},

        { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1792, 3584, 3840, 1536, 0},

        { 0, 0, 0, 0, 0, 0, 0, 0, 1280, 2304, 2304, 2304, 2816, 1792, 1536, 0, 0, 1792, 3840, 4608, 0, 0},

        {0, 0, 0, 0, 0, 2816, 3072, 3072, 3584, 3840, 3840, 4096, 4096, 3840, 3328, 2304, 3072, 3584, 6400, 5376, 3328, 0},

        { 0, 0, 0, 1792, 3328, 4864, 5888, 6656, 5120, 4352, 5120, 6400, 6912, 6400, 5632, 5632, 6400, 5888, 4352, 3328, 3328, 0},

        { 0, 0, 2048, 3584, 4352, 5376, 4352, 3584, 3328, 3072, 2816, 3072, 3840, 4352, 4096, 3840, 4608, 3584, 3072, 1536, 0, 0},

        { 0, 1792, 3328, 3840, 3072, 3328, 1792, 0, 0, 0, 0, 0, 0, 3072, 2048,1792, 3328, 2048, 0, 0, 0, 0},

        { 0, 1792, 2304, 2048, 1536, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},

        { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},

        { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},

        { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},

        { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},

        { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}

    };


// Temperature Map - at some point in time - generated by buildTempMap(float heatFactor)

static float temperatures[][];

// This function is called first by Processing Environment
void setup() {
  size(screenWidth, screenHeight);    // set up screen dimensions
  initialiseRange() ;  // initialise emulation variables (potential min,max temperatures)
   loop() ;            // call draw() function indefinately

}



// Draw function called - every screen refresh
void draw() {
  background(204);        // clear background
  updateTempMap(time) ;   // heat lake up -over a period of time 
  plotPartialContour() ;  // plot it's heat map
  time = time + 1 ;    // update time
}


// Calculates min-max temperatures - 
void initialiseRange() {
    // Calculate Min-Max Temperature Value of lake
    buildTempMap(0.0f) ;
    minmaxCalc() ;
    
    buildTempMap(1.0f) ;  
    minmaxCalc() ;
    
    
  
}

// Heat lake up - over time

void updateTempMap(int time) {

   float p = sin(6*(time % 60)/60f);    // simulate Sun moving over the lake (p = 1.0 is mid-day)
   buildTempMap(p) ;
   

}

// Build Temperature Map as a function of Depth Map and heatFactor (0 <= heatFactor <= 1)

void buildTempMap(float heatFactor) {
  
       temperatures = new float[depthmap.length][depthmap[0].length];

        for (int y = 0; y <>

            for (int x = 0; x <>

                float depth = (float)depthmap[y][x];

                float tempAtDepth_H = depth;

                if (depth != 0f) {
                    tempAtDepth_H = heatFactor * (depth/2.0f - depth) + depth; // Work out temperature on surface as a function of depth
                } 
                temperatures[y][x] = tempAtDepth_H ; 
            }

        }
  
  
}

    // Used at the start of the calculation to work at the min and maximum temperatures 
        
    private void minmaxCalc() {
      

int wid = (temperatures[0].length-1);
int hgt = (temperatures.length -1) ;

        // Calculate min and max temperatures
        

        for (int y = 0; y <>

            for (int x = 0; x <>

                if (temperatures[y][x] > wmaxtemp) {

                    wmaxtemp = temperatures[y][x];

                }

                if ((temperatures[y][x] <>

                    wmintemp = temperatures[y][x];

                }

            }

        }
    }
    
    // Plot contour map of our Lake - 
    
    private void plotPartialContour() 
    {


        for (int y = 0; y <>

            for (int x = 0; x <>

              
                for (float j = 0; j <= 1.0f ; j+=scalef) {

                    for (float k = 0; k <= 1.0f; k+=scalef) {

     plotWaterTemp(x,y,k,j,wmintemp,wmaxtemp,1.0/scalef) ;
                    } // for k

                } // for j

            } // for x

        } // for y

    }
    
    // Plot water temperature at a particular point - anchored from point x,y 
    // j and k are values between 0 and 1 - which represent a pint
    
    void plotWaterTemp(int x,int y,
float j,float k,float wmintemp,float wmaxtemp,float rscalef) 
    {
      

                color c1 ;


     float iTemp = calcTemp(temperatures[y][x],

                                    temperatures[y][x + 1],

                                    temperatures[y + 1][x + 1],

                                    temperatures[y + 1][x], j, k);

              

                //floor 
                if (iTemp <>
                    iTemp = wmintemp ;
                } 
                
                
               
                int gs = (int)(255*(iTemp-wmintemp)/(wmaxtemp-wmintemp)) ;  // pick a grey level - 0 - 255
                
                if (gs > 200) 
                    gs = 255 ;
                    

                //c1 = interpColour(0,0,255,255,0,0,gs/255f) ;
 
                gs /= 32 ;
                
                //gs = 7 - gs ;
                
                c1 = color(colTabs[gs][0],colTabs[gs][1],colTabs[gs][2],255) ;
                  
                 
                fill(c1) ;
                noStroke();
rect((x + j)*rscalef, (y + k)*rscalef, 1, 1);

    }

  // This the main calculation which interperlates a temperature value 
  // over a 2D square. The four temperatures of each point of the square 
  // are given (t0,t1,t2,t3)  We pass these temperatures 
  // and the required point x,y which we need to
  // calculate the temperature from.
  // x and y are 'normalised' distances from t0 - ie. 0 <= x <= 1 , 0 <= y <= 1 
  // so -
  // calcTemp(t0,t1,t2,t3,0,0) -- returns t0
  // calcTemp(t0,t1,t2.t3,1,0) -- returns t1
  // calcTemp(t0,t1,t2.t3,1,1) -- returns t2
  // calcTemp(t0,t1,t2.t3,0,1) -- returns t3
  
  float calcTemp(float t0, float t1, float t2, float t3, float x, float y)
  {
    float xb = (1.0-x) ;
    float yb = (1.0-y) ;
    return (t0*xb*yb + t1*x*yb + t2*x*y + t3*xb*y) ;
  } 

    // Not used
    float interp(float startv,float endv,float t) {
      
        return (endv-startv)*t + startv ;
        
    }
    
     // Not used
     color interpColour(int startR,int startG,int startB,int endR,int endG,int endB, float frac) {
      
        return color((int)interp(startR,endR,frac),(int)interp(startG,endG,frac),(int)interp(startB,endB,frac)) ;
      
    }
    
  


Wednesday 15 October 2008

Contour Maps

Random Posts - Cute little function I worked out to plot cool looking contour maps -
Used for Bill Dance's Gone Fishin' Game -

You give four 2D spatial variables - eg. 4 Water temperature values measure over one square metre of a lake.
And then you can use the function to interpolate the temperature at a given point (x,y)
( 0 <= x <= 1) , ( 0 <= y <= 1)

// to-------t1 //
// |aaaaaaaaa| //
//|vvvvvvvvv | //
// t3-------t2 //


//distances are 1 UNIT apart t0,t1,t2,t3 are temperatures // x and y are distances (0-1) x +ve t0-->t1, y +ve t0-->t3
// returns an interpolated value for coordinate x,y
// Produces nice contour maps

float calcTemp(float t0, float t1, float t2, float t3, float x, float y)
{
float xb = (1.0-x) ;
float yb = (1.0-y) ;
return (t0*xb*yb + t1*x*yb + t2*x*y + t3*xb*y) ;
}

Welcome

Welcome!