Click here to Skip to main content
Click here to Skip to main content
Go to top

Simple 3D Pie Chart in WPF

, 6 Mar 2009
Rate this:
Please Sign up or sign in to vote.
A starting point for creating 3D pie charts
3DPieSource

Introduction

This article is just meant as a starter guide for creating a 3D pie chart in WPF. It's not meant to be a user control that you plug in, but rather give you a starting point with a minimum amount of code.

Background

I have the requirement to show statistical data in a 3D pie chart. So I did what everyone else does - search the web for an example. I didn't want to purchase a third party app since we were using WPF and it has support for 3D controls and what we were doing was pretty straight forward. I did find some examples but they were found lacking because:

  1. They were part of a larger library that contained a bunch of other 3D examples that I don't need.
  2. The code did much more than I needed.
  3. It didn't do exactly what I needed (e.g. show labels)

So I created my own project as a POC and here it is.

There is not much to the code - it all exists in the code behind for Window1 (Window1.xaml.cs).
The window contains a Viewport3D control where all the 3D objects will reside. In addition to the pie slices, it will contain the camera and the light source.

The bulk of the work is done in CreateSlice which given a starting point and a percentage calculates the width of the slice and creates a ModelUIElement3D to add to the Viewport3D. The advantage of using a ModelUIElement3D is that it has standard UI events you can listen to like MouseDown. To create the slice, I basically start at the origin, pull out the slice a little, then calculate the points along the edge of the slice. The more points you calculate, the smoother the curve will look. On XP, 3D controls are aliased so they will not look as nice. You can force this through some registry keys but it may not work on all systems.

// create the slice
int max = (int)(percent * 200);
mg.Positions.Add(new Point3D(0, 0, 0));
for (int i = 0; i <= max; i++)
{
    Point ArcPoint = new Point((size * Math.Sin(currentAngle * 2 * Math.PI)),
                   (-size * Math.Cos(currentAngle * 2 * Math.PI)));
    currentAngle += 0.005;
    mg.Positions.Add(new Point3D(ArcPoint.X, ArcPoint.Y, 0));
}

Now I have the top layer of the pie.

max = mg.Positions.Count;
for (int i = 0; i < max; i++)
    CreateTriangle(mg, 0, i + 1, i + 2);

I then copy this collection of points and decrease the Z value to create the bottom part of the pie and then add in the sides.

// add bottom layer
for (int i = 0; i < max; i++)
    mg.Positions.Add(new Point3D(mg.Positions[i].X, mg.Positions[i].Y, -3));

#region draw sides
// draw straight sides
CreateTriangle(mg, 0, max + 1, 1);
CreateTriangle(mg, max, max + 1, 0);
CreateTriangle(mg, max, max - 1, mg.Positions.Count - 1);
CreateTriangle(mg, max, 0, max - 1);

// draw curved sides
for (int i = 1; i < max; i++)
{
    CreateTriangle(mg, i, i + max, i + 1);
    CreateTriangle(mg, i + 1, i + max, i + max + 1);
}
#endregion

An event handler is used to listen to when the user clicks on the slice and the slice is added to the view port:

pieSlice.Model = gm;
pieSlice.MouseDown += new MouseButtonEventHandler(pieSlice_MouseDown);

pieSlice.Transform = new TranslateTransform3D(popOutPoint.X, popOutPoint.Y,0);
this.mainViewport.Children.Add(pieSlice);

To get the text to draw, I create a TextBlock and paint it on 2D plane which is positioned to the outer edge of the center of the pie slice.
When the user clicks on a slice, I change its DiffuseMaterial to make it stand out and then raise the slice along the Z axis.

Points of Interest

A few things to keep in mind when working with 3D graphics: 

  1. When creating the triangles to display, the points must be added in a clockwise order.
  2. If edges of a triangle are shared (meaning the points), then the surface will look smooth due to how light is reflected off of them. If not, then you will see the individual lines. If you want to see harder edges, you can duplicate the points, or you can use Normals to customize however you wish. This example does not use Normals at all.

History

  • 6th March, 2009: Initial post

License

This article, along with any associated source code and files, is licensed under A Public Domain dedication

Share

About the Author

Joe Hillenbrand
Architect ReSound
United States United States
No Biography provided

Comments and Discussions

 
-- There are no messages in this forum --
| Advertise | Privacy | Mobile
Web03 | 2.8.140916.1 | Last Updated 6 Mar 2009
Article Copyright 2009 by Joe Hillenbrand
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid