Page 1 of 1

## C++ Windows Charting Library Part 4 Rate Topic: //<![CDATA[ rating = new ipb.rating( 'topic_rate_', { url: 'http://www.dreamincode.net/forums/index.php?app=forums&module=ajax&section=topics&do=rateTopic&t=306307&amp;s=8dde640c7a0445753e6929ba9af31274&md5check=' + ipb.vars['secure_hash'], cur_rating: 0, rated: 0, allow_rate: 0, multi_rate: 1, show_rate_text: true } ); //]]>

### #1 snoopy11

• Engineering ● Software

Reputation: 1021
• Posts: 3,094
• Joined: 20-March 10

Posted 09 January 2013 - 07:23 AM

C++ Windows Charting Library Part 4

In this Part 4 I will be discussing how to make a 3D Pie Chart but before I start I would like to go over the normal 2D Pie Chart again as I wasn't that happy with the filling routine for the Pie.

I have redesigned the filling routine to a more logical approach and I am now happier with how the pie in 2D and 3D is being filled.

I will post the entire code again and go over the changes to chartObject::DrawPie then I will discuss the new class chart3D and the new drawing routine chart3D::DrawPie3D

ChartKM.h

```//ChartKM.h
#ifndef CHARTKM_H_INCLUDED
#define CHARTKM_H_INCLUDED
#include <vector>
#include <cstring>
#include <Windows.h>

#ifndef MSVC
#define CLEARTYPE_QUALITY       5
#define CLEARTYPE_NATURAL_QUALITY       6
#endif

using namespace std;

class chartObject
{
protected:

int Total;
float Units;
float Degrees;
vector<float> Percentage;
float a;
float x2;
float y2;
float ValueItem;
unsigned FreqBar;
float LargestBar;
int szNames;
int szInfo;
int szGroup;
string xName;
string yName;
BOOL vLegend;
string Title;
vector<string> Names;
vector <float> Info;
vector <float> Frequency;
vector <float> b;
vector <COLORREF> colors;
vector <string> GroupName;
vector <string> ItemName;
vector <float>  ItemValue;
vector <float>  LineValueX;
vector <float>  LineValueY;
float  LineRangeX;
float  LineRangeY;
vector <int> ItemGroup;

public:

//constructor
chartObject();

//destructor
~chartObject();

//Draws Pie Chart
void DrawPie(HDC hdcDst,int x,int y, int szPieX, int szPieY, COLORREF bkcolor);
//Draws Bar Chart
void DrawBar(HDC hdcDst,int x, int y, int szBarX, int szBarY, COLORREF bkcolor);
//Draws Line Chart
void DrawLine(HDC hdcDst,int x, int y, int szBarX, int szBarY, COLORREF bkcolor);
void AddData(string Labels, float Data, COLORREF color);
//Adds Group Data for Bar and Line Charts
// Adds Item Data for Bar Charts
void AddItemData(string nmItem, float value, int GroupNo);
// Adds Item Data for Line Charts
void AddLineData(string nmItem, float valueX, float valueY);
// Adds Group and Range Data for Line Charts
void AddRangeData(float RangeX, float RangeY, int GroupNo);
// Gets the Totals for Pie Charts
int GetTotal();
// Gets the frequency for Pie Charts
void GetFrequency();
// Adds a Title to Chart;
// Adds a Legend to a Pie Chart
void Legend(BOOL szLegend);
// Add Titles for x and y axis
void SetAxisTitles(string szAxisX, string szAxisY);
// Get Total for Bars
void GetTotalBar();
// Get Amount of Groups for Bars
void GetGroupBar();
// Get Largest Amount Of Item Data for Bars
void GetLargestBar();

};

class chart3D:public chartObject {

public:

void DrawPie3D(HDC hdcDst,int x,int y, int szPieX, int szPieY, COLORREF bkcolor);
};

#endif

```

ChartKM.cpp

```#include <Windows.h>
#include <cmath>
#include <iomanip>
#include <sstream>
#ifdef MSVC
#pragma comment(lib, "libGdi32.a")// link to gdi functions
#endif
#define round(a)(int(a+0.5))
//we need this for windows stuff.

#include "ChartKM.h"

chartObject::chartObject()
{

szNames =0;
szInfo = 0;
Total =0;
Degrees = 0;
Title = "";
a = 0;
x2 = 0;
y2 = 0;
szNames = 0;
szInfo = 0;
vLegend = TRUE;
ValueItem = 0;
Units = 0.0f;
ItemValue.clear();
ItemName.clear();
GroupName.clear();
}

chartObject::~chartObject()
{

}

void chartObject::DrawPie(HDC hdcDst,int x, int y,int szPieX, int szPieY,COLORREF bkcolor)
{

float xr = 0.0f;
float yr = 0.0f;
float Degrees2 =0.0f;

HPEN pen = CreatePen(PS_SOLID,1,bkcolor);
HFONT font;
font = CreateFont(14,0,0,0,FW_DONTCARE,FALSE,FALSE,FALSE,DEFAULT_CHARSET,OUT_OUTLINE_PRECIS,
CLIP_DEFAULT_PRECIS,CLEARTYPE_QUALITY, VARIABLE_PITCH,TEXT("Arial Bold"));
SelectObject(hdcDst, font);
SelectObject(hdcDst,pen);
//Draw Circle
Arc(hdcDst, x,y,szPieX+x,szPieY+y,x,y,x,y);
//Draw First Line
MoveToEx(hdcDst,(szPieX/2)+x,(szPieY/2)+y,NULL);
LineTo(hdcDst,szPieX+x,(szPieY/2)+y);
//Set Background Color for Text
SetBkColor(hdcDst,GetPixel(hdcDst,0,0));
//Gets Totals for Pie Chart
Total = GetTotal();
GetFrequency();

//Draw Lines of arc

//float y1= 0.0f;
//Draw segments
for(int j = 0; j<szInfo; j++)
{

HBRUSH hbr = CreateSolidBrush(colors[j]);
SelectObject(hdcDst,hbr);

MoveToEx(hdcDst,(szPieX/2)+x,(szPieY/2)+y,NULL);
Percentage.push_back( Frequency[j]*100 );

a = Frequency[j]*360;
if(j==0)
b.push_back(a);
else
b.push_back(b[j-1]+a);
Degrees= (float)(3.14*b[j])/180;
LineTo(hdcDst,round(x2),round(y2));

//Fill Segments
//Fill Pie
if(j==0)
{
Degrees2 = (float)(3.14*(a/2))/180;

}
else
{
Degrees2= (float)(3.14*(b[j-1]+(a/2)))/180;
}

SelectObject(hdcDst,hbr);
FloodFill(hdcDst,(int)round(xr),(int)round(yr),bkcolor);
}

if(Title !="")
{
TextOut(hdcDst,(x+szPieX/2)-(Title.length()*2)-Title.size(),y-24,Title.c_str(),Title.size());
}

if(vLegend)
{
//Draw Legend
TextOut(hdcDst,x+szPieX+15,y,"Legend",6);
string buffer;
stringstream sbuf;
char buf[20];
float d = 0.0f;
for(int i = 0; i<szNames; i++)
{
buffer = "";
sbuf.clear();

d = Info[i];
// write strings
buffer.append(Names[i]);
buffer.append(" ");
sbuf << d;
sbuf >> buf;
buffer.append(buf);
TextOut(hdcDst,x+szPieX+40,y+(25*(i+1)),buffer.c_str(),buffer.size());
//Draw Colored Boxes
Rectangle(hdcDst,x+szPieX+15,y+(25*(i+1)),x+szPieX+28,y+(25*(i+1)+12));
RECT rc;
rc.left= x+szPieX+16;
rc.top = y+(25*(i+1))+1;
rc.right = x+szPieX+28-1;
rc.bottom = y+(25*(i+1)+12)-1;
HBRUSH hbr = CreateSolidBrush(colors[i]);

FillRect(hdcDst,&rc,hbr);
}
}

DeleteObject(pen);
DeleteObject(font);

}

void chartObject::AddData(string Labels, float Data, COLORREF color)
{

Names.push_back(Labels);
szNames = Names.size();
Info.push_back(Data);
szInfo = Info.size();
colors.push_back(color);

}

int chartObject::GetTotal()
{
float Totals=0.0f;

for(int i = 0; i<szInfo; i++)
{

Totals =Totals + Info[i];
}

return (int) (Totals+0.5);
}

void chartObject::GetFrequency()
{
float result;

for(int i = 0; i<szInfo; i++)
{
result = Info[i]/Total;
Frequency.push_back(result) ;
}

return;
}

{
Title.assign(szTitle);
}

void chartObject::Legend(BOOL szLegend)
{
vLegend = szLegend;
}

{
GroupName.push_back(nmGroup);
colors.push_back(color);
}

void chartObject::AddItemData(string nmItem, float value, int GroupNo)
{
ItemName.push_back(nmItem);
ItemValue.push_back(value);
ItemGroup.push_back(GroupNo);
}
void chartObject::SetAxisTitles(string szAxisX, string szAxisY)
{
xName.assign(szAxisX);
yName.assign(szAxisY);

}

void chartObject::GetTotalBar()
{
for(unsigned i = 0; i<ItemValue.size(); i++)
{
ValueItem = ValueItem+ItemValue[i];
}

ValueItem = ValueItem / (ItemValue.size()+1);
}

void chartObject::GetGroupBar()
{
FreqBar = GroupName.size();

}

void chartObject::GetLargestBar()
{
LargestBar  = ItemValue[0];
for(unsigned i =1; i<ItemValue.size(); i++)
{
if(LargestBar<ItemValue[i])
{
LargestBar = ItemValue[i];
}
}

}

void chartObject::DrawBar(HDC hdcDst,int x, int y, int szBarX, int szBarY, COLORREF bkcolor)
{
HPEN pen = CreatePen(PS_SOLID,1,bkcolor);
SelectObject(hdcDst,pen);
HFONT font;
//Set Background Color for Text
SetBkColor(hdcDst,GetPixel(hdcDst,0,0));
font = CreateFont(14,0,900,900,FW_DONTCARE,FALSE,FALSE,FALSE,DEFAULT_CHARSET,OUT_OUTLINE_PRECIS,
CLIP_DEFAULT_PRECIS,CLEARTYPE_QUALITY, VARIABLE_PITCH,TEXT("Arial Bold"));
SelectObject(hdcDst, font);
//Draw y axis
MoveToEx(hdcDst,x+25+14,(szBarY)+y,NULL);
LineTo(hdcDst,x+25+14,y);
//Draw x axis
MoveToEx(hdcDst,x+25+14,(szBarY)+y,NULL);
LineTo(hdcDst,szBarX+x+25+14,(szBarY)+y);

TextOut(hdcDst,x,((szBarY+y/2)+(yName.length()/2)),yName.c_str(),yName.length());// Draw y-axis label
font = CreateFont(14,0,0,0,FW_DONTCARE,FALSE,FALSE,FALSE,DEFAULT_CHARSET,OUT_OUTLINE_PRECIS,
CLIP_DEFAULT_PRECIS,CLEARTYPE_QUALITY, VARIABLE_PITCH,TEXT("Arial Bold"));
SelectObject(hdcDst, font);
TextOut(hdcDst,((szBarX-x)/2)-(xName.length()/2),y+szBarY+42,xName.c_str(),xName.length());//Draw x-axis label
TextOut(hdcDst,x+(25),y+szBarY,"0",1);// Draw a zero at origin

TextOut(hdcDst,((szBarX-x)/2)-(Title.length()/2),y-24,Title.c_str(),Title.length());//Draw Title

//Get Totals for Bar Chart
GetTotalBar();
GetGroupBar();
GetLargestBar();

//Draw Graph
Units = LargestBar/3.0f;
int graph = szBarY/3;
for(int i = 0; i<3; i++)
{
MoveToEx(hdcDst,x+25+14,(graph*i)+y,NULL);
LineTo(hdcDst,x+25+14+szBarX+5,(graph*i)+y);
stringstream  number;
number << setprecision(3);
number << (LargestBar-(Units*i));
string num = "";
number >> num;
TextOut(hdcDst,x+25+14+szBarX+7,(graph*i)+y,num.c_str(),num.length());//draw numbers

}
for(unsigned i= 0; i<GroupName.size(); i++)
{
//draw Legend
Rectangle(hdcDst,(x+50-12-1),y+szBarY+42+(25*(i+1)-1),(x+50-12-1+12),y+szBarY+42+(25*(i+1)+12));
RECT rc;
rc.left= (x+50-12);
rc.top = y+szBarY+42+(25*(i+1));
rc.right = (x+50)-2;
rc.bottom = y+szBarY+42+(25*(i+1)+12)-1;
HBRUSH hbr = CreateSolidBrush(colors[i]);

FillRect(hdcDst,&rc,hbr);
TextOut(hdcDst,(x)+(GroupName[i].length()+50),y+szBarY+42+(25*(i+1)),GroupName[i].c_str(),GroupName[i].length());//Drawlabels

}
MoveToEx(hdcDst,x+25+14+szBarX,(y+szBarY),NULL);
LineTo(hdcDst,x+25+14+szBarX,(y+szBarY+15));
MoveToEx(hdcDst,x+25+14+szBarX,y,NULL);
LineTo(hdcDst,x+25+14+szBarX,y+szBarY);
int amt = (ItemValue.size())/(GroupName.size());
int sections = (szBarX)/amt;
int counter = 0;
int count = 0;
// Draw Bar Data
for(unsigned i =0; i<(ItemValue.size()); i=i+GroupName.size())
{
counter = (i/GroupName.size())* sections;
MoveToEx(hdcDst,x+25+14+counter,(y+szBarY),NULL);
LineTo(hdcDst,x+25+14+counter,(y+szBarY+15));
TextOut(hdcDst,(x+25+14+counter)+(ItemName[i].length()),(y+szBarY+15),ItemName[i].c_str(),ItemName[i].length());

for(unsigned j = 0; j<(GroupName.size()); j++)
{
RECT rect;
float result = szBarY-(szBarY*(ItemValue[count]/LargestBar))+y;
rect.bottom = y+szBarY;
rect.right =  x+25+14+counter+5+((szBarX/20)*(j+1));
rect.top =  (LONG)(result);
rect.left = (x+25+14+counter+5+((szBarX/20)*j));

HBRUSH hbr = CreateSolidBrush(colors[j]);
FillRect(hdcDst,&rect,hbr);
count++;

}
}
DeleteObject(pen);
DeleteObject(font);
}

void chartObject::AddLineData(string nmItem, float valueX, float valueY)
{
ItemName.push_back(nmItem);
LineValueX.push_back(valueX);
LineValueY.push_back(valueY);
}

void chartObject::AddRangeData(float RangeX, float RangeY, int GroupNo)
{
LineRangeX = RangeX;
LineRangeY = RangeY;
ItemGroup.push_back(GroupNo);

}

void chartObject::DrawLine(HDC hdcDst,int x, int y, int szBarX, int szBarY, COLORREF bkcolor)
{
HPEN pen = CreatePen(PS_SOLID,1,bkcolor);
SelectObject(hdcDst,pen);
HFONT font;
//Set Background Color for Text
SetBkColor(hdcDst,GetPixel(hdcDst,0,0));
font = CreateFont(14,0,900,900,FW_DONTCARE,FALSE,FALSE,FALSE,DEFAULT_CHARSET,OUT_OUTLINE_PRECIS,
CLIP_DEFAULT_PRECIS,CLEARTYPE_QUALITY, VARIABLE_PITCH,TEXT("Arial Bold"));
SelectObject(hdcDst, font);
//Draw y axis
MoveToEx(hdcDst,x+50+14,(szBarY)+y,NULL);
LineTo(hdcDst,x+50+14,y);
//Draw x axis
MoveToEx(hdcDst,x+50+14,(szBarY)+y,NULL);
LineTo(hdcDst,szBarX+x+50+14,(szBarY)+y);
TextOut(hdcDst,x,((szBarY+y/2)+(yName.length()/2)),yName.c_str(),yName.length());// Draw y-axis label
// change font
font = CreateFont(14,0,0,0,FW_DONTCARE,FALSE,FALSE,FALSE,DEFAULT_CHARSET,OUT_OUTLINE_PRECIS,
CLIP_DEFAULT_PRECIS,CLEARTYPE_QUALITY, VARIABLE_PITCH,TEXT("Arial Bold"));
SelectObject(hdcDst, font);
TextOut(hdcDst,((szBarX+x+50)/2)-(xName.length()/2)+50,y+szBarY+42,xName.c_str(),xName.length());//Draw x-axis label
TextOut(hdcDst,x+(50),y+szBarY,"0",1);// Draw a zero at origin
//Draw Range at top of graph y axis
stringstream ss;
ss << LineRangeY;
string number;
ss >> number;
TextOut(hdcDst,x+50-(number.length()*4),y-4,number.c_str(),number.length());
//Draw Range at top of graph x axis
ss.clear();
ss << LineRangeX;
ss >> number;
TextOut(hdcDst,x+szBarX+50+14-(number.length()*4),y+szBarY+4,number.c_str(),number.length());

TextOut(hdcDst,((szBarX+x+50+14)/2)-((Title.length()*4)/2),y-24,Title.c_str(),Title.length());//Draw Title
// Draw Halfway segment points
MoveToEx(hdcDst, ((szBarX/2)+x+50+14), y+szBarY,NULL);
LineTo(hdcDst, ((szBarX/2)+x+50+14), y+szBarY+4);
ss.clear();
ss << (LineRangeX/2);
ss >> number;
TextOut(hdcDst,(szBarX/2)+50+14+x-((number.length()*4)/2),y+szBarY+6,number.c_str(),number.length());
MoveToEx(hdcDst,x+50+14,y+(szBarY/2),NULL);
LineTo(hdcDst, (x+50+14)-4,y+(szBarY/2));
ss.clear();
ss << (LineRangeY/2);
ss >> number;
TextOut(hdcDst,50+x-((number.length()*4)),y+(szBarY/2),number.c_str(),number.length());
string container;
HPEN pen2;
int x1=x+50+14;
int y1=y+szBarY;
//Start Drawing Data inside loops
for(unsigned k = 0; k < GroupName.size(); k++)
{
container.clear();
container = GroupName[k];
x1=x+50+14;
y1=y+szBarY;
MoveToEx(hdcDst,x1,y1,NULL);
for(unsigned j=0; j<GroupName.size(); j++)
{
if(GroupName[j] == container)
{
pen2 = CreatePen(PS_SOLID,1,colors[j]);
SelectObject(hdcDst, pen2);
}
}

for(unsigned i=0; i<LineValueX.size(); i++)
{
if(ItemName[i] == container)
{
x1=  (int)(x+50+14+((LineValueX[i]/LineRangeX)*szBarX));
y1 = (int)(y +szBarY-((LineValueY[i]/LineRangeY)*szBarY));
LineTo(hdcDst,x1,y1);
}
MoveToEx(hdcDst,x1,y1,NULL);
}//End loop i
}//End loop k

HBRUSH hbr = NULL;
//Draw Legend
if(vLegend)
{
//Draw Legend
TextOut(hdcDst,x+szBarX+15+50,y,"Legend",6);
string buffer;

//float d = 0.0f;
for(unsigned i = 0; i<GroupName.size(); i++)
{
buffer = "";

// write strings
buffer.append(GroupName[i]);
TextOut(hdcDst,x+szBarX+70+15,y+(25*(i+1)),buffer.c_str(),buffer.size());
//Draw Colored Boxes
Rectangle(hdcDst,x+szBarX+15+50,y+(25*(i+1)),x+szBarX+28+50,y+(25*(i+1)+12));
RECT rc;
rc.left= x+szBarX+16+50;
rc.top = y+(25*(i+1))+1;
rc.right = x+szBarX+28-1+50;
rc.bottom = y+(25*(i+1)+12)-1;
hbr = CreateSolidBrush(colors[i]);

FillRect(hdcDst,&rc,hbr);
}
}

SelectObject(hdcDst,pen);
DeleteObject(pen);
DeleteObject(pen2);
DeleteObject(font);
DeleteObject(hbr);
}

void chart3D::DrawPie3D(HDC hdcDst,int x,int y, int szPieX, int szPieY, COLORREF bkcolor)
{

HPEN pen = CreatePen(PS_SOLID,1,bkcolor);
HFONT font;
font = CreateFont(14,0,0,0,FW_DONTCARE,FALSE,FALSE,FALSE,DEFAULT_CHARSET,OUT_OUTLINE_PRECIS,
CLIP_DEFAULT_PRECIS,CLEARTYPE_QUALITY, VARIABLE_PITCH,TEXT("Arial Bold"));
SelectObject(hdcDst, font);
SelectObject(hdcDst,pen);
//Draw Circle
Arc(hdcDst, x,y,szPieX+x,szPieY+y,x,y,x,y);
//Draw First Line
MoveToEx(hdcDst,(szPieX/2)+x,(szPieY/2)+y,NULL);
LineTo(hdcDst,szPieX+x,(szPieY/2)+y);
//Set Background Color for Text
SetBkColor(hdcDst,GetPixel(hdcDst,0,0));
//Gets Totals for Pie Chart
Total = GetTotal();
GetFrequency();

//Draw Lines of arc

Arc(hdcDst,x,y,x+szPieX,(int)(y+(szPieY+16)),x,y+(szPieY/2),x+szPieX,y+(szPieY/2));

float xr = 0.0f;
float yr = 0.0f;
float Degrees2 =0.0f;
//Draw segments
for(int j = 0; j<szInfo; j++)
{
COLORREF clr = colors[j];
BYTE R = GetRValue(colors[j]);
BYTE G = GetGValue(colors[j]);
BYTE B = GetBValue(colors[j]);
int Flag =0;
// Get a darker shade of the primary color for the rink
if(R>=G&&R>=B)/>
{
R=R-40;
clr = RGB(R,G,B)/>;
Flag =1;
}
if(G>=R&&G>=B&&Flag==0)
{
G=G-40;
clr = RGB(R,G,B)/>;
Flag=1;
}
if(B>=G&&B>=R&&Flag==0)
{
B=B-40;
clr = RGB(R,G,B)/>;
Flag=1;
}
HBRUSH hbr = CreateSolidBrush(colors[j]);
HBRUSH hbr2 = CreateSolidBrush(clr);
SelectObject(hdcDst,hbr);

MoveToEx(hdcDst,(szPieX/2)+x,(szPieY/2)+y,NULL);
Percentage.push_back( Frequency[j]*100 );

a = Frequency[j]*360;
if(j==0)
b.push_back(a);
else
b.push_back(b[j-1]+a);
Degrees= (float)(3.14*b[j])/180;
// draw segment lines
LineTo(hdcDst,round(x2),round(y2));
if(b[j]>180&&b[j]<360)
{
LineTo(hdcDst,round(x3),round(y3));
}
//Fill Pie
if(j==0)
{
Degrees2 = (float)(3.14*(a/2))/180;

}
else
{
Degrees2= (float)(3.14*(b[j-1]+(a/2)))/180;
}

SelectObject(hdcDst,hbr);
FloodFill(hdcDst,(int)round(xr),(int)round(yr),bkcolor);
// Fill Rink
if(b[j]>190&&b[j]<=350)
{
Degrees2 = (float)(3.14*((b[j]-4)))/180;

SelectObject(hdcDst,hbr2);
FloodFill(hdcDst,(int)round(xr),(int)round(yr),bkcolor);
}

if(b[j]>350&&b[j]<361)
{
Degrees2 = (float)(3.14*((b[j-1]+6)))/180;

SelectObject(hdcDst,hbr2);
FloodFill(hdcDst,(int)round(xr),(int)round(yr),bkcolor);

}

}

if(Title !="")
{
TextOut(hdcDst,(x+szPieX/2)-(Title.length()*2)-Title.size(),y-24,Title.c_str(),Title.size());
}

if(vLegend)
{
//Draw Legend
TextOut(hdcDst,x+szPieX+15,y,"Legend",6);
string buffer;
stringstream sbuf;
char buf[20];
float d = 0.0f;
for(int i = 0; i<szNames; i++)
{
buffer = "";
sbuf.clear();

d = Info[i];
// write strings
buffer.append(Names[i]);
buffer.append(" ");
sbuf << d;
sbuf >> buf;
buffer.append(buf);
TextOut(hdcDst,x+szPieX+40,y+(25*(i+1)),buffer.c_str(),buffer.size());
//Draw Colored Boxes
Rectangle(hdcDst,x+szPieX+15,y+(25*(i+1)),x+szPieX+28,y+(25*(i+1)+12));
RECT rc;
rc.left= x+szPieX+16;
rc.top = y+(25*(i+1))+1;
rc.right = x+szPieX+28-1;
rc.bottom = y+(25*(i+1)+12)-1;
HBRUSH hbr = CreateSolidBrush(colors[i]);

FillRect(hdcDst,&rc,hbr);
}
}

DeleteObject(pen);
DeleteObject(font);

}

```

The section of code that has changed in DrawPie

```                //Fill Segments
//Fill Pie
if(j==0)
{
Degrees2 = (float)(3.14*(a/2))/180;

}
else
{
Degrees2= (float)(3.14*(b[j-1]+(a/2)))/180;
}

SelectObject(hdcDst,hbr);
FloodFill(hdcDst,(int)round(xr),(int)round(yr),bkcolor);
}

```

As you can see I have replaced all the complicated if statements with a more logical and concise approach what I am basically doing here is taking the angle of the segment and halving it at the same time I reduce the radius of the circle also by one half. This means I am now filling from the middle of the segment instead of the edge of the segment like I was doing before.

Now we can discuss the chart3d class.

In ChartKM.h

```class chart3D:public chartObject {

public:

void DrawPie3D(HDC hdcDst,int x,int y, int szPieX, int szPieY, COLORREF bkcolor);
};

```

This class inherits from the chartObject class and at the moment has only one function.

We will now go on and discuss this function.

```void chart3D::DrawPie3D(HDC hdcDst,int x,int y, int szPieX, int szPieY, COLORREF bkcolor)
{

HPEN pen = CreatePen(PS_SOLID,1,bkcolor);
HFONT font;
font = CreateFont(14,0,0,0,FW_DONTCARE,FALSE,FALSE,FALSE,DEFAULT_CHARSET,OUT_OUTLINE_PRECIS,
CLIP_DEFAULT_PRECIS,CLEARTYPE_QUALITY, VARIABLE_PITCH,TEXT("Arial Bold"));
SelectObject(hdcDst, font);
SelectObject(hdcDst,pen);
//Draw Circle
Arc(hdcDst, x,y,szPieX+x,szPieY+y,x,y,x,y);
//Draw First Line
MoveToEx(hdcDst,(szPieX/2)+x,(szPieY/2)+y,NULL);
LineTo(hdcDst,szPieX+x,(szPieY/2)+y);
//Set Background Color for Text
SetBkColor(hdcDst,GetPixel(hdcDst,0,0));
//Gets Totals for Pie Chart
Total = GetTotal();
GetFrequency();

//Draw Lines of arc

Arc(hdcDst,x,y,x+szPieX,(int)(y+(szPieY+16)),x,y+(szPieY/2),x+szPieX,y+(szPieY/2));

float xr = 0.0f;
float yr = 0.0f;
float Degrees2 =0.0f;
//Draw segments
for(int j = 0; j<szInfo; j++)
{
COLORREF clr = colors[j];
BYTE R = GetRValue(colors[j]);
BYTE G = GetGValue(colors[j]);
BYTE B = GetBValue(colors[j]);
int Flag =0;
// Get a darker shade of the primary color for the rink
if(R>=G&&R>=B)/>/>
{
R=R-40;
clr = RGB(R,G,B)/>/>;
Flag =1;
}
if(G>=R&&G>=B&&Flag==0)
{
G=G-40;
clr = RGB(R,G,B)/>/>;
Flag=1;
}
if(B>=G&&B>=R&&Flag==0)
{
B=B-40;
clr = RGB(R,G,B)/>/>;
Flag=1;
}
HBRUSH hbr = CreateSolidBrush(colors[j]);
HBRUSH hbr2 = CreateSolidBrush(clr);
SelectObject(hdcDst,hbr);

MoveToEx(hdcDst,(szPieX/2)+x,(szPieY/2)+y,NULL);
Percentage.push_back( Frequency[j]*100 );

a = Frequency[j]*360;
if(j==0)
b.push_back(a);
else
b.push_back(b[j-1]+a);
Degrees= (float)(3.14*b[j])/180;
// draw segment lines
LineTo(hdcDst,round(x2),round(y2));
if(b[j]>180&&b[j]<360)
{
LineTo(hdcDst,round(x3),round(y3));
}
//Fill Pie
if(j==0)
{
Degrees2 = (float)(3.14*(a/2))/180;

}
else
{
Degrees2= (float)(3.14*(b[j-1]+(a/2)))/180;
}

SelectObject(hdcDst,hbr);
FloodFill(hdcDst,(int)round(xr),(int)round(yr),bkcolor);
// Fill Rink
if(b[j]>190&&b[j]<=350)
{
Degrees2 = (float)(3.14*((b[j]-4)))/180;

SelectObject(hdcDst,hbr2);
FloodFill(hdcDst,(int)round(xr),(int)round(yr),bkcolor);
}

if(b[j]>350&&b[j]<361)
{
Degrees2 = (float)(3.14*((b[j-1]+6)))/180;

SelectObject(hdcDst,hbr2);
FloodFill(hdcDst,(int)round(xr),(int)round(yr),bkcolor);

}

}

if(Title !="")
{
TextOut(hdcDst,(x+szPieX/2)-(Title.length()*2)-Title.size(),y-24,Title.c_str(),Title.size());
}

if(vLegend)
{
//Draw Legend
TextOut(hdcDst,x+szPieX+15,y,"Legend",6);
string buffer;
stringstream sbuf;
char buf[20];
float d = 0.0f;
for(int i = 0; i<szNames; i++)
{
buffer = "";
sbuf.clear();

d = Info[i];
// write strings
buffer.append(Names[i]);
buffer.append(" ");
sbuf << d;
sbuf >> buf;
buffer.append(buf);
TextOut(hdcDst,x+szPieX+40,y+(25*(i+1)),buffer.c_str(),buffer.size());
//Draw Colored Boxes
Rectangle(hdcDst,x+szPieX+15,y+(25*(i+1)),x+szPieX+28,y+(25*(i+1)+12));
RECT rc;
rc.left= x+szPieX+16;
rc.top = y+(25*(i+1))+1;
rc.right = x+szPieX+28-1;
rc.bottom = y+(25*(i+1)+12)-1;
HBRUSH hbr = CreateSolidBrush(colors[i]);

FillRect(hdcDst,&rc,hbr);
}
}

DeleteObject(pen);
DeleteObject(font);

}

```

We create a new pen and font and select them into our dc.

We draw a circle and draw our first line.

We set the background color for text then get our Totals same as with ::DrawPie.

We then draw an arc that will be the rink of of our 3D Pie.

I then set up four radii variables

two are for the segments while the other two are for the rink.

xr, yr and Degrees2 are for drawing the rink parts we set those later on.

We set up a loop to loop through all the segments.

I then set up a new COLORREF variable clr to hold a darker shade of the color given.

We do this by working out what is the biggest part of the color Red, Green or Blue and taking 40 off this value to give a slightly darker shade of the original color.

We create two new brushes one for painting the pie and one for the rink.

I then draw the segment lines and then the rink segment lines.

We then paint the segments then the rink.

We draw the Legend and tidy up.

The following is an example program which uses the new class.

main.cpp

```#include <Windows.h>
#include <ChartKM.h>

#pragma comment(lib, "ChartKM.lib")

/*  Declare Windows procedure  */
LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);

/*  Make the class name into a global variable  */
char szClassName[ ] = "CodeBlocksWindowsApp";

int WINAPI WinMain (HINSTANCE hThisInstance,
HINSTANCE hPrevInstance,
LPSTR lpszArgument,
int nCmdShow)
{
HWND hwnd;               /* This is the handle for our window */
MSG messages;            /* Here messages to the application are saved */
WNDCLASSEX wincl;        /* Data structure for the windowclass */

/* The Window structure */
wincl.hInstance = hThisInstance;
wincl.lpszClassName = szClassName;
wincl.lpfnWndProc = WindowProcedure;      /* This function is called by windows */
wincl.style = CS_DBLCLKS;                 /* Catch double-clicks */
wincl.cbSize = sizeof (WNDCLASSEX);

/* Use default icon and mouse-pointer */
wincl.cbClsExtra = 0;                      /* No extra bytes after the window class */
wincl.cbWndExtra = 0;                      /* structure or the window instance */
/* Use Windows's default colour as the background of the window */
wincl.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);

/* Register the window class, and if it fails quit the program */
if (!RegisterClassEx (&wincl))
return 0;

/* The class is registered, let's create the program*/
hwnd = CreateWindowEx (
0,                   /* Extended possibilites for variation */
szClassName,         /* Classname */
"Charting Demo Application.",       /* Title Text */
WS_OVERLAPPEDWINDOW, /* default window */
CW_USEDEFAULT,       /* Windows decides the position */
CW_USEDEFAULT,       /* where the window ends up on the screen */
600,                 /* The programs width */
400,                 /* and height in pixels */
HWND_DESKTOP,        /* The window is a child-window to desktop */
hThisInstance,       /* Program Instance handler */
NULL                 /* No Window Creation data */
);

/* Make the window visible on the screen */
ShowWindow (hwnd, nCmdShow);

/* Run the message loop. It will run until GetMessage() returns 0 */
while (GetMessage (&messages, NULL, 0, 0))
{
/* Translate virtual-key messages into character messages */
TranslateMessage(&messages);
/* Send message to WindowProcedure */
DispatchMessage(&messages);
}

/* The program return-value is 0 - The value that PostQuitMessage() gave */
return messages.wParam;
}

/*  This function is called by the Windows function DispatchMessage()  */

LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{

static chart3D Chart2;

static HDC hdc,memhdc;
static HBITMAP hbmNewBitMap;
PAINTSTRUCT ps;

switch (message)                  /* handle the messages */
{
case WM_CREATE:
{

Chart2.AddTitle("Traffic Survey High Street, Kirby 2003");

hdc = GetDC(hwnd);
memhdc = CreateCompatibleDC(hdc);

//create the bitmap
hbmNewBitMap=CreateCompatibleBitmap(hdc, 600, 600);

//shove the image into the dc
SelectObject(memhdc, hbmNewBitMap);

RECT rect;
rect.left = 0;
rect.top = 0;
rect.right = 600;
rect.bottom = 600;
//Fill the bitmap with the screen color
FillRect(memhdc,&rect,(HBRUSH)GetStockObject(WHITE_BRUSH));

// Draw the Chart onto the memory dc

Chart2.DrawPie3D(memhdc,25,25,250,150,RGB(0,0,0));

return 0;
}

case WM_SIZE:
{
InvalidateRect(hwnd,NULL,TRUE);
return 0;
}

case WM_PAINT:
{

BeginPaint(hwnd,&ps);

//Draw the 3d Chart from Memory to Screen device context
BitBlt(ps.hdc,25,50,400,400,memhdc,0,0,SRCCOPY);

EndPaint(hwnd,&ps);

return 0;
}

case WM_DESTROY:
PostQuitMessage (0); /* send a WM_QUIT to the message queue */
DeleteDC(memhdc);

DeleteObject((HBITMAP)hbmNewBitMap);

break;
default:                      /* for messages that we don't deal with */
return DefWindowProc (hwnd, message, wParam, lParam);
}

return 0;
}

```

The majority of it is standard windows stuff so we will start in WM_CREATE:

we set up a new 3d chart, a device context to the screen , hdc and a memory device context memhdc.

We create a new bitmap.

We add in the chart data..... pretty simple this bit.

We shove the bitmap into our compatible memory device context

We fill the bitmap with our screen color this also fills the memhdc with the screen color too.

We draw the chart onto our memhdc.

In WM_PAINT:

We finally bit blit the memory device context onto our screen device context

Hey presto we now have a 3D Pie Chart.

Next up will be 3D Bar Charts

See you next time.

Snoopy.

This post has been edited by baavgai: 17 February 2013 - 01:43 PM
Reason for edit:: space cleaning

Is This A Good Question/Topic? 0

Page 1 of 1

 .related ul { list-style-type: circle; font-size: 12px; font-weight: bold; } .related li { margin-bottom: 5px; background-position: left 7px !important; margin-left: -35px; } .related h2 { font-size: 18px; font-weight: bold; } .related a { color: blue; }