using ScottPlot.Plottable; using ScottPlot; using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; using Plot3D; // enums using eRaster = Plot3D.Editor3D.eRaster; using ePolygonMode = Plot3D.Editor3D.ePolygonMode; using eSelEvent = Plot3D.Editor3D.eSelEvent; using eSelType = Plot3D.Editor3D.eSelType; using eObjType = Plot3D.Editor3D.eObjType; using eTooltip = Plot3D.Editor3D.eTooltip; using eNormalize = Plot3D.Editor3D.eNormalize; using eMouseCtrl = Plot3D.Editor3D.eMouseCtrl; using eScatterShape = Plot3D.Editor3D.eScatterShape; using eColorScheme = Plot3D.Editor3D.eColorScheme; using eInvalidate = Plot3D.Editor3D.eInvalidate; using eLegendPos = Plot3D.Editor3D.eLegendPos; // classes using cObject3D = Plot3D.Editor3D.cObject3D; using cPoint3D = Plot3D.Editor3D.cPoint3D; using cShape3D = Plot3D.Editor3D.cShape3D; using cLine3D = Plot3D.Editor3D.cLine3D; using cPolygon3D = Plot3D.Editor3D.cPolygon3D; using cColorScheme = Plot3D.Editor3D.cColorScheme; using cMessgData = Plot3D.Editor3D.cMessgData; using cSurfaceData = Plot3D.Editor3D.cSurfaceData; using cScatterData = Plot3D.Editor3D.cScatterData; using cLineData = Plot3D.Editor3D.cLineData; using cPolygonData = Plot3D.Editor3D.cPolygonData; using cUserInput = Plot3D.Editor3D.cUserInput; // callback function using delRendererFunction = Plot3D.Editor3D.delRendererFunction; using static Plot3D.Editor3D; using System.Diagnostics; using System.Drawing.Imaging; using System.Text.RegularExpressions; using System.IO; using Telerik.WinControls; using static Telerik.WinControls.UI.ValueMapper; using HexcalMC.Base; using ACS.SPiiPlusNET; namespace HexcalMC { internal enum eDemo { Math_Callback, Math_Formula, Surface_Fill, Surface_Grid, Surface_Fill_Missing, Surface_Grid_Missing, Nested_Graphs, Scatter_Plot, Connected_Lines, Scatter_Shapes, Pyramid, Sphere_Fill_Closed, Sphere_Fill_Open, Sphere_Grid, Valentine, Animation, } public partial class EtalonForm : System.Windows.Forms.Form { private eDemo me_Demo; private eColorScheme me_ColorScheme; private Timer mi_StatusTimer = new Timer(); private cMessgData mi_MesgTop = new cMessgData("", -7, 7, Color.Blue); // For special hint private cMessgData mi_MesgBottom = new cMessgData("", -7, -7, Color.Gray); // For selection mode // Only for demo "Animation" private Timer mi_AnimationTimer = new Timer(); private cScatterData mi_SinusData; private cPoint3D[] mi_Pyramid; private int ms32_AnimationAngle; // etalon解析变量 private List etalon_points = new List(); private List filteredPoints = new List(); //过滤后的点 private List dwellTimes = new List(); private static Timer refresh_time = new Timer(); private static int currentIndex = 0; private readonly MainFrom mainFrom; private readonly Api _acs; //ACS控制器 public EtalonForm(MainFrom _mainFrom) { InitializeComponent(); mainFrom = _mainFrom; this._acs = _mainFrom._acs; } private void EtalonForm_Load(object sender, EventArgs e) { InitScatterPlot(); //清空绘图 DebugDfn.textBox_Msg = this.text_etalon_info; } private void InitScatterPlot() //绘图区初始化 { comboColors.Sorted = false; foreach (eColorScheme e_Scheme in Enum.GetValues(typeof(eColorScheme))) { comboColors.Items.Add(e_Scheme.ToString().Replace('_', ' ')); } comboColors.SelectedIndex = (int)eColorScheme.Monochrome; //默认色卡 comboRaster.Sorted = false; foreach (eRaster e_Raster in Enum.GetValues(typeof(eRaster))) { comboRaster.Items.Add(e_Raster); } comboRaster.SelectedIndex = (int)eRaster.Labels; //坐标系栅格样式 //设置默认 comboMouse.SelectedIndex = 0; // 设置定时器 refresh_time.Interval = 100; refresh_time.Tick += new EventHandler(OnAnimationTimer); refresh_time.Start(); } private void DemoScatterPlot(bool b_Lines) { comboColors.Enabled = true; // Some of the demos will disable this combobox me_ColorScheme = (eColorScheme)comboColors.SelectedIndex; checkMirrorX.Checked = editor3D.AxisX.Mirror; checkMirrorY.Checked = editor3D.AxisY.Mirror; // 3 pixels for line width and for circle radius const int SIZE = 3; cColorScheme i_Scheme = new cColorScheme(me_ColorScheme); cScatterData i_ShapeData = new cScatterData(i_Scheme); cLineData i_LineData = new cLineData(i_Scheme); List i_Points = new List(); for (double P = -22.0; P < 22.0; P += 0.1) { double d_X = Math.Sin(P) * P; double d_Y = Math.Cos(P) * P; double d_Z = P; if (d_Z > 0.0) d_Z /= 3.0; cPoint3D i_Point = new cPoint3D(d_X, d_Y, d_Z, "Scatter Point"); if (b_Lines) { i_Points.Add(i_Point); } else // Shapes { // You can store the returned shape in a variable and later modify it's properties cShape3D i_Shape = i_ShapeData.AddShape(i_Point, eScatterShape.Circle, SIZE, null); } } // You can store the returned lines in a variable and later modify their properties cLine3D[] i_Lines = i_LineData.AddConnectedLines(i_Points, SIZE, null); // Depending on your use case you can also specify MaintainXY or MaintainXYZ here editor3D.Clear(); editor3D.Normalize = eNormalize.Separate; editor3D.AddRenderData(i_ShapeData, i_LineData); editor3D.Selection.HighlightColor = Color.FromArgb(90, 90, 90); editor3D.Selection.Callback = OnSelectEvent; editor3D.Selection.MultiSelect = true; editor3D.Selection.Enabled = true; editor3D.UndoBuffer.Enabled = true; editor3D.Invalidate(); } private eInvalidate OnSelectEvent(eSelEvent e_Event, Keys e_Modifiers, int s32_DeltaX, int s32_DeltaY, cObject3D i_Object)// { eInvalidate e_Invalidate = eInvalidate.NoChange; bool b_CTRL = (e_Modifiers & Keys.Control) > 0; // The left mouse button went down with ALT key down and CTRL key up if (e_Event == eSelEvent.MouseDown && !b_CTRL && i_Object != null) { i_Object.Selected = !i_Object.Selected; // After changing the selection status the object must be redrawn. e_Invalidate = eInvalidate.Invalidate; } else if (e_Event == eSelEvent.MouseDrag && b_CTRL) { // The user is dragging the mouse with ALT + CTRL keys down. Convert the mouse // movement in the 2D space into a movement in the 3D space. cPoint3D i_Project = editor3D.ReverseProject(s32_DeltaX, s32_DeltaY); // GetSelectedPoints() returns only unique points. cPoint3D[] i_Selected = editor3D.Selection.GetSelectedPoints(eSelType.All); foreach (cPoint3D i_Point in i_Selected) { switch (me_Demo) { case eDemo.Pyramid: case eDemo.Scatter_Shapes: case eDemo.Scatter_Plot: case eDemo.Connected_Lines: // The pyramid line end points / scatter shapes can be moved freely in // the 3D space i_Point.Move(i_Project.X, i_Project.Y, i_Project.Z); break; case eDemo.Surface_Fill: case eDemo.Surface_Grid: case eDemo.Surface_Fill_Missing: case eDemo.Surface_Grid_Missing: // The points in the Surface grid have a fixed X,Y position, only Z can // be modified. i_Point.Move(0, 0, i_Project.Z); break; default: Debug.Assert(false); break; } } // Set flag to recalculate the coordinate system, then Invalidate() e_Invalidate = eInvalidate.CoordSystem; } mi_StatusTimer.Stop(); mi_StatusTimer.Start(); return e_Invalidate; } private void comboRaster_SelectedIndexChanged(object sender, EventArgs e) //坐标栅格样式 { editor3D.Raster = (eRaster)comboRaster.SelectedIndex; editor3D.Invalidate(); } private void checkMirrorY_CheckedChanged(object sender, EventArgs e) //Y轴镜像 { editor3D.AxisY.Mirror = checkMirrorY.Checked; editor3D.Invalidate(); } private void checkMirrorX_CheckedChanged(object sender, EventArgs e) //x轴镜像 { editor3D.AxisX.Mirror = checkMirrorX.Checked; editor3D.Invalidate(); } private void btnReset_Click(object sender, EventArgs e) //重置视图 { editor3D.SetCoefficients(1350, 70, 230); editor3D.Invalidate(); } private void btnScreenshot_Click(object sender, EventArgs e) //截图保存 { SaveFileDialog i_Dlg = new SaveFileDialog(); i_Dlg.Title = "Save as PNG image"; i_Dlg.Filter = "PNG Image|*.png"; i_Dlg.DefaultExt = ".png"; if (DialogResult.Cancel == i_Dlg.ShowDialog(this)) return; Bitmap i_Bitmap = editor3D.GetScreenshot(); try { i_Bitmap.Save(i_Dlg.FileName, ImageFormat.Png); } catch (Exception Ex) { MessageBox.Show(this, Ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } } private void comboMouse_SelectedIndexChanged(object sender, EventArgs e) //鼠标控制方式 { switch (comboMouse.SelectedIndex) { case 0: editor3D.SetUserInputs(eMouseCtrl.L_Theta_R_Phi); labelMouseInfo.Text = "鼠标左键:升高,鼠标右键:旋转"; break; case 1: editor3D.SetUserInputs(eMouseCtrl.L_Theta_L_Phi); labelMouseInfo.Text = "鼠标左键:升高和旋转"; break; case 2: editor3D.SetUserInputs(eMouseCtrl.M_Theta_M_Phi); labelMouseInfo.Text = "鼠标中键:升高和旋转"; break; default: Debug.Assert(false); break; } labelMouseInfo.Text += ", 鼠标左键 + SHIFT:移动、鼠标左键 + CTRL 或滚轮:缩放、鼠标左键 + ALT:选择"; } private void comboColors_SelectedIndexChanged(object sender, EventArgs e) { me_ColorScheme = (eColorScheme)comboColors.SelectedIndex; //判断 points 是否为空,表示当前是否已经有真实数据 if (etalon_points.Count > 0) { PointScatterPlot(etalon_points); //更新真实数据 } //else //{ // DemoScatterPlot(false); //更新虚拟数据 //} } private void btn_startmove_Click(object sender, EventArgs e) //开始运动 { DebugDfn.AddLogText("开始运动"); int timeout = 5000; Axis[] axes = { Axis.ACSC_AXIS_0, Axis.ACSC_AXIS_1, Axis.ACSC_AXIS_8, Axis.ACSC_NONE }; //判断电机状态 if (!mainFrom.totalAxisEnabled) { DebugDfn.AddLogText("存在电机未使能"); _acs.WaitMotorEnabled(Axis.ACSC_AXIS_0, 1, timeout); //Y轴 // Wait axis 1 enabled during 5 sec _acs.WaitMotorEnabled(Axis.ACSC_AXIS_1, 1, timeout); _acs.WaitMotorEnabled(Axis.ACSC_AXIS_8, 1, timeout); DebugDfn.AddLogText("电机已启用"); } // 创建多点运动 double dwellTime = dwellTimes.Average()*1000; //将秒转换为毫秒 DebugDfn.AddLogText("平均停顿时间(毫秒):" + dwellTime); _acs.MultiPointM(MotionFlags.ACSC_NONE, axes, dwellTime); //判断是否有点 if (filteredPoints.Count == 0) { DebugDfn.AddLogText("没有点"); return; } // 添加符合条件的点到运动路径中 foreach (var point in filteredPoints) { double[] points = new double[3]; points[0] = point.Y; points[1] = point.X; points[2] = point.Z; _acs.AddPointM(axes, points); } // 打印添加点的数量 DebugDfn.AddLogText("添加点的数量:" + filteredPoints.Count); // Finish the motion End of the multi-point motion _acs.EndSequenceM(axes); //启动统计 mainFrom.StartCounting(); } private void btn_stop_Click(object sender, EventArgs e) //停止运动 { DebugDfn.AddLogText("停止运动"); try { Axis[] m_arrAxisList = new Axis[] { Axis.ACSC_AXIS_0, Axis.ACSC_AXIS_1, Axis.ACSC_AXIS_8, Axis.ACSC_NONE }; if (m_arrAxisList != null) _acs.HaltM(m_arrAxisList); DebugDfn.AddLogText("立即停止 已发送命令"); } catch (Exception ex) { MessageBox.Show(ex.Message, "ERROR", MessageBoxButtons.OK, MessageBoxIcon.Error); Debug.WriteLine(ex.Message); } //停止统计 mainFrom.StopCounting(); } private void btn_etalon_import_Click(object sender, EventArgs e) //解析Etalon文件 { //打开文件对号框,选择 mpf格式文件 OpenFileDialog i_Dlg = new OpenFileDialog(); i_Dlg.Title = "导入Etalon文件"; i_Dlg.Filter = "Etalon文件|*.mpf"; i_Dlg.DefaultExt = ".mpf"; i_Dlg.Multiselect = false; if (DialogResult.Cancel == i_Dlg.ShowDialog(this)) return; //读取文件 string s_File = i_Dlg.FileName; //设置路径显示 DebugDfn.AddLogText("导入Etalon文件:" + s_File); //解析文件 parse_mpf_file(s_File); DebugDfn.AddLogText("Etalon文件解析完成"); } private bool parse_mpf_file(string mpf_file_path) // 编写解析mpf文件的函数 { //; Machine: ZIM //; Position: 1 //; Created: 2/15/2023 12:29:13 PM //; Program: TRAC-CAL V48, Build: 10, 5/13/2022 8:29:25 AM //; File: 'cncData.xml' //G71 //G90 //G500 //G01 X8000.000 Y200.000 Z-1400.000 F2000 //坐标 //G04 F=2 // 停顿时间 //G01 X7800.000 Y300.000 Z-1400.000 F2000 //G04 F=2 //G01 X7600.000 Y400.000 Z-1400.000 F2000 //G04 F=2 //G01 X7400.000 Y500.000 Z-1400.000 F2000 //G04 F=2 //G01 X7200.000 Y600.000 Z-1400.000 F2000 //判断文件是否存在 if (!File.Exists(mpf_file_path)) { MessageBox.Show("文件不存在"); return false; } //清空之前的数据 etalon_points.Clear(); filteredPoints.Clear(); dwellTimes.Clear(); //读取文件 string[] lines = File.ReadAllLines(mpf_file_path); Regex regex = new Regex(@"G01 X(?[-+]?\d*\.?\d+) Y(?[-+]?\d*\.?\d+) Z(?[-+]?\d*\.?\d+)"); Regex dwellRegex = new Regex(@"G04 F=(?\d+)"); foreach (string line in lines) { Match match = regex.Match(line); if (match.Success) { double x = double.Parse(match.Groups["X"].Value); double y = double.Parse(match.Groups["Y"].Value); double z = double.Parse(match.Groups["Z"].Value); etalon_points.Add(new Point(x, y, z)); } Match dwellMatch = dwellRegex.Match(line); if (dwellMatch.Success) { int f = int.Parse(dwellMatch.Groups["F"].Value); dwellTimes.Add(f); } } // 输出解析结果 //Console.WriteLine("Points:"); //foreach (var point in etalon_points) //{ // Console.WriteLine($"X: {point.X}, Y: {point.Y}, Z: {point.Z}"); //} //Console.WriteLine("Dwell Times:"); //foreach (var dwellTime in dwellTimes) //{ // Console.WriteLine($"F: {dwellTime}"); //} //过滤点集 foreach (var point in etalon_points) { if (MainFrom.IsWithinLimit(point)) //判断点是否在行程范围内 { filteredPoints.Add(point); } } //打印过滤后的点集大小 DebugDfn.AddLogText("过滤后的点集大小:" + filteredPoints.Count); PointScatterPlot(filteredPoints);//绘制散点图 return true; } private void PointScatterPlot(List points) //绘制散点图 { comboColors.Enabled = true; // Some of the demos will disable this combobox me_ColorScheme = (eColorScheme)comboColors.SelectedIndex; checkMirrorX.Checked = editor3D.AxisX.Mirror; checkMirrorY.Checked = editor3D.AxisY.Mirror; // 3 pixels for line width and for circle radius const int SIZE = 3; cColorScheme i_Scheme = new cColorScheme(me_ColorScheme); cScatterData i_ShapeData = new cScatterData(i_Scheme); cLineData i_LineData = new cLineData(i_Scheme); List i_Points = new List(); foreach (var point in points) { double d_X = point.X; double d_Y = point.Y; double d_Z = point.Z; cPoint3D i_Point = new cPoint3D(d_X, d_Y, d_Z, "Scatter Point"); // You can store the returned shape in a variable and later modify it's properties cShape3D i_Shape = i_ShapeData.AddShape(i_Point, eScatterShape.Circle, SIZE, null); } // You can store the returned lines in a variable and later modify their properties cLine3D[] i_Lines = i_LineData.AddConnectedLines(i_Points, SIZE, null); // Depending on your use case you can also specify MaintainXY or MaintainXYZ here editor3D.Clear(); editor3D.Normalize = eNormalize.Separate; editor3D.AddRenderData(i_ShapeData, i_LineData); editor3D.Selection.HighlightColor = Color.FromArgb(90, 90, 90); editor3D.Selection.Callback = OnSelectEvent; editor3D.Selection.MultiSelect = true; editor3D.Selection.Enabled = true; editor3D.UndoBuffer.Enabled = true; editor3D.Invalidate(); } public class Point { public double X { get; } public double Y { get; } public double Z { get; } public Point(double x, double y, double z) { X = x; Y = y; Z = z; } } private void btn_clear_Click(object sender, EventArgs e) //清空绘图 { editor3D.Clear(); editor3D.Normalize = eNormalize.Separate; editor3D.Invalidate(); } private void btn_draw_test_Click(object sender, EventArgs e) { DemoScatterPlot(false); } private void OnAnimationTimer(object sender, EventArgs e) { cScatterData i_ShapeData = new cScatterData(); currentIndex = mainFrom.GetInPosCount();//获取当前点的数量 if (currentIndex < filteredPoints.Count) { // 更新点的颜色 for (int i = 0; i <= currentIndex; i++) { double d_X = filteredPoints[i].X; double d_Y = filteredPoints[i].Y; double d_Z = filteredPoints[i].Z; cPoint3D i_Point = new cPoint3D(d_X, d_Y, d_Z, "Scatter Point"); SolidBrush i_brush = new SolidBrush(Color.Red); // You can store the returned shape in a variable and later modify it's properties cShape3D i_Shape = i_ShapeData.AddShape(i_Point, eScatterShape.Circle, 5, i_brush, null); } // 对于剩余部分的点,不做颜色更新 for (int i = currentIndex; i < filteredPoints.Count; i++) { double d_X = filteredPoints[i].X; double d_Y = filteredPoints[i].Y; double d_Z = filteredPoints[i].Z; cPoint3D i_Point = new cPoint3D(d_X, d_Y, d_Z, "Scatter Point"); SolidBrush i_brush = new SolidBrush(Color.Gray); // You can store the returned shape in a variable and later modify it's properties cShape3D i_Shape = i_ShapeData.AddShape(i_Point, eScatterShape.Circle, 3, i_brush, null); } //打印 所有点的数量和 currentIndex Console.WriteLine("所有点的数量:" + filteredPoints.Count + "当前点的数量:" + currentIndex); } editor3D.Clear(); editor3D.Normalize = eNormalize.Separate; editor3D.AddRenderData(i_ShapeData); editor3D.Invalidate(); } } }