CS 553 -- Winter Quarter 2009

Project #2: Simple Grayscale Point Cloud

40 Points

Due: January 12



This page was last updated: January 5, 2009


The Scenario

You have run a temperature simulation of a 3D room that has 4 heat sources. You are given the temperature data from the simulation at each node in a 3D grid. You will be creating several visualizations (in Projects 2, 3, 4, and 5) to understand the distribution of temperatures within the 3D room.

Requirements:

  1. Put this project number and your name in the title bar.

  2. The coordinate range of the data volume is: -1.0 ≤ x,y,z ≤ 1.0

    The number of node points you place within this region will be up to you.

  3. For the temperature range of the data, use: 0.0 ≤ t ≤ 100.0

    The temperatures defined by the equation actually go higher than 100 degrees in places, but don't worry about it. After computing t, just clamp it to 100.:

    const float TEMPMIN = {   0.f };
    const float TEMPMAX = { 100.f };
    . . .
    if( t > TEMPMAX )
    	t = TEMPMAX;
    

  4. Display the temperature data as a point cloud. The number of data points to use is up to you:
    #define NX	???
    #define NY	???
    #define NZ	???
    

  5. Color the dot using grayscale -- a low intensity for a low temperature and a high intensity for a high temperature. Don't go all the way to black -- you won't be able to see your lowest temperature points.

    const float GRAYMIN = { 0.20f };
    const float GRAYMAX = { 1.00f };
    . . .
    if( t > TEMPMAX )
    	t = TEMPMAX;
    float gray = GRAYMIN + ( GRAYMAX - GRAYMIN ) * ( t - TEMPMIN ) / ( TEMPMAX - TEMPMIN );
    glColor3f( gray, gray, gray );		// r = g = b gives gray
    

Getting the Temperature Data

I am going to let you "cheat" on the scalar data. Instead of reading it from a file as would normally be done, compute a scalar temperature value at each node point in each plane according to the following formula:

where:
where:

i Xi Yi Zi Ai
01.000.000.0090.00
1-1.000.300.00120.00
20.001.000.00120.00
30.000.401.00170.00

Setting up the Data in your Program

If you are comfortable with structures, a 3D array of structures is a good way to store and access the data for this project:

struct node
{
        float x, y, z;          // location
        float t;                // temperature
	float rgb[3];		// the assigned color (to be used later)
        float rad;              // radius (to be used later)
        float grad;             // total gradient (to be used later)
};

struct node  Nodes[NX][NY][NZ];

If you are not comfortable with C structures, a 3D array for X, a 3D array for Y, etc. will work too.

InitGraphics() is a good place to set all these values. Fill the (x,y,z) components of each structure in the 3D array, and use those (x,y,z) to compute a temperature.

Code to Compute the Scalar Value

struct centers
{
        float xc, yc, zc;       // center location
        float a;                // amplitude
} Centers[] =
{
	{	 1.00f,	 0.00f,	 0.00f,	 90.00f	},
	{	-1.00f,	 0.30f,	 0.00f,	120.00f	},
	{	 0.00f,	 1.00f,	 0.00f,	120.00f	},
	{	 0.00f,	 0.40f,	 1.00f,	170.00f	},
};

float
Temperature( float x, float y, float z )
{
        float t = 0.0;

        for( int i = 0; i < 4; i++ )
        {
                float dx = x - Centers[i].xc;
                float dy = y - Centers[i].yc;
                float dz = z - Centers[i].zc;
                float rsqd = SQR(dx) + SQR(dy) + SQR(dz);
                t += Centers[i].a * exp( -5.*rsqd );
        }

	if( t > TEMPMAX )
		t = TEMPMAX;

        return t;
}

What is that SQR function?

Since there is no raise-to-a-power operator in C, and because the pow( ) function uses time-consuming logs and exponentials, the most efficient way to square something is to multiply it by itself. This can be messy-looking if the something is an expression. A way to clean this up and make the intent more obvious is to create a square-the-number function.

In C++, this is done quite nicely by putting these lines near the top of your program:

inline float SQR( float x )
{
	return x * x;
}

In C (and C++), it can be done like this:

#define SQR(x)		( (x) * (x) )

although there is some danger in doing it this way. Since we are using C++ anyway, I would recommend that you do it the first way.

In Subroutine InitLists():

PointList = glGenLists( 1 );
glNewList( PointList, GL_COMPILE );
	glPointSize( ?? );	// hardwire this, or set it with a spinner
	glBegin( GL_POINTS );
	for( int i = 0; i < NX; i++ )
	{
		float x = -1.  +  2. * (float)i / (float)(NX-1);
  		for( int j = 0; j < NY; j++ )
  		{
			float y = ???
    			for( int k = 0; k < NZ; k++ )
    			{
				float z = ???
				?????
				glColor3f( ??? );
				glVertex3f( ??? );
    			}
  		}
	}
	glEnd();
glEndList( );

In Subroutine Display():

. . .
glCallList( PointList );
. . .

Grading:

Item Points
Correct points display 20
Correct grayscale distribution 20
Potential Total 40