C#,SharpGL开发的3D图表控件
另外一个版本是使用OpenTK开发,文字显示效果不太理想,因此换了SharpGL重新写了一个。
文字是缓存为图片,然后使用坐标映射的方式绘制到图表上。
资源忘了复制链接,欢迎来白嫖
public partial class QChart : UserControl
{
public QChart()
{
InitializeComponent();
BackColor = Color.White;
LineColor = Color.Gray;
DotColor = Color.Red;
TitleColor = Color.Red;
TxtColor = Color.Black;
XTitle = "X";
YTitle = "Y";
ZTitle = "Z";
XRange = 5;
YRange = 3;
ZRange = 3;
_rotationy = 1;
FontSize = 12;//文字大小
minx = miny = minz = 0;
maxx = maxy = maxz = 10;
XStep = YStep = ZStep = 1;
}
private int _x;
private float _rotationx, _rotationy;
private float zIndex = 12;//俯视角度,好看
private bool locked = false;//是否锁定
private List<Point3D> points;
public float FontSize { get; set; }
/// <summary>
/// 坐标线条颜色
/// </summary>
public Color LineColor { get; set; }
/// <summary>
/// 点颜色
/// </summary>
public Color DotColor { get; set; }
/// <summary>
/// 标题颜色
/// </summary>
public Color TitleColor { get; set; }
/// <summary>
/// 刻度颜色
/// </summary>
public Color TxtColor { get; set; }
/// <summary>
/// X轴标题
/// </summary>
public String XTitle { get; set; }
/// <summary>
/// Y轴标题
/// </summary>
public String YTitle { get; set; }
/// <summary>
/// Z轴标题
/// </summary>
public String ZTitle { get; set; }
public int XRange { get; set; }
public int YRange { get; set; }
public int ZRange { get; set; }
public double maxx { get; set; }
public double minx { get; set; }
public double maxy { get; set; }
public double miny { get; set; }
public double maxz { get; set; }
public double minz { get; set; }
/// <summary>
/// X方向的刻度间隔,默认1
/// </summary>
public int XStep { get; set; }
/// <summary>
/// y方向的刻度间隔,默认1
/// </summary>
public int YStep { get; set; }
/// <summary>
/// Z方向的刻度间隔,默认1
/// </summary>
public int ZStep { get; set; }
private Point mouse = new Point();//记录鼠标位置
private void openGLControl1_OpenGLDraw(object sender, RenderEventArgs e)
{
// Get the OpenGL object, just to clean up the code.
OpenGL gl = this.openGLControl1.OpenGL;
gl.Clear(OpenGL.GL_COLOR_BUFFER_BIT | OpenGL.GL_DEPTH_BUFFER_BIT);
gl.ClearColor((float)(BackColor.R / 255.0), (float)(BackColor.G / 255.0), (float)(BackColor.B / 255.0), 1f);//背景色
gl.Clear(OpenGL.GL_COLOR_BUFFER_BIT | OpenGL.GL_DEPTH_BUFFER_BIT | OpenGL.GL_STENCIL_BUFFER_BIT);
gl.MatrixMode(OpenGL.GL_MODELVIEW);
gl.LoadIdentity();
gl.Rotate(_rotationx, 1, 0, 0);//X轴旋转
gl.Rotate(_rotationy, 0, 1, 0);//Y轴旋转
//绘制坐标
gl.Color(LineColor.R, LineColor.G, LineColor.B);//线颜色
//gl.DrawText(0, 0, TitleColor, "宋体", FontSize, "ss");
//水平线,X面
for (int i = -XRange; i <= XRange; i++)
{
gl.Begin(OpenGL.GL_LINES);
gl.Vertex(i, -YRange, -ZRange);
gl.Vertex(i, -YRange, ZRange);
gl.End();
}
for (int i = -ZRange; i <= ZRange; i++)
{
gl.Begin(OpenGL.GL_LINES);
gl.Vertex(-XRange, -YRange, i);
gl.Vertex(XRange, -YRange, i);
gl.End();
}
//竖直线,Y面
for (int i = -YRange; i <= YRange; i++)
{
gl.Begin(OpenGL.GL_LINES);
gl.Vertex(-XRange, i, -ZRange);
gl.Vertex(-XRange, i, ZRange);
gl.End();
}
for (int i = -ZRange; i <= ZRange; i++)
{
gl.Begin(OpenGL.GL_LINES);
gl.Vertex(-XRange, -YRange, i);
gl.Vertex(-XRange, YRange, i);
gl.End();
}
//Z面
for (int i = -YRange; i <= YRange; i++)
{
gl.Begin(OpenGL.GL_LINES);
gl.Vertex(-XRange, i, -ZRange);
gl.Vertex(XRange, i, -ZRange);
gl.End();
}
for (int i = -XRange; i <= XRange; i++)
{
gl.Begin(OpenGL.GL_LINES);
gl.Vertex(i, -YRange, -ZRange);
gl.Vertex(i, YRange, -ZRange);
gl.End();
}
if (XStep < 1) XStep = 1;
//刻度x
for (int i = -XRange; i <= XRange; i+=XStep)
{
double v = (i + XRange) / (2.0 * XRange) * (maxx - minx);
DrawText(String.Format("{0:f2}", v), i - 0.2f, -YRange - 0.5f, -ZRange - 0.2f, TxtColor);
}
//DrawTextCN(XTitle, XRange + 0.5f, -YRange - 0.25f, -ZRange, TitleColor);
if (YStep < 1) YStep = 1;
//刻度Y
for (int i = -YRange; i < YRange; i+= YStep)
{
double v = (i + YRange) / (2.0 * YRange) * (maxy - miny);
DrawText(String.Format("{0:f2}", v), -XRange - 0.2f, i, -ZRange - 0.2f, TxtColor);
}
// DrawTextCN(YTitle, -XRange, YRange, -ZRange, TitleColor);
if (ZStep < 1) ZStep = 1;
//刻度Z
for (int i = -ZRange; i < ZRange; i+=ZStep)
{
double v = (i + ZRange) / (2.0 * YRange) * (maxz - minz);
DrawText(String.Format("{0:f2}", v), -XRange - 0.5f, -YRange - 0.5f, i, TxtColor);
}
// DrawTextCN(ZTitle, -XRange, -YRange - 0.5f, ZRange + 0.5f, TitleColor);
//输出三个坐标标题
gl.Color(TitleColor.R, TitleColor.G, TitleColor.B);
drawCNString(" ", 99, 99, 99, gl);
drawCNString(ZTitle, -XRange, -YRange,ZRange+0.5f, gl);
drawCNString(XTitle+0.5f , XRange, -YRange, -ZRange, gl);
drawCNString(YTitle , -XRange, YRange+0.5f, -ZRange, gl);
//如果有点,才绘制点
if (points != null && points.Count > 0)
{
gl.Color(DotColor.R, DotColor.G, DotColor.B);
// gl.PointSize(4);
foreach (Point3D p in points)
{
double x = XRange * (2 * (p.X - minx) / (maxx - minx) - 1);
double y = YRange * (2 * (p.Y - miny) / (maxy - miny) - 1);
double z = ZRange * (2 * (p.Z - minz) / (maxz - minz) - 1);
if (p.OnMouse) gl.PointSize(6);
else gl.PointSize(4);
gl.Begin(OpenGL.GL_POINTS);
gl.Vertex(x, y, z);
gl.End();
}
// GL.DrawPixels
}
gl.Flush();
}
private void DrawText(String s, double x, double y, double z, Color color)
{
OpenGL gl = this.openGLControl1.OpenGL;
var sv = SharpGL.SceneGraph.OpenGLSceneGraphExtensions.Project(gl, new SharpGL.SceneGraph.Vertex((float)x, (float)y, (float)z));
gl.DrawText((int)sv.X, (int)sv.Y, (float)(color.R / 255.0), (float)(color.G / 255.0), (float)(color.B / 255.0), "宋体", FontSize, s);
}
private void drawCNString(string str, float x, float y,float z, OpenGL gl)
{
int i;
// Create the font based on the face name.
var hFont = Win32.CreateFont((int)FontSize+4, 0, 0, 0, Win32.FW_DONTCARE, 0, 0, 0, Win32.DEFAULT_CHARSET,
Win32.OUT_OUTLINE_PRECIS, Win32.CLIP_DEFAULT_PRECIS, Win32.CLEARTYPE_QUALITY, Win32.CLEARTYPE_NATURAL_QUALITY, "宋体");
// Select the font handle.
var hOldObject = Win32.SelectObject(gl.RenderContextProvider.DeviceContextHandle, hFont);
// Create the list base.
var list = gl.GenLists(1);
gl.RasterPos(x, y,z);
// 逐个输出字符
for (i = 0; i < str.Length;i++)
{
bool result = Win32.wglUseFontBitmapsW(gl.RenderContextProvider.DeviceContextHandle, str[i], 1, list);
gl.CallList(list);
}
// 回收所有临时资源
//free(wstring);
gl.DeleteLists(list, 1);
// Reselect the old font.
Win32.SelectObject(gl.RenderContextProvider.DeviceContextHandle, hOldObject);
// Free the font.
Win32.DeleteObject(hFont);
//glDeleteLists(list, 1);
}
/// <summary>
/// 传入坐标集合
/// </summary>
/// <param name="points"></param>
public void ShowPoints(List<Point3D> points)
{
this.points = points;
if (points == null || points.Count == 0) return;
maxx = points[0].X;
minx = points[0].X;
maxy = points[0].Y;
miny = points[0].Y;
maxz = points[0].Z;
minz = points[0].Z;
foreach (Point3D p in points)
{
if (p.X > maxx) maxx = p.X;
if (p.X < minx) minx = p.X;
if (p.Y > maxy) maxy = p.Y;
if (p.Y < miny) miny = p.Y;
if (p.Z > maxz) maxz = p.Z;
if (p.Z < minz) minz = p.Z;
}
//防止直接到边界
maxx += 0.2;
minx -= 0.2;
maxy += 0.2;
miny -= 0.2;
maxz += 0.2;
minz -= 0.2;
}
private void QChart_Load(object sender, EventArgs e)
{
openGLControl1.OpenGLInitialized += OpenGLControl1_OpenGLInitialized;
this.Resize += QChart_Resize;
openGLControl1.MouseDown += on_MouseDown;
openGLControl1.MouseLeave += on_MouseLeave;
openGLControl1.MouseMove += on_MouseMove;
openGLControl1.MouseUp += on_MouseUp;
openGLControl1.MouseWheel += on_MouseWheel;
SetupViewport();
}
private void OpenGLControl1_OpenGLInitialized(object sender, EventArgs e)
{
SetupViewport();
}
private void QChart_Resize(object sender, EventArgs e)
{
SetupViewport();
}
//按键事件
protected override void OnKeyDown(KeyEventArgs e)
{
base.OnKeyDown(e);
if (e.KeyCode == Keys.Space)
{
this._x++;
SetupViewport();
this.Invalidate();
}
}
private void SetupViewport()
{
var w = this.Width;
var h = this.Height;
OpenGL GL = openGLControl1.OpenGL;
GL.MatrixMode(OpenGL.GL_PROJECTION);
GL.LoadIdentity();
GL.Viewport(0, 0, w, h); // Use all of the glControl painting area
if (h == 0) h = 1;
GL.Perspective(60.0f, w / h, 0.01, 100);
GL.LookAt(0, 0, zIndex, 0, 0, 0, 0, 1, 0);
}
private bool msDown = false;//是否鼠标按下
private int oldX = 0;//原始X坐标
private int oldY = 0;
private void on_MouseWheel(object sender, MouseEventArgs e)
{
// MessageBox.Show(e.Delta+"");
if (e.Delta > 0)
{
zIndex += 1;
if (zIndex > 20) zIndex = 20;
}
else if (e.Delta < 0)
{
zIndex -= 1;
if (zIndex < 8) zIndex = 8;
}
SetupViewport();
this.Invalidate();
}
private void on_MouseDown(object sender, MouseEventArgs e)
{
msDown = true;
oldX = e.X;//记录
oldY = e.Y;
Cursor = Cursors.Hand;
;
}
private void on_MouseMove(object sender, MouseEventArgs e)
{
if (points != null && points.Count > 0)
{
OpenGL gl = openGLControl1.OpenGL;
double[] viewmatrix=new double[16];
double[] projection = new double[16];
int[] viewport = new int[4];
gl.GetDouble(OpenGL.GL_MODELVIEW_MATRIX, viewmatrix);
gl.GetDouble(OpenGL.GL_PROJECTION,projection);
gl.GetInteger(OpenGL.GL_VIEWPORT, viewport);
for (int i = 0; i < points.Count; i++)
{
points[i].OnMouse = false;
}
int x = e.X;
int y = e.Y;
for (int i = 0; i < points.Count; i++)
{
var sv = SharpGL.SceneGraph.OpenGLSceneGraphExtensions.Project(gl, new SharpGL.SceneGraph.Vertex((float)points[i].X, (float)points[i].Y, (float)points[i].Z));
if (Math.Abs(sv.X - x) < 3 && Math.Abs(sv.Y - y) < 3)
{
points[i].OnMouse = true;
break;
}
}
}
if (!msDown) return;
int dx = e.X - oldX;
int dy = e.Y - oldY;
if (dy > 0) _rotationx += 0.5f;
else if (dy < 0) _rotationx -= 0.5f;
if (dx > 0) _rotationy += 0.5f;
else if (dx < 0) _rotationy -= 0.5f;
SetupViewport();
this.Invalidate();
}
private void on_MouseUp(object sender, MouseEventArgs e)
{
msDown = false;
Cursor = Cursors.Default;
}
private void on_MouseLeave(object sender, EventArgs e)
{
msDown = false;
}
}
核心代码如下
C#,SharpGL开发的3D图表控件相关推荐
- 用于金融科技应用开发的高性能图表控件
金钱使世界运转,因此,跟踪和控制金融交易和信息是当今互联世界中任何企业.金融机构或个人最重要的活动之一.为此,你需要金融技术应用. 根据不同的目的,金融技术应用可能有不同的功能,使其符合用户需要.例如 ...
- (转)基于MVC4+EasyUI的Web开发框架经验总结(4)--使用图表控件Highcharts
http://www.cnblogs.com/wuhuacong/p/3736564.html 在我们做各种应用的时候,我们可能都会使用到图表统计,以前接触过一些不同的图表控件,在无意中发现了图表控件 ...
- C# winform使用scottplot图表控件快速入门设置XY轴缩放
Hello大家好我是开箱测评小汪,在C#项目开发中使用图表控件,有时候我们希望放大或缩小图表控件来看数据细节和整体数据情况.所有本期课程将带介绍Scottplot图表控件如何来实现这个功能. 本期课程 ...
- android图表控件 坐标,android-charts 基于Java和Android开发的图形图表控件 | 李大仁博客...
王晓龙 April 8th, 2014 at 09:44 | #1 我再github上看到了你写的控件,给了我很大启发,我现在在做K线图一类的图表,正好用到了您开发的这款控件,但是有些地方使用的不太舒 ...
- 提供多种2D和3D图表类型以及组合图、仪表的图表控件CHARTING
.netCHARTING是一款功能强大的图表控件,利用.NET framework和GDI+为工作于ASP.NET和Winform的C#和VB.NET软件开发人 员提供可托管的图表解决方案,提供了多种 ...
- android开发原点表框架,Android图表控件MPAndroidChart——LineChart实现 XY轴、原点线的直尺刻度样式...
接上文: Android图表控件MPAndroidChart--曲线图LineChart的使用(多条曲线) 其他相关文章: Android图表控件MPAndroidChart的简单介绍(MPAndro ...
- 微软图表控件MsChart
转自:http://tech.ddvip.com/2008-11/122640479791375.html 昨天在网上看到了微软发布了.NET 3.5框架下的图表控件,第一时间抓下来看了一下,发觉功能 ...
- 基于.NET的图表控件解决方案
2019独角兽企业重金招聘Python工程师标准>>> .netCHARTING是一个非常棒的.NET图表控件,对中文支持非常好,而且操作方便,开发快速,既有webform 也有wi ...
- ProEssentials实时三维图表控件
原文来自方案网 http://www.fanganwang.com/Product-detail-item-1465.html,欢迎转载. 关键字:图表控件,工业图表,金融图表,工程图表 ProEss ...
- 三款ActiveX图表控件对比评测 TeeChart VS ProEssentials…
概述:本文分别对几款优秀的ActiveX图表控件:TeeChart Pro ActiveX.ProEssentials.ChartDirector作了优势分析,对比评测,希望对用户的图表选型有所帮助. ...
最新文章
- 为啥不能用uuid做MySQL的主键!?
- 数据中心基础设施建设方案
- 二、入门爬虫,爬取百度图片
- 纵横免root框架打不开应用怎么办_很好用的软件多开神奇安卓欧皇十框架!!!...
- mysql 列换行 表设计 设计_今天来讲一下怎么利用MySql进行库表设计
- win10怎么设置默认输入法_win10系统输入法失效打不了字怎么办
- workerman相关
- Atom打开报错:Cannot load the system dictionary for zh-CN
- 使用 matlab 数字图像处理(九)—— 去卷积(deconvolution,逆滤波复原)
- 【面试】前端面试人事问题
- 以太网和wifi协议
- ppt保存为高分辨率图片(ppt2016)
- 【定量分析、量化金融与统计学】统计推断基础 番外(3)---假设检验例题讲解
- 《JOEL说软件》中文版翻译质量令人失望
- 攻防世界 WEB Web_python_flask_sql_injection
- 音频电解电容应用方法及经验
- BZOJ 2565 最长双回文串
- pink老师学习之Echarts
- TPS62240DDCR同步降压DC-DC转换器
- Python pathlib Path