[C#] 绘制函数图像. 可拖动, 可缩放, 可调整精度 您所在的位置:网站首页 如何绘制二次函数曲线图形图片 [C#] 绘制函数图像. 可拖动, 可缩放, 可调整精度

[C#] 绘制函数图像. 可拖动, 可缩放, 可调整精度

2024-07-09 23:55| 来源: 网络整理| 查看: 265

欸嘿, 这就是程序图了, 通过鼠标拖拽可以移动, 鼠标滚轮可以缩放, 右下角还可以选择要绘制的函数. 项目仓库链接在文章末尾

基本原理:

Graphics 绘图, 不用我说了吧? 如果你不是很懂, 留言, 我会专门写一篇文章来介绍 Graphics.

带入求值, 没啥难的. 线是一个个点连起来的, 也就是: 然后, 标尺, 也是一个个线呗, 那个数字的话, 就是这个: 填充小三角的话, 就是这个:

关于优化:

首先是计算问题, 保证仅仅计算需要显示的区域, 区域外的坐标不予以计算, 以节省资源.

然后是闪屏问题, 使用BufferedGraphics, 既能解决闪屏问题, 又不会像Bitmap缓冲那样闪屏.

关于绘图闪屏问题, 网上有很多解决方案, 最核心的, 无非是双缓冲, 也就是先将图绘制到缓冲区, 再将缓冲区的内容绘制到屏幕上.   实现双缓冲有两种方式, 一就是通过创建一个Bitmap, 将图画到Bitmap上, 然后画完之后, 再将Bitmap画到屏幕上(Graphics.DrawImage()), 缺点是会造成撕裂问题. 第二种方式是 BufferedGraphics, 这是一个比Bitmap更好用的东西, 不会造成撕裂.

封装一下: using System; using System.Collections.Generic; using System.Drawing; using System.Linq; namespace Null.FuncDraw { public static class FuncDraw { /// /// 根据数字坐标获取像素位置 /// /// x坐标 /// y坐标 /// 原点位置 /// 原点位置 /// 缩放 /// 像素位置 public static Point GetPointFromCoords(double xCoord, double yCoord, int xOffset, int yOffset, double scale) { return new Point((int)(xCoord * scale + xOffset), (int)(-yCoord * scale + yOffset)); } /// /// /// /// 数字坐标 /// 原点位置 /// 缩放 /// 像素位置 public static Point GetPointFromCoords(PointF coords, Point offset, double scale) { return new Point((int)(coords.X * scale + offset.X), (int)(-coords.Y * scale + offset.Y)); } /// /// 根据像素位置获取数字坐标 /// /// 水平位置 /// 竖直位置 /// 原点位置 /// 原点位置 /// 缩放 /// 输出: 数字X坐标 /// 输出: 数字Y坐标 public static void GetCoordsFromPoint(int x, int y, int xOffset, int yOffset, double scale, out double xCoord, out double yCoord) { xCoord = (x - xOffset) / scale; yCoord = -((y - yOffset) / scale); return; } /// /// 根据像素长度返回数字 /// /// 像素长度 /// 缩放 /// 数字 public static double GetNumberFromPixel(int length, double scale) { return length / scale; } /// /// 根据数字来获取它距离原点的像素长度 /// /// 数字 /// 缩放 /// 像素长度 public static double GetPixelFromNumber(int number, double scale) { return number * scale; } /// /// 画函数图像 /// /// 要画的函数 /// X的取值 /// 绘图Graphics /// 画线所用的Pen /// 画函数的区域 /// 原点的位置 /// 原点的位置 /// 缩放参数 public static void DrawFunc(Func func, IEnumerable inputs, Graphics graphics, Pen pen, Rectangle drawArea, int xOffset, int yOffset, double scale) { double[] nums = inputs.ToArray(); Point[] coords = new Point[nums.Length]; int drawAreaLeft = drawArea.X, drawAreaRight = drawAreaLeft + drawArea.Width, drawAreaTop = drawArea.Y, drawAreaBottom = drawAreaTop + drawArea.Height; double y; for (int i = 0, len = nums.Length; i Point point1 = coords[i - 1]; Point point2 = coords[i]; point1xIn1 = point1.X >= drawAreaLeft; point1xIn2 = point1.X = drawAreaTop; point1yIn2 = point1.Y = drawAreaLeft; point2xIn2 = point2.X = drawAreaTop; point2yIn2 = point2.Y }; Point yTop = new Point(xOffset, drawArea.Y), yBottom = new Point(xOffset, drawArea.Y + drawArea.Height), // 确认轴的位置 xLeft = new Point(drawArea.X, yOffset), xRight = new Point(drawArea.X + drawArea.Width, yOffset); graphics.DrawLine(pen, yTop, yBottom); // 画轴 graphics.DrawLine(pen, xLeft, xRight); int triangleHeight = (int)(Math.Tan(Math.PI / 3) * barLength); // 坐标轴末端小三角的高度 Point[] triangle1 = new Point[] { yTop, new Point(yTop.X - barLength, yTop.Y + triangleHeight), new Point(yTop.X + barLength, yTop.Y + triangleHeight) }, triangle2 = new Point[] { xRight, new Point(xRight.X - triangleHeight, xRight.Y + barLength), new Point(xRight.X - triangleHeight, xRight.Y - barLength) }; graphics.FillPolygon(brush, triangle1); // 画三角 graphics.FillPolygon(brush, triangle2); foreach (double x in xNumbers) { Point numBase = GetPointFromCoords(x, 0, xOffset, yOffset, scale); Point numEnd = new Point(numBase.X, numBase.Y - barLength); graphics.DrawLine(pen, numBase, numEnd); // 画x轴数 drawText(numBase, x); } foreach (double y in yNumbers) { Point numBase = GetPointFromCoords(0, y, xOffset, yOffset, scale); Point numEnd = new Point(numBase.X + barLength, numBase.Y); graphics.DrawLine(pen, numBase, numEnd); // 画y轴数 drawText(numBase, y); } } } } 注意事项:

Graphics 在绘制某些超级远的东西时, 例如这个坐标时 (2147483647,2147483647), 总之就是非常大, 那可能会不能绘制, 报 Overflow 异常 (已解决)

还有一些要用的内容:

CSDN 文章: C# 中的 Range 函数 CSDN 文章: C# IEnumerable 连接, 将迭代器串起来

更新记录:

最新版本已经支持自定义函数表达式

项目: 项目仓库: https://github.com/SlimeNull/Null.FuncDraw


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有