using System; using System.Collections.Generic; using System.Drawing.Drawing2D; using System.Drawing; using System.Linq; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; namespace Mesnac.Controls.ChemicalWeighing { /// 整个组件的代码辅助工具,提供了一个基础的类库方法 public class HslHelper { static HslHelper() { HslHelper.StringFormatDefault = new StringFormat(); HslHelper.StringFormatCenter = new StringFormat(); HslHelper.StringFormatCenter.Alignment = StringAlignment.Center; HslHelper.StringFormatCenter.LineAlignment = StringAlignment.Center; HslHelper.StringFormatLeft = new StringFormat(); HslHelper.StringFormatLeft.LineAlignment = StringAlignment.Center; HslHelper.StringFormatLeft.Alignment = StringAlignment.Near; HslHelper.StringFormatRight = new StringFormat(); HslHelper.StringFormatRight.LineAlignment = StringAlignment.Center; HslHelper.StringFormatRight.Alignment = StringAlignment.Far; HslHelper.StringFormatTopCenter = new StringFormat(); HslHelper.StringFormatTopCenter.Alignment = StringAlignment.Center; HslHelper.StringFormatTopCenter.LineAlignment = StringAlignment.Near; } /// 返回中间范围值数据,如果大于最大值,则返回最大值,如果小于最小值,则返回最小值 /// 最小值 /// 实际值 /// 最大值 /// 中间值信息 public static int Middle(int min, int value, int max) { if (value > max) return max; return value < min ? min : value; } /// 从一个矩形的图形中获取菱形的坐标数组 /// 矩形 /// 数组结果 public static Point[] GetRhombusFromRectangle(Rectangle rect) => new Point[5] { new Point(rect.X, rect.Y + rect.Height / 2), new Point(rect.X + rect.Width / 2, rect.Y + rect.Height - 1), new Point(rect.X + rect.Width - 1, rect.Y + rect.Height / 2), new Point(rect.X + rect.Width / 2, rect.Y), new Point(rect.X, rect.Y + rect.Height / 2) }; /// 计算绘图时的相对偏移值 /// 0-100分的最大值,就是指准备绘制的最大值 /// 0-100分的最小值,就是指准备绘制的最小值 /// 实际绘图区域的高度 /// 需要绘制数据的当前值 /// 相对于0的位置,还需要增加上面的偏值 public static float ComputePaintLocationY(int max, int min, int height, int value) => (double)(max - min) == 0.0 ? (float)height : (float)height - (float)(value - min) * 1f / (float)(max - min) * (float)height; /// 计算绘图Y轴时的相对偏移值 /// 0-100分的最大值,就是指准备绘制的最大值 /// 0-100分的最小值,就是指准备绘制的最小值 /// 实际绘图区域的高度 /// 需要绘制数据的当前值 /// 相对于0的位置,还需要增加上面的偏值 public static float ComputePaintLocationY(float max, float min, float height, float value) { if ((double)max - (double)min == 0.0) return height; float num = max - min; if ((double)num == 0.0) num = 1f; return height - (value - min) / num * height; } /// 计算绘图X轴时的相对偏移值 /// 0-100分的最大值,就是指准备绘制的最大值 /// 0-100分的最小值,就是指准备绘制的最小值 /// 实际绘图区域的宽度 /// 需要绘制数据的当前值 /// 相对于0的位置,还需要增加上面的偏值 public static float ComputePaintLocationX(float max, float min, float width, float value) { if ((double)max - (double)min == 0.0) return width; float num = max - min; if ((double)num == 0.0) num = 1f; return (value - min) / num * width; } /// 根据绘制的值计算原始的值信息 /// 0-100分的最大值,就是指准备绘制的最大值 /// 0-100分的最小值,就是指准备绘制的最小值 /// 实际绘图区域的高度 /// 实际绘制的位置信息 /// 实际的值信息 public static float ComputeValueFromPaintLocationY( float max, float min, float height, float paint) { if ((double)max - (double)min == 0.0) return max; float num = max - min; if ((double)num == 0.0) num = 1f; return (height - paint) * num / height + min; } /// 计算绘图时的相对偏移值 /// 坐标轴信息 /// 实际绘图区域的高度 /// 需要绘制数据的当前值 /// 相对于0的位置,还需要增加上面的偏值 public static float ComputePaintLocationY( ReferenceAxis referenceAxis, float height, float value) { return HslHelper.ComputePaintLocationY(referenceAxis.Max, referenceAxis.Min, height, value); } /// 绘制坐标系中的刻度线 /// 绘图对象 /// 画坐标轴的画笔 /// /// /// /// /// /// /// /// /// /// /// /// /// public static void PaintCoordinateDivide( Graphics g, System.Drawing.Pen penLine, System.Drawing.Pen penDash, Font font, System.Drawing.Brush brush, StringFormat sf, int degree, int max, int min, int width, int height, int left = 60, int right = 8, int up = 8, int down = 8) { for (int index = 0; index <= degree; ++index) { int num1 = (max - min) * index / degree + min; int num2 = (int)HslHelper.ComputePaintLocationY(max, min, height - up - down, num1) + up + 1; g.DrawLine(penLine, left - 1, num2, left - 4, num2); if (index != 0) g.DrawLine(penDash, left, num2, width - right, num2); g.DrawString(num1.ToString(), font, brush, (RectangleF)new Rectangle(-5, num2 - font.Height / 2, left, font.Height), sf); } } /// 根据指定的方向绘制一个箭头 /// /// /// /// /// public static void PaintTriangle( Graphics g, System.Drawing.Brush brush, Point point, int size, GraphDirection direction) { Point[] points = new Point[4]; switch (direction) { case GraphDirection.Upward: points[0] = new Point(point.X - size, point.Y); points[1] = new Point(point.X + size, point.Y); points[2] = new Point(point.X, point.Y - 2 * size); break; case GraphDirection.Leftward: points[0] = new Point(point.X, point.Y - size); points[1] = new Point(point.X, point.Y + size); points[2] = new Point(point.X - 2 * size, point.Y); break; case GraphDirection.Rightward: points[0] = new Point(point.X, point.Y - size); points[1] = new Point(point.X, point.Y + size); points[2] = new Point(point.X + 2 * size, point.Y); break; default: points[0] = new Point(point.X - size, point.Y); points[1] = new Point(point.X + size, point.Y); points[2] = new Point(point.X, point.Y + 2 * size); break; } points[3] = points[0]; g.FillPolygon(brush, points); } /// 绘制向左或是向右的箭头,例如 << 或是 >> /// 画刷资源 /// 画笔资源 /// 绘制的矩形 /// 方向信息 public static void DrawLeftRight( Graphics g, System.Drawing.Pen pen, Rectangle rectangle, GraphDirection direction) { if (direction == GraphDirection.Leftward) { g.DrawLines(pen, new Point[3] { new Point(rectangle.X + rectangle.Width / 2, rectangle.Y), new Point(rectangle.X, rectangle.Y + rectangle.Height / 2), new Point(rectangle.X + rectangle.Width / 2, rectangle.Y + rectangle.Height) }); g.DrawLines(pen, new Point[3] { new Point(rectangle.X + rectangle.Width, rectangle.Y), new Point(rectangle.X + rectangle.Width / 2, rectangle.Y + rectangle.Height / 2), new Point(rectangle.X + rectangle.Width, rectangle.Y + rectangle.Height) }); } else { if (direction != GraphDirection.Rightward) return; g.DrawLines(pen, new Point[3] { new Point(rectangle.X, rectangle.Y), new Point(rectangle.X + rectangle.Width / 2, rectangle.Y + rectangle.Height / 2), new Point(rectangle.X, rectangle.Y + rectangle.Height) }); g.DrawLines(pen, new Point[3] { new Point(rectangle.X + rectangle.Width / 2, rectangle.Y), new Point(rectangle.X + rectangle.Width, rectangle.Y + rectangle.Height / 2), new Point(rectangle.X + rectangle.Width / 2, rectangle.Y + rectangle.Height) }); } } /// 根据指定的方向绘制一个箭头 /// /// /// /// /// public static void PaintTriangle( Graphics g, System.Drawing.Brush brush, PointF point, int size, GraphDirection direction) { PointF[] points = new PointF[4]; switch (direction) { case GraphDirection.Upward: points[0] = new PointF(point.X - (float)size, point.Y); points[1] = new PointF(point.X + (float)size, point.Y); points[2] = new PointF(point.X, point.Y - (float)(2 * size)); break; case GraphDirection.Leftward: points[0] = new PointF(point.X, point.Y - (float)size); points[1] = new PointF(point.X, point.Y + (float)size); points[2] = new PointF(point.X - (float)(2 * size), point.Y); break; case GraphDirection.Rightward: points[0] = new PointF(point.X, point.Y - (float)size); points[1] = new PointF(point.X, point.Y + (float)size); points[2] = new PointF(point.X + (float)(2 * size), point.Y); break; default: points[0] = new PointF(point.X - (float)size, point.Y); points[1] = new PointF(point.X + (float)size, point.Y); points[2] = new PointF(point.X, point.Y + (float)(2 * size)); break; } points[3] = points[0]; g.FillPolygon(brush, points); } /// /// 一个通用的数组新增个数方法,会自动判断越界情况,越界的情况下,会自动的截断或是填充 -> /// A common array of new methods, will automatically determine the cross-border situation, in the case of cross-border, will be automatically truncated or filled /// /// 数据类型 /// 原数据 /// 等待新增的数据 /// 原数据的最大值 public static void AddArrayData(ref T[] array, T[] data, int max) { if (data == null || data.Length == 0) return; if (array.Length == max) { Array.Copy((Array)array, data.Length, (Array)array, 0, array.Length - data.Length); Array.Copy((Array)data, 0, (Array)array, array.Length - data.Length, data.Length); } else if (array.Length + data.Length > max) { T[] objArray = new T[max]; for (int index = 0; index < max - data.Length; ++index) objArray[index] = array[index + (array.Length - max + data.Length)]; for (int index = 0; index < data.Length; ++index) objArray[objArray.Length - data.Length + index] = data[index]; array = objArray; } else { T[] objArray = new T[array.Length + data.Length]; for (int index = 0; index < array.Length; ++index) objArray[index] = array[index]; for (int index = 0; index < data.Length; ++index) objArray[objArray.Length - data.Length + index] = data[index]; array = objArray; } } /// 尺寸转换,计算旋转后的尺寸。 /// /// /// public static SizeF ConvertSize(SizeF size, float angle) { System.Drawing.Drawing2D.Matrix matrix = new System.Drawing.Drawing2D.Matrix(); matrix.Rotate(angle); PointF[] pts = new PointF[4]; pts[0].X = (float)(-(double)size.Width / 2.0); pts[0].Y = (float)(-(double)size.Height / 2.0); pts[1].X = (float)(-(double)size.Width / 2.0); pts[1].Y = size.Height / 2f; pts[2].X = size.Width / 2f; pts[2].Y = size.Height / 2f; pts[3].X = size.Width / 2f; pts[3].Y = (float)(-(double)size.Height / 2.0); matrix.TransformPoints(pts); float num1 = float.MaxValue; float num2 = float.MinValue; float num3 = float.MaxValue; float num4 = float.MinValue; foreach (PointF pointF in pts) { if ((double)pointF.X < (double)num1) num1 = pointF.X; if ((double)pointF.X > (double)num2) num2 = pointF.X; if ((double)pointF.Y < (double)num3) num3 = pointF.Y; if ((double)pointF.Y > (double)num4) num4 = pointF.Y; } return new SizeF(num2 - num1, num4 - num3); } /// 绘制旋转文本 /// /// /// /// /// /// /// public static void DrawString( Graphics g, string s, Font font, System.Drawing.Brush brush, PointF point, StringFormat format, float angle) { System.Drawing.Drawing2D.Matrix transform1 = g.Transform; System.Drawing.Drawing2D.Matrix transform2 = g.Transform; transform2.RotateAt(angle, point); g.Transform = transform2; g.DrawString(s, font, brush, point, format); g.Transform = transform1; } private static int GetPow(int digit) { int pow = 1; for (int index = 0; index < digit; ++index) pow *= 10; return pow; } /// 将int数组转换为double数组 /// int数组值 /// 结果值 public static double[] TranlateArrayToDouble(int[] values) { if (values == null) return (double[])null; double[] numArray = new double[values.Length]; for (int index = 0; index < values.Length; ++index) numArray[index] = (double)values[index]; return numArray; } /// 将float数组转换为double数组值 /// float数组值 /// 结果值 public static double[] TranlateArrayToDouble(float[] values) { double[] numArray = new double[values.Length]; for (int index = 0; index < values.Length; ++index) numArray[index] = (double)values[index]; return numArray; } /// 获得数据的上限值,这个上限值是自动计算的。 /// 数据值 /// 数据值 public static int CalculateMaxSectionFrom(double[] values) { double a = ((IEnumerable)values).Max(); if (a <= 5.0) return 5; if (a <= 9.0) return 10; int int32 = Convert.ToInt32(Math.Ceiling(a)); int digit = int32.ToString().Length - 2; int num = int.Parse(int32.ToString().Substring(0, 2)); if (num < 11) return 12 * HslHelper.GetPow(digit); if (num < 13) return 14 * HslHelper.GetPow(digit); if (num < 15) return 16 * HslHelper.GetPow(digit); if (num < 17) return 18 * HslHelper.GetPow(digit); if (num < 19) return 20 * HslHelper.GetPow(digit); if (num < 21) return 22 * HslHelper.GetPow(digit); if (num < 23) return 24 * HslHelper.GetPow(digit); if (num < 25) return 26 * HslHelper.GetPow(digit); if (num < 27) return 28 * HslHelper.GetPow(digit); if (num < 29) return 30 * HslHelper.GetPow(digit); if (num < 33) return 34 * HslHelper.GetPow(digit); if (num < 40) return 40 * HslHelper.GetPow(digit); if (num < 50) return 50 * HslHelper.GetPow(digit); if (num < 60) return 60 * HslHelper.GetPow(digit); if (num < 80) return 80 * HslHelper.GetPow(digit); return num < 95 ? 100 * HslHelper.GetPow(digit) : 100 * HslHelper.GetPow(digit); } /// public static int CalculateMaxSectionFrom(Dictionary values) => HslHelper.CalculateMaxSectionFrom(values.Select, double>((Func, double>)(m => ((IEnumerable)m.Value).Max())).ToArray()); /// 获取当前颜色更淡的颜色信息 /// 颜色信息 /// 颜色 public static System.Drawing.Color GetColorLight(System.Drawing.Color color) => HslHelper.GetColorLight(color, 40); /// 获取当前颜色更深的颜色信息 /// 颜色信息 /// 颜色 public static System.Drawing.Color GetColorDeep(System.Drawing.Color color) => HslHelper.GetColorLight(color, -40); /// 获取当前颜色更淡的颜色信息,需要指定系数0-100,0时是原来的原色,100时是纯白色 /// 颜色信息 /// 获取颜色的系数信息 /// 颜色 public static System.Drawing.Color GetColorLight(System.Drawing.Color color, int scale) => scale > 0 ? System.Drawing.Color.FromArgb((int)color.R + ((int)byte.MaxValue - (int)color.R) * scale / 100, (int)color.G + ((int)byte.MaxValue - (int)color.G) * scale / 100, (int)color.B + ((int)byte.MaxValue - (int)color.B) * scale / 100) : System.Drawing.Color.FromArgb((int)color.R + (int)color.R * scale / 100, (int)color.G + (int)color.G * scale / 100, (int)color.B + (int)color.B * scale / 100); /// 获取颜色的偏移信息 /// 颜色值 /// 颜色偏移信息 /// 颜色值 public static System.Drawing.Color GetColorOffset(System.Drawing.Color color, int offset) { int red = (int)color.R + offset; if (red < 0) red = 0; if (red > (int)byte.MaxValue) red = (int)byte.MaxValue; int green = (int)color.G + offset; if (green < 0) green = 0; if (green > (int)byte.MaxValue) green = (int)byte.MaxValue; int blue = (int)color.B + offset; if (blue < 0) blue = 0; if (blue > (int)byte.MaxValue) blue = (int)byte.MaxValue; return System.Drawing.Color.FromArgb(red, green, blue); } /// 获取当前颜色更淡的颜色信息 /// 颜色信息 /// 颜色 public static System.Drawing.Color GetColorLightFive(System.Drawing.Color color) => HslHelper.GetColorLight(color, 50); /// 获取当前颜色更淡的颜色信息 /// 颜色信息 /// 颜色 public static System.Windows.Media.Color GetColorLight(System.Windows.Media.Color color) => System.Windows.Media.Color.FromRgb((byte)((uint)color.R + (uint)(((int)byte.MaxValue - (int)color.R) * 40 / 100)), (byte)((uint)color.G + (uint)(((int)byte.MaxValue - (int)color.G) * 40 / 100)), (byte)((uint)color.B + (uint)(((int)byte.MaxValue - (int)color.B) * 40 / 100))); /// 获取当前颜色更淡的颜色信息 /// 颜色信息 /// 颜色 public static System.Windows.Media.Color GetColorLightFive(System.Windows.Media.Color color) => System.Windows.Media.Color.FromRgb((byte)((uint)color.R + (uint)(((int)byte.MaxValue - (int)color.R) * 50 / 100)), (byte)((uint)color.G + (uint)(((int)byte.MaxValue - (int)color.G) * 50 / 100)), (byte)((uint)color.B + (uint)(((int)byte.MaxValue - (int)color.B) * 50 / 100))); /// 从字符串表示的点位信息里解析出真正的点位信息 /// 字符串的点位 /// 原来的长度信息 /// 原来的高度信息 /// 实际的宽度信息 /// 实际的高度信息 /// x偏移量信息 /// y偏移量信息 /// public static PointF[] GetPointsFrom( string points, float soureWidth, float sourceHeight, float width, float height, float dx = 0.0f, float dy = 0.0f) { string[] strArray = points.Split(new char[1] { ' ' }, StringSplitOptions.RemoveEmptyEntries); PointF[] pointsFrom = new PointF[strArray.Length]; for (int index = 0; index < strArray.Length; ++index) { int length = strArray[index].IndexOf(','); float single1 = Convert.ToSingle(strArray[index].Substring(0, length)); float single2 = Convert.ToSingle(strArray[index].Substring(length + 1)); pointsFrom[index] = new PointF(width * (single1 + dx) / soureWidth, height * (single2 + dy) / sourceHeight); } return pointsFrom; } /// 根据矩形及其各个定点的配置信息,获取圆角的路径信息,可以指定每个定点的圆角情况 /// /// /// /// /// /// /// public static GraphicsPath GetRoundRectange( Rectangle rectangle, int radius, bool topLeft, bool topRight, bool buttomRight, bool buttomLeft) { GraphicsPath roundRectange = new GraphicsPath(); Point pt1_1 = new Point(rectangle.X + (topLeft ? radius : 0), rectangle.Y); Point pt2_1 = new Point(rectangle.X + rectangle.Width - 1 - (topRight ? radius : 0), rectangle.Y); roundRectange.AddLine(pt1_1, pt2_1); if (topRight && radius > 0) roundRectange.AddArc(rectangle.X + rectangle.Width - radius * 2 - 1, rectangle.Y, radius * 2, radius * 2, 270f, 90f); Point pt1_2 = new Point(rectangle.X + rectangle.Width - 1, rectangle.Y + (topRight ? radius : 0)); Point pt2_2 = new Point(rectangle.X + rectangle.Width - 1, rectangle.Y + rectangle.Height - 1 - (buttomRight ? radius : 0)); roundRectange.AddLine(pt1_2, pt2_2); if (buttomRight && radius > 0) roundRectange.AddArc(rectangle.X + rectangle.Width - radius * 2 - 1, rectangle.Y + rectangle.Height - radius * 2 - 1, radius * 2, radius * 2, 0.0f, 90f); Point pt1_3 = new Point(rectangle.X + rectangle.Width - 1 - (buttomRight ? radius : 0), rectangle.Y + rectangle.Height - 1); Point pt2_3 = new Point(rectangle.X + (buttomLeft ? radius : 0), rectangle.Y + rectangle.Height - 1); roundRectange.AddLine(pt1_3, pt2_3); if (buttomLeft && radius > 0) roundRectange.AddArc(rectangle.X, rectangle.Y + rectangle.Height - radius * 2 - 1, radius * 2, radius * 2, 90f, 90f); Point pt1_4 = new Point(rectangle.X, rectangle.Y + rectangle.Height - 1 - (buttomLeft ? radius : 0)); Point pt2_4 = new Point(rectangle.X, rectangle.Y + (topLeft ? radius : 0)); roundRectange.AddLine(pt1_4, pt2_4); if (topLeft && radius > 0) roundRectange.AddArc(rectangle.X, rectangle.Y, radius * 2, radius * 2, 180f, 90f); return roundRectange; } private static string FloatMatchEvaluator(Match m) => m.Value.Length == 5 ? m.Value.Substring(0, 3) : m.Value.Substring(0, 2); /// 获取浮点数值的格式化文本信息,如果发生了异常,则返回错误消息 /// 格式化信息 /// 值信息 /// 是否保留0的信息 /// 等待显示的文本 public static string GetFormatString(string format, float value, bool remainZero = false) { try { string input = string.Format(format, (object)value); return remainZero ? input : Regex.Replace(input, "[Ee][+-][0]+", new MatchEvaluator(HslHelper.FloatMatchEvaluator)); } catch { return "Wrong"; } } /// 矩形中间的字符串对齐机制 public static StringFormat StringFormatCenter { get; set; } /// 矩形的左侧中间的对齐机制 public static StringFormat StringFormatLeft { get; set; } /// 矩形的右侧的中间对齐机制 public static StringFormat StringFormatRight { get; set; } /// 矩形的的默认的左上角对齐的机制 public static StringFormat StringFormatDefault { get; set; } /// 矩形的下方中间的对齐的机制 public static StringFormat StringFormatTopCenter { get; set; } } }