另外一个版本是使用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; ? ? ? ? } ? ? }
核心代码如下
|