using Bro.Common.Helper; using Bro.Common.Interface; using Newtonsoft.Json; using System; using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.Threading.Tasks; using static Bro.Common.Helper.EnumHelper; namespace Bro.Common.Model { /// /// 自定义的点坐标类型 /// public class CustomizedPoint : IComplexDisplay, ICSVOutput, INotifyPropertyChanged { private float x = 0; [Category("坐标设置")] [Description("X坐标")] public float X { get => x; set { if (value != x) { x = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("X")); } } } private float y = 0; [Category("坐标设置")] [Description("Y坐标")] public float Y { get => y; set { if (value != y) { y = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Y")); } } } public CustomizedPoint() { } public CustomizedPoint(float x, float y) { X = x; Y = y; } public CustomizedPoint(Point p) { X = p.X; Y = p.Y; } public CustomizedPoint(PointF p) { X = p.X; Y = p.Y; } public CustomizedPoint(CustomizedPoint p) { X = p.X; Y = p.Y; } /// /// 根据PLC的读取数值获取点位坐标 /// /// 0:X低位 1:X高位 2:Y低位 3:Y高位 public CustomizedPoint(List plcValues) { if (plcValues == null || plcValues.Count != 4) return; var list = plcValues.ParseUnsignShortListToInt(); X = list[0]; Y = list[1]; } public event PropertyChangedEventHandler PropertyChanged; public static List GetPoints(List Xs, List Ys) { List points = new List(); for (int i = 0; i < Xs.Count && i < Ys.Count; i++) { points.Add(new CustomizedPoint((float)Xs[i], (float)Ys[i])); } return points; } public static double GetDistance(CustomizedPoint p1, CustomizedPoint p2) { return Math.Sqrt(Math.Pow((p1.X - p2.X), 2) + Math.Pow((p1.Y - p2.Y), 2)); } public virtual string GetDisplayText() { return string.Format("X:{0};Y:{1}", X, Y); } public virtual string GetCSVHead() { return "X,Y"; } public virtual string GetCSVData() { return X.ToString("f3") + ";" + Y.ToString("f3"); } //public static double GetCustomizedPointDistance(CustomizedPoint startPoint, CustomizedPoint endPoint) //{ // return Math.Sqrt(Math.Pow(endPoint.X - startPoint.X, 2) + Math.Pow(endPoint.Y - startPoint.Y, 2)); //} public CustomizedPoint OffsetClone(CustomizedPoint point) { return new CustomizedPoint(X + point.X, Y + point.Y); } public void Offset(CustomizedPoint point) { X += point.X; Y += point.Y; } public static CustomizedPoint operator -(CustomizedPoint p1, CustomizedPoint p2) { return new CustomizedPoint(p1.X - p2.X, p1.Y - p2.Y); } public static CustomizedPoint operator +(CustomizedPoint p1, CustomizedPoint p2) { return new CustomizedPoint(p1.X + p2.X, p1.Y + p2.Y); } } /// /// 螺丝平面测量点位 /// public class ScrewPlanPoint : CustomizedPoint { [Category("坐标设置")] [Description("基准校正后的Z坐标")] [Browsable(false)] [JsonIgnore] public float Z { get; set; } [Category("点位设置")] [Description("点位索引,用于区分位移传感器的数据来源")] public int Index { get; set; } [Category("点位设置")] [Description("是否是基准点位,true:是基准点位;false:是测量点位")] public bool IsBasePoint { get; set; } [Category("平面度")] [Description("Z坐标基准")] public float Z_Correction { get; set; } private float? flatness = null; [Category("平面度")] [Description("平面度/高度值")] [Browsable(false)] [JsonIgnore] public float? Flatness { get => flatness; set { flatness = value; if (flatness != null && !IsBasePoint) { IsOK = flatness.Value <= HeightThreshold; } } } private float z_original = 0; [Category("坐标设置")] [Description("获取的原始Z坐标")] [Browsable(false)] [JsonIgnore] public float Z_Original { get { return z_original; } set { z_original = value; Z = z_original - Z_Correction; } } [Category("标准设置")] [Description("高度阈值。大于该值认为高度超标")] public float HeightThreshold { get; set; } = 17000; [Browsable(false)] [JsonIgnore] public bool IsOK { get; set; } = true; public override string GetCSVData() { //if (IsBasePoint) //{ // return "NuN"; //} //return Flatness == null ? "NA" : Flatness.Value.ToString("f3"); //return $"{Z.ToString("f2")},{Z_Original.ToString("f2")},{Z_Correction.ToString("f2")},{(Flatness == null ? "NA" : Flatness.Value.ToString("f2"))}"; return $"{(IsBasePoint ? "NA" : (IsOK ? "OK" : "IsFloating"))},{(Flatness ?? 0).ToString("f2")},{Z.ToString("f2")},{Z_Original.ToString("f2")},{Z_Correction.ToString("f2")}"; } public override string GetCSVHead() { //if (IsBasePoint) // return "NuN"; //return "Screw" + Index + " Flatness"; string prefix = "Screw"; if (IsBasePoint) { prefix = "Base"; } //return $"{prefix}{Index}Height,{prefix}{Index}Measurement,{prefix}{Index}Calibration,{prefix}{Index}Flatness"; return $"{prefix}{Index}IsFloating,{prefix}{Index}Height,{prefix}{Index}Calib_Height,{prefix}{Index}Measurement,{prefix}{Index}Calibration"; } } public class CustomizedPointWithAngle : CustomizedPoint { [Category("坐标设置")] [Description("角度")] [DisplayName("角度")] public float Angle { get; set; } public CustomizedPointWithAngle() { } public CustomizedPointWithAngle(float x, float y, float r) { X = x; Y = y; Angle = r; } //public CustomizedPointWithAngle(CustomizedPointWithAngle point) //{ //} /// /// 根据PLC的读取数值获取点位坐标 /// /// 0:X低位 1:X高位 2:Y低位 3:Y高位 4:R低位 5:R高位 public CustomizedPointWithAngle(List plcValues) { if (plcValues == null || plcValues.Count != 6) return; var list = plcValues.ParseUnsignShortListToInt(); X = list[0]; Y = list[1]; Angle = list[2]; } public static List GetPoints(List Xs, List Ys, List Rs) { List points = new List(); for (int i = 0; i < Xs.Count && i < Ys.Count; i++) { points.Add(new CustomizedPointWithAngle((float)Xs[i], (float)Ys[i], (float)Rs[i])); } return points; } public override string GetDisplayText() { return base.GetDisplayText() + ";Angle:" + Angle.ToString(); } } public class AvailablePoint : CustomizedPointWithAngle, ICloneable { public bool IsAvailable { get; set; } = false; public bool IsUsed { get; set; } = false; public AvailablePoint() { } public override string GetDisplayText() { return base.GetDisplayText() + (IsAvailable ? "" : " 不可用 "); } public object Clone() { AvailablePoint point = new AvailablePoint { //point.DataFrom(this); X = X, Y = Y, Angle = Angle, IsAvailable = IsAvailable }; return point; } } public class CalibrationPoint : IComplexDisplay, INotifyPropertyChanged { [Category("标定坐标")] [Description("平台坐标-X")] public float X { get; set; } [Category("标定坐标")] [Description("平台坐标-X")] public float Y { get; set; } [Category("像素坐标")] [Description("像素坐标-U")] public float U { get; set; } [Category("像素坐标")] [Description("像素坐标-V")] public float V { get; set; } private bool isBasePoint = false; [Category("快捷设置")] [Description("是否基准点")] [DisplayName("基准点")] public bool IsBasePoint { get => isBasePoint; set { isBasePoint = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("IsBasePoint")); } } public CalibrationPoint() { } public CalibrationPoint(PointF p, bool isImagePoint = true) { if (isImagePoint) { U = p.X; V = p.Y; } else { X = (int)p.X; Y = (int)p.Y; } } public CalibrationPoint(CustomizedPoint imagePoint, CustomizedPoint platPoint) { U = imagePoint.X; V = imagePoint.Y; X = (int)platPoint.X; Y = (int)platPoint.Y; } public event PropertyChangedEventHandler PropertyChanged; public string GetDisplayText() { return string.Format("X:{0},Y:{1};U:{2},V:{3}", X, Y, U.ToString("f3"), V.ToString("f3")); } } public class DirectionAidPoint : AvailablePoint { //private PriorityDirection? direction = null; public PriorityDirection? Direction { get; set; } //{ // get => direction; // set // { // if (value != null) // { // if (value == PriorityDirection.X) // { // MainAxisValue = X; // MinorAxisValue = Y; // } // else // { // MainAxisValue = Y; // MinorAxisValue = X; // } // } // direction = value; // } //} public float MainAxisValue { get => ((Direction ?? PriorityDirection.X) == PriorityDirection.X) ? X : Y; set { if ((Direction ?? PriorityDirection.X) == PriorityDirection.X) { X = value; } else { Y = value; } } } public float MinorAxisValue { get => ((Direction ?? PriorityDirection.X) == PriorityDirection.X) ? Y : X; set { if ((Direction ?? PriorityDirection.X) == PriorityDirection.X) { Y = value; } else { X = value; } } } public DirectionAidPoint() { } public DirectionAidPoint(CustomizedPoint p) { X = p.X; Y = p.Y; if (p is CustomizedPointWithAngle temp) { Angle = temp.Angle; } } public DirectionAidPoint(float x, float y) { X = x; Y = y; } } public class ComplexPoint : ICSVOutput, INotifyPropertyChanged, IComplexDisplay { public DirectionAidPoint ImagePoint { get; set; } public DirectionAidPoint ImagePointAfterRotation { get; set; } public DirectionAidPoint PlatPoint { get; set; } public bool IsDirectionPositive { get; set; } public bool IsTurnPoint { get; set; } = false; //public bool IsTurnPoint { get; set; } = false; //public int X { get; set; } //public int Y { get; set; } #region For UI private bool? isCurrent = null; /// /// 是否时当前输出给PLC的点位,主要是为了方便界面显示时做区分 /// public bool? IsCurrent { get => isCurrent; set { if (isCurrent != value) { isCurrent = value; //PropertyChanged?.BeginInvoke(this, new PropertyChangedEventArgs("IsCurrent"), null, null); Task.Run(() => { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("IsCurrent")); }); } } } private DateTime updateTime = DateTime.Now; public DateTime UpdateTime { get => updateTime; set { if (updateTime != value) { updateTime = value; PropertyChanged?.BeginInvoke(this, new PropertyChangedEventArgs("UpdateTime"), null, null); } } } public event PropertyChangedEventHandler PropertyChanged; #endregion public string GetCSVData() { if (ImagePoint == null) { ImagePoint = new DirectionAidPoint(0, 0); } return $"{ImagePoint.X.ToString("f3")},{ImagePoint.Y.ToString("f3")},{PlatPoint.X.ToString("f3")},{PlatPoint.Y.ToString("f3")},{PlatPoint.Angle.ToString("f3")},{(PlatPoint.IsAvailable ? "" : "不可用")}"; } public string GetCSVHead() { return "U,V,X,Y,Angle,IsAvailable"; } public string GetDisplayText() { return $"U:{ImagePoint.X} V:{ImagePoint.Y} X:{PlatPoint.X} Y:{PlatPoint.Y}"; } } public static class CustomizedPointHelper { public static string GetCustomizedPointsCSVHead(this List points, string prefix, int count = 0) { string head = ""; if (count == 0) { count = points.Count; } for (int i = 1; i <= count; i++) { head += prefix + "_" + i.ToString() + "_X,"; head += prefix + "_" + i.ToString() + "_Y,"; } return head.TrimEnd(new char[] { ',' }); } public static string GetCustomizedPointsCSVData(this List points, int count = 0, bool isXYInvert = false) { string data = ""; if (count == 0) { count = points.Count; } for (int i = 0; i < count; i++) { if (points != null && i < points.Count) { if (isXYInvert) { data += points[i].Y.ToString("f3") + "," + points[i].X.ToString("f3") + ","; } else { data += points[i].X.ToString("f3") + "," + points[i].Y.ToString("f3") + ","; } } else { data += "NA,NA,"; } } return data.TrimEnd(new char[] { ',' }); //return string.Join(",", points.Select(p => p.X.ToString("f3") + "," + p.Y.ToString("f3"))); } public static string GetCustomizedPointGGRCSVHead(this List points) { string head = ""; for (int i = 1; i <= points.Count; i++) { head += i.ToString() + "_X,"; head += i.ToString() + "_Y,"; } if (points.Count >= 2) { for (int i = 1; i <= points.Count; i++) { for (int j = i + 1; j <= points.Count; j++) { head += (i + "_" + j + "_Dist,"); } } } return head.TrimEnd(new char[] { ',' }); } public static string GetCustomizedPointsGRRCSVData(this List points) { string data = ""; for (int i = 0; i < points.Count; i++) { data += points[i].X.ToString("f3") + "," + points[i].Y.ToString("f3") + ","; } if (points.Count >= 2) { for (int i = 1; i <= points.Count; i++) { for (int j = i + 1; j <= points.Count; j++) { data += (CustomizedPoint.GetDistance(points[i - 1], points[j - 1]).ToString("f3") + ","); } } } return data.TrimEnd(new char[] { ',' }); } } public class RobotPoint : IComplexDisplay { [Category("点位信息")] [Description("坐标X")] public float X { get; set; } [Category("点位信息")] [Description("坐标Y")] public float Y { get; set; } [Category("点位信息")] [Description("坐标Z")] public float Z { get; set; } [Category("点位信息")] [Description("角度A")] public float A { get; set; } [Category("点位信息")] [Description("角度B")] public float B { get; set; } [Category("点位信息")] [Description("角度C")] public float C { get; set; } public string GetDisplayText() { return $"X:{X.ToString()} Y:{Y.ToString()} Z:{Z.ToString()} A:{A.ToString()} B:{B.ToString()} C:{C.ToString()}"; } public double[] GetArray() { return new double[] { X, Y, Z, A, B, C }; } public static RobotPoint GetRobotPointByArray(double[] array) { if (array.Length != 6) { return null; } RobotPoint point = new RobotPoint { X = (float)array[0], Y = (float)array[1], Z = (float)array[2], A = (float)array[3], B = (float)array[4], C = (float)array[5] }; return point; } public static float GetDistance(RobotPoint pointA, RobotPoint pointB) { return (float)Math.Sqrt(Math.Pow(pointA.X - pointB.X, 2) + Math.Pow(pointA.Y - pointB.Y, 2) + Math.Pow(pointA.Z - pointB.Z, 2)); } } }