在.NET中使用GDI+构建三维直方图

来源:互联网 发布:淘宝怎么看购买记录 编辑:程序博客网 时间:2024/04/29 20:49
在.NET中使用GDI+构建三维直方图
  
  2004-12-18 18:10:57      
随着社会的发展、科学的进步,地理信息系统(GIS)技术在社会各个领域中的应用越来越广泛。其中专题图在地理信息系统应用中具有非常重要的作用、专题图的应用大大增强了信息表达的直观性。目前在GIS软件领域 各种GIS平台软件以及GIS开发组件都提供了丰富的专题图设置功能。

ESRI公司的GIS开发组件MapObjects中也提供了丰富的专题图功能,如:图表专题(包括直方图和饼图)、独立值、点密度、分类分级等。使用过MapObjects进行专题开发的人会发现:其中图表专题中MapObjects提供的图表显示是平面二维的,显示效果极其平淡,没有ArcMap中图表专题里的那种三维立体效果。有没有办法使这些图表象ArcMap中那样显示为三维立体的效果呢?MapObjects的ChartRenderer中提供了自定义图表的方法,也就是把ChartType设置为ChartTypeConstants中的moCustom,然后把ChartRenderer的CustomChart属性设置为我们自定义图表对象就可以了。

话是如此,但是如何创建这个自定义图表对象呢,MapObjects 提供了ICustomChart接口,我们要做的就是实现这个接口。在一般的开发语言中我们需要通过底层的API绘图函数来实现其中图形方面的操作,不过在.NET中我们可以使用强大的GDI+来实现这些操作,下面我们以C#.Net为例使用GDI+实现ICustomChart接口,创建美观、大方、直观、立体感强的三维直方图统计专题。
 
第一步:新建一个C#类库项目CustomChartRenderer(图1)

第二步:添加程序集的应用。ESRI.MapObjects2.Core 和 ESRI.MapObjects2.Custom并继承ESRI.MapObjects2.Custom.ICustomChart(图2、3)
 
第三步:添加对ICustomChart继承接口的实现。在.NET开发界面的类似图中找到
ICustomChart接口,点击右键菜单中的“添加”——>“实现接口”(图4)
“实现接口”后我们的代码中会多了如下三个函数,我们要做的也就是完成这三个函数在渲染的过程中执行的顺序为SetupDC——> Draw——> ResetDC。
#region ICustomChart 成员
public void ResetDC(int hDC)
{
// TODO: 添加 Custom3DBarRenderer.ResetDC 实现
}
public void SetupDC(object Map, object MapLayer, object ChartRenderer, int hDC, double dpi)
{
// TODO: 添加 Custom3DBarRenderer.SetupDC 实现
}
public void Draw(int hDC, int x, int y, ref double[] values, double normValue, double sizeValue)
{
// TODO: 添加 Custom3DBarRenderer.Draw 实现
}
#endregion
 
第四步:添加成员变量、属性和自定义函数,自定义函数Setup3DBarRenderer主要负责对数据进行预处理和统计计算,计算图表渲染中的最大值,以便根据数值的大小分配直方图柱子的高度。
private int[] m_iColors; //记录直方条的颜色
private float m_MaxBarHeight = 50; //直方图的最大高度
private float m_MinBarHeight = 1; //直方图的最小高度
private float m_BarWidth = 10; //直方图的宽度
private float m_fTotal = 0; //用于记录统计字段中的最大直
private bool m_blDrawOutline = true; //是否绘制边框
private System.Drawing.Color m_OutlineColor = System.Drawing.Color.Black; //边框的颜色
public void Setup3DBarRenderer(ESRI.MapObjects2.Core.MapLayer lyr,ESRI.MapObjects2.Core.ChartRenderer cr)
{
if(lyr != null && cr != null)
{
//初始化颜色数组根据FieldCount动态创建
this.m_iColors = new int[cr.FieldCount];
for(short i=0;i<cr.FieldCount;i++)
{
this.m_iColors[i] = int.Parse(cr.get_Color(i).ToString());
}
ESRI.MapObjects2.Core.Recordset rec;
float fTotal = 0;
rec = lyr.Records;
while (!rec.EOF)
{
for(short i = 0 ; i < cr.FieldCount - 1;i++)
{
float fTemp = float.Parse(rec.Fields.Item(cr.get_Field(i)).ValueAsString);
if(fTotal < fTemp)
{//保存最大的值 以便计算绘制直方图的高
fTotal = fTemp;
}
}
rec.MoveNext();
}
this.m_fTotal = fTotal;
}
}
// 公开一些属性以便根据需要进行修改
public float BarWidth { get; set; }
public bool DrawOutline { get; set; }
public float MaxBarHeight { get; set; }
public float MinBarHeight { get; set; }
public Color OutlineColor { get; set; }
 
第五步:实现继承的接口ESRI.MapObjects2.Custom.ICustomChart中的方法Draw()。
public void Draw(int hDC, int x, int y, ref double[] values, double normValue, double sizeValue)
{
// TODO: 添加 Custom3DBarRenderer.Draw 实现
float iBarHeight = 0;
float iBarWidth = 0;
System.Drawing.Graphics g = System.Drawing.Graphics.FromHdc(new System.IntPtr(hDC)); //创建Graphics对象
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias; //消除图形的锯齿
System.Drawing.SolidBrush tempBrush = null;
System.Drawing.Pen pOutLine = new System.Drawing.Pen(new System.Drawing.SolidBrush(this.m_OutlineColor),0.2f);
iBarWidth = this.m_BarWidth;
float CurrentX,CurrentY;
CurrentX = x - this.m_BarWidth * values.Length / 2;
CurrentY = y;
for(int i=0;i<values.Length;i++)
{
//创建画刷 并计算矩形的高度
tempBrush = new System.Drawing.SolidBrush(System.Drawing.ColorTranslator.FromWin32(this.m_iColors[i]));
iBarHeight = System.Convert.ToSingle((values[i] * this.m_MaxBarHeight/this.m_fTotal).ToString());
if(iBarHeight < this.m_MinBarHeight)
{
iBarHeight = this.m_MinBarHeight;
}
if(iBarHeight > this.m_MaxBarHeight)
{
iBarHeight = this.m_MaxBarHeight;
}
//绘制矩形
System.Drawing.PointF[] pRect = new System.Drawing.PointF[4];
pRect[0].X = CurrentX;
pRect[0].Y = CurrentY;
pRect[1].X = CurrentX + iBarWidth ;
pRect[1].Y = CurrentY;
pRect[2].X = CurrentX + iBarWidth ;
pRect[2].Y = CurrentY - iBarHeight;
pRect[3].X = CurrentX;
pRect[3].Y = CurrentY - iBarHeight;
//绘制矩形顶部的阴影
System.Drawing.PointF[] pTopFill = new System.Drawing.PointF[4];
pTopFill[0].X = CurrentX;
pTopFill[0].Y = CurrentY - iBarHeight;
pTopFill[1].X = CurrentX + iBarWidth ;
pTopFill[1].Y = CurrentY - iBarHeight;
pTopFill[2].X = CurrentX + iBarWidth * 3/2 ;
pTopFill[2].Y = CurrentY - iBarHeight - iBarWidth * 1/2;
pTopFill[3].X = CurrentX + iBarWidth * 1/2 ;
pTopFill[3].Y = CurrentY - iBarHeight - iBarWidth * 1/2;
CurrentX = CurrentX +iBarWidth;
//斜面阴影部分
System.Drawing.PointF[] pShadow= new System.Drawing.PointF[4];
pShadow[0].X = CurrentX;
pShadow[0].Y = CurrentY;
pShadow[1].X = CurrentX + iBarWidth/2 ;
pShadow[1].Y = CurrentY - iBarWidth/2;
pShadow[2].X = CurrentX + iBarWidth/2 ;
pShadow[2].Y = CurrentY - iBarHeight - iBarWidth * 1/2;
pShadow[3].X = CurrentX ;
pShadow[3].Y = CurrentY - iBarHeight;
//绘制3D图形 包括正面、斜面、顶部
g.FillPolygon(tempBrush,pRect);
g.FillPolygon(new HatchBrush(HatchStyle.Percent50,tempBrush.Color),pTopFill);
g.FillPolygon(tempBrush,pShadow);
//如果设置了绘制边界线 则绘制边界
if(this.m_blDrawOutline)
{
g.DrawPolygon(pOutLine,pRect);
g.DrawPolygon(pOutLine,pTopFill);
g.DrawPolygon(pOutLine,pShadow);
}
}
}
 
最后,建立测试工程应用我们创建的三维直方图统计专题(点击按扭为地图设上此专题),看看设置完成后的效果,是不是比普通的二维直方图更好呢?。关键代码如下:
prprivate void button1_Click(object sender, System.EventArgs e)
{
//取得图层
ESRI.MapObjects2.Core.MapLayer lyr = this.axMap1.Layers.Item(0) as ESRI.MapObjects2.Core.MapLayer;
//创建ChartRenderer对象 并使用moCustom类型
ESRI.MapObjects2.Core.ChartRenderer pChartRenderer = new ESRI.MapObjects2.Core.ChartRendererClass();
pChartRenderer.FieldCount = 3;
pChartRenderer.set_Field(0, "GDP");
pChartRenderer.set_Color(0,(uint)ESRI.MapObjects2.Core.ColorConstants.moRed);
pChartRenderer.set_Field(1,"AGRICULTUR");
pChartRenderer.set_Color(1,(uint)ESRI.MapObjects2.Core.ColorConstants.moYellow);
pChartRenderer.set_Field(2,"Industry");
pChartRenderer.set_Color(2,(uint)ESRI.MapObjects2.Core.ColorConstants.moGreen);
pChartRenderer.ChartType = ESRI.MapObjects2.Core.ChartTypeConstants.moCustom;
//创建Custom3dBarRenderer对象并赋值给pChartRenderer
Gissky.Common.Mo.CustomChartRenderer.Custom3DBarRenderer r = new Gissky.Common.Mo.CustomChartRenderer.Custom3DBarRenderer();
r.Setup3DBarRenderer(lyr,pChartRenderer);
pChartRenderer.CustomChart = r;
lyr.Renderer = pChartRenderer;
this.axMap1.CtlRefresh();
}

原创粉丝点击