Files
LM-Middleware/HexcalMC/Motion/EtalonForm.cs
T

784 lines
27 KiB
C#

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.Timers;
using System.Windows.Forms;
using ACS.SPiiPlusNET;
using HexcalMC.Base;
using Plot3D;
using ScottPlot;
using ScottPlot.Plottable;
using Telerik.WinControls;
using Telerik.WinControls.UI;
using static Plot3D.Editor3D;
using static Telerik.WinControls.UI.ValueMapper;
using cColorScheme = Plot3D.Editor3D.cColorScheme;
using cLine3D = Plot3D.Editor3D.cLine3D;
using cLineData = Plot3D.Editor3D.cLineData;
using cMessgData = Plot3D.Editor3D.cMessgData;
// classes
using cObject3D = Plot3D.Editor3D.cObject3D;
using cPoint3D = Plot3D.Editor3D.cPoint3D;
using cPolygon3D = Plot3D.Editor3D.cPolygon3D;
using cPolygonData = Plot3D.Editor3D.cPolygonData;
using cScatterData = Plot3D.Editor3D.cScatterData;
using cShape3D = Plot3D.Editor3D.cShape3D;
using cSurfaceData = Plot3D.Editor3D.cSurfaceData;
using cUserInput = Plot3D.Editor3D.cUserInput;
// callback function
using delRendererFunction = Plot3D.Editor3D.delRendererFunction;
using eColorScheme = Plot3D.Editor3D.eColorScheme;
using eInvalidate = Plot3D.Editor3D.eInvalidate;
using eLegendPos = Plot3D.Editor3D.eLegendPos;
using eMouseCtrl = Plot3D.Editor3D.eMouseCtrl;
using eNormalize = Plot3D.Editor3D.eNormalize;
using eObjType = Plot3D.Editor3D.eObjType;
using ePolygonMode = Plot3D.Editor3D.ePolygonMode;
// enums
using eRaster = Plot3D.Editor3D.eRaster;
using eScatterShape = Plot3D.Editor3D.eScatterShape;
using eSelEvent = Plot3D.Editor3D.eSelEvent;
using eSelType = Plot3D.Editor3D.eSelType;
using eTooltip = Plot3D.Editor3D.eTooltip;
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 System.Windows.Forms.Timer mi_StatusTimer = new System.Windows.Forms.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 System.Windows.Forms.Timer mi_AnimationTimer = new System.Windows.Forms.Timer();
private cScatterData mi_SinusData;
private cPoint3D[] mi_Pyramid;
private int ms32_AnimationAngle;
// etalon解析变量
private List<Point> etalon_points = new List<Point>();
private List<Point> filteredPoints = new List<Point>(); //过滤后的点
private List<int> dwellTimes = new List<int>();
private static System.Windows.Forms.Timer refresh_time = new System.Windows.Forms.Timer();
private static int currentIndex = 0;
private readonly MainFrom mainFrom;
private readonly Api _acs; //ACS控制器
public Axis[] axes =
{
Axis.ACSC_AXIS_0,
Axis.ACSC_AXIS_1,
Axis.ACSC_AXIS_8,
Axis.ACSC_NONE,
}; //使能的轴
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;
}
// 从 Point 转换
public static Point3D FromPoint(Point point)
{
return new Point3D(point.X, point.Y, point.Z);
}
}
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;
}
#region
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<cPoint3D> i_Points = new List<cPoint3D>();
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); //更新虚拟数据
//}
}
#endregion
#region etalon文件解析
private void moveToPoint()
{
DebugDfn.AddLogText("添加到运动队列");
int timeout = 5000;
//判断电机状态
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;
}
//打印点的数量
DebugDfn.AddLogText("待添加点的数量:" + filteredPoints.Count);
// 添加符合条件的点到运动路径中
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("添加点:" + points[0] + " " + points[1] + " " + points[2]);
}
// 打印添加点的数量
DebugDfn.AddLogText("已添加点的数量:" + filteredPoints.Count);
// Finish the motion End of the multi-point motion
_acs.EndSequenceM(axes);
mainFrom.StopCounting();
//启动统计
mainFrom.StartCounting();
}
private void btn_startmove_Click(object sender, EventArgs e) //开始运动
{
int timeout = 5000;
//判断电机状态
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("电机已启用");
}
//判断是否有点
if (filteredPoints.Count == 0)
{
MessageBox.Show("没有需要移动的点,请先导入", "ERROR");
return;
}
//打印点的数量
DebugDfn.AddLogText("待添加点的数量:" + filteredPoints.Count);
//启动运动定时器
timer_move.Start();
refresh_time.Start();
}
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();
refresh_time.Stop();
timer_move.Stop();
currentIndex = 0;
}
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(?<X>[-+]?\d*\.?\d+) Y(?<Y>[-+]?\d*\.?\d+) Z(?<Z>[-+]?\d*\.?\d+)"
);
Regex dwellRegex = new Regex(@"G04 F=(?<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;
}
#endregion
#region 3D
private void PointScatterPlot(List<Point> points) //绘制散点图
{
//清空绘图
editor3D.Clear();
editor3D.Normalize = eNormalize.Separate;
editor3D.Invalidate();
//判断点集是否为空
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<cPoint3D> i_Points = new List<cPoint3D>();
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();
}
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
);
}
editor3D.Clear();
editor3D.Normalize = eNormalize.Separate;
editor3D.AddRenderData(i_ShapeData);
editor3D.Invalidate();
}
}
#endregion
#region
private void timer_move_Tick(object sender, EventArgs e)
{
// 检查是否到达目标点
if (IsAtTarget())
{
// 移动到下一个点
MoveToNextPoint();
}
}
private void MoveToNextPoint()
{
if (filteredPoints.Count > 0 && currentIndex < filteredPoints.Count)
{
//增加2秒延时
Thread.Sleep(2000);
Point nextPoint = filteredPoints[currentIndex];
//打印 nextPoint
DebugDfn.AddLogText("下发指令:" + currentIndex + " 点:" + nextPoint.X + " " + nextPoint.Y + " " + nextPoint.Z );
mainFrom.SetPositionXyz(Point.FromPoint(nextPoint)); //移动到下一个点
currentIndex++;
}
else
{
DebugDfn.AddLogText("All points have been visited.");
timer_move.Stop();
}
}
private bool IsAtTarget()
{
// 这里你需要实现实际的到位判断逻辑
// 例如,通过读取传感器数据或运动控制器的状态
// 这里假设总是返回 true 作为示例
return mainFrom.GetIsMoving();
}
#endregion
}
}