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!