Saturday, 18 October 2008

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)) ;
      
    }
    
  


No comments: