Drawing 3d pies for statistical purposes

Hi,

could you please tell me how to draw 3d pies por statistical purposes. They should be displaced away from the common center.

Thanks a lot

Cuba Ramos

i would use quadrics like partial disks and cylinders,but if you want more control over your pies maybe write your own “quadrics” code.

i’d prefer the quadrics; less work

Triangle fans should work well; you can use loops between the glBegin and glEnd to vary colours or whatever based upon your statistical data. Then use another loop with a little trig and glQuads to build up the sides of the pie for depth. Use glTranslatef to put em where you want em.

Hello Sebastian and Glenn,
I am very grateful for your help.
I wrote some code but it is helpless slow (in W95 context). Would you eventually have an idea how to speed it up?. Thanks a lot.

Cuba Ramos

The code looks like this (entry point: DrawScene):

// DrawGraph.cpp : interface of the CDrawGraph class
//
/////////////////////////////////////////////////////////////////////////////

#include “stdafx.h”
#include “DrawGraph.h”
#include <math.h>
#include <GL/glut.h>

#define drawOneLine(x1,y1,x2,y2) glBegin(GL_LINES);
glVertex2f((x1),(y1)); glVertex2f((x2),(y2)); glEnd();

// GLuint startList;
// Start, Sweep
GLdouble gldAngles[][2] = {
{ -90.0f, 225.0f},
{ 130.0f, 90.0f},
{ 220.0f, 50.0f}
};
/*
// Start, Sweep
GLdouble gldAngles[][2] = {
{ -90.0f, 300.0f},
{ 130.0f, 90.0f},
{ 220.0f, 50.0f}
};
*/
// int iSeparationFactor = 10;
// GLdouble gldStartAngle, GLdouble gldSweepAngle;

void CDrawGraph::displayText10(int pictureNumber)
{
GLfloat white[3] = { 0.0, 0.0, 0.0 };
// GLfloat white[3] = { 1.0, 1.0, 1.0 };

// glClear(GL_COLOR_BUFFER_BIT);
// glColor3fv(white);

char buffer[100];
glColor3f(0.0, 0.0, 0.0);

if (iAngleGrads[pictureNumber][0] > 0)
{
glRasterPos2f(-1.5, 0.7);
printString(“above target”);

   glRasterPos2f(-1.5f, 0.5f);
   sprintf (buffer, "%3.2f %%", ((float)iAngleGrads[pictureNumber][0]/3.6));
   printString(buffer);

}

if (iAngleGrads[pictureNumber][1] > 0)
{
glRasterPos2f(0.0f, -0.7f);
printString(“inside target”);

   glRasterPos2f(0.0f, -0.9f);
   sprintf (buffer, "%3.2f %%", ((float)iAngleGrads[pictureNumber][1]/3.6));
   printString(buffer);

}

if (iAngleGrads[pictureNumber][2] > 0)
{
glRasterPos2f(0.75f, 0.7f);
printString(“below target”);

   glRasterPos2f(0.75f, 0.5f);
   sprintf (buffer, "%3.2f %%", ((float)iAngleGrads[pictureNumber][2]/3.6));
   printString(buffer);

}

// glFlush ();
}

void CDrawGraph::displayText12(int pictureNumber)
{
glColor3f(0.0, 0.0, 0.0);

char s[12];

// Legende
glRasterPos2f(-1.6f, 0.1f);
sprintf (s, “N = %2d”, iN[pictureNumber]);
printString(s);

glRasterPos2f(-1.6f, -0.2f);
sprintf (s, “Hypo: %1d”, iHypo[pictureNumber]);
printString(s);

glRasterPos2f(-1.6f, -0.5f);
sprintf (s, “Hi: %1d”, iHi[pictureNumber]);
printString(s);

glRasterPos2f(-1.6f, -0.8f);
sprintf (s, “Lo: %1d”, iLo[pictureNumber]);
printString(s);

// glFlush ();
}

void CDrawGraph::displayTitle12(int pictureNumber)
{
GLfloat white[3] = { 0.0, 0.0, 0.0 };
// GLfloat white[3] = { 1.0, 1.0, 1.0 };

// glClear(GL_COLOR_BUFFER_BIT);
// glColor3fv(white);

glColor3f(0.0, 0.0, 0.0);

// Title
glRasterPos2f(-0.7f, 0.9f);
switch( pictureNumber )
{
case 0:
printString(“Before breakfast”);
break;
case 1 :
printString(“Before lunch”);
break;
case 2 :
printString(“Before dinner”);
break;
case 3 :
printString(“After breakfast”);
break;
case 4 :
printString(“After lunch”);
break;
case 5 :
printString(“After dinner”);
break;
case 6 :
printString(“Bed”);
break;
case 7 :
printString(“Night”);
break;
case 8 :
printString(“Overall”);
break;
default:
break;
}

}

void CDrawGraph::getRasterFont(int nPoints, bool bBold)
{
// TEXTMETRIC tm;
// CFont testFont;
// char text[100];
CSize tExtent;
int nBold;

if (bBold==TRUE)
	nBold = 700;
else
	nBold = 400;

// testFont.CreateFont(-nPoints * 20, 0, 0, 0, 400, FALSE, FALSE, 0,
HFONT testFont = CreateFont(-nPoints, 0, 0, 0, nBold, FALSE, FALSE, 0,
ANSI_CHARSET, OUT_DEFAULT_PRECIS,
CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,
DEFAULT_PITCH | FF_SWISS, “Arial”);

HDC hdc =  wglGetCurrentDC();
SelectObject (hdc, testFont); 

// SelectObject (hdc, GetStockObject (SYSTEM_FONT));
wglUseFontBitmaps (hdc, 0, 255, 1000);
}

void CDrawGraph::initFont(int nPoints, bool bBold)
{
glShadeModel (GL_FLAT);
getRasterFont(nPoints, bBold);
}

void CDrawGraph: rintString(char *s)
{
glPushAttrib (GL_LIST_BIT);
glListBase(1000);
// glListBase(fontOffset);
glCallLists(strlen(s), GL_UNSIGNED_BYTE, (GLubyte *) s);
glPopAttrib ();
}

CDrawGraph::CDrawGraph()
{
// TODO: add construction code here

}

CDrawGraph::CDrawGraph(int iAngleGrads[9][3],
float fHeight,
float fRadiusFactor,
int iRelativeInitialAngleGrads,
float fDisplRadFact, // Displacement radius factor
int iN[9],
int iHypo[9],
int iHi[9],
int iLo[9]
)
{
int k;
int j;

for (k=0; k&lt;iGraphs; k++)
{
	for (j=0; j&lt;iPies; j++)
	{
		this-&gt;iAngleGrads[k][j] = iAngleGrads[k][j];
	}
}

this-&gt;fHeight = fHeight;
this-&gt;fRadiusFactor = fRadiusFactor;
this-&gt;iRelativeInitialAngleGrads = iRelativeInitialAngleGrads;
this-&gt;fDisplRadFact = fDisplRadFact;

for (k=0; k&lt;iGraphs; k++)
{
	this-&gt;iN[k] = iN[k];
	this-&gt;iHypo[k] = iHypo[k];
	this-&gt;iHi[k] = iHi[k];
	this-&gt;iLo[k] = iLo[k];
}

}

CDrawGraph::~CDrawGraph()
{
}

// SetDCPixelFormat sets the pixel format for a device context in
// preparation for creating a rendering context.

void CDrawGraph::SetDCPixelFormat(HDC hdc)
{

HANDLE       hHeap;
int          nColors, i;
LPLOGPALETTE lpPalette;
BYTE         byRedMask, byGreenMask, byBlueMask;

static PIXELFORMATDESCRIPTOR pfd = 
{
    sizeof(PIXELFORMATDESCRIPTOR),  // Size of this structure
    1,                              // Version number
    PFD_DRAW_TO_WINDOW |            // Flags
    PFD_SUPPORT_OPENGL |
    PFD_DOUBLEBUFFER,
    PFD_TYPE_RGBA,                  // Use RGBA pixel values
    24,                             // Try to use 24-bit color
    0, 0, 0, 0, 0, 0,               // Don't care about these
    0, 0,                           // No alpha buffer
    32, 0, 0, 0, 0,                 // 32-bit accumulation buffer
    32,                             // 32-bit depth buffer
    0,                              // No stencil buffer
    0,                              // No auxiliary buffers
    PFD_MAIN_PLANE,                 // Layer type
    0,                              // Reserved (must be 0)
    0, 0, 0                         // No layer masks
};

int nPixelFormat;

nPixelFormat = ChoosePixelFormat(hdc, &pfd);
SetPixelFormat(hdc, nPixelFormat, &pfd);


DescribePixelFormat(hdc, nPixelFormat, 
                    sizeof(PIXELFORMATDESCRIPTOR),
                    &pfd);

if(pfd.dwFlags & PFD_NEED_PALETTE) 
{
    nColors = 1 &lt;&lt; pfd.cColorBits;
    hHeap = GetProcessHeap();

    lpPalette = (LPLOGPALETTE) HeapAlloc(hHeap, 0,
                    sizeof(LOGPALETTE) + (nColors * 
                                 sizeof(PALETTEENTRY)));

    lpPalette-&gt;palVersion = 0x300;
    lpPalette-&gt;palNumEntries = nColors;

    byRedMask = (1 &lt;&lt; pfd.cRedBits) - 1;
    byGreenMask = (1 &lt;&lt; pfd.cGreenBits) - 1;
    byBlueMask = (1 &lt;&lt; pfd.cBlueBits) - 1;

    for(i = 0; i &lt; nColors; i++) 
    {
        lpPalette-&gt;palPalEntry[i].peRed =
            (((i &gt;&gt; pfd.cRedShift) & byRedMask) * 255) / 
                                                 byRedMask;
        lpPalette-&gt;palPalEntry[i].peGreen =
            (((i &gt;&gt; pfd.cGreenShift) & byGreenMask) * 255) /
                                                byGreenMask;
        lpPalette-&gt;palPalEntry[i].peBlue =
            (((i &gt;&gt; pfd.cBlueShift) & byBlueMask) * 255) / 
                                                 byBlueMask;
        lpPalette-&gt;palPalEntry[i].peFlags = 0;
    }

// Create the palette and free the allocated memory
m_hPalette = CreatePalette(lpPalette);
HeapFree(hHeap, 0, lpPalette);

// Realize the color palette
if(m_hPalette != NULL)
{
SelectPalette(hdc, m_hPalette, FALSE);
RealizePalette(hdc);
}
}
}

//---------------------------------------------------------------
// CDrawGraph:: D r a w S c e n e
//
// DrawScene uses OpenGL commands to draw a number of
// objects in a scene.

void CDrawGraph: rawScene()
{
// Define a few colors. In OpenGL, RGB values are specified as
// floating-point numbers between 0.0 and 1.0.

// Clear the color and depth buffers.
// glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

// Set up the viewpoint
// Note coordinate system is:
//
// y
//
// ^
// | z-axis points out
// |
// |
// z (.)-----------> x
//
//

int k;
int i;
int j;
i = 0;
j = 0;
for (k=0; k&lt;iGraphs; k++)
{
	if ((0==(k % iPies)) && (k &gt;= iPies))
	{
		i = 0;
		++j;
	}
	::glViewport((-cx/3) + ((i)*(cx/3)) + cx/90, (cy/3) - ((j)*(cy/3)), cx, cy);
	init (k);
	display (k);
	++i;
}

::glViewport(cx/6, -cy/6, cx, cy);
glColor3f(0.0, 0.0, 0.0);
drawOneLine (0.0f, 0.0f, 4.0f, 0.0f);
drawOneLine (0.0f, 0.0f, 0.0f, -4.0f);
glEnable (GL_LINE_STIPPLE);
glLineStipple (1, 0x0101);	/* dotted */
::glViewport(0, -cy/6, cx, cy);
drawOneLine (-6.5f, 0.0f, 10.0f, 0.0f);
::glViewport(cx/6, 0, cx, cy);
drawOneLine (0.0f, 10.0f, 0.0f, -10.0f);
::glViewport(-cx/6, 0, cx, cy);
drawOneLine (0.0f, 5.0f, 0.0f, -5.0f);
glDisable (GL_LINE_STIPPLE);

::glViewport(0, 0, cx, cy);

// Render the scene in the window’s DC
// SwapBuffers(wglGetCurrentDC());
}

/////////////////////////////////////////////////////////////////////////////
void CDrawGraph::SetDarkColor(int iPie)
{
GLfloat red_mat_ambient[] = { 0.5f, 0.0f, 0.0f, 1.0f };
GLfloat green_mat_ambient[] = { 0.0f, 0.5f, 0.0f, 1.0f };
GLfloat blue_mat_ambient[] = { 0.0f, 0.0f, 0.5f, 1.0f };

switch( iPie )
{
case 0:
glColor4fv(red_mat_ambient);
break;
case 1 :
glColor4fv(green_mat_ambient);
break;
case 2 :
glColor4fv(blue_mat_ambient);
break;
default:
break;
}

}

/////////////////////////////////////////////////////////////////////////////
void CDrawGraph::SetColor(int iPie)
{
GLfloat red_mat_ambient[] = { 1.0, 0.0, 0.0, 1.0 };
GLfloat green_mat_ambient[] = { 0.0, 1.0, 0.0, 1.0 };
GLfloat blue_mat_ambient[] = { 0.0, 0.0, 1.0, 1.0 };

switch( iPie )
{
case 0:
glColor4fv(red_mat_ambient);
break;
case 1 :
glColor4fv(green_mat_ambient);
break;
case 2 :
glColor4fv(blue_mat_ambient);
break;
default:
break;
}

}

/* Everything above this line could be in a library

  • that defines a font. To make it work, you’ve got

  • to call makeRasterFont() before you start making

  • calls to printString().
    */
    /////////////////////////////////////////////////////////////////////////////
    void CDrawGraph::init(int kGraph)
    {
    float fDisplAngRadians; // Displacement angle grads
    float fAngleRadians;
    float fSweepAngleRadians;
    int iInitialAngleGrads;
    int i;
    int j;
    int k;

    k = kGraph;

    glClearColor(1.0, 1.0, 1.0, 0.0);

    iInitialAngleGrads = 0;

    glEnable(GL_DEPTH_TEST);

    startList = glGenLists(iPies);

// draw 3 pies
for (j=0; j<iPies; j++)
{
glNewList(startList+j, GL_COMPILE);
// glNewList(startList+j+k, GL_COMPILE);

	SetColor(j); 
	if ((k==2) && (j==1) && (iAngleGrads[k][j]==360))
		glColor4f(0.8, 0.8, 0.8, 1.0);

	switch( j ) 
	{
		case 0:
			iInitialAngleGrads = iRelativeInitialAngleGrads;
			break;
		case 1 :
			iInitialAngleGrads = iInitialAngleGrads + iAngleGrads[k][j-1];
			break;
		case 2 :
			iInitialAngleGrads = iInitialAngleGrads + iAngleGrads[k][j-1];
			break;
		default:
			break;
	}

// We calculate here the displacement of the center
fDisplAngRadians =
((float)iInitialAngleGrads +
(float)(iAngleGrads[k][j]) / 2.0) * (PI/180.0);

// glPolygonMode(GL_FRONT, GL_LINE);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);

	glLineWidth(1.0f);

// glPolygonMode(GL_FRONT, GL_LINE);

// Surfaces

// triangle fan

	glBegin(GL_TRIANGLE_FAN);
	glVertex3f (fDisplRadFact*cos(fDisplAngRadians),
		fDisplRadFact*sin(fDisplAngRadians), 0.0);
	for (i=0; i&lt;=(2*iAngleGrads[k][j]); i++)
	{
	  fAngleRadians = (((float)(iInitialAngleGrads*PI) + ((float)(i/2.0)*PI)))/180.0;
	  glVertex3f(
		  fRadiusFactor * cos(fAngleRadians)+fDisplRadFact*cos(fDisplAngRadians), 
		  fRadiusFactor * sin(fAngleRadians)+fDisplRadFact*sin(fDisplAngRadians), 
		  0);
	}
	glEnd();

	glBegin(GL_TRIANGLE_FAN);
	glVertex3f (fDisplRadFact*cos(fDisplAngRadians),
		fDisplRadFact*sin(fDisplAngRadians), fHeight);
	for (i=0; i&lt;=(2*iAngleGrads[k][j]); i++)
	{
	  fAngleRadians = (((float)(iInitialAngleGrads*PI) + ((float)(i/2.0)*PI)))/180.0;
	  glVertex3f(
		  fRadiusFactor * cos(fAngleRadians)+fDisplRadFact*cos(fDisplAngRadians), 
		  fRadiusFactor * sin(fAngleRadians)+fDisplRadFact*sin(fDisplAngRadians), 
		  fHeight);
	}
	glEnd();

	SetDarkColor(j); 
	if ((k==2) && (j==1) && (iAngleGrads[k][j]==360))
		glColor4f(0.5, 0.5, 0.5, 1.0);

	glBegin(GL_QUAD_STRIP);
	for (i=0; i&lt;=(2*iAngleGrads[k][j]); i++)
	{
	  fAngleRadians = (((float)(iInitialAngleGrads*PI) + ((float)(i/2.0)*PI)))/180.0;
	  glVertex3f(
		  fRadiusFactor * cos(fAngleRadians)+fDisplRadFact*cos(fDisplAngRadians), 
		  fRadiusFactor * sin(fAngleRadians)+fDisplRadFact*sin(fDisplAngRadians), 
		  0);
	  glVertex3f(
		  fRadiusFactor * cos(fAngleRadians)+fDisplRadFact*cos(fDisplAngRadians), 
		  fRadiusFactor * sin(fAngleRadians)+fDisplRadFact*sin(fDisplAngRadians), 
		  fHeight);
	}
	glEnd();

	fSweepAngleRadians = fAngleRadians;

	fAngleRadians = ((iInitialAngleGrads) * PI) / 180.0;

	glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);

	glBegin(GL_QUADS);
	glVertex3f (fDisplRadFact*cos(fDisplAngRadians),
		fDisplRadFact*sin(fDisplAngRadians), 0.0);
	glVertex3f(
		fRadiusFactor * cos(fAngleRadians)+fDisplRadFact*cos(fDisplAngRadians), 
		fRadiusFactor * sin(fAngleRadians)+fDisplRadFact*sin(fDisplAngRadians), 
		0);
	glVertex3f(
		fRadiusFactor * cos(fAngleRadians)+fDisplRadFact*cos(fDisplAngRadians), 
		fRadiusFactor * sin(fAngleRadians)+fDisplRadFact*sin(fDisplAngRadians), 
		fHeight);
	glVertex3f (fDisplRadFact*cos(fDisplAngRadians),
		fDisplRadFact*sin(fDisplAngRadians), fHeight);
	glEnd();

	glBegin(GL_QUADS);
	glVertex3f (fDisplRadFact*cos(fDisplAngRadians),
		fDisplRadFact*sin(fDisplAngRadians), 0.0);
	glVertex3f(
		fRadiusFactor * cos(fSweepAngleRadians)+fDisplRadFact*cos(fDisplAngRadians), 
		fRadiusFactor * sin(fSweepAngleRadians)+fDisplRadFact*sin(fDisplAngRadians), 
		0);
	glVertex3f(
		fRadiusFactor * cos(fSweepAngleRadians)+fDisplRadFact*cos(fDisplAngRadians), 
		fRadiusFactor * sin(fSweepAngleRadians)+fDisplRadFact*sin(fDisplAngRadians), 
		fHeight);
	glVertex3f (fDisplRadFact*cos(fDisplAngRadians),
		fDisplRadFact*sin(fDisplAngRadians), fHeight);
	glEnd();

	// Legende

/*
glClear(GL_COLOR_BUFFER_BIT);
glColor4f(1.0, 0.0, 0.0, 1.0);
glRasterPos2i(20, 60);
printString(“Hello”);
*/
glEndList();

}

}

void CDrawGraph::display(int kGraph)
{

int j;
int k;
float x;
float y;
float z;

k = kGraph;

x = (k + 1) * 2.55f;
y = (k + 1) * 1.4f;
z = (k + 1) * 0.0f;

// glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_LINE_SMOOTH);
glPushMatrix();
for (j=0; j<iPies; j++)
{
glPushMatrix();
if (k==0)
{
// glTranslatef(-x, y, z);
}
initFont(12, TRUE);
displayTitle12(k);
initFont(12, FALSE);
displayText12(k);
initFont(10, FALSE);
displayText10(k);
glPolygonMode(GL_FRONT, GL_LINE);
glColor3f(0.0, 0.0, 0.0);
// glLineWidth(0.0f);
glRectf (-1.7f, -0.9f, -0.9f, 0.38f);
glPushMatrix();
glRotatef(-45.0f, 1.0f, 0.0f, 0.0f);
glCallList(startList+j);
// glCallList(startList+j+k);
glPopMatrix();
glPopMatrix();

	glDeleteLists(startList+j, 1);
}
glPopMatrix();

/*
glPushMatrix();

// glTranslatef(-x, y, z);
initFont(12);
displayText12(1);
initFont(10);
displayText10(1);

glPolygonMode(GL_FRONT, GL_LINE);
glColor3f(0.0, 0.0, 0.0);

// glLineWidth(0.0f);
glRectf (-3.0f, -1.5f, -1.4f, 0.0);
glPopMatrix();
*/
glFlush();

}