65.9K
CodeProject 正在变化。 阅读更多。
Home

WPF 中的简单 3D 饼图

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.19/5 (9投票s)

2009 年 3 月 6 日

公共领域

3分钟阅读

viewsIcon

56385

downloadIcon

2152

创建 3D 饼图的起点。

3DPieSource

引言

本文仅旨在作为在 WPF 中创建 3D 饼图的入门指南。它并非旨在成为您可以插入的用户控件,而是为您提供一个起点,代码量最少。

背景

我需要在一个 3D 饼图中显示统计数据。所以,我做了其他所有人都在做的事情——在网上搜索示例。我不想购买第三方应用程序,因为我们正在使用 WPF,它支持 3D 控件,而且我们正在做的事情非常简单。我确实找到了一些示例,但它们被发现缺乏,因为

  1. 它们是包含大量我不需要的其他 3D 示例的较大库的一部分。
  2. 代码的功能超出了我的需要。
  3. 它没有完全按照我的需要去做(例如,显示标签)

所以我创建了自己的项目作为 POC,这就是它。

代码不多 - 它们都存在于 Window1 (Window1.xaml.cs) 的代码隐藏中。
该窗口包含一个 Viewport3D 控件,所有 3D 对象都将驻留其中。除了饼图切片之外,它还将包含相机和光源。

大部分工作是在 CreateSlice 中完成的,给定一个起点和一个百分比,它会计算切片的宽度并创建一个 ModelUIElement3D 以添加到 Viewport3D。使用 ModelUIElement3D 的优势在于它具有标准的 UI 事件,您可以监听,例如 MouseDown。为了创建切片,我基本上从原点开始,稍微拉出切片,然后计算切片边缘的点。您计算的点越多,曲线看起来就越平滑。在 XP 上,3D 控件会被混叠,因此它们看起来不会那么好。您可以通过一些注册表项来强制执行此操作,但它可能不适用于所有系统。

// 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));
}

现在我有了饼图的顶层。

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

然后我复制这组点并减小 Z 值以创建饼图的底部,然后添加侧面。

// 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

事件处理程序用于监听用户何时单击切片,并将切片添加到视口

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

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

为了绘制文本,我创建了一个 TextBlock 并将其绘制在 2D 平面上,该平面位于饼图切片中心的外部边缘。
当用户单击一个切片时,我将其 DiffuseMaterial 更改为使其突出显示,然后沿 Z 轴抬起切片。

关注点

使用 3D 图形时需要记住的一些事项:

  1. 创建要显示的三角形时,必须按顺时针顺序添加点。
  2. 如果三角形的边被共享(意味着点),则由于光线在它们上的反射方式,表面看起来会很光滑。如果没有,那么您将看到各个线。如果您想看到更硬的边缘,可以复制这些点,或者您可以使用法线来自定义您想要的。此示例根本不使用法线。

历史

  • 2009 年 3 月 6 日:初始帖子
© . All rights reserved.