Re: 3D Pie Chart!
From: Jerry Coffin (jcoffin_at_taeus.us)
Date: 05/18/04
- Next message: Gary Chang: "Re: Can I clean up AFX_DATA_MAP, etc sections in .NET 2003"
- Previous message: Joseph M. Newcomer: "Re: Debug and Release build"
- In reply to: Vai2000: "3D Pie Chart!"
- Next in thread: Jerry Coffin: "Re: 3D Pie Chart!"
- Reply: Jerry Coffin: "Re: 3D Pie Chart!"
- Messages sorted by: [ date ] [ thread ]
Date: Tue, 18 May 2004 00:25:04 -0600
In article <#6i9y15OEHA.3016@tk2msftngp13.phx.gbl>, vai@onebox.com
says...
> Hi All, I have been playing around with drawing Pie Chart for sometime...I
> thank you all fro feedbacks...Final goal is to render a 3D chart? How I do
> accomplish that? just like Windows.
The basic idea of this is fairly simple, but the execution gets long
and picky, so this is going to be a pretty long post.
The idea is to start by making the ellipse wider than is tall, to
give the appearance of looking at it from an angle. Then we have to
draw in the cylindrical area below front part of the ellipse (I.e.
all the areas where the point.y > center.y. Finally, to shade the
vertical section, we have to make that part darker.
Compared to what I posted yesterday, the document part is almost the
same, but with 'int height;' added -- this will be the height of the
cylinder. We also need to add code to initialize this -- from the
looks of things a value between 10 and 20 is reasonable.
Then, we modify the drawing code to account for an ellipse instead of
a circle. For a circle, we multiply both the sin and the cosine by
the radius to get the x and y values respectively.
For an ellipse, we multiply the cosine by the horizontal radius, and
the sine by the vertical radius, giving code like this:
struct ellipse {
POINT center;
int hradius;
int vradius;
};
struct pie_section {
POINT one;
POINT two;
double end_angle;
};
pie_section pie_sect (double start_angle,
ellipse const &e,
section const &s)
{
double angle, end_angle;
pie_section ret;
angle = s.percent / 100.0 * 2.0 * 3.1416;
end_angle = start_angle + angle;
ret.one.x = e.center.x + e.hradius * cos(end_angle);
ret.one.y = e.center.y + e.vradius * sin(end_angle);
ret.two.x = e.center.x + e.hradius * cos(start_angle);
ret.two.y = e.center.y + e.vradius * sin(start_angle);
ret.end_angle = end_angle;
return ret;
}
Now we need a little utility routine to convert a color to a shaded
color. To do that, we split the color up into the three components,
divide each by 2, and convert the result back to a color. This gives
slightly inaccurate colors, but for our purposes it'll work:
COLORREF shaded(COLORREF c) {
int red = GetRValue(c)/2;
int green = GetGValue(c)/2;
int blue = GetBValue(c)/2;
return RGB(red, green, blue);
}
Then we have to draw all this to make our complete pie chart. Since
the drawing is getting a little complex, we'll separate out a
function to draw one section, and then have OnDraw invoke it for each
section:
void draw_section(CDC *pDC,
ellipse const &e,
section const &s,
double &sa)
{
CRect box;
box.left = e.center.x-e.hradius;
box.right = e.center.x+e.hradius;
box.top = e.center.y-e.vradius;
box.bottom = e.center.y+e.vradius;
// draw the pie-section
CBrush brush;
brush.CreateSolidBrush(s.color);
pDC->SelectObject(brush);
pie_section p = pie_sect(sa, e, s);
pDC->Pie(box, p.one, p.two);
brush.DeleteObject();
// Shade in the vertical section of the cylinder. This particular
// algorithm is in the "It's after midnight so I don't care how slow
// it is" category. <G>
CPen pen;
pen.CreatePen(0, 1, shaded(s.color));
CPen *old_pen = (CPen *)pDC->SelectObject(&pen);
for (double a=sa; a<p.end_angle; a+=1.0/e.hradius) {
unsigned long x = e.center.x + e.hradius * cos(a);
unsigned long y = e.center.y + e.vradius * sin(a);
if ( y > e.center.y ) {
pDC->MoveTo(x,y+1);
pDC->LineTo(x, y+e.height);
}
}
pDC->SelectObject(old_pen);
pen.DeleteObject();
// update the start angle for the next section.
sa = p.end_angle;
}
Now OnDraw is pretty simple: it just has to figure up the size of the
pie chart, then use the function above to draw each section:
void CPieView::OnDraw(CDC* pDC)
{
CPieDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
double next_angle = -3.14/2.0;
CRect rect;
GetClientRect(&rect);
// figure specs for the ellipse:
ellipse e;
e.center.x = rect.Width()/2;
e.center.y = rect.Height()/2;
e.hradius = min(rect.Width()/2, rect.Height()/2);
e.vradius = e.hradius / 2;
e.height = pDoc->height;
// and draw in the sections:
for (int i=0; i<pDoc->sections.size(); ++i)
draw_section(pDC, e, pDoc->sections[i], next_angle);
}
And I sincerely hope that's enough on that subject for a while.
--
Later,
Jerry.
The universe is a figment of its own imagination.
- Next message: Gary Chang: "Re: Can I clean up AFX_DATA_MAP, etc sections in .NET 2003"
- Previous message: Joseph M. Newcomer: "Re: Debug and Release build"
- In reply to: Vai2000: "3D Pie Chart!"
- Next in thread: Jerry Coffin: "Re: 3D Pie Chart!"
- Reply: Jerry Coffin: "Re: 3D Pie Chart!"
- Messages sorted by: [ date ] [ thread ]
Relevant Pages
|