diff --git a/CanFly.Canvas/CanFly.Canvas.csproj b/CanFly.Canvas/CanFly.Canvas.csproj new file mode 100644 index 0000000..8037f3d --- /dev/null +++ b/CanFly.Canvas/CanFly.Canvas.csproj @@ -0,0 +1,28 @@ + + + + + net8.0-windows + enable + enable + ..\ + output + true + true + AnyCPU;x64 + + + + + + + + + + + diff --git a/CanFly.Canvas/Helper/PointHelper.cs b/CanFly.Canvas/Helper/PointHelper.cs new file mode 100644 index 0000000..e8bb4c9 --- /dev/null +++ b/CanFly.Canvas/Helper/PointHelper.cs @@ -0,0 +1,88 @@ +using System; +using System.Collections.Generic; +using System.Drawing.Drawing2D; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CanFly.Canvas.Helper +{ + public static class PointHelper + { + public static Point ToPoint(this PointF pf) + { + return new Point((int)pf.X, (int)pf.Y); + } + + /// + /// 将相对于控件的坐标转换为相对于图像的坐标 + /// + /// 控件中指定点的点位坐标,坐标原点为控件左上角 + /// 该点以图像坐标系为基准的坐标值,坐标原点为图像左上角 + public static PointF ToImageCoordinate(this Point p, Matrix m) + { + PointF pf = new PointF(p.X, p.Y); + return ToImageCoordinate(pf, m); + } + + /// + /// 将相对于控件的坐标转换为相对于图像的坐标 + /// + /// 控件中指定点的点位坐标,坐标原点为控件左上角 + /// 该点以图像坐标系为基准的坐标值,坐标原点为图像左上角 + public static PointF ToImageCoordinate(this PointF p, Matrix m) + { + PointF[] ps = new PointF[] { p }; + Matrix invertMatrix = m.Clone(); + //想要从旧空间到新空间的逆变换,所以我们需要对这个矩阵求逆 + invertMatrix.Invert(); + invertMatrix.TransformPoints(ps); + return ps[0]; + } + + /// + /// 将相对于图像的坐标转换为相对于控件坐标系 + /// + /// 图像中指定点的点位坐标,坐标原点为图像左上角 + /// 该点以空间坐标系为基准的坐标值,坐标原点为空间坐左上角 + public static PointF ToControlCoordinate(this PointF p, Matrix m) + { + PointF[] ps = new PointF[] { p }; + m.TransformPoints(ps); + return ps[0]; + } + + + + + public static float Distance(PointF p1, PointF p2) + { + return (float)Math.Sqrt(Math.Pow(p2.X - p1.X, 2) + Math.Pow(p2.Y - p1.Y, 2)); + } + + public static float DistanceToLine(PointF point, PointF start, PointF end) + { + float lineLengthSquared = DistanceSquared(start, end); + if (lineLengthSquared == 0) + { + return Distance(point, start); // 线段的两个端点重合 + } + + float t = ((point.X - start.X) * (end.X - start.X) + (point.Y - start.Y) * (end.Y - start.Y)) / lineLengthSquared; + t = Math.Clamp(t, 0, 1); // 限制 t 在 [0, 1] 范围内 + + PointF projection = new PointF( + start.X + t * (end.X - start.X), + start.Y + t * (end.Y - start.Y)); + + return Distance(point, projection); + } + + + public static float DistanceSquared(PointF p1, PointF p2) + { + return (float)(Math.Pow(p2.X - p1.X, 2) + Math.Pow(p2.Y - p1.Y, 2)); + } + + } +} diff --git a/CanFly.Canvas/Model/ClickArea.cs b/CanFly.Canvas/Model/ClickArea.cs new file mode 100644 index 0000000..802973c --- /dev/null +++ b/CanFly.Canvas/Model/ClickArea.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CanFly.Canvas.Model +{ + /// + /// 点击的区域 + /// + internal enum ClickArea + { + + /// + /// 未知区域 + /// + AREA_UNKNOW, + + + /// + /// 图片区域 + /// + AREA_IMG, + + + /// + /// 缺陷元素区域 + /// + AREA_DEFECT, + } +} diff --git a/CanFly.Canvas/Model/Cursor.cs b/CanFly.Canvas/Model/Cursor.cs new file mode 100644 index 0000000..dd838aa --- /dev/null +++ b/CanFly.Canvas/Model/Cursor.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace LabelSharp.Config +{ + public static class CustomCursors + { + + public static Cursor CURSOR_DEFAULT = Cursors.Arrow; + public static Cursor CURSOR_POINT = Cursors.Hand; + public static Cursor CURSOR_DRAW = Cursors.Cross; + public static Cursor CURSOR_MOVE = Cursors.Hand; + public static Cursor CURSOR_GRAB = Cursors.Hand; + + + + + } +} diff --git a/CanFly.Canvas/Model/Exception/InvalidShapeException.cs b/CanFly.Canvas/Model/Exception/InvalidShapeException.cs new file mode 100644 index 0000000..6b1ba58 --- /dev/null +++ b/CanFly.Canvas/Model/Exception/InvalidShapeException.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CanFly.Canvas.Model.Exception +{ + internal class InvalidShapeException : System.Exception + { + } +} diff --git a/CanFly.Canvas/Shape/BaseShape.cs b/CanFly.Canvas/Shape/BaseShape.cs new file mode 100644 index 0000000..b5acaa8 --- /dev/null +++ b/CanFly.Canvas/Shape/BaseShape.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CanFly.Canvas.Shape +{ + public abstract class BaseShape + { + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + } +} diff --git a/CanFly.Canvas/Shape/DoubleClickActionEnum.cs b/CanFly.Canvas/Shape/DoubleClickActionEnum.cs new file mode 100644 index 0000000..944c28d --- /dev/null +++ b/CanFly.Canvas/Shape/DoubleClickActionEnum.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CanFly.Canvas.Shape +{ + internal enum DoubleClickActionEnum + { + None, + Close, + + } +} diff --git a/CanFly.Canvas/Shape/FlyShape.cs b/CanFly.Canvas/Shape/FlyShape.cs new file mode 100644 index 0000000..4d96583 --- /dev/null +++ b/CanFly.Canvas/Shape/FlyShape.cs @@ -0,0 +1,938 @@ +using System; +using System.Collections.Generic; +using System.Drawing.Drawing2D; +using System.Linq; +using System.Runtime.Serialization.Formatters.Binary; +using System.Runtime.Serialization; +using System.Text; +using System.Threading.Tasks; +using CanFly.Canvas.Helper; +using Newtonsoft.Json; +using System.Diagnostics; +using System.Net.NetworkInformation; +using System.Drawing; + + +namespace CanFly.Canvas.Shape +{ + [Serializable] + public class FlyShape + { + private const float DFT_VTX_EPSILON = 4f; + private float _epsilon = DFT_VTX_EPSILON; + + public float LineWidth { get; set; } = 2f; + + + #region Shape颜色 + + #region drawing + public Color line_color = Color.FromArgb(128, 0, 255, 0); + public Color fill_color = Color.FromArgb(64, 0, 0, 0); + public Color vertex_fill_color = Color.FromArgb(255, 0, 255, 0); + #endregion + + #region selecting / hovering + public Color select_line_color = Color.FromArgb(255, 255, 255, 255); + public Color select_fill_color = Color.FromArgb(64, 0, 255, 0); + public Color hvertex_fill_color = Color.FromArgb(255, 255, 255, 255); + #endregion + + #endregion + + + private PointTypeEnum point_type = PointTypeEnum.ROUND; + private float point_size = 8.0f; + + private float _scale = 1.0f; + private float scale + { + get + { + return _scale; + } + set + { + _scale = value; + } + } + + + + + private ShapeTypeEnum _shape_type; + private Matrix _matrix = new Matrix(); + + + + + public ShapeTypeEnum ShapeType + { + get => _shape_type; + set { _shape_type = value; } + } + + + public string label = ""; + public int? group_id = null; + private List _points + { + get; + set; + } = new List(); + + public List Points + { + get { return _points; } + set + { + this._points = value; + } + } + + + private List _pointsRaw = new List(); + + + /// + /// 辅助节点 + /// + public List GuidePoints = new List(); + + public float _currentRotateAngle; + private bool _isRotating = false; + + + public List point_labels = new List(); + + + private ShapeTypeEnum _shape_type_raw; + + + /// + /// 是否填充多边形。使用:select_fill_color 或 fill_color 填充。 + /// + public bool fill = false; + + + public bool Selected { get; set; } = false; + public object? flags; + public string description = ""; + private List other_data = new List(); + + + private int _highlightIndex = -1; + private HighlightModeEnum _highlightMode = HighlightModeEnum.NEAR_VERTEX; + + + private Dictionary _highlightSettings = new Dictionary() + { + { HighlightModeEnum.NEAR_VERTEX,new HighlightSetting(4,PointTypeEnum.ROUND)}, + { HighlightModeEnum.MOVE_VERTEX,new HighlightSetting(1.5f,PointTypeEnum.SQUARE)}, + }; + + + private bool _closed = false; + private Color _vertex_fill_color; + + + /// + /// 当图形是Line时,是否绘制辅助矩形框 + /// + public bool IsDrawLineVirtualRect { get; set; } = false; + /// + /// 画Line时辅助矩形的宽度 + /// + public float LineVirtualRectWidth = 40; + public PointF[] LineVirtualRectPoints = new PointF[4]; + + + public FlyShape() + { + + } + + + + private PointF ScalePoint(PointF point) + { + return point; + + //return new PointF( + // (float)(point.X * scale), + // (float)(point.Y * scale)); + } + + + + + public void Close() + { + this._closed = true; + } + + + public void AddPoint(PointF point, int label = 1) + { + if (_points != null && _points.Count > 0 && point.Equals(_points.ElementAt(0))) + { + Close(); + } + else + { + if (_points.Count > 0 && this[-1].Equals(point)) + { + return; + } + _points.Add(point); + point_labels.Add(label); + } + } + + + + public bool CanAddPoint() + { + return ShapeType == ShapeTypeEnum.Polygon + || ShapeType == ShapeTypeEnum.LineStrip; + } + + + + public PointF? PopPoint() + { + if (_points != null && _points.Count > 0) + { + if (point_labels != null && point_labels.Count > 0) + { + point_labels.RemoveAt(point_labels.Count - 1); + } + + PointF lastPoint = _points[_points.Count - 1]; + _points.RemoveAt(_points.Count - 1); + return lastPoint; + } + return null; + + } + + + + public void InsertPoint(int i, PointF point, int label = 1) + { + _points.Insert(i, point); + point_labels.Insert(i, label); + } + + + public void RemovePoint(int i) + { + if (!CanAddPoint()) + { + return; + } + + if (ShapeType == ShapeTypeEnum.Polygon && _points.Count <= 3) + { + return; + } + else if (ShapeType == ShapeTypeEnum.LineStrip && _points.Count <= 2) + { + return; + } + + + _points.RemoveAt(_points.Count - 1); + point_labels.RemoveAt(point_labels.Count - 1); + } + + + + public bool IsClosed() => _closed; + + + public void SetOpen() { _closed = false; } + + + #region 矩形辅助函数 + + /// + /// 矩形模式下,选中的点索引 + /// + [JsonIgnore] + private int _rectSelectedVertex = -1; + [JsonIgnore] + private PointF _rectSelectedMoveVertex; + [JsonIgnore] + private PointF _rectCenterPoint; + + [JsonIgnore] + private bool isVertexMoving; + + /// + /// 正在移动节点 + /// + [JsonIgnore] + public bool IsVertexMoving + { + get + { + return isVertexMoving; + } + internal set + { + //float centerX = (_points[0].X + _points[2].X) / 2f; + //float centerY = (_points[0].Y + _points[2].Y) / 2f; + //_rectCenterVertex = new PointF(centerX, centerY); + isVertexMoving = value; + } + } + //private PointF[] TransformPoints(List points, PointF center, float angle) + //{ + // PointF[] ptsArray = points.ToArray(); + // using (Matrix matrix = new Matrix()) + // { + // matrix.RotateAt(angle, center); + // matrix.TransformPoints(ptsArray); + // } + // return ptsArray; + //} + //GraphicsPath vrtx_path = new GraphicsPath(); + + #endregion + + + public void Paint(Graphics painter) + { + if (_points == null || _points.Count == 0) + { + return; + } + + Color color = Selected ? select_line_color : line_color; + using Pen pen = new Pen(color, LineWidth); + + // Create paths + GraphicsPath line_path = new GraphicsPath(); + GraphicsPath vrtx_path = new GraphicsPath(); + GraphicsPath guide_vrtx_path = new GraphicsPath(); + + switch (ShapeType) + { + //case ShapeTypeEnum.Rectangle: + // { + // if (_points.Count == 2) + // { + // float centerX = (_points[0].X + _points[1].X) / 2f; + // float centerY = (_points[0].Y + _points[1].Y) / 2f; + // _rectCenterPoint = new PointF(centerX, centerY); + + + // line_path.StartFigure(); + + // if (_points[1].X < _points[0].X) + // { + // _points[1] = new PointF(_points[0].X + LineWidth / 2f, _points[1].Y); + // } + // if (_points[1].Y < _points[0].Y) + // { + // _points[1] = new PointF(_points[1].X, _points[0].Y + LineWidth / 2f); + // } + + // //float x = Math.Min(_points[0].X, _points[1].X); + // //float y = Math.Min(_points[0].Y, _points[1].Y); + + // float w = Math.Abs(ScalePoint(_points[1]).X - ScalePoint(_points[0]).X); + // float h = Math.Abs(ScalePoint(_points[1]).Y - ScalePoint(_points[0]).Y); + + // RectangleF drawRect = new(new PointF(_points[0].X, _points[0].Y), new SizeF(w, h)); + + // bool bRotated = false; + // NomalizeRotateAngle(); + + // Matrix oMatrix = null; + + // if (_currentRotateAngle > 0) + // { + // // Create rotation matrix + // oMatrix = new Matrix(); + // oMatrix.RotateAt(_currentRotateAngle, _rectCenterPoint, MatrixOrder.Append); + // painter.Transform = oMatrix; + // bRotated = true; + // } + // //Store rectangle region + // //Region _drawRectRegion = new Region(drawRect); + // if (oMatrix != null) + // line_path.Transform(oMatrix); + + + // line_path.AddRectangle(drawRect); + + + // // Reset transform + // if (bRotated) + // { + // bRotated = false; + // painter.ResetTransform(); + // } + // //_matrix.Reset(); + // //_matrix.RotateAt(_currentRotateAngle, new PointF( + // // (_points[0].X + _points[1].X) / 2, + // // (_points[0].Y + _points[1].Y) / 2)); + // //line_path.Transform(_matrix); + + + // //line_path.AddPolygon(_pointsRaw.ToArray()); + + // } + + // if (_regionVertex.Length != _points.Count) + // { + // _regionVertex = new Region[_points.Count]; + // } + + + // for (int i = 0; i < _points.Count; i++) + // { + // DrawVertex(vrtx_path, i); + // } + + // vrtx_path.Transform(_matrix); + + // } + + // break; + case ShapeTypeEnum.Rectangle: + { + if (_points.Count == 2) + { + float centerX = (_points[0].X + _points[1].X) / 2f; + float centerY = (_points[0].Y + _points[1].Y) / 2f; + _rectCenterPoint = new PointF(centerX, centerY); + + line_path.StartFigure(); + + if (_points[1].X < _points[0].X) + { + _points[1] = new PointF(_points[0].X + LineWidth / 2f, _points[1].Y); + } + if (_points[1].Y < _points[0].Y) + { + _points[1] = new PointF(_points[1].X, _points[0].Y + LineWidth / 2f); + } + + float w = Math.Abs(ScalePoint(_points[1]).X - ScalePoint(_points[0]).X); + float h = Math.Abs(ScalePoint(_points[1]).Y - ScalePoint(_points[0]).Y); + + RectangleF drawRect = new(new PointF(_points[0].X, _points[0].Y), new SizeF(w, h)); + + line_path.AddRectangle(drawRect); + + _matrix.Reset(); + _matrix.RotateAt(_currentRotateAngle, _rectCenterPoint); // 使用更新后的旋转角度 + line_path.Transform(_matrix); + } + + if (_regionVertex.Length != _points.Count) + { + _regionVertex = new Region[_points.Count]; + } + + for (int i = 0; i < _points.Count; i++) + { + DrawVertex1(vrtx_path, i); + } + + vrtx_path.Transform(_matrix); + + + } + break; + case ShapeTypeEnum.Circle: + { + if (_points.Count == 2) + { + float radius = PointHelper.Distance(ScalePoint(_points[0]), ScalePoint(_points[1])); + line_path.AddEllipse( + ScalePoint(_points[0]).X - radius, + ScalePoint(_points[0]).Y - radius, + radius * 2, + radius * 2); + } + for (int i = 0; i < _points.Count; i++) + { + DrawVertex(vrtx_path, i); + } + } + break; + + case ShapeTypeEnum.LineStrip: + { + line_path.StartFigure(); + line_path.AddLine(ScalePoint(_points[0]), ScalePoint(_points[0])); + + for (int i = 0; i < _points.Count; i++) + { + PointF pt = _points[i]; + line_path.AddLine(ScalePoint(pt), ScalePoint(pt)); + DrawVertex(vrtx_path, i); + } + } + break; + + case ShapeTypeEnum.Line: + { + // 添加框线到路径 + var tmpPoints = _points.Select(p => ScalePoint(p)).ToList(); + line_path.AddLines(tmpPoints.ToArray()); + + if (IsDrawLineVirtualRect && tmpPoints.Count == 2) + { + var center = new PointF((tmpPoints[0].X + tmpPoints[1].X) / 2, + (tmpPoints[0].Y + tmpPoints[1].Y) / 2); + + // 计算两点之间的角度 + float dx = tmpPoints[1].X - tmpPoints[0].X; + float dy = tmpPoints[1].Y - tmpPoints[0].Y; + float distance = PointHelper.Distance(tmpPoints[0], tmpPoints[1]); + double angle = Math.Atan2(dy, dx) * (180.0 / Math.PI); // 转换为度数 + + float l = center.X - distance / 2; + float t = center.Y - LineVirtualRectWidth / 2; + float r = center.X + distance / 2; + float b = center.Y + LineVirtualRectWidth / 2; + + PointF ptLT = new PointF(l, t); + PointF ptRT = new PointF(r, t); + PointF ptRB = new PointF(r, b); + PointF ptLB = new PointF(l, b); +#if false + RectangleF rect = new RectangleF(ptLT, new SizeF(distance, LineVirtualRectWidth)); + + GraphicsPath rectPath = new GraphicsPath(); + rectPath.AddRectangle(rect); + + //// 设置矩阵以进行旋转和位移 + Matrix matrix = new Matrix(); + matrix.RotateAt((float)angle, center); // 旋转 + + // 应用变换 + rectPath.Transform(matrix); + // 画框线 + painter.DrawPath(pen, rectPath); +#else + RectangleF rect = new RectangleF(ptLT, new SizeF(distance, LineVirtualRectWidth)); + + LineVirtualRectPoints = new PointF[4] { + ptLT,ptRT,ptRB,ptLB + }; + + //// 设置矩阵以进行旋转和位移 + Matrix matrix = new Matrix(); + matrix.RotateAt((float)angle, center); // 旋转 + matrix.TransformPoints(LineVirtualRectPoints); + + GraphicsPath rectPath = new GraphicsPath(); + rectPath.AddPolygon(LineVirtualRectPoints); + + Pen rectpen = new Pen(Color.FromArgb(60, 0, 255, 0), 1); + + // 画框线 + painter.DrawPath(rectpen, rectPath); + +#endif + } + + + // 添加节点到路径 + for (int i = 0; i < _points.Count; i++) + { + DrawVertex(vrtx_path, i); + } + + if (IsClosed()) + { + line_path.AddLine(ScalePoint(_points[0]), ScalePoint(_points[0])); + } + } + break; + case ShapeTypeEnum.Polygon: + case ShapeTypeEnum.Point: + default: + { + // 添加多边形框线到路径 + line_path.AddLines(_points.Select(p => ScalePoint(p)).ToArray()); + + // 添加节点到路径 + for (int i = 0; i < _points.Count; i++) + { + DrawVertex(vrtx_path, i); + } + + if (IsClosed()) + { + line_path.AddLine(ScalePoint(_points[0]), ScalePoint(_points[0])); + } + } + break; + + } + + + #region 将点绘制到画布上 + + // 画框线 + painter.DrawPath(pen, line_path); + + // 填充节点 + if (vrtx_path.PointCount > 0) + { + painter.DrawPath(pen, vrtx_path); + painter.FillPath(new SolidBrush(vertex_fill_color), vrtx_path); + } + + + if (fill) // 是否填充多边形 + { + Color fillColor = Selected ? select_fill_color : fill_color; + painter.FillPath(new SolidBrush(fillColor), line_path); + } + + #endregion + + } + + + private Region[] _regionVertex = new Region[] { }; + + private void DrawVertex1(GraphicsPath path, int i) + { + PointF pt = _points[i]; + _regionVertex[i] = new Region(new RectangleF( + pt.X - _epsilon, pt.Y - _epsilon, + _epsilon * 2, _epsilon * 2)); + + // 将节点变换 + PointF[] transformedPoint = new PointF[] { pt }; + _matrix.TransformPoints(transformedPoint); // 变换节点位置 + + pt = transformedPoint[0]; // 获取变换后的节点位置 + + // 绘制节点 + float d = point_size; // Point size + PointTypeEnum shape = point_type; // Point shape + PointF point = ScalePoint(pt); + + if (i == _highlightIndex) + { + var setting = _highlightSettings[_highlightMode]; + var size = setting.PointSize; + shape = setting.PointType; + d *= size; // Example for highlighting + } + + if (_highlightIndex >= 0) + { + _vertex_fill_color = hvertex_fill_color; + } + else + { + _vertex_fill_color = vertex_fill_color; + } + + switch (shape) + { + case PointTypeEnum.SQUARE: + path.AddRectangle(new RectangleF(point.X - d / 2, point.Y - d / 2, d, d)); + break; + case PointTypeEnum.ROUND: + path.AddEllipse(point.X - d / 2, point.Y - d / 2, d, d); + break; + default: + throw new InvalidOperationException("Unsupported vertex shape"); + } + } + private void DrawVertex(GraphicsPath path, int i) + { + PointF pt = _points[i]; + + float d = point_size; // Point size + PointTypeEnum shape = point_type; // Point shape + PointF point = ScalePoint(pt); + + if (i == _highlightIndex) + { + var setting = _highlightSettings[_highlightMode]; + var size = setting.PointSize; + shape = setting.PointType; + d *= size; // Example for highlighting + } + + if (_highlightIndex >= 0) + { + _vertex_fill_color = hvertex_fill_color; + } + else + { + _vertex_fill_color = vertex_fill_color; + } + + switch (shape) + { + case PointTypeEnum.SQUARE: + path.AddRectangle(new RectangleF(point.X - d / 2, point.Y - d / 2, d, d)); + break; + case PointTypeEnum.ROUND: + path.AddEllipse(point.X - d / 2, point.Y - d / 2, d, d); + break; + default: + throw new InvalidOperationException("Unsupported vertex shape"); + } + + + } + + + /// + /// 查找离鼠标最近且距离小于阈值的节点 + /// + /// 鼠标位置 + /// 阈值 + /// 返回节点的索引 + public int NearestVertex(PointF point, float epsilon = DFT_VTX_EPSILON) + { + switch (ShapeType) + { + case ShapeTypeEnum.Rectangle: + { + + for (int i = 0; i < _regionVertex.Length; i++) + { + if (_regionVertex[i] == null) + { + break; + } + if (_regionVertex[i].IsVisible(point)) + { + return i; + } + } + } + break; + default: + { + _epsilon = epsilon; + float min_distance = float.MaxValue; + int min_i = -1; + + PointF scaledPoint = new PointF(point.X * scale, point.Y * scale); + + for (int i = 0; i < _points.Count; i++) + { + // 缩放顶点 + PointF scaledVertex = new PointF(_points[i].X * scale, _points[i].Y * scale); + float dist = PointHelper.Distance(scaledVertex, scaledPoint); + + // 检查距离是否在 epsilon 范围内 + if (dist <= epsilon && dist < min_distance) + { + min_distance = dist; + min_i = i; + } + } + + return min_i; + } + } + + return -1; + + } + + + public int NearestEdge(PointF point, float epsilon) + { + float min_distance = float.MaxValue; + int post_i = -1; + + PointF scaledPoint = new PointF(point.X * scale, point.Y * scale); + + + + for (int i = 0; i < _points.Count; i++) + { + // 计算边的两个端点 + PointF start = new PointF(this[i - 1].X * scale, this[i - 1].Y * scale); + PointF end = new PointF(this[i].X * scale, this[i].Y * scale); + + // 计算到线段的距离 + float dist = PointHelper.DistanceToLine(scaledPoint, start, end); + + // 检查距离是否在 epsilon 范围内 + if (dist <= epsilon && dist < min_distance) + { + min_distance = dist; + post_i = i; + } + } + + return post_i; + } + + + public bool ContainsPoint(PointF point) + { + return MakePath().IsVisible(point); + } + + + + private GraphicsPath MakePath() + { + GraphicsPath path = new GraphicsPath(); + + if (ShapeType == ShapeTypeEnum.Rectangle) + { + if (_points.Count == 2) + { + // 创建矩形路径 + RectangleF rect = new RectangleF( + Math.Min(_points[0].X, _points[1].X), + Math.Min(_points[0].Y, _points[1].Y), + Math.Abs(_points[1].X - _points[0].X), + Math.Abs(_points[1].Y - _points[0].Y)); + + path.AddRectangle(rect); + } + } + else if (ShapeType == ShapeTypeEnum.Circle) + { + if (_points.Count == 2) + { + // 计算半径 + float radius = PointHelper.Distance(_points[0], _points[1]); + path.AddEllipse(_points[0].X - radius, _points[0].Y - radius, radius * 2, radius * 2); + } + } + else + { + // 处理多边形 + path.StartFigure(); + path.AddLine(_points[0], _points[1]); + + for (int i = 2; i < _points.Count; i++) + { + path.AddLine(_points[i - 1], _points[i]); + } + path.CloseFigure(); // 结束图形 + } + + return path; + } + + + public RectangleF BoundingRect() + { + return MakePath().GetBounds(); + } + + + + public void MoveBy(PointF offset) + { + for (int i = 0; i < _points.Count; i++) + { + _points[i] = new PointF(_points[i].X + offset.X, _points[i].Y + offset.Y); + } + } + + + /// + /// 移动特定顶点 + /// + /// + /// + /// + public void MoveVertexBy(int index, PointF offset) + { + if (index >= 0 && index < _points.Count) + { + _rectSelectedVertex = index; + _rectSelectedMoveVertex = new PointF(_points[index].X, _points[index].Y); + _points[index] = new PointF(_points[index].X + offset.X, _points[index].Y + offset.Y); + } + else + { + throw new ArgumentOutOfRangeException(nameof(index), "Index is out of range."); + } + } + + + public void HighlightVertex(int i, HighlightModeEnum action) + { + this._highlightIndex = i; + this._highlightMode = action; + } + + + + public void HighlightClear() + { + _highlightIndex = -1; + } + + + public FlyShape Copy() + { + var jsonStr = JsonConvert.SerializeObject(this); + FlyShape copyShp = JsonConvert.DeserializeObject(jsonStr); + return copyShp; + } + + + + public int Length => _points.Count(); + + + + public PointF this[int index] + { + + get + { + if (index == -1) + { + return _points[_points.Count - 1]; + } + return _points[index]; + } + set + { + if (index == -1) + { + _points[_points.Count - 1] = value; + } + else + { + _points[index] = value; + } + } + + } + + + + private void NomalizeRotateAngle() + { + if (_currentRotateAngle >= 360) + { + _currentRotateAngle %= 360; + } + else if (_currentRotateAngle < 0) + { + _currentRotateAngle = 360 - (-_currentRotateAngle % 360); + } + } + + } +} diff --git a/CanFly.Canvas/Shape/HighlightSetting.cs b/CanFly.Canvas/Shape/HighlightSetting.cs new file mode 100644 index 0000000..b52241b --- /dev/null +++ b/CanFly.Canvas/Shape/HighlightSetting.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CanFly.Canvas.Shape +{ + + public enum PointTypeEnum + { + SQUARE = 0, + ROUND = 1, + } + + + public enum HighlightModeEnum + { + MOVE_VERTEX = 0, + NEAR_VERTEX = 1, + } + + + [Serializable] + public class HighlightSetting + { + + + public float PointSize { get; set; } + + + public PointTypeEnum PointType { get; set; } + + + + public HighlightSetting(float pointSize, PointTypeEnum pointType) + { + this.PointSize = pointSize; + PointType = pointType; + } + + + } + +} diff --git a/CanFly.Canvas/Shape/ShapeTypeEnum.cs b/CanFly.Canvas/Shape/ShapeTypeEnum.cs new file mode 100644 index 0000000..ac4646e --- /dev/null +++ b/CanFly.Canvas/Shape/ShapeTypeEnum.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CanFly.Canvas.Shape +{ + public enum ShapeTypeEnum + { + + + Point, + Line, + Rectangle, + Circle, + Polygon, + LineStrip, + + + } +} diff --git a/CanFly.Canvas/UI/FlyCanvas.Designer.cs b/CanFly.Canvas/UI/FlyCanvas.Designer.cs new file mode 100644 index 0000000..872796a --- /dev/null +++ b/CanFly.Canvas/UI/FlyCanvas.Designer.cs @@ -0,0 +1,56 @@ +namespace CanFly.Canvas.UI +{ + partial class FlyCanvas + { + /// + /// 必需的设计器变量。 + /// + private System.ComponentModel.IContainer components = null; + + ///// + ///// 清理所有正在使用的资源。 + ///// + ///// 如果应释放托管资源,为 true;否则为 false。 + //protected override void Dispose(bool disposing) + //{ + // if (disposing && (components != null)) + // { + // components.Dispose(); + // } + // base.Dispose(disposing); + //} + + #region 组件设计器生成的代码 + + /// + /// 设计器支持所需的方法 - 不要修改 + /// 使用代码编辑器修改此方法的内容。 + /// + private void InitializeComponent() + { + components = new System.ComponentModel.Container(); + + SuspendLayout(); + + // + // Canvas + // + AutoScaleDimensions = new SizeF(7F, 17F); + AutoScaleMode = AutoScaleMode.Font; + Margin = new Padding(2); + Name = "Canvas"; + Size = new Size(96, 106); + SizeChanged += Canvas_SizeChanged; + KeyDown += FlyCanvas_KeyDown; + MouseDoubleClick += FlyCanvas_MouseDoubleClick; + MouseDown += FlyCanvas_MouseDown; + MouseMove += FlyCanvas_OnMouseMove; + MouseUp += FlyCanvas_MouseUp; + MouseWheel += FlyCanvas_MouseWheel; + + ResumeLayout(false); + } + + #endregion + } +} diff --git a/CanFly.Canvas/UI/FlyCanvas.cs b/CanFly.Canvas/UI/FlyCanvas.cs new file mode 100644 index 0000000..e361abb --- /dev/null +++ b/CanFly.Canvas/UI/FlyCanvas.cs @@ -0,0 +1,2019 @@ +using CanFly.Canvas.Helper; +using CanFly.Canvas.Model; +using CanFly.Canvas.Shape; +using LabelSharp.Config; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Diagnostics; +using System.Drawing.Drawing2D; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; +using MethodInvoker = System.Windows.Forms.MethodInvoker; + + + +namespace CanFly.Canvas.UI +{ + public partial class FlyCanvas : UserControl + { + public event Action OnMenuItemCopyToHere; + public event Action OnMenuItemMoveToHere; + + + public event Action zoomRequest; + public event Action ZoomRequestF; + public event Action scrollRequest; + public event Action newShape; + public event Action> selectionChanged; + public event Action ShapeMoved; + public event Action> OnShapeMoving; + public event Action DrawingPolygon; + public event Action vertexSelected; + public event Action mouseMoved; + + public event Action OnShapeUpdateEvent; + + + public ShapeTypeEnum _createMode = ShapeTypeEnum.Polygon; + public bool _fill_drawing = false; + + + private float epsilon = 8.0f; + private DoubleClickActionEnum double_click = DoubleClickActionEnum.Close; + private int num_backups = 10; + private bool _isEditMode = true; + + public List Shapes { get; set; } = new List(); + + /// + /// 外部绘制的 + /// + public List OutsideShapes { get; set; } = new List(); + + public List> shapesBackups = new(); + private FlyShape? current = null; + public List selectedShapes = new List(); + private List selectedShapesCopy = new List(); + + private FlyShape line = new FlyShape(); + private PointF prevPoint; + private PointF prevMovePoint; + private PointF[] offsets = new PointF[2] { new PointF(), new PointF() }; + + private float MOVE_SPEED = 5.0f; + + + /// + /// 是否允许多选 + /// + public bool AllowMultiSelect { get; set; } = false; + + public int _width { get; private set; } + public int _height { get; private set; } + + + //public List MenuStripsWithoutSelection = new List(); + //public List MenuStripsWithSelection = new List(); + + + + /// + /// 缩放比例,该参数必须大于0 + /// + private float _scale = 1.0f; + + public new float Scale + { + get { return _scale; } + set + { + + if (value <= 0.0001) + { + return; + } + _scale = value; + ZoomRequestF?.Invoke(_scale); + } + } + + + public Bitmap? pixmap;// = new Bitmap(); + + private Dictionary visible = new Dictionary(); + private bool _hideBackround = false; + private bool hideBackround = false; + + #region 高亮显示的图形 + + private Shape.FlyShape? hShape; + private Shape.FlyShape? prevhShape; + private int hVertex = -1; + private int prevhVertex = -1; + private int hEdge; + private int prevhEdge; + + #endregion + + private bool movingShape = false; + private bool snapping = true; + private bool hShapeIsSelected = false; + private Graphics _painter; + + private Cursor _cursor = CustomCursors.CURSOR_DEFAULT; + private Cursor _preCursor = CustomCursors.CURSOR_DEFAULT; + + + /// + /// 点击的区域 + /// + internal enum ClickArea + { + + /// + /// 未知区域 + /// + AREA_UNKNOW, + + + /// + /// 图片区域 + /// + AREA_IMG, + + + /// + /// 缺陷元素区域 + /// + AREA_DEFECT, + } + private ClickArea _clickArea = ClickArea.AREA_UNKNOW; + + + /// + /// 矩形框 + /// + private Rectangle _rcImg = new Rectangle(0, 0, 0, 0); + + + /// + /// 变换矩阵 + /// + private Matrix _matrix = new Matrix(); + + + public Matrix Matrix => _matrix.Clone(); + + + + //private Bitmap image; + //private List rectangles = new List(); + //private Rectangle currentRectangle; + //private bool drawing = false; + + + public FlyCanvas() + { + + InitializeComponent(); + + // this.KeyDown += FlyCanvas_KeyDown; + // this.KeyPress += FlyCanvas_KeyPress; + + this.DoubleBuffered = true; + SetStyle(ControlStyles.AllPaintingInWmPaint//控件忽略窗口消息 WM_ERASEBKGND 以减少闪烁 + | ControlStyles.UserPaint//由控件而不是由操作系统来绘制控件自身,即自定义绘制 + | ControlStyles.OptimizedDoubleBuffer//控件将首先绘制到缓冲区而不是直接绘制到屏幕,这可以减少闪烁 + | ControlStyles.ResizeRedraw, true);//控件会在调整大小时进行重绘 + + + + //InitTask(); + + } + + + + private void Init() + { + _clickArea = ClickArea.AREA_UNKNOW;//枚举 + _rcImg = new Rectangle(0, 0, 0, 0); + + _matrix.Reset();//重置为单位矩阵 + // strImgPath = string.Empty; + pixmap = null; + + } + + + + public bool FillDrawing + { + get { return _fill_drawing; } + set { _fill_drawing = value; } + } + + + + /// + /// 图形类型 + /// + public ShapeTypeEnum CreateMode + { + get { return _createMode; } + set { _createMode = value; } + } + + + public void StoreShapes() + { + var shapesBackup = new List(); + foreach (var shape in Shapes) + { + shapesBackup.Add(shape.Copy()); + } + // 限制备份数量 + if (shapesBackups.Count >= num_backups) + { + shapesBackups.RemoveRange(0, shapesBackups.Count - num_backups + 1); // 移除多余的备份 + } + + shapesBackups.Add(shapesBackup); // 添加当前备份 + } + + + + public bool IsShapeRestorable + { + get + { + if (shapesBackups.Count < 2) + { + return false; + } + return true; + } + } + + + + public void RestoreShape() + { + if (!this.IsShapeRestorable) + { + return; + } + + // 确保备份不为空 + if (shapesBackups.Count == 0) + { + return; // 如果没有备份,直接返回 + } + + shapesBackups.RemoveAt(shapesBackups.Count - 1); + // 弹出最新的备份 + List shapesBackup = shapesBackups[^1]; // 获取最后的备份而不移除它 + shapesBackups.RemoveAt(shapesBackups.Count - 1); // 移除最新的备份 + + // 恢复形状 + this.Shapes = shapesBackup; + this.selectedShapes = new List(); // 清空选中的形状 + + foreach (Shape.FlyShape shape in Shapes) + { + shape.Selected = false; // 取消所有形状的选中状态 + } + + Invalidate(); + } + + + + public bool IsVisible(FlyShape shape) + { + if (visible.Keys.Contains(shape)) + { + return visible[shape]; + } + return true; + } + + + public bool Drawing() => !_isEditMode; + + public bool Editing() => _isEditMode; + + + + private void UnHighlight() + { + if (hShape != null) + { + hShape.HighlightClear(); + Invalidate(); + } + prevhShape = hShape; + prevhVertex = hVertex; + prevhEdge = hEdge; + + hShape = null; + hVertex = -1; + hEdge = -1; + } + + + public bool SelectedVertex() => hVertex >= 0; + public bool SelectedEdge() => hEdge >= 0; + + + + + + private void DeSelectShape() + { + if (this.selectedShapes != null) + { + this.SetHiding(false); + + { + this.selectedShapes.ForEach(shape => shape.Selected = false); + this.selectedShapes.Clear(); + } + + this.selectionChanged?.Invoke(new List()); + this.hShapeIsSelected = false; + Invalidate(); + } + } + + + public List DeleteSelected() + { + List deleted_shapes = new List(); + if (this.selectedShapes != null) + { + foreach (var shape in this.selectedShapes) + { + this.Shapes.Remove(shape); + deleted_shapes.Add(shape); + } + this.StoreShapes(); + this.selectedShapes = new List(); + Invalidate(); + } + return deleted_shapes; + } + + + private void DeleteShape(Shape.FlyShape shape) + { + if (this.selectedShapes.Contains(shape)) + { + this.selectedShapes.Remove(shape); + } + if (this.Shapes.Contains(shape)) + { + this.Shapes.Remove(shape); + } + this.StoreShapes(); + Invalidate(); + } + + + public void LoadImage(string path) + { + //image = new Bitmap(path); + //this.Invalidate(); + } + + + + + private PointF _panBasePoint = PointF.Empty; + + + + + private void Finalise() + { + this.current.Close(); + + this.Shapes.Add(this.current); + this.StoreShapes(); + this.current = null; + this.SetHiding(false); + newShape?.Invoke(); + Invalidate(); + } + + + + private void SetHiding(bool enable = true) + { + this._hideBackround = enable ? this.hideBackround : false; + } + + + private void FlyCanvas_MouseWheel(object? sender, MouseEventArgs e) + { + // base.OnMouseWheel(e); + //绑定滚轮键 + if (_clickArea == ClickArea.AREA_UNKNOW || _clickArea == ClickArea.AREA_IMG) + { + var delta = e.Delta; + float scaleFactor = delta > 0 ? 1.1f : 0.9f; + Scale *= scaleFactor; + if (Scale >= 10) + { + return; + } + + var p = e.Location.ToImageCoordinate(_matrix); + var mat = new Matrix(); + mat.Translate(p.X, p.Y); + + mat.Scale(scaleFactor, scaleFactor); + + mat.Translate(-p.X, -p.Y); + _matrix.Multiply(mat); + + Refresh(); + } + } + + + #region + + + private bool OutputOfPixmap(PointF p) + { + var w = this.pixmap.Width; + var h = this.pixmap.Height; + return !(p.X >= 0 && p.X <= (w - 1) && p.Y >= 0 && p.Y <= (h - 1)); + } + + + + + public FlyShape SetLastLabel(string text, object flags) + { + int index = Shapes.Count - 1; + Shapes[index].label = text; + Shapes[index].flags = flags; + shapesBackups.RemoveAt(shapesBackups.Count - 1); + StoreShapes(); + return Shapes[index]; + } + + + + public void UndoLastLine() + { + current = Shapes[^1]; + Shapes.RemoveAt(Shapes.Count - 1); + current.SetOpen(); + + + // TODO: + switch (CreateMode) + { + + case ShapeTypeEnum.Polygon: + case ShapeTypeEnum.LineStrip: + line.Points = new List { current[^1], current[0] }; + break; + + case ShapeTypeEnum.Rectangle: + case ShapeTypeEnum.Line: + case ShapeTypeEnum.Circle: + current.Points = new List { current.Points[0] }; + break; + + case ShapeTypeEnum.Point: + current = null; + break; + + default: + break; + } + + + DrawingPolygon?.Invoke(true); + + + } + + + + public void UndoLastPoint() + { + if (current == null || current.IsClosed()) + { + return; + } + current.PopPoint(); + if (current.Length > 0) + { + line[0] = current[-1]; + } + else + { + current = null; + DrawingPolygon?.Invoke(false); + } + Invalidate(); + } + + + + public void LoadPixmap(Bitmap pixmap, bool clear_shapes = true) + { + if (this.pixmap != null) + { + this.pixmap.Dispose(); + } + Init(); + this.pixmap = pixmap; + _rcImg.Width = this.pixmap.Width; + _rcImg.Height = this.pixmap.Width; + + if (clear_shapes) + { + Shapes = new List(); + } + FitImage(); + this.BackColor = Color.Gray; + Refresh(); + + this.Focus(); + } + + + + /// + /// 自适应图片,缩放到符合控件尺寸 + /// + public void FitImage() + { + if (null == this.pixmap) + { + return; + } + + _matrix = new Matrix(); + + try + { + // 先将图片缩放到适配控件尺寸 + // 宽高比例中的较大值 + float wRatio = 1f * pixmap.Width / Width; + float hRatio = 1f * pixmap.Height / Height; + float ratio = 1 / Math.Max(wRatio, hRatio); + + + _matrix.Scale(ratio, ratio); + _width = (int)(pixmap.Width * ratio); + _height = (int)(pixmap.Height * ratio); + + // 再将图片平移到控件中心 + // 将plMain的中心转换为图片坐标 + PointF pControlCenter = new(Width / 2.0f, Height / 2.0f); + PointF pImgCoordinate = pControlCenter.ToImageCoordinate(_matrix); + + //目标坐标减去当前坐标 + _matrix.Translate(pImgCoordinate.X - pixmap.Width / 2.0f, + pImgCoordinate.Y - pixmap.Height / 2.0f); + + } + catch (Exception) + { + throw; + } + + //强制控件使其工作区无效并立即重绘自己和任何子控件 + Invalidate(); + } + + public void LoadShapes(List shapes, bool replace = true) + { + if (replace) + { + this.Shapes = new List(shapes); + } + else + { + shapes.AddRange(shapes); + } + StoreShapes(); + current = null; + hShape = null; + hVertex = -1; + hEdge = -1; + Invalidate(); + } + + + + public void SetShapeVisible(Shape.FlyShape shape, bool value) + { + visible[shape] = value; + Invalidate(); + } + + + #endregion + + + private void Canvas_SizeChanged(object sender, EventArgs e) + { + Invalidate(); + } + + + private void OverrideCursor(Cursor cursor) + { + RestoreCursor(); + _preCursor = _cursor; + _cursor = cursor; + this.Cursor = cursor; + } + + + private void RestoreCursor() + { + this._cursor = _preCursor; + this.Cursor = this._cursor; + } + + + public void ResetState() + { + this.RestoreCursor(); + this.pixmap = null; + this.shapesBackups = new(); + this.Invalidate(); + } + + + + + /// + /// 鼠标按下事件 + /// + private void FlyCanvas_MouseDown(object? sender, MouseEventArgs e) + { + PointF pos = e.Location.ToImageCoordinate(_matrix); + + bool is_shift_pressed = (ModifierKeys & Keys.Shift) == Keys.Shift; + + if (MouseButtons.Left == e.Button) + { + if (Drawing()) + { + if (current != null) // 画后续的点 + { + switch (CreateMode) + { + case ShapeTypeEnum.Polygon: + { + if (!this.line[1].Equals(current[-1])) + { + this.current.AddPoint(this.line[1]); + this.line[0] = this.current[-1]; + if (this.current.IsClosed()) + { + this.Finalise(); + } + } + } + break; + + case ShapeTypeEnum.Rectangle: // 矩形 + { + this.current.Points = this.line.Points; + OnShapeUpdateEvent?.Invoke(this.current); + this.Finalise(); + + break; + } + case ShapeTypeEnum.Circle: + case ShapeTypeEnum.Line: + { + this.current.Points = this.line.Points; + OnShapeUpdateEvent?.Invoke(this.current); + this.Finalise(); + } + break; + + case ShapeTypeEnum.LineStrip: + { + this.current.AddPoint(this.line[1]); + this.line[0] = this.current[-1]; + if ((ModifierKeys & Keys.Control) == Keys.Control) + { + this.Finalise(); + } + } + break; + default: + break; + } + } + else if (!OutputOfPixmap(pos)) // 画第一个点 + { + this.current = new FlyShape() + { + ShapeType = this.CreateMode, + }; + + this.current.AddPoint(pos, is_shift_pressed ? 0 : 1); + + if (CreateMode == ShapeTypeEnum.Point) // 画点 + { + this.Finalise(); + } + else // 画其他图形 + { + if (this.CreateMode == ShapeTypeEnum.Circle) + { + this.current.ShapeType = ShapeTypeEnum.Circle; + } + this.line.Points = new List() { pos, pos }; + this.line.point_labels = new List { 1, 1 }; + this.SetHiding(); + this.DrawingPolygon?.Invoke(true); + + } + } + } + else if (Editing()) + { + if (this.SelectedEdge() && ((ModifierKeys & Keys.Alt) == Keys.Alt)) + { + this.AddPointToEdge(); + } + else if (this.SelectedVertex() + && ((ModifierKeys & Keys.Alt) == Keys.Alt) + && ((ModifierKeys & Keys.Shift) == Keys.Shift)) + { + this.RemoveSelectedPoint(); + } + + + bool group_mode = false; + if (AllowMultiSelect) + { + group_mode = (ModifierKeys & Keys.Control) == Keys.Control; + } + this.SelectShapePoint(pos, group_mode); + this.prevPoint = pos; + Invalidate(); + } // else if (Editing()) + } // if (MouseButtons.Left == e.Button) + else if (MouseButtons.Right == e.Button && this.Editing()) + { + bool group_mode = false; + if (AllowMultiSelect) + { + group_mode = (ModifierKeys & Keys.Control) == Keys.Control; + } + + if (this.selectedShapes == null + || (this.hShape != null && !this.selectedShapes.Contains(this.hShape))) + { + this.SelectShapePoint(pos, group_mode); + Invalidate(); + } + this.prevPoint = pos; + + + } // else if (MouseButtons.Right == e.Button && this.Editing()) + else if (MouseButtons.Middle == e.Button) + { + + if (_rcImg.Contains(pos.ToPoint())) + { + _clickArea = ClickArea.AREA_IMG; + _panBasePoint = pos; + } + + } // else if (MouseButtons.Middle == e.Button) + + + Refresh(); + } + + + private void FlyCanvas_MouseUp(object? sender, MouseEventArgs e) + { + if (MouseButtons.Left == e.Button || MouseButtons.Right == e.Button) + { + _panBasePoint = Point.Empty; + _clickArea = ClickArea.AREA_UNKNOW; + } + + if (e.Button == MouseButtons.Right) + { + // menuWithSelection.Show(this, e.Location); + } + else if (e.Button == MouseButtons.Left) + { + if (this.Editing()) + { + if (this.hShape != null && this.hShapeIsSelected && !this.movingShape) + { + var shps = this.selectedShapes.Where(shp => !shp.Equals(this.hShape)).ToList(); + this.selectedShapes.ForEach(shp => shp.Selected = false); + this.selectedShapes = shps; + this.selectedShapes.ForEach(shp => shp.Selected = true); + this.selectionChanged?.Invoke(this.selectedShapes); + } + } + AfterMouseRelease(); + } + } + + + /// + /// 鼠标移动事件 + /// + private void FlyCanvas_OnMouseMove(object? sender, MouseEventArgs e) + { + PointF pos = e.Location.ToImageCoordinate(_matrix); + + mouseMoved?.Invoke(pos); + + this.prevMovePoint = pos; + RestoreCursor(); + + bool is_shift_pressed = (ModifierKeys & Keys.Shift) == Keys.Shift; + + + if (Drawing()) // 绘图状态 + { + this.line.ShapeType = this.CreateMode; + this.OverrideCursor(CustomCursors.CURSOR_DRAW); + + if (this.current == null) + { + return; + } + + if (this.OutputOfPixmap(pos)) + { + // TODO: 处理超出边界的情况 + } + else if (this.snapping + && this.current.Length > 1 + && this.CreateMode == ShapeTypeEnum.Polygon + && this.CloseEnough(pos, this.current[0])) + { + pos = this.current[0]; + this.OverrideCursor(CustomCursors.CURSOR_POINT); + this.current.HighlightVertex(0, HighlightModeEnum.NEAR_VERTEX); + } + + + switch (CreateMode) + { + case ShapeTypeEnum.Polygon: + case ShapeTypeEnum.LineStrip: + { + this.line.Points = new() { this.current[-1], pos }; + this.line.point_labels = new() { 1, 1 }; + } + break; + // case ShapeTypeEnum.Rectangle: // 矩形 + // { + //#if false // 改动5 + // float minX = Math.Min(this.current[0].X, pos.X); + // float maxX = Math.Max(this.current[0].X, pos.X); + // float minY = Math.Min(this.current[0].Y, pos.Y); + // float maxY = Math.Max(this.current[0].Y, pos.Y); + + // List tmpPoints = new List() { + // new PointF(minX, minY), + // new PointF(maxX, minY), + // new PointF(maxX, maxY), + // new PointF(minX, maxY), + // }; + + // this.line.Points = tmpPoints; + //#else + // this.line.Points = new() { this.current[0], pos }; + //#endif + // this.line.point_labels = new() { 1, 1 }; + // this.line.Close(); + // } + // break; + + case ShapeTypeEnum.Rectangle: // 矩形 + { +#if false + float minX = Math.Min(this.current[0].X, pos.X); + float maxX = Math.Max(this.current[0].X, pos.X); + float minY = Math.Min(this.current[0].Y, pos.Y); + float maxY = Math.Max(this.current[0].Y, pos.Y); + + List tmpPoints = new List() { + new PointF(minX, minY), + new PointF(maxX, minY), + new PointF(maxX, maxY), + new PointF(minX, maxY), + }; + + this.line.Points = tmpPoints; +#else + this.line.Points = new() { this.current[0], pos }; +#endif + this.line.point_labels = new() { 1, 1 }; + this.line.Close(); + } + break; + case ShapeTypeEnum.Circle: + { + this.line.Points = new() { this.current[0], pos }; + this.line.point_labels = new() { 1, 1 }; + this.line.ShapeType = ShapeTypeEnum.Circle; + OnShapeUpdateEvent?.Invoke(this.line); + } + break; + case ShapeTypeEnum.Line: + { + this.line.Points = new() { this.current[0], pos }; + this.line.point_labels = new() { 1, 1 }; + this.line.Close(); + OnShapeUpdateEvent?.Invoke(this.line); + } + break; + + case ShapeTypeEnum.Point: + { + this.line.Points = new() { this.current[0] }; + this.line.point_labels = new() { 1 }; + this.line.Close(); + } + break; + + default: + break; + } + Refresh(); + this.current.HighlightClear(); + return; + } + + + // 多边形复制移动 + if (e.Button == MouseButtons.Right) + { + if (this.selectedShapesCopy != null + && this.selectedShapesCopy.Count > 0 + && this.prevPoint != null) + { + this.OverrideCursor(CustomCursors.CURSOR_MOVE); + this.BoundedMoveShapes(this.selectedShapesCopy, pos); + } + else if (this.selectedShapes != null && this.selectedShapes.Count > 0) + { + this.selectedShapesCopy = this.selectedShapes.Select(shp => shp.Copy()).ToList(); + } + Invalidate(); + return; + } + + + // 多边形/节点 移动 + if (e.Button == MouseButtons.Left) + { + if (this.SelectedVertex()) + { + this.BoundedMoveVertex(pos); + Invalidate(); + this.movingShape = true; + } + else if (this.selectedShapes != null + && this.selectedShapes.Count > 0 + && this.prevPoint != null) + { + this.OverrideCursor(CustomCursors.CURSOR_MOVE); + this.BoundedMoveShapes(this.selectedShapes, pos); + OnShapeMoving?.Invoke(this.selectedShapes); + Invalidate(); + this.movingShape = true; + } + return; + } + + + + //# Just hovering over the canvas, 2 possibilities: + //# - Highlight shapes + //# - Highlight vertex + //# Update shape/vertex fill and tooltip value accordingly. + var tmpShapes = this.Shapes.Where(shp => this.IsVisible(shp)).Reverse(); + if (tmpShapes.Any()) + { + bool found = false; + + foreach (var shape in tmpShapes) + { + // 寻找距离鼠标最近的节点 + int index = shape.NearestVertex(pos, this.epsilon); + int index_edge = shape.NearestEdge(pos, this.epsilon); + if (index >= 0) + { + if (this.SelectedVertex()) + { + this.hShape?.HighlightClear(); + } + this.prevhVertex = this.hVertex = index; + this.prevhShape = this.hShape = shape; + this.prevhEdge = this.hEdge; + this.hEdge = -1; + shape.HighlightVertex(index, HighlightModeEnum.MOVE_VERTEX); + this.OverrideCursor(CustomCursors.CURSOR_POINT); + // TODO: Tooltip + + Invalidate(); + found = true; + break; + } + else if (index_edge >= 0 && shape.CanAddPoint()) + { + if (this.SelectedVertex()) + { + this.hShape?.HighlightClear(); + } + this.prevhVertex = this.hVertex; + this.hVertex = -1; + this.prevhShape = this.hShape = shape; + this.prevhEdge = this.hEdge = index_edge; + this.OverrideCursor(CustomCursors.CURSOR_POINT); + // TODO: Tooltip + Invalidate(); + found = true; + break; + } + else if (shape.ContainsPoint(pos)) + { + if (this.SelectedVertex()) + { + this.hShape?.HighlightClear(); + } + this.prevhVertex = this.hVertex; + this.hVertex = -1; + this.prevhShape = this.hShape = shape; + this.prevhEdge = this.hEdge; + this.hEdge = -1; + this.OverrideCursor(CustomCursors.CURSOR_GRAB); + Invalidate(); + found = true; + break; + } + } + + if (!found) + { + UnHighlight(); + } + + this.vertexSelected?.Invoke(this.hVertex >= 0); + } + + // 鼠标中键移动触发移动事件 + if (MouseButtons.Middle == e.Button) + { + if (PointF.Empty == _panBasePoint) + { + return; + } + + switch (_clickArea) + { + case ClickArea.AREA_IMG: // 点击了图像区域 + { + PointF p = e.Location.ToImageCoordinate(_matrix); + + float x = p.X - _panBasePoint.X; + float y = p.Y - _panBasePoint.Y; + _matrix.Translate(x, y); + + break; + } + } + } + + Refresh(); + + } + + + + protected override void OnPaint(PaintEventArgs e) + { + base.OnPaint(e); + try + { + //获取表示控件的工作区的矩形 + Rectangle rect = ClientRectangle; + + Graphics oriGraphics = e.Graphics; + + //设置平滑程度为高质量,减少抗锯齿的出现 + oriGraphics.SmoothingMode = SmoothingMode.HighQuality; + + // 双缓冲绘图 + //获取当前应用程序域的 BufferedGraphicsContext,此实例管理该应用程序的所有默认双缓冲 + BufferedGraphicsContext currentContext = BufferedGraphicsManager.Current; + //BufferedGraphics 对象管理与呈现图面(例如窗体或控件)关联的内存缓冲 + BufferedGraphics myBuffer = currentContext.Allocate(oriGraphics, rect); + //实例化一个直接表示内存缓冲的 Graphics 对象,可将图形呈现到内存缓冲,绘制到此对象中 + Graphics bufferGraphics = myBuffer.Graphics; + bufferGraphics.SmoothingMode = SmoothingMode.HighQuality; + //高质量低速度呈现 + bufferGraphics.PixelOffsetMode = PixelOffsetMode.HighQuality; + //使用的插值算法 + bufferGraphics.InterpolationMode = InterpolationMode.NearestNeighbor; + //清除整个绘图面并以指定背景色填充,Console.BackColor指获取当前控件的背景色 + bufferGraphics.Clear(Color.FromArgb(0xf0, 0xf0, 0xf0)); + + bufferGraphics.MultiplyTransform(_matrix); + + + #region 画背景图 + + if (pixmap != null) + { + try + { + bufferGraphics.DrawImage(pixmap, 0, 0, pixmap.Width, pixmap.Height); + //if (_path != null) + //{ + // bufferGraphics.DrawPath(new Pen(Brushes.Yellow, 1f), _path); + //} + } + catch { } + } + else + { + pixmap = null; + return; + } + + #endregion + + + + + + #region + + foreach (var shape in Shapes) + { + if ((shape.Selected || !this._hideBackround) + && this.IsVisible(shape)) + { + shape.fill = shape.Selected || (shape == this.hShape); + shape.Paint(bufferGraphics); + } + } + + if (this.current != null) + { + this.current.Paint(bufferGraphics); + this.line.Paint(bufferGraphics); + } + + if (this.selectedShapesCopy != null) + { + foreach (var s in this.selectedShapesCopy) + { + s.Paint(bufferGraphics); + } + } + + // TODO: + this.FillDrawing = true; + + if (this.FillDrawing + && this.CreateMode == ShapeTypeEnum.Polygon + && this.current != null + && this.current.Length >= 2) + { + var drawing_shape = this.current.Copy(); + if (drawing_shape.fill_color.A == 0) + { + drawing_shape.fill_color = Color.FromArgb(64, drawing_shape.fill_color); + } + drawing_shape.AddPoint(this.line[1]); + drawing_shape.fill = true; + drawing_shape.Paint(bufferGraphics); + } + + + #endregion + + #region 绘制外部传递的图形 + + // this.OutsideShapes.ForEach(shp => shp.Paint(bufferGraphics)); + for (int i = 0; i < OutsideShapes.Count; i++) + { + OutsideShapes[i].Paint(bufferGraphics); + } + + + #endregion + + + myBuffer.Render(oriGraphics); + //释放资源 + bufferGraphics.Dispose(); + myBuffer.Dispose(); + currentContext.Dispose(); + } + catch (Exception ex) + { + throw; + } + } + + + + + private void SelectShapePoint(PointF point, bool multiple_selection_mode) + { + if (this.SelectedVertex()) + { + this.hShape?.HighlightVertex(this.hVertex, HighlightModeEnum.MOVE_VERTEX); + } + else + { + List reversedShapes = Shapes.ToList(); + reversedShapes.Reverse(); + foreach (var shape in reversedShapes) + { + if (this.IsVisible(shape) && shape.ContainsPoint(point)) + { + this.SetHiding(); + if (this.selectedShapes.Contains(shape)) + { + this.hShapeIsSelected = true; + } + else + { + if (multiple_selection_mode) + { + shape.Selected = true; + this.selectedShapes.Add(shape); + this.selectionChanged?.Invoke(this.selectedShapes); + } + else + { + shape.Selected = true; + this.selectedShapes = new List() { shape }; + this.selectionChanged?.Invoke(this.selectedShapes); + } + this.hShapeIsSelected = false; + } + return; + } + } + } + this.DeSelectShape(); + } + + private void RemoveSelectedPoint() + { + throw new NotImplementedException(); + } + + private void AddPointToEdge() + { + throw new NotImplementedException(); + } + + private bool BoundedMoveShapes(List shapes, PointF pos) + { + if (this.OutputOfPixmap(pos)) + { + return false; + } + + PointF o1 = new PointF( + pos.X + this.offsets[0].X, + pos.Y + this.offsets[0].Y); + if (this.OutputOfPixmap(o1)) + { + pos = new PointF( + pos.X - Math.Min(0, o1.X), + pos.Y - Math.Min(0, o1.Y)); + } + + PointF o2 = new PointF( + pos.X + this.offsets[1].X, + pos.Y + this.offsets[1].Y); + if (this.OutputOfPixmap(o1)) + { + pos = new PointF( + pos.X + Math.Min(0, this.pixmap.Width - o2.X), + pos.Y + Math.Min(0, this.pixmap.Height - o2.Y)); + } + + try + { + PointF dp = new PointF(pos.X - this.prevPoint.X, pos.Y - this.prevPoint.Y); + foreach (FlyShape shape in shapes) + { + shape.MoveBy(dp); + } + this.prevPoint = pos; + return true; + } + catch + { + } + return false; + } + + + private void BoundedMoveVertex(PointF pos) + { + PointF point = this.hShape[this.hVertex]; + if (this.OutputOfPixmap(pos)) + { + pos = this.IntersectionPoint(point, pos); + } + this.hShape.IsVertexMoving = true; + this.hShape.MoveVertexBy(this.hVertex, new PointF(pos.X - point.X, pos.Y - point.Y)); + OnShapeUpdateEvent?.Invoke(hShape); + } + + + private PointF IntersectionPoint(PointF p1, PointF p2) + { + Size size = this.pixmap.Size; + List points = new List() + { + new PointF(0, 0), + new PointF(size.Width - 1, 0), + new PointF(size.Width - 1, size.Height - 1), + new PointF(0, size.Height - 1), + }; + + float x1 = Math.Min(Math.Max(p1.X, 0), size.Width - 1); + float y1 = Math.Min(Math.Max(p1.Y, 0), size.Height - 1); + + float x2 = p2.X; + float y2 = p2.Y; + + // Get the intersection details + var intersections = IntersectingEdges( + new PointF(x1, y1), + new PointF(x2, y2), + points); + var closestIntersection = intersections.OrderBy(result => result.distance).FirstOrDefault(); + + if (closestIntersection.Equals(default((double distance, int index, PointF intersectionPoint)))) + { + return PointF.Empty; // No intersection found + } + + var (d, i, intersection) = closestIntersection; + + // Define the edge points + float x3 = points[i].X; + float y3 = points[i].Y; + float x4 = points[(i + 1) % 4].X; + float y4 = points[(i + 1) % 4].Y; + + if (intersection == new PointF(x1, y1)) + { + // Handle cases where the previous point is on one of the edges. + if (x3 == x4) + { + return new PointF(x3, Math.Min(Math.Max(0, y2), Math.Max(y3, y4))); + } + else // y3 == y4 + { + return new PointF(Math.Min(Math.Max(0, x2), Math.Max(x3, x4)), y3); + } + } + + return intersection; + } + + + private IEnumerable<(double distance, int index, PointF intersectionPoint)> IntersectingEdges(PointF point1, PointF point2, List points) + { + float x1 = point1.X; + float y1 = point1.Y; + float x2 = point2.X; + float y2 = point2.Y; + + for (int i = 0; i < 4; i++) + { + float x3 = points[i].X; + float y3 = points[i].Y; + float x4 = points[(i + 1) % 4].X; + float y4 = points[(i + 1) % 4].Y; + + float denom = (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1); + float nua = (x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3); + float nub = (x2 - x1) * (y1 - y3) - (y2 - y1) * (x1 - x3); + + if (denom == 0) + { + continue; + } + + float ua = nua / denom; + float ub = nub / denom; + + if (ua >= 0 && ua <= 1 && ub >= 0 && ub <= 1) + { + float x = x1 + ua * (x2 - x1); + float y = y1 + ua * (y2 - y1); + PointF m = new PointF((x3 + x4) / 2, (y3 + y4) / 2); + float d = PointHelper.Distance(m, new PointF(x2, y2)); + yield return (d, i, new PointF(x, y)); + } + + } + + + + } + + + private bool CloseEnough(PointF p1, PointF p2) + { + var d1 = PointHelper.Distance(p1, p2); + //var d2 = (this.epsilon / this.Scale); + //return d1 < d2; + // TODO: + //return false; + return d1 < 16; + } + + + + + + private void InitTask() + { + TaskFactory taskFactory = new TaskFactory(TaskCreationOptions.LongRunning, TaskContinuationOptions.LongRunning); + taskFactory.StartNew(MenuWithSelectionEvent); + } + + + + private void AfterMouseRelease() + { + if (this.InvokeRequired) + { + this.Invoke(new MethodInvoker(AfterMouseRelease)); + return; + } + + if (this.movingShape && this.hShape != null) + { + this.hShape.IsVertexMoving = false; + int index = this.Shapes.IndexOf(this.hShape); + + if (shapesBackups.Count > 0) + { + if (this.shapesBackups[this.shapesBackups.Count - 1][index].Points + != this.Shapes[index].Points) + { + this.StoreShapes(); + this.ShapeMoved?.Invoke(); + } + } + + + + this.movingShape = false; + } + } + + + private bool CanCloseShape() + { + var b1 = this.Drawing(); + var b2 = this.current != null && this.current.Length > 2; + + return b1 && b2; + } + + + + private void FlyCanvas_MouseDoubleClick(object? sender, MouseEventArgs e) + { + if (this.double_click != DoubleClickActionEnum.Close) + { + return; + } + + if (this.CreateMode == ShapeTypeEnum.Polygon && this.CanCloseShape()) + { + this.Finalise(); + } + } + + + //private List TestReflect() + //{ + // List shapes = new List(); + // List names = new List(); + + + // // 获取对象的类型 + // Type type = this.GetType(); + + // // 获取所有公共字段 + // FieldInfo[] fields = type.GetFields(BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic); + // foreach (var field in fields) + // { + // if (field.FieldType.IsSubclassOf(typeof(Shape.FlyShape)) || field.FieldType == typeof(Shape.FlyShape)) + // { + // shapes.Add((Shape.FlyShape)field.GetValue(this)); + // names.Add(field.Name); + // } + // } + + // // 获取所有公共属性 + // PropertyInfo[] properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic); + // foreach (var property in properties) + // { + // if (property.PropertyType.IsSubclassOf(typeof(Shape.FlyShape)) || property.PropertyType == typeof(Shape.FlyShape)) + // { + // shapes.Add((Shape.FlyShape)property.GetValue(this)); + // names.Add(property.Name); + // } + // } + + // return shapes; + //} + + + + /// + /// 重写 ProcessDialogKey 使控件可以监听方向键与删除键 + /// + protected override bool ProcessDialogKey(Keys keyData) + { + if (keyData == Keys.Up || keyData == Keys.Down || + keyData == Keys.Left || keyData == Keys.Right || keyData == Keys.Delete) + { + return false; + } + else + { + return base.ProcessDialogKey(keyData); + } + } + + //protected override void OnKeyDown(KeyEventArgs e) + + + private void FlyCanvas_KeyPress(object? sender, KeyPressEventArgs e) + { + //var modifiers = e.Modifiers; + //var key = e.KeyCode; + + Debug.WriteLine(""); + + //if (this.Drawing()) + //{ + // if (key == Keys.Escape && this.current != null) + // { + // this.current = null; + // this.DrawingPolygon?.Invoke(false); + // this.Invalidate(); + // } + // else if (key == Keys.Return && this.CanCloseShape()) + // { + // this.Finalise(); + // } + // else if ((ModifierKeys & Keys.Alt) == Keys.Alt) + // { + // this.snapping = false; + // } + //} + //else if (Editing()) + //{ + // switch (key) + // { + // case Keys.Up: + // this.MoveByKeyboard(new PointF(0f, -MOVE_SPEED)); + // break; + // case Keys.Down: + // this.MoveByKeyboard(new PointF(0f, MOVE_SPEED)); + // break; + // case Keys.Left: + // this.MoveByKeyboard(new PointF(-MOVE_SPEED, 0f)); + // break; + // case Keys.Right: + // this.MoveByKeyboard(new PointF(MOVE_SPEED, 0f)); + // break; + + // case Keys.Delete: + // DeleteSelected(); + // Invalidate(); + // break; + + + // default: + // break; + // } + //} + } + + + + private void FlyCanvas_KeyDown(object? sender, KeyEventArgs e) + { + var modifiers = e.Modifiers; + var key = e.KeyCode; + + if (this.Drawing()) + { + if (key == Keys.Escape && this.current != null) + { + this.current = null; + this.DrawingPolygon?.Invoke(false); + this.Invalidate(); + } + else if (key == Keys.Return && this.CanCloseShape()) + { + this.Finalise(); + } + else if ((ModifierKeys & Keys.Alt) == Keys.Alt) + { + this.snapping = false; + } + } + else if (Editing()) + { + switch (key) + { + case Keys.Up: + this.MoveByKeyboard(new PointF(0f, -MOVE_SPEED)); + break; + case Keys.Down: + this.MoveByKeyboard(new PointF(0f, MOVE_SPEED)); + break; + case Keys.Left: + this.MoveByKeyboard(new PointF(-MOVE_SPEED, 0f)); + break; + case Keys.Right: + this.MoveByKeyboard(new PointF(MOVE_SPEED, 0f)); + break; + + case Keys.Delete: + DeleteSelected(); + Invalidate(); + break; + + + default: + break; + } + } + } + + private void MoveByKeyboard(PointF offset) + { + if (this.selectedShapes == null) + { + return; + } + + this.BoundedMoveShapes(this.selectedShapes, + new PointF(this.prevPoint.X + offset.X, this.prevPoint.Y + offset.Y)); + this.Invalidate(); + this.movingShape = true; + + } + + + + /// + /// 清理所有正在使用的资源。 + /// + /// 如果应释放托管资源,为 true;否则为 false。 + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + isControlAlive = false; // 设置标志,停止循环 + menuCloseEvent.Set(); // 唤醒等待的线程,确保退出循环 + components.Dispose(); + } + base.Dispose(disposing); + } + + + #region 右键菜单点击事件 + + + + private bool isControlAlive = true; + private bool menuWithSelectionItemClicked = false; + private AutoResetEvent menuCloseEvent = new(false); + + + + private void MenuWithSelectionEvent() + { + while (isControlAlive) + { + try + { + bool ret = menuCloseEvent.WaitOne(); + + if (!ret) + { + continue; + } + + if (menuWithSelectionItemClicked) // 点击了菜单项 + { + menuWithSelectionItemClicked = false; + } + else if (this.selectedShapesCopy != null && this.selectedShapesCopy.Count > 0) // 未点击菜单项 + { + this.selectedShapesCopy = new List(); + Invalidate(); + AfterMouseRelease(); + } + } + catch + { + } + } + } + + + #region 选择了Shape时的右键菜单点击事件 + + + + + private void menuItemCopyToHere_Click(object sender, EventArgs e) + { + OnMenuItemCopyToHere?.Invoke(); + AfterMouseRelease(); + + } + + private void menuItemMoveToHere_Click(object sender, EventArgs e) + { + OnMenuItemMoveToHere?.Invoke(); + AfterMouseRelease(); + } + + + private void menuWithSelection_Closed(object sender, ToolStripDropDownClosedEventArgs e) + { + menuCloseEvent.Set(); + Debug.WriteLine($"{DateTime.Now.ToString("HH:mm:ss.fff")}\t menuWithSelection_Closed"); + } + + + + private void menuWithSelection_ItemClicked(object sender, ToolStripItemClickedEventArgs e) + { + menuWithSelectionItemClicked = true; + Debug.WriteLine($"{DateTime.Now.ToString("HH:mm:ss.fff")}\t menuWithSelection_ItemClicked"); + } + + #endregion + + #endregion + + + public bool EndMove(bool copy) + { + if (!(this.selectedShapes != null && this.selectedShapes.Count > 0 + && this.selectedShapesCopy != null && this.selectedShapesCopy.Count > 0 + && this.selectedShapesCopy.Count == this.selectedShapes.Count)) + { + return false; + } + + + if (copy) + { + for (int i = 0; i < this.selectedShapesCopy.Count; i++) + { + Shape.FlyShape shape = this.selectedShapesCopy[i]; + this.Shapes.Add(shape); + this.selectedShapes[i].Selected = false; + this.selectedShapes[i] = shape; + } + } + else + { + for (int i = 0; i < this.selectedShapesCopy.Count; i++) + { + var shape = this.selectedShapesCopy[i]; + this.selectedShapes[i].Points = shape.Points; + } + } + + this.selectedShapesCopy = new List(); + this.Invalidate(); + this.StoreShapes(); + return true; + } + + + + public void SelectedShapes(List shapes) + { + this.SetHiding(); + this.selectionChanged?.Invoke(shapes); + this.Invalidate(); + } + + + public void DeSelectecShape() + { + if (this.selectedShapes != null && this.selectedShapes.Count > 0) + { + this.SetHiding(false); + this.selectionChanged?.Invoke(new List()); + this.hShapeIsSelected = false; + this.Invalidate(); + } + } + + + + + + + + + + ///// + ///// 设置编辑状态 + ///// + ///// false:创建图形,true:编辑图形 + //public void SetEditing(bool value = true) + //{ + // this._isEditMode = !value; + // if (!this._isEditMode) + // { + // // CREATE -> EDIT + // //Repaint(); + // } + // else + // { + // // EDIT -> CREATE + // UnHighlight(); + // DeSelectShape(); + // } + //} + + + + /// + /// 设置编辑状态 + /// + /// false:创建图形,true:编辑图形 + public void StopDraw() + { + this._isEditMode = true; + + // EDIT -> CREATE + UnHighlight(); + DeSelectShape(); + + } + + + + + /// + /// 设置为绘图状态 + /// + public void StartDraw(ShapeTypeEnum shapeType) + { + this._isEditMode = false; + this._createMode = shapeType; + + // CREATE -> EDIT + //Repaint(); + } + + + private void Canvas_shapeSelectionChanged(List selected_shapes) + { + //this._noSelectionsSlot = true; + //this.canvas.selectedShapes.ForEach(shp => shp.Selected = false); + //this.dgvLabelList.ClearSelection(); + //this.selectedShapes = selected_shapes; + //this.selectedShapes.ForEach(shape => + //{ + // shape.Selected = true; + // foreach (DataGridViewRow row in this.dgvLabelList.Rows) + // { + // if (row.IsNewRow) + // { + // continue; + // } + // if (row.Tag is not ShapeListItemTag listItemTag) + // { + // continue; + // } + // if (listItemTag.Shape == shape) + // { + // row.Selected = true; + // } + // } + //}); + //this._noSelectionsSlot = false; + + //bool n_selected = selected_shapes.Count > 0; + + //this.btnDeleteSelectedShape.Enabled = n_selected; + //this.btnCopySelectedShape.Enabled = n_selected; + //this.btnEditMode.Enabled = n_selected; + + } + + + + public void ClearDraw() + { + this.OutsideShapes.Clear(); + Invalidate(); + } + + public void DrawCircle(PointF center, float r, float lineWidth = 2) + { + FlyShape flyShape = new FlyShape(); + flyShape.Points.Add(center); + flyShape.Points.Add(new PointF(center.X + r, center.Y)); + flyShape.ShapeType = ShapeTypeEnum.Circle; + flyShape.line_color = Color.Red; + flyShape.LineWidth = lineWidth; + + OutsideShapes.Add(flyShape); + + Invalidate(); + } + + + + /// + /// + /// + /// + /// + /// + public void DrawLine(PointF p1, PointF p2, float rectWidth=0) + { + FlyShape shp = new FlyShape(); + shp.Points.Add(p1); + shp.Points.Add(p2); + shp.ShapeType = ShapeTypeEnum.Line; + shp.line_color = Color.Red; + shp.LineWidth = 2; + if (rectWidth > 0) + { + shp.IsDrawLineVirtualRect = true; + shp.LineVirtualRectWidth = rectWidth; + } + + OutsideShapes.Add(shp); + + Invalidate(); + } + + public void DrawRectangle(PointF p1, PointF p2, float rotate) + { + FlyShape flyShape = new FlyShape(); + flyShape.Points.Add(p1); + //flyShape.Points.Add(new PointF(p2.X, p1.Y)); // 改动6 + flyShape.Points.Add(p2); + //flyShape.Points.Add(new PointF(p1.X, p2.Y)); // 改动6 + flyShape.ShapeType = ShapeTypeEnum.Rectangle; + flyShape.line_color = Color.Red; + flyShape.LineWidth = 2; + flyShape._currentRotateAngle = rotate; + + OutsideShapes.Add(flyShape); + + Invalidate(); + } + + } +} diff --git a/CanFly.Canvas/UI/FlyCanvas.resx b/CanFly.Canvas/UI/FlyCanvas.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/CanFly.Canvas/UI/FlyCanvas.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/CanFly/Helper/HDevEngineTool.cs b/CanFly/Helper/HDevEngineTool.cs new file mode 100644 index 0000000..7c30831 --- /dev/null +++ b/CanFly/Helper/HDevEngineTool.cs @@ -0,0 +1,676 @@ +using HalconDotNet; +using System.Diagnostics; +using System.Drawing.Imaging; +using System.Runtime.ExceptionServices; +using System.Runtime.InteropServices; + +namespace CanFly.Helper +{ + public class HDevEngineTool : IDisposable + { + #region 常量 + + // path of external procedures + readonly string ProcedurePath = Environment.CurrentDirectory + "\\Vision\\"; + + #endregion + + #region 成员变量 + + /// + /// 处理过程名 + /// + public string ProcedureName; + + /// + /// hdev程序启动引擎 + /// + private readonly HDevEngine myEngine; + + /// + /// 过程载入工具 .hdvp + /// + private HDevProcedureCall procedureCall; + + /// + /// 程序运行是否成功 + /// + public bool IsSuccessful { get; set; } = false; + + /// + /// 控制参数字典 + /// + public Dictionary InputTupleDic { get; set; } + + /// + /// 图形参数字典 + /// + public Dictionary InputImageDic { get; set; } + + #endregion + + #region 初始化 + /// + /// 实例化 默认搜索路径为: 启动路径//Vision// + /// + public HDevEngineTool() + { + ProcedureName = ""; + myEngine = new HDevEngine(); + myEngine.SetProcedurePath(ProcedurePath); + + InputImageDic = new Dictionary(); + InputTupleDic = new Dictionary(); + } + + /// + /// 实例化 + /// + /// 外部函数搜索路径 + public HDevEngineTool(string path) + { + myEngine = new HDevEngine(); + myEngine.SetProcedurePath(path); + + InputImageDic = new Dictionary(); + InputTupleDic = new Dictionary(); + } + #endregion + + + + /// + /// 设置函数运行所需参数 + /// + /// 控制参数 + /// 图形参数 + public void SetDictionary(Dictionary _tupleDictionary, Dictionary _imageDictionary) + { + InputTupleDic = _tupleDictionary; + InputImageDic = _imageDictionary; + } + + + + /// + /// 载入过程 .hdvp + /// + /// 过程名 + public void LoadProcedure(string procedureName) + { + ProcedureName = procedureName; + try + { + HDevProcedure procedure = new HDevProcedure(procedureName); + procedureCall = new HDevProcedureCall(procedure); + } + catch (HDevEngineException Ex) + { + Trace.TraceInformation("HDevProgram {0} Load fail ,Error Line : {1}, Line number: {2}, Halcon error number : {3}", Ex.ProcedureName, Ex.LineText, Ex.LineNumber, Ex.HalconError); + return; + } + } + + + + /// + /// 执行过程 + /// + [HandleProcessCorruptedStateExceptions] + public bool RunProcedure(out string errorMsg, out int timeElasped) + { + //lock (_runLock) + { + errorMsg = ""; + Stopwatch sw = new Stopwatch(); + sw.Start(); + try + { + foreach (KeyValuePair pair in InputTupleDic) + { + procedureCall.SetInputCtrlParamTuple(pair.Key, pair.Value); + } + + foreach (KeyValuePair pair in InputImageDic) + { + procedureCall.SetInputIconicParamObject(pair.Key, pair.Value); + } + + procedureCall.Execute(); + + IsSuccessful = true; + } + catch (HDevEngineException ex) + { + IsSuccessful = false; + errorMsg = $"HDevProgram {ex.ProcedureName} Run fail , Line number: {ex.LineNumber}, Halcon error number : {ex.HalconError},ex:{ex.Message}"; + } + finally + { + sw.Stop(); + timeElasped = (int)sw.ElapsedMilliseconds; + } + return IsSuccessful; + } + } + + object _runLock = new object(); + /// + /// 执行过程 + /// + public Tuple, Dictionary, string, int> RunProcedure(Dictionary inputHTupleDict, Dictionary inputImgDict, List outputHTuples = null, List outputObjs = null) + { + lock (_runLock) + { + string errorMsg = ""; + int timeElasped = 0; + bool result = false; + Dictionary outputHTupleDict = new Dictionary(); + Dictionary outputObjDict = new Dictionary(); + + Stopwatch sw = new Stopwatch(); + sw.Start(); + try + { + if (inputHTupleDict != null && inputHTupleDict.Count > 0) + { + foreach (KeyValuePair pair in inputHTupleDict) + { + procedureCall.SetInputCtrlParamTuple(pair.Key, pair.Value); + } + } + + if (InputImageDic != null && inputImgDict.Count > 0) + { + foreach (KeyValuePair pair in inputImgDict) + { + procedureCall.SetInputIconicParamObject(pair.Key, pair.Value); + } + } + + procedureCall.Execute(); + + result = true; + } + catch (HDevEngineException ex) + { + result = false; + errorMsg += $"HDevProgram {ex.ProcedureName} Run fail , Line number: {ex.LineNumber}, Halcon error number : {ex.HalconError},ex:{ex.Message}"; + } + finally + { + sw.Stop(); + timeElasped = (int)sw.ElapsedMilliseconds; + } + + if (result) + { + if (outputHTuples != null && outputHTuples.Count > 0) + { + outputHTuples.ForEach(t => + { + try + { + outputHTupleDict[t] = procedureCall.GetOutputCtrlParamTuple(t); + } + catch (Exception ex) + { + result = false; + errorMsg += $"\r\n获取{t}结果异常:{ex.Message}"; + + outputHTupleDict[t] = null; + } + }); + } + + if (outputObjs != null && outputObjs.Count > 0) + { + outputObjs.ForEach(t => + { + try + { + outputObjDict[t] = procedureCall.GetOutputIconicParamObject(t); + } + catch (Exception ex) + { + result = false; + errorMsg += $"\r\n获取{t}结果异常:{ex.Message}"; + + outputObjDict[t] = null; + } + }); + } + } + Tuple, Dictionary, string, int> ret = new Tuple, Dictionary, string, int>(result, outputHTupleDict, outputObjDict, errorMsg, timeElasped); + return ret; + } + } + + public HTuple GetResultTuple(string key) + { + try + { + if (IsSuccessful) + { + return procedureCall.GetOutputCtrlParamTuple(key); + } + else + { + return new HTuple(); + } + } + catch (Exception ex) + { + return new HTuple(); + } + + } + + public HObject GetResultObject(string key, bool ignoreError = false) + { + try + { + if (ignoreError || IsSuccessful) + { + return procedureCall.GetOutputIconicParamObject(key); + } + else + { + return new HObject(); + } + } + catch (Exception ex) + { + return new HObject(); + } + } + + public void Dispose() + { + procedureCall?.Dispose(); + myEngine?.Dispose(); + } + } + + public static class HalconHelper + { + [DllImport("kernel32.dll", EntryPoint = "CopyMemory", SetLastError = false)] + public static extern void CopyMemory(IntPtr dest, IntPtr src, uint count); + + public static HImage Convert8GrayBitmapToHImage(this Bitmap bmp) + { + HImage himage = new HImage(); + try + { + //判断输入图像不为null + if (bmp == null) + { + return null; + } + + { + //重绘himage + //HImage curImage = new HImage(); + BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, PixelFormat.Format8bppIndexed); + himage.GenImage1("byte", bmp.Width, bmp.Height, bmpData.Scan0); + bmp.UnlockBits(bmpData); + //himage = curImage; + } + return himage; + } + catch (Exception e) + { + return null; + } + } + + public static Bitmap ConvertHImageToBitmap(this HObject hImage) + { + HOperatorSet.CountChannels(hImage, out HTuple chanels); + if (chanels.I == 1) + { + return hImage.ConvertHImageTo8GrayBitmap(); + } + else + { + return hImage.ConvertHImageToRGBBitmap(); + //return hImage.HObject2BitmapRGB(); + } + } + + public static Bitmap HObject2BitmapRGB(this HObject hObject) + { + ////获取图像尺寸 + HTuple width0, height0, type, width, height; + //获取图像尺寸 + HOperatorSet.GetImageSize(hObject, out width0, out height0); + // 创建交错格式图像 + HOperatorSet.InterleaveChannels(hObject, out HObject InterImage, "argb", "match", 255); //"rgb", 4 * width0, 0 "argb", "match", 255 + + //获取交错格式图像指针 + HOperatorSet.GetImagePointer1(InterImage, out HTuple Pointer, out type, out width, out height); + IntPtr ptr = Pointer; + //构建新Bitmap图像 + Bitmap res32 = new Bitmap(width / 4, height, width, PixelFormat.Format32bppArgb, ptr); // Format32bppArgb Format24bppRgb + + //32位Bitmap转24位 + var res24 = new Bitmap(res32.Width, res32.Height, PixelFormat.Format24bppRgb); + Graphics graphics = Graphics.FromImage(res24); + graphics.DrawImage(res32, new Rectangle(0, 0, res32.Width, res32.Height)); + + return res24; + } + + public static Bitmap ConvertHImageTo8GrayBitmap(this HObject hImage) + { + try + { + HTuple type, width, height, pointer; + HOperatorSet.GetImagePointer1(hImage, out pointer, out type, out width, out height); + + Bitmap bmp = new Bitmap(width.I, height.I, PixelFormat.Format8bppIndexed); + ColorPalette pal = bmp.Palette; + for (int i = 0; i <= 255; i++) + { + pal.Entries[i] = Color.FromArgb(255, i, i, i); + } + bmp.Palette = pal; + + BitmapData bitmapData = bmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed); + + if (width % 4 == 0) + { + CopyMemory(bitmapData.Scan0, (IntPtr)pointer.D, (uint)(bitmapData.Stride * height.I)); + } + else + { + Parallel.For(0, height.I, h => + { + CopyMemory(bitmapData.Scan0 + h * bitmapData.Stride, (IntPtr)(pointer.D + h * width.I), (uint)width.I); + }); + } + + bmp.UnlockBits(bitmapData); + return bmp; + } + catch (Exception ex) + { + return null; + } + } + + public static Bitmap ConvertHImageToRGBBitmap(this HObject hImage) + { + try + { + HOperatorSet.GetImagePointer3(hImage, out HTuple pointRed, out HTuple pointGreen, out HTuple pointBlue, out HTuple type, out HTuple width, out HTuple height); + Bitmap image = new Bitmap(width.I, height.I, PixelFormat.Format24bppRgb); + BitmapData imageData = image.LockBits(new Rectangle(0, 0, width.I, height.I), ImageLockMode.ReadWrite, image.PixelFormat); + IntPtr pR = (IntPtr)pointRed.D; + IntPtr pG = (IntPtr)pointGreen.D; + IntPtr pB = (IntPtr)pointBlue.D; + Parallel.For(0, imageData.Height, h => + { + Parallel.For(0, imageData.Width, w => + { + int dest = h * imageData.Stride + w * 3; + int source = h * imageData.Width + w; + + Marshal.WriteByte(imageData.Scan0, dest, Marshal.ReadByte(pB, source)); + Marshal.WriteByte(imageData.Scan0, dest + 1, Marshal.ReadByte(pG, source)); + Marshal.WriteByte(imageData.Scan0, dest + 2, Marshal.ReadByte(pR, source)); + }); + }); + + image.UnlockBits(imageData); + return image; + } + catch (Exception exc) + { + return null; + } + } + + public static Bitmap ConvertHImageTo16GrayBitmap(this HImage originHImage) + { + //IntPtr pointer = hImage.GetImagePointer1(out string type, out int width, out int height); + + //int widthIn4 = (int)Math.Ceiling(width / 4.0) * 4; + + ////Bitmap bmp = new Bitmap(widthIn4, height, PixelFormat.Format48bppRgb); + //Bitmap showImage = new Bitmap(widthIn4, height, PixelFormat.Format48bppRgb); + + //Rectangle rect = new Rectangle(0, 0, widthIn4, height); + ////BitmapData bitmapData = bmp.LockBits(rect, ImageLockMode.WriteOnly, PixelFormat.Format48bppRgb); + //BitmapData showImageData = showImage.LockBits(rect, ImageLockMode.WriteOnly, PixelFormat.Format48bppRgb); + //unsafe + //{ + // byte* data = (byte*)pointer; + // //byte* bitmapBuffer = (byte*)bitmapData.Scan0; + // byte* showBitmapBuffer = (byte*)showImageData.Scan0; + + // Parallel.For(0, width * height, i => + // { + // int index = (i + 1) % width + widthIn4 * ((int)Math.Floor((double)(i + 1) / width)) - 1; + + // //showBitmapBuffer[index * 6] = bitmapBuffer[index * 6] = data[i * 2]; + // //showBitmapBuffer[index * 6 + 1] = bitmapBuffer[index * 6 + 1] = data[i * 2 + 1]; + // showBitmapBuffer[index * 6] = data[i * 2]; + // showBitmapBuffer[index * 6 + 1] = data[i * 2 + 1]; + // }); + //} + + ////bmp.UnlockBits(bitmapData); + //showImage.UnlockBits(showImageData); + + //return showImage; + + // dev_set_draw('margin') + //read_image(Image, '0.tif') + + HImage hImage = originHImage.Clone(); + + //* 如果16位图像非常暗的话,建议在这一步进行提亮,因为后面8位图像大幅度提亮易造成色阶断裂,出现不连续的像素块 + // * scale_image(Image, Image, 25, 0) + //hImage = hImage.ScaleImage(25.0, 0.0); + + //get_domain(Image, rectangle) + //* 获取全图中像素灰度值的最大和最小值 + //min_max_gray(rectangle, Image, 0, Min, Max, range) + hImage.MinMaxGray(hImage.GetDomain(), 0, out double min, out double max, out double range); + + //* 将16位图的灰度值映射到0 - 255上 + double mult = 255.0 / (max - min); + double add = -mult * min; + hImage = hImage.ScaleImage(mult, add); + + //* 转换为'byte'类型 + //convert_image_type(Image_scaled, ImageConverted, 'byte') + hImage = hImage.ConvertImageType("byte"); + + Bitmap showImage = hImage.ConvertHImageTo8GrayBitmap(); + + hImage.Dispose(); + + return showImage; + + //* 如果转换以后图像整体对比度太低的话,可以提高对比度(这里是对8位图像处理) + //Min:= 20 + //Max:= 160 + //Mult:= 255.0 / (Max - Min) + //Add:= -Mult * Min + //scale_image(ImageConverted, ImageConverted_scaled, Mult, Add) + } + + public static List HTupleToDouble(this HTuple tuple) + { + List list = new List(); + + for (int i = 0; i < tuple.Length; i++) + { + list.Add(tuple[i].D); + } + + return list; + } + + + + + public static HImage ConvertHObjectToHImage(this HObject obj) + { + HOperatorSet.CountChannels(obj, out HTuple channels); + + HImage img = new HImage(); + if (channels.I == 1) + { + HTuple pointer, type, width, height; + HOperatorSet.GetImagePointer1(obj, out pointer, out type, out width, out height); + + img.GenImage1(type, width, height, pointer); + } + else + { + HTuple pRed, pGreen, pBlue, type, width, height; + HOperatorSet.GetImagePointer3(obj, out pRed, out pGreen, out pBlue, out type, out width, out height); + + img.GenImage3(type, width, height, pRed, pGreen, pBlue); + } + + return img; + } + + #region 灰度图转换为伪彩图 + public static Bitmap ConvertGrayImageToPesudoColorfulImage(this HImage hImage, double max = 0, double min = 0, double zoom = 1, bool isShowHeightTip = false, int zResolution = 100000) + { + hImage.GetImageSize(out int width, out int height); + hImage.MinMaxGray(new HRegion(0.0, 0.0, width, height), 3, out HTuple roiMin, out HTuple roiMax, out _); + + if (max == 0) + { + max = roiMax; + } + + if (min == 0) + { + min = roiMin; + } + + double mult = 235 / (zoom * (max - min)); + double add = (0 - mult) * min * zoom + 10; + HOperatorSet.ScaleImage(hImage, out HObject imageScaled, mult, add); + HOperatorSet.ConvertImageType(imageScaled, out imageScaled, "byte"); + Stopwatch sw = new Stopwatch(); + sw.Start(); + + HOperatorSet.GetImagePointer1(imageScaled, out HTuple pointer, out HTuple type, out _, out _); + Bitmap bitmap = new Bitmap(width, height, PixelFormat.Format24bppRgb); + BitmapData bitmapData = bitmap.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, bitmap.PixelFormat); + + unsafe + { + byte* data = (byte*)(IntPtr)pointer; + byte* bitmapDataBuff = (byte*)bitmapData.Scan0; + + if (width % 4 != 0) + { + Parallel.For(0, height, h => + { + Parallel.For(0, width, w => + { + byte gray = data[h * width + w]; + byte[] convertBytes = ConvertByteToColorfulArray(gray); + + Marshal.Copy(convertBytes, 0, (IntPtr)(bitmapDataBuff + h * bitmapData.Stride + w * 3), 3); + }); + }); + } + else + { + Parallel.For(0, width * height, i => + { + byte gray = data[i]; + byte[] convertBytes = ConvertByteToColorfulArray(gray); + + Marshal.Copy(convertBytes, 0, (IntPtr)(bitmapDataBuff + i * 3), 3); + }); + } + } + bitmap.UnlockBits(bitmapData); + + if (isShowHeightTip) + { + List lableList = new List() { 5, 30, 60, 90, 120, 150, 180, 210, 240, 255 }; + Dictionary lableColorDict = lableList.ToDictionary( + u => (u - add) / (mult * zResolution), + u => + { + byte[] colorBytes = ConvertByteToColorfulArray(u); + return Color.FromArgb(colorBytes[2], colorBytes[1], colorBytes[0]); + }); + + using (Graphics g = Graphics.FromImage(bitmap)) + { + int rectHeight = (int)(bitmap.Height / (5.0 * lableColorDict.Count)); + Font font = new Font("宋体", (int)(rectHeight * 0.75), GraphicsUnit.Pixel); + + string lable = lableColorDict.ElementAt(0).Key.ToString("f3"); + SizeF lableSize = g.MeasureString(lable, font); + int rectWidth = (int)(lableSize.Width * 1.5); + + int startX = 0; + int startY = 0; + foreach (KeyValuePair pair in lableColorDict) + { + g.FillRectangle(new SolidBrush(pair.Value), startX, startY, rectWidth, rectHeight); + g.DrawString(pair.Key.ToString("f3"), font, new SolidBrush(Color.White), (float)(startX + (rectWidth - lableSize.Width) / 2.0), (float)(startY + (rectHeight - lableSize.Height) / 2.0)); + + startY += rectHeight; + } + } + } + + sw.Stop(); + //LogAsync(DateTime.Now, EnumHelper.LogLevel.Information, $"转换耗时{sw.ElapsedMilliseconds}ms"); + return bitmap; + } + + private static byte[] ConvertByteToColorfulArray(byte gray) + { + byte[] bytes = new byte[3]; + if (gray == 0) + { + bytes[2] = 255; + bytes[1] = 255; + bytes[0] = 255; + } + if (gray > 0 && gray <= 63) + { + bytes[2] = 0; + bytes[+1] = (byte)(254 - 4 * gray); + bytes[0] = 255; + } + if (gray >= 64 && gray <= 127) + { + bytes[2] = 0; + bytes[1] = (byte)(4 * gray - 254); + bytes[0] = (byte)(510 - 4 * gray); + } + if (gray >= 128 && gray <= 191) + { + bytes[2] = (byte)(4 * gray - 510); + bytes[1] = 255; + bytes[0] = 0; + } + if (gray >= 192 && gray <= 255) + { + bytes[2] = 255; + bytes[1] = (byte)(1022 - 4 * gray); + bytes[0] = 0; + } + + return bytes; + } + #endregion + } +} diff --git a/CanFly/Program.cs b/CanFly/Program.cs new file mode 100644 index 0000000..89948a3 --- /dev/null +++ b/CanFly/Program.cs @@ -0,0 +1,17 @@ +namespace CanFly +{ + //internal static class Program + //{ + // /// + // /// The main entry point for the application. + // /// + // [STAThread] + // static void Main() + // { + // // To customize application configuration such as set high DPI settings or default font, + // // see https://aka.ms/applicationconfiguration. + // ApplicationConfiguration.Initialize(); + // Application.Run(new FrmMain2()); + // } + //} +} \ No newline at end of file diff --git a/CanFly/Properties/Resources.Designer.cs b/CanFly/Properties/Resources.Designer.cs new file mode 100644 index 0000000..aeeb7f5 --- /dev/null +++ b/CanFly/Properties/Resources.Designer.cs @@ -0,0 +1,73 @@ +//------------------------------------------------------------------------------ +// +// 此代码由工具生成。 +// 运行时版本:4.0.30319.42000 +// +// 对此文件的更改可能会导致不正确的行为,并且如果 +// 重新生成代码,这些更改将会丢失。 +// +//------------------------------------------------------------------------------ + +namespace XKRS.CanFly.Properties { + using System; + + + /// + /// 一个强类型的资源类,用于查找本地化的字符串等。 + /// + // 此类是由 StronglyTypedResourceBuilder + // 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。 + // 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen + // (以 /str 作为命令选项),或重新生成 VS 项目。 + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// 返回此类使用的缓存的 ResourceManager 实例。 + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("XKRS.CanFly.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// 重写当前线程的 CurrentUICulture 属性,对 + /// 使用此强类型资源类的所有资源查找执行重写。 + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// 查找 System.Drawing.Bitmap 类型的本地化资源。 + /// + internal static System.Drawing.Bitmap Close { + get { + object obj = ResourceManager.GetObject("Close", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + } +} diff --git a/CanFly/Properties/Resources.resx b/CanFly/Properties/Resources.resx new file mode 100644 index 0000000..d77aec4 --- /dev/null +++ b/CanFly/Properties/Resources.resx @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + ..\Resources\Close.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + \ No newline at end of file diff --git a/CanFly/Resources/Close.png b/CanFly/Resources/Close.png new file mode 100644 index 0000000..4c35b76 Binary files /dev/null and b/CanFly/Resources/Close.png differ diff --git a/CanFly/Resources/circle.png b/CanFly/Resources/circle.png new file mode 100644 index 0000000..0634f9e Binary files /dev/null and b/CanFly/Resources/circle.png differ diff --git a/CanFly/UI/BaseFrmGuide.Designer.cs b/CanFly/UI/BaseFrmGuide.Designer.cs new file mode 100644 index 0000000..97e8cd9 --- /dev/null +++ b/CanFly/UI/BaseFrmGuide.Designer.cs @@ -0,0 +1,117 @@ +namespace CanFly.UI +{ + partial class BaseFrmGuide + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + flowLayoutPanel = new FlowLayoutPanel(); + pbLogo = new PictureBox(); + lblTitle = new Label(); + flowPanelContent = new FlowLayoutPanel(); + panelMain = new Panel(); + flowLayoutPanel.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)pbLogo).BeginInit(); + panelMain.SuspendLayout(); + SuspendLayout(); + // + // flowLayoutPanel + // + flowLayoutPanel.Controls.Add(pbLogo); + flowLayoutPanel.Controls.Add(lblTitle); + flowLayoutPanel.Dock = DockStyle.Top; + flowLayoutPanel.Location = new Point(0, 0); + flowLayoutPanel.Name = "flowLayoutPanel1"; + flowLayoutPanel.Size = new Size(692, 36); + flowLayoutPanel.TabIndex = 0; + // + // pbLogo + // + pbLogo.Location = new Point(3, 3); + pbLogo.Name = "pbLogo"; + pbLogo.Size = new Size(30, 30); + pbLogo.SizeMode = PictureBoxSizeMode.StretchImage; + pbLogo.TabIndex = 0; + pbLogo.TabStop = false; + pbLogo.Visible = false; + // + // lblTitle + // + lblTitle.AutoSize = true; + lblTitle.Dock = DockStyle.Fill; + lblTitle.Font = new Font("Microsoft YaHei UI", 12F, FontStyle.Bold, GraphicsUnit.Point); + lblTitle.Location = new Point(39, 0); + lblTitle.Name = "lblTitle"; + lblTitle.Size = new Size(20, 36); + lblTitle.TabIndex = 1; + lblTitle.Text = " "; + lblTitle.TextAlign = ContentAlignment.MiddleLeft; + // + // flowPanelContent + // + flowPanelContent.Dock = DockStyle.Fill; + flowPanelContent.Location = new Point(0, 0); + flowPanelContent.Name = "flowPanelContent"; + flowPanelContent.Size = new Size(692, 511); + flowPanelContent.TabIndex = 1; + // + // panelMain + // + panelMain.AutoScroll = true; + panelMain.Controls.Add(flowPanelContent); + panelMain.Dock = DockStyle.Fill; + panelMain.Location = new Point(0, 36); + panelMain.Name = "panelMain"; + panelMain.Size = new Size(692, 511); + panelMain.TabIndex = 2; + // + // BaseFrmGuide + // + AutoScaleDimensions = new SizeF(7F, 17F); + AutoScaleMode = AutoScaleMode.Font; + ClientSize = new Size(692, 547); + Controls.Add(panelMain); + Controls.Add(flowLayoutPanel); + FormBorderStyle = FormBorderStyle.None; + Name = "BaseFrmGuide"; + Text = "BaseFrmGuide"; + Load += BaseFrmGuide_Load; + flowLayoutPanel.ResumeLayout(false); + flowLayoutPanel.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)pbLogo).EndInit(); + panelMain.ResumeLayout(false); + ResumeLayout(false); + } + + #endregion + + private FlowLayoutPanel flowLayoutPanel; + private PictureBox pbLogo; + private Label lblTitle; + protected FlowLayoutPanel flowPanelContent; + private Panel panelMain; + } +} \ No newline at end of file diff --git a/CanFly/UI/BaseFrmGuide.cs b/CanFly/UI/BaseFrmGuide.cs new file mode 100644 index 0000000..66c2421 --- /dev/null +++ b/CanFly/UI/BaseFrmGuide.cs @@ -0,0 +1,53 @@ +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; + +namespace CanFly.UI +{ + public partial class BaseFrmGuide : Form + { + public BaseFrmGuide() + { + InitializeComponent(); + + // 处理 Panel 的大小变化事件,以动态更新控件宽度 + panelMain.SizeChanged += PanelMain_SizeChanged; ; + } + + + private void PanelMain_SizeChanged(object? sender, EventArgs e) + { + foreach (Control control in flowPanelContent.Controls) + { + control.Width = panelMain.Width - 6; // 根据 Panel 的宽度调整控件 + } + } + + + public void SetTitle(string title) + { + this.lblTitle.Text = title; + } + + + public void SetLogo(Image logo) + { + this.pbLogo.BackgroundImage = logo; + this.pbLogo.SizeMode = PictureBoxSizeMode.StretchImage; + this.pbLogo.Refresh(); + } + + private void BaseFrmGuide_Load(object sender, EventArgs e) + { + + } + + + } +} diff --git a/CanFly/UI/BaseFrmGuide.resx b/CanFly/UI/BaseFrmGuide.resx new file mode 100644 index 0000000..8b2ff64 --- /dev/null +++ b/CanFly/UI/BaseFrmGuide.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/CanFly/UI/FrmMain.Designer.cs b/CanFly/UI/FrmMain.Designer.cs new file mode 100644 index 0000000..d51c67d --- /dev/null +++ b/CanFly/UI/FrmMain.Designer.cs @@ -0,0 +1,279 @@ + + +namespace CanFly +{ + partial class FrmMain + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(FrmMain)); + panel1 = new Panel(); + canvas = new Canvas.UI.FlyCanvas(); + statusStrip1 = new StatusStrip(); + lblStatus = new ToolStripStatusLabel(); + flowLayoutPanel1 = new FlowLayoutPanel(); + btnLoadImage = new Button(); + btnCreateCircle = new Button(); + btnCreateRect = new Button(); + btnStopDraw = new Button(); + btnTestOutsideDraw = new Button(); + btnTestClearDraw = new Button(); + btnTestCircleMeasure = new Button(); + btnTest = new Button(); + splitContainer = new SplitContainer(); + panelGuide = new Panel(); + btnRotateTest = new Button(); + panel1.SuspendLayout(); + statusStrip1.SuspendLayout(); + flowLayoutPanel1.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)splitContainer).BeginInit(); + splitContainer.Panel1.SuspendLayout(); + splitContainer.Panel2.SuspendLayout(); + splitContainer.SuspendLayout(); + SuspendLayout(); + // + // panel1 + // + panel1.BorderStyle = BorderStyle.FixedSingle; + panel1.Controls.Add(canvas); + panel1.Controls.Add(statusStrip1); + panel1.Dock = DockStyle.Fill; + panel1.Location = new Point(0, 0); + panel1.Name = "panel1"; + panel1.Size = new Size(947, 791); + panel1.TabIndex = 1; + // + // canvas + // + canvas.AllowMultiSelect = false; + canvas.CreateMode = Canvas.Shape.ShapeTypeEnum.Polygon; + canvas.Dock = DockStyle.Fill; + canvas.Enabled = false; + canvas.FillDrawing = false; + canvas.Location = new Point(0, 0); + canvas.Margin = new Padding(2); + canvas.Name = "canvas"; + canvas.OutsideShapes = (List)resources.GetObject("canvas.OutsideShapes"); + canvas.Scale = 1F; + canvas.Shapes = (List)resources.GetObject("canvas.Shapes"); + canvas.Size = new Size(945, 767); + canvas.TabIndex = 2; + // + // statusStrip1 + // + statusStrip1.Items.AddRange(new ToolStripItem[] { lblStatus }); + statusStrip1.Location = new Point(0, 767); + statusStrip1.Name = "statusStrip1"; + statusStrip1.Size = new Size(945, 22); + statusStrip1.TabIndex = 1; + statusStrip1.Text = "statusStrip1"; + // + // lblStatus + // + lblStatus.Name = "lblStatus"; + lblStatus.Size = new Size(44, 17); + lblStatus.Text = " "; + // + // flowLayoutPanel1 + // + flowLayoutPanel1.BorderStyle = BorderStyle.FixedSingle; + flowLayoutPanel1.Controls.Add(btnLoadImage); + flowLayoutPanel1.Controls.Add(btnCreateCircle); + flowLayoutPanel1.Controls.Add(btnCreateRect); + flowLayoutPanel1.Controls.Add(btnStopDraw); + flowLayoutPanel1.Controls.Add(btnTestOutsideDraw); + flowLayoutPanel1.Controls.Add(btnTestClearDraw); + flowLayoutPanel1.Controls.Add(btnTestCircleMeasure); + flowLayoutPanel1.Controls.Add(btnTest); + flowLayoutPanel1.Controls.Add(btnRotateTest); + flowLayoutPanel1.Dock = DockStyle.Top; + flowLayoutPanel1.Location = new Point(0, 0); + flowLayoutPanel1.Name = "flowLayoutPanel1"; + flowLayoutPanel1.Size = new Size(1185, 40); + flowLayoutPanel1.TabIndex = 2; + // + // btnLoadImage + // + btnLoadImage.Location = new Point(3, 3); + btnLoadImage.Name = "btnLoadImage"; + btnLoadImage.Size = new Size(75, 30); + btnLoadImage.TabIndex = 0; + btnLoadImage.Text = "加载图像"; + btnLoadImage.UseVisualStyleBackColor = true; + btnLoadImage.Click += btnLoadImage_Click; + // + // btnCreateCircle + // + btnCreateCircle.Enabled = false; + btnCreateCircle.Location = new Point(84, 3); + btnCreateCircle.Name = "btnCreateCircle"; + btnCreateCircle.Size = new Size(75, 30); + btnCreateCircle.TabIndex = 1; + btnCreateCircle.Text = "绘制圆形"; + btnCreateCircle.UseVisualStyleBackColor = true; + btnCreateCircle.Click += btnCreateCircle_Click; + // + // btnCreateRect + // + btnCreateRect.Location = new Point(165, 3); + btnCreateRect.Name = "btnCreateRect"; + btnCreateRect.Size = new Size(75, 30); + btnCreateRect.TabIndex = 6; + btnCreateRect.Text = "绘制矩形"; + btnCreateRect.UseVisualStyleBackColor = true; + btnCreateRect.Click += btnCreateRect_Click; + // + // btnStopDraw + // + btnStopDraw.Enabled = false; + btnStopDraw.Location = new Point(246, 3); + btnStopDraw.Name = "btnStopDraw"; + btnStopDraw.Size = new Size(75, 30); + btnStopDraw.TabIndex = 2; + btnStopDraw.Text = "停止绘制"; + btnStopDraw.UseVisualStyleBackColor = true; + btnStopDraw.Click += btnStopDraw_Click; + // + // btnTestOutsideDraw + // + btnTestOutsideDraw.Location = new Point(327, 3); + btnTestOutsideDraw.Name = "btnTestOutsideDraw"; + btnTestOutsideDraw.Size = new Size(75, 30); + btnTestOutsideDraw.TabIndex = 3; + btnTestOutsideDraw.Text = "测试绘图"; + btnTestOutsideDraw.UseVisualStyleBackColor = true; + btnTestOutsideDraw.Click += btnTestOutsideDraw_Click; + // + // btnTestClearDraw + // + btnTestClearDraw.Location = new Point(408, 3); + btnTestClearDraw.Name = "btnTestClearDraw"; + btnTestClearDraw.Size = new Size(75, 30); + btnTestClearDraw.TabIndex = 4; + btnTestClearDraw.Text = "清除绘图"; + btnTestClearDraw.UseVisualStyleBackColor = true; + btnTestClearDraw.Click += btnTestClearDraw_Click; + // + // btnTestCircleMeasure + // + btnTestCircleMeasure.Location = new Point(489, 3); + btnTestCircleMeasure.Name = "btnTestCircleMeasure"; + btnTestCircleMeasure.Size = new Size(89, 30); + btnTestCircleMeasure.TabIndex = 5; + btnTestCircleMeasure.Text = "测试圆形算法"; + btnTestCircleMeasure.UseVisualStyleBackColor = true; + btnTestCircleMeasure.Click += btnTestCircleMeasure_Click; + // + // btnTest + // + btnTest.Location = new Point(584, 3); + btnTest.Name = "btnTest"; + btnTest.Size = new Size(89, 30); + btnTest.TabIndex = 7; + btnTest.Text = "测试"; + btnTest.UseVisualStyleBackColor = true; + btnTest.Click += btnTest_Click; + // + // splitContainer + // + splitContainer.Dock = DockStyle.Fill; + splitContainer.Location = new Point(0, 40); + splitContainer.Name = "splitContainer"; + // + // splitContainer.Panel1 + // + splitContainer.Panel1.Controls.Add(panelGuide); + splitContainer.Panel1MinSize = 150; + // + // splitContainer.Panel2 + // + splitContainer.Panel2.Controls.Add(panel1); + splitContainer.Size = new Size(1185, 791); + splitContainer.SplitterDistance = 234; + splitContainer.TabIndex = 3; + // + // panelGuide + // + panelGuide.BorderStyle = BorderStyle.FixedSingle; + panelGuide.Dock = DockStyle.Fill; + panelGuide.Location = new Point(0, 0); + panelGuide.Name = "panelGuide"; + panelGuide.Size = new Size(234, 791); + panelGuide.TabIndex = 0; + // + // btnRotateTest + // + btnRotateTest.Location = new Point(679, 3); + btnRotateTest.Name = "btnRotateTest"; + btnRotateTest.Size = new Size(89, 30); + btnRotateTest.TabIndex = 8; + btnRotateTest.Text = "测试旋转"; + btnRotateTest.UseVisualStyleBackColor = true; + btnRotateTest.Click += btnRotateTest_Click; + // + // FrmMain + // + AutoScaleDimensions = new SizeF(7F, 17F); + AutoScaleMode = AutoScaleMode.Font; + ClientSize = new Size(1185, 831); + Controls.Add(splitContainer); + Controls.Add(flowLayoutPanel1); + Name = "FrmMain"; + Text = "Form1"; + WindowState = FormWindowState.Maximized; + Load += FrmMain_Load; + panel1.ResumeLayout(false); + panel1.PerformLayout(); + statusStrip1.ResumeLayout(false); + statusStrip1.PerformLayout(); + flowLayoutPanel1.ResumeLayout(false); + splitContainer.Panel1.ResumeLayout(false); + splitContainer.Panel2.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)splitContainer).EndInit(); + splitContainer.ResumeLayout(false); + ResumeLayout(false); + } + + #endregion + private Panel panel1; + private FlowLayoutPanel flowLayoutPanel1; + private SplitContainer splitContainer; + private Panel panelGuide; + private Button btnLoadImage; + private Button btnCreateCircle; + private Button btnStopDraw; + private StatusStrip statusStrip1; + private Canvas.UI.FlyCanvas canvas; + private ToolStripStatusLabel lblStatus; + private Button btnTestOutsideDraw; + private Button btnTestClearDraw; + private Button btnTestCircleMeasure; + private Button btnCreateRect; + private Button btnTest; + private Button btnRotateTest; + } +} diff --git a/CanFly/UI/FrmMain.cs b/CanFly/UI/FrmMain.cs new file mode 100644 index 0000000..f576131 --- /dev/null +++ b/CanFly/UI/FrmMain.cs @@ -0,0 +1,345 @@ +using CanFly.Canvas.Shape; +using CanFly.Helper; +using CanFly.UI; +using CanFly.UI.GuidePanel; +using CanFly.Util; +using HalconDotNet; +using System.Diagnostics; +using System.Runtime.CompilerServices; +using System.Windows.Forms; + +namespace CanFly +{ + public partial class FrmMain : Form + { + + private string _currentImageFile = ""; + private System.Windows.Forms.Timer _statusTimer = new System.Windows.Forms.Timer(); + private BaseGuideControl? _currentGuideCtrl; + + + public FrmMain() + { + InitializeComponent(); + this.canvas.mouseMoved += Canvas_mouseMoved; + this.canvas.OnShapeUpdateEvent += Canvas_OnShapeUpdateEvent; + this.canvas.selectionChanged += Canvas_selectionChanged; + + this.canvas.OnShapeMoving += Canvas_OnShapeMoving; + } + + + + private void FrmMain_Load(object sender, EventArgs e) + { + _currentImageFile = @"C:\Users\DEV\Desktop\˿\Cam7_130252457.jpg"; + Bitmap bitmap = (Bitmap)Image.FromFile(_currentImageFile); + this.canvas.LoadPixmap(bitmap); + this.btnCreateCircle.Enabled = true; + this.canvas.Enabled = true; + } + + + private void btnLoadImage_Click(object sender, EventArgs e) + { + OpenFileDialog ofd = new OpenFileDialog(); + ofd.Filter = "ͼļ|*.jpg;*.png"; + ofd.Multiselect = false; + if (ofd.ShowDialog() == DialogResult.OK) + { + _currentImageFile = ofd.FileName; + //this.canvasMain.LoadImageFile(_currentImageFile); + Bitmap bitmap = (Bitmap)Image.FromFile(_currentImageFile); + this.canvas.LoadPixmap(bitmap); + this.btnCreateCircle.Enabled = true; + } + } + + + private void btnCreateCircle_Click(object sender, EventArgs e) + { + //FrmGuideCircle frmGuideCircle = new FrmGuideCircle(); + //panelGuide.ShowForm(frmGuideCircle); + + SwitchGuideForm(ShapeTypeEnum.Circle); + this.canvas.StartDraw(ShapeTypeEnum.Circle); + + this.btnCreateCircle.Enabled = false; + this.btnStopDraw.Enabled = true; + this.canvas.Enabled = true; + } + + + + private void btnCreateRect_Click(object sender, EventArgs e) + { + this.canvas.StartDraw(ShapeTypeEnum.Rectangle); + + this.btnCreateCircle.Enabled = false; + this.btnStopDraw.Enabled = true; + this.canvas.Enabled = true; + } + + + + private void btnStopDraw_Click(object sender, EventArgs e) + { + //panelGuide.Controls.Clear(); + StopDrawMode(); + } + + + + private void StartDrawMode() + { + + } + + + private void StopDrawMode() + { + this.canvas.StopDraw(); + + + this.btnStopDraw.Enabled = false; + this.btnCreateCircle.Enabled = true; + } + + + + + + private void Status(string message, int delay = 5000) + { + _statusTimer.Stop(); + // ʾϢ + lblStatus.Text = message; + + // һʱ + + _statusTimer.Interval = delay; // ӳʱ + _statusTimer.Tick += (sender, e) => + { + _statusTimer.Stop(); // ֹͣʱ + lblStatus.Text = string.Empty; // ״̬Ϣ + }; + _statusTimer.Start(); // ʱ + } + + + + + private void Canvas_mouseMoved(PointF pos) + { + if (InvokeRequired) + { + Invoke(Canvas_mouseMoved, pos); + return; + } + + lblStatus.Text = $"X:{pos.X}, Y:{pos.Y}"; + + } + + + + + private void Canvas_selectionChanged(List shapes) + { + if (shapes.Count != 1) + { + // panelGuide.Controls.Clear(); + return; + } + //SwitchGuideForm(shapes[0].ShapeType); + Canvas_OnShapeUpdateEvent(shapes[0]); + + } + + + + private void SwitchGuideForm(ShapeTypeEnum shapeType) + { + if (_currentGuideCtrl == null) + { + switch (shapeType) + { + case ShapeTypeEnum.Point: + break; + case ShapeTypeEnum.Line: + break; + case ShapeTypeEnum.Rectangle: + break; + case ShapeTypeEnum.Circle: + _currentGuideCtrl = new GuideCircleCtrl(); + _currentGuideCtrl.CurrentImageFile = _currentImageFile; + + _currentGuideCtrl.OnControlCloseEvent += () => + { + panelGuide.Controls.Clear(); + StopDrawMode(); + }; + break; + case ShapeTypeEnum.Polygon: + break; + case ShapeTypeEnum.LineStrip: + break; + default: + break; + } + } + //_currentGuideCtrl?.AddToPanel(panelGuide); + } + + + + private void Canvas_OnShapeMoving(List shapes) + { + if (shapes.Count != 1) + { + panelGuide.Controls.Clear(); + return; + } + + // _currentGuideCtrl?.UpdateShape(shapes[0]); + } + + + + private void Canvas_OnShapeUpdateEvent(FlyShape shape) + { + switch (shape.ShapeType) + { + case ShapeTypeEnum.Point: + break; + case ShapeTypeEnum.Line: + break; + case ShapeTypeEnum.Rectangle: + break; + case ShapeTypeEnum.Circle: + { + //_currentGuideCtrl?.UpdateShape(shape); + } + break; + case ShapeTypeEnum.Polygon: + break; + case ShapeTypeEnum.LineStrip: + break; + default: + break; + } + } + + + + private void btnTestOutsideDraw_Click(object sender, EventArgs e) + { + Random random = new Random((int)DateTime.Now.Ticks); + + for (int i = 0; i < 10; i++) + { + // this.canvas.DrawCircle(new PointF(500, 500), 100); + + int x = random.Next() % 500; + int y = random.Next() % 500; + int r = random.Next() % 200; + + Debug.WriteLine($"X:{x}\tY:{y}\tR:{r}"); + + this.canvas.DrawCircle(new PointF(x, y), r); + } + } + + private void btnTestClearDraw_Click(object sender, EventArgs e) + { + this.canvas.ClearDraw(); + } + + + + private async void btnTestCircleMeasure_Click(object sender, EventArgs e) + { + //string dir = Path.Combine(Environment.CurrentDirectory, "hscripts"); + //string file = "CircleMeasure.hdvp"; + //string filePath = Path.Combine(dir, file); + //if (!File.Exists(filePath)) + //{ + // MessageBox.Show($"ļ {filePath} "); + // return; + //} + + //HObject? hImage = null; + + //try + //{ + // HDevEngineTool tool = new HDevEngineTool(dir); + // tool.LoadProcedure(Path.GetFileNameWithoutExtension(file)); + + // // string imageFile = Path.Combine(Environment.CurrentDirectory, "hscripts", "image.png"); + + // HOperatorSet.ReadImage(out hImage, _currentImageFile); + // tool.InputImageDic["INPUT_Image"] = hImage; + // tool.InputTupleDic["XCenter"] = 981.625; + // tool.InputTupleDic["YCenter"] = 931.823; + // tool.InputTupleDic["Radius"] = 900.141; + + // Stopwatch sw = new Stopwatch(); + // sw.Start(); + // if (!tool.RunProcedure(out string error, out _)) + // { + // throw new Exception(); + // } + // sw.Stop(); + + + + // var flag = tool.GetResultTuple("OUTPUT_Flag").HTupleToDouble(); + // List x = tool.GetResultTuple("RXCenter").HTupleToDouble(); + // var y = tool.GetResultTuple("RYCenter").HTupleToDouble(); + // var r = tool.GetResultTuple("RRadius").HTupleToDouble(); + + // if (flag.Count > 0 && x.Count > 0 && y.Count > 0 && r.Count > 0) + // { + // this.canvas.DrawCircle(new PointF((float)x[0], (float)y[0]), (float)r[0]); + // } + + // // + // Debug.WriteLine(""); + //} + //catch (Exception) + //{ + // throw; + //} + //finally + //{ + // hImage?.Dispose(); + //} + + + } + + private void btnTest_Click(object sender, EventArgs e) + { + this.canvas.DrawRectangle(new PointF(300, 300), + new PointF(800, 500), 33f); + } + + + private void btnRotateTest_Click(object sender, EventArgs e) + { + if (this.canvas.Shapes.Count == 0) + { + return; + } + + this.canvas.Shapes[0]._currentRotateAngle += 10; + + //var shp = this.canvas.Shapes[this.canvas.Shapes.Count - 1].Copy(); + //shp.Rotate += 10; + //this.canvas.Shapes.Add(shp); + + + this.canvas.Invalidate(); + } + } +} diff --git a/CanFly/UI/FrmMain.resx b/CanFly/UI/FrmMain.resx new file mode 100644 index 0000000..251a30f --- /dev/null +++ b/CanFly/UI/FrmMain.resx @@ -0,0 +1,148 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + + + AAEAAAD/////AQAAAAAAAAAMAgAAAERDYW5GbHkuQ2FudmFzLCBWZXJzaW9uPTEuMC4wLjAsIEN1bHR1 + cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49bnVsbAQBAAAAdlN5c3RlbS5Db2xsZWN0aW9ucy5HZW5l + cmljLkxpc3RgMVtbQ2FuRmx5LkNhbnZhcy5TaGFwZS5GbHlTaGFwZSwgQ2FuRmx5LkNhbnZhcywgQ3Vs + dHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1udWxsXV0DAAAABl9pdGVtcwVfc2l6ZQhfdmVyc2lv + bgQAAB5DYW5GbHkuQ2FudmFzLlNoYXBlLkZseVNoYXBlW10CAAAACAgJAwAAAAAAAAAAAAAADAQAAAAz + Q2FuRmx5LkNhbnZhcywgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1udWxsBwMAAAAAAQAA + AAAAAAAEHENhbkZseS5DYW52YXMuU2hhcGUuRmx5U2hhcGUEAAAACw== + + + + + AAEAAAD/////AQAAAAAAAAAMAgAAAERDYW5GbHkuQ2FudmFzLCBWZXJzaW9uPTEuMC4wLjAsIEN1bHR1 + cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49bnVsbAQBAAAAdlN5c3RlbS5Db2xsZWN0aW9ucy5HZW5l + cmljLkxpc3RgMVtbQ2FuRmx5LkNhbnZhcy5TaGFwZS5GbHlTaGFwZSwgQ2FuRmx5LkNhbnZhcywgQ3Vs + dHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1udWxsXV0DAAAABl9pdGVtcwVfc2l6ZQhfdmVyc2lv + bgQAAB5DYW5GbHkuQ2FudmFzLlNoYXBlLkZseVNoYXBlW10CAAAACAgJAwAAAAAAAAAAAAAADAQAAAAz + Q2FuRmx5LkNhbnZhcywgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1udWxsBwMAAAAAAQAA + AAAAAAAEHENhbkZseS5DYW52YXMuU2hhcGUuRmx5U2hhcGUEAAAACw== + + + + 17, 17 + + \ No newline at end of file diff --git a/CanFly/UI/FrmMain3.Designer.cs b/CanFly/UI/FrmMain3.Designer.cs new file mode 100644 index 0000000..3000ef9 --- /dev/null +++ b/CanFly/UI/FrmMain3.Designer.cs @@ -0,0 +1,75 @@ + + +namespace XKRS.CanFly +{ + partial class FrmMain3 + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + statusStrip1 = new StatusStrip(); + panelContent = new Panel(); + SuspendLayout(); + // + // statusStrip1 + // + statusStrip1.Location = new Point(0, 808); + statusStrip1.Name = "statusStrip1"; + statusStrip1.Size = new Size(1185, 22); + statusStrip1.TabIndex = 4; + statusStrip1.Text = "statusStrip1"; + // + // panelContent + // + panelContent.Dock = DockStyle.Fill; + panelContent.Location = new Point(0, 0); + panelContent.Margin = new Padding(4, 3, 4, 3); + panelContent.Name = "panelContent"; + panelContent.Size = new Size(1185, 808); + panelContent.TabIndex = 5; + // + // FrmMain3 + // + AutoScaleDimensions = new SizeF(7F, 17F); + AutoScaleMode = AutoScaleMode.Font; + ClientSize = new Size(1185, 830); + Controls.Add(panelContent); + Controls.Add(statusStrip1); + FormBorderStyle = FormBorderStyle.FixedSingle; + Margin = new Padding(2, 3, 2, 3); + Name = "FrmMain3"; + StartPosition = FormStartPosition.CenterScreen; + Text = "尺寸测量"; + Load += FrmMain_Load; + ResumeLayout(false); + PerformLayout(); + } + + #endregion + private StatusStrip statusStrip1; + private Panel panelContent; + } +} diff --git a/CanFly/UI/FrmMain3.cs b/CanFly/UI/FrmMain3.cs new file mode 100644 index 0000000..1848989 --- /dev/null +++ b/CanFly/UI/FrmMain3.cs @@ -0,0 +1,435 @@ +using CanFly.Canvas.Shape; +using CanFly.Helper; +using CanFly.UI; +using CanFly.UI.GuidePanel; +using CanFly.Util; +using HalconDotNet; +using System.Diagnostics; +using System.Runtime.CompilerServices; +using System.Windows.Forms; + +namespace XKRS.CanFly +{ + + public partial class FrmMain3 : Form + { + + private string _currentImageFile = ""; + private System.Windows.Forms.Timer _statusTimer = new System.Windows.Forms.Timer(); + private BaseGuideControl? _currentGuideCtrl; + + + private GuideCircleCtrl guideCircleCtrl = new GuideCircleCtrl(); + private GuideLineCircleCtrl guideLineCircleCtrl = new GuideLineCircleCtrl(); + private GuideLineLineCtrl guideLineLineCtrl = new GuideLineLineCtrl(); + private GuideLineCtrl guideLineCtrl = new GuideLineCtrl(); + private GuideHeightCtrl guideHeightCtrl = new GuideHeightCtrl(); + string Type=string.Empty; + + + public string inputtext=string.Empty; + public string outtext = string.Empty; + public FrmMain3(string type) + { + InitializeComponent(); + + Type=type; + + guideCircleCtrl.Dock = DockStyle.Fill; + guideCircleCtrl.OnControlCloseEvent -= () => panelContent.Controls.Clear(); + guideCircleCtrl.OnControlCloseEvent += () => panelContent.Controls.Clear(); + + + guideLineCircleCtrl.Dock = DockStyle.Fill; + guideLineCircleCtrl.OnControlCloseEvent -= () => panelContent.Controls.Clear(); + guideLineCircleCtrl.OnControlCloseEvent += () => panelContent.Controls.Clear(); + + guideLineLineCtrl.Dock = DockStyle.Fill; + guideLineLineCtrl.OnControlCloseEvent -= () => panelContent.Controls.Clear(); + guideLineLineCtrl.OnControlCloseEvent += () => panelContent.Controls.Clear(); + + guideLineCtrl.Dock = DockStyle.Fill; + guideLineCtrl.OnControlCloseEvent -= () => panelContent.Controls.Clear(); + guideLineCtrl.OnControlCloseEvent += () => panelContent.Controls.Clear(); + + + guideHeightCtrl.Dock = DockStyle.Fill; + guideHeightCtrl.OnControlCloseEvent -= () => panelContent.Controls.Clear(); + guideHeightCtrl.OnControlCloseEvent += () => panelContent.Controls.Clear(); + } + + + + private void FrmMain_Load(object sender, EventArgs e) + { + switch (Type) + { + case "1": + SwitchMeasureMode(guideCircleCtrl); + break; + case "2": + SwitchMeasureMode(guideLineCtrl); + break; + case "3": + SwitchMeasureMode(guideLineLineCtrl); + break; + case "4": + SwitchMeasureMode(guideLineCircleCtrl); + break; + case "5": + SwitchMeasureMode(guideHeightCtrl); + break; + default: + break; + } + } + + + private void btnLoadImage_Click(object sender, EventArgs e) + { + //OpenFileDialog ofd = new OpenFileDialog(); + //ofd.Filter = "ͼļ|*.jpg;*.png"; + //ofd.Multiselect = false; + //if (ofd.ShowDialog() == DialogResult.OK) + //{ + // _currentImageFile = ofd.FileName; + // Bitmap bitmap = (Bitmap)Image.FromFile(_currentImageFile); + // this.canvas.LoadPixmap(bitmap); + // this.btnCreateCircle.Enabled = true; + //} + } + + + + private void btnMeasureCircle_Click(object sender, EventArgs e) + { + //var contentCtrls = panelContent.Controls; + + //if (contentCtrls.Count > 0) + //{ + // if (contentCtrls[0] == guideCircleCtrl) + // { + // return; + // } + //} + + //panelContent.Controls.Clear(); + //panelContent.Controls.Add(guideCircleCtrl); + + SwitchMeasureMode(guideCircleCtrl); + } + + + private void btnMeasureLineCircle_Click(object sender, EventArgs e) + { + SwitchMeasureMode(guideLineCircleCtrl); + } + + + private void SwitchMeasureMode(BaseGuideControl control) + { + var contentCtrls = panelContent.Controls; + + if (contentCtrls.Count > 0) + { + if (contentCtrls[0] == control) + { + return; + } + } + + panelContent.Controls.Clear(); + + control.OnDataPassed -= Control_OnDataPassed; + control.OnDataPassed += Control_OnDataPassed; + + + + //control.Dock = DockStyle.Fill; + //control.OnControlCloseEvent -= () => panelContent.Controls.Clear(); + //control.OnControlCloseEvent += () => panelContent.Controls.Clear(); + panelContent.Controls.Add(control); + } + + private void Control_OnDataPassed(string obj,string obj1) + { + inputtext = obj; + outtext = obj1; + this.Close(); + } + + private void btnCreateRect_Click(object sender, EventArgs e) + { + //this.canvas.StartDraw(ShapeTypeEnum.Rectangle); + //this.btnCreateCircle.Enabled = false; + //this.btnStopDraw.Enabled = true; + //this.canvas.Enabled = true; + } + + + + private void btnStopDraw_Click(object sender, EventArgs e) + { + //panelGuide.Controls.Clear(); + StopDrawMode(); + } + + + + private void StartDrawMode() + { + + } + + + private void StopDrawMode() + { + //this.canvas.StopDraw(); + + + //this.btnStopDraw.Enabled = false; + //this.btnCreateCircle.Enabled = true; + } + + + + + + private void Status(string message, int delay = 5000) + { + //_statusTimer.Stop(); + //// ʾϢ + //lblStatus.Text = message; + + //// һʱ + + //_statusTimer.Interval = delay; // ӳʱ + //_statusTimer.Tick += (sender, e) => + //{ + // _statusTimer.Stop(); // ֹͣʱ + // lblStatus.Text = string.Empty; // ״̬Ϣ + //}; + //_statusTimer.Start(); // ʱ + } + + + + + private void Canvas_mouseMoved(PointF pos) + { + //if (InvokeRequired) + //{ + // Invoke(Canvas_mouseMoved, pos); + // return; + //} + + //lblStatus.Text = $"X:{pos.X}, Y:{pos.Y}"; + + } + + + + + private void Canvas_selectionChanged(List shapes) + { + if (shapes.Count != 1) + { + // panelGuide.Controls.Clear(); + return; + } + //SwitchGuideForm(shapes[0].ShapeType); + Canvas_OnShapeUpdateEvent(shapes[0]); + + } + + + + private void SwitchGuideForm(ShapeTypeEnum shapeType) + { + //if (_currentGuideCtrl == null) + //{ + // switch (shapeType) + // { + // case ShapeTypeEnum.Point: + // break; + // case ShapeTypeEnum.Line: + // break; + // case ShapeTypeEnum.Rectangle: + // break; + // case ShapeTypeEnum.Circle: + // _currentGuideCtrl = new GuideCircleCtrl(); + // _currentGuideCtrl.ImageFile = _currentImageFile; + // _currentGuideCtrl.OnDrawCircle += this.canvas.DrawCircle; + // _currentGuideCtrl.OnClose += () => + // { + // panelGuide.Controls.Clear(); + // StopDrawMode(); + // }; + // break; + // case ShapeTypeEnum.Polygon: + // break; + // case ShapeTypeEnum.LineStrip: + // break; + // default: + // break; + // } + //} + //_currentGuideCtrl?.AddToPanel(panelGuide); + } + + + + private void Canvas_OnShapeMoving(List shapes) + { + //if (shapes.Count != 1) + //{ + // panelGuide.Controls.Clear(); + // return; + //} + + //_currentGuideCtrl?.UpdateShape(shapes[0]); + } + + + + private void Canvas_OnShapeUpdateEvent(FlyShape shape) + { + switch (shape.ShapeType) + { + case ShapeTypeEnum.Point: + break; + case ShapeTypeEnum.Line: + break; + case ShapeTypeEnum.Rectangle: + break; + case ShapeTypeEnum.Circle: + { + //_currentGuideCtrl?.UpdateShape(shape); + } + break; + case ShapeTypeEnum.Polygon: + break; + case ShapeTypeEnum.LineStrip: + break; + default: + break; + } + } + + + + private void btnTestOutsideDraw_Click(object sender, EventArgs e) + { + //Random random = new Random((int)DateTime.Now.Ticks); + + //for (int i = 0; i < 10; i++) + //{ + // // this.canvas.DrawCircle(new PointF(500, 500), 100); + + // int x = random.Next() % 500; + // int y = random.Next() % 500; + // int r = random.Next() % 200; + + // Debug.WriteLine($"X:{x}\tY:{y}\tR:{r}"); + + // this.canvas.DrawCircle(new PointF(x, y), r); + //} + } + + private void btnTestClearDraw_Click(object sender, EventArgs e) + { + //this.canvas.ClearDraw(); + } + + + + private async void btnTestCircleMeasure_Click(object sender, EventArgs e) + { + //string dir = Path.Combine(Environment.CurrentDirectory, "hscripts"); + //string file = "CircleMeasure.hdvp"; + //string filePath = Path.Combine(dir, file); + //if (!File.Exists(filePath)) + //{ + // MessageBox.Show($"ļ {filePath} "); + // return; + //} + + //HObject? hImage = null; + + //try + //{ + // HDevEngineTool tool = new HDevEngineTool(dir); + // tool.LoadProcedure(Path.GetFileNameWithoutExtension(file)); + + // // string imageFile = Path.Combine(Environment.CurrentDirectory, "hscripts", "image.png"); + + // HOperatorSet.ReadImage(out hImage, _currentImageFile); + // tool.InputImageDic["INPUT_Image"] = hImage; + // tool.InputTupleDic["XCenter"] = 981.625; + // tool.InputTupleDic["YCenter"] = 931.823; + // tool.InputTupleDic["Radius"] = 900.141; + + // Stopwatch sw = new Stopwatch(); + // sw.Start(); + // if (!tool.RunProcedure(out string error, out _)) + // { + // throw new Exception(); + // } + // sw.Stop(); + + + + // var flag = tool.GetResultTuple("OUTPUT_Flag").HTupleToDouble(); + // List x = tool.GetResultTuple("RXCenter").HTupleToDouble(); + // var y = tool.GetResultTuple("RYCenter").HTupleToDouble(); + // var r = tool.GetResultTuple("RRadius").HTupleToDouble(); + + // if (flag.Count > 0 && x.Count > 0 && y.Count > 0 && r.Count > 0) + // { + // this.canvas.DrawCircle(new PointF((float)x[0], (float)y[0]), (float)r[0]); + // } + + // // + // Debug.WriteLine(""); + //} + //catch (Exception) + //{ + // throw; + //} + //finally + //{ + // hImage?.Dispose(); + //} + + + } + + private void btnTest_Click(object sender, EventArgs e) + { + //this.canvas.DrawRectangle(new PointF(300, 300), + // new PointF(800, 500), 33f); + } + + + private void btnRotateTest_Click(object sender, EventArgs e) + { + //if (this.canvas.Shapes.Count == 0) + //{ + // return; + //} + + //this.canvas.Shapes[0]._currentRotateAngle += 10; + //this.canvas.Invalidate(); + } + + private void btnMeasureLineline_Click(object sender, EventArgs e) + { + SwitchMeasureMode(guideLineLineCtrl); + } + + private void btnMeasureLine_Click(object sender, EventArgs e) + { + SwitchMeasureMode(guideLineCtrl); + } + } +} diff --git a/CanFly/UI/FrmMain3.resx b/CanFly/UI/FrmMain3.resx new file mode 100644 index 0000000..cc3d870 --- /dev/null +++ b/CanFly/UI/FrmMain3.resx @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + \ No newline at end of file diff --git a/CanFly/UI/GuidePanel/BaseGuideControl.cs b/CanFly/UI/GuidePanel/BaseGuideControl.cs new file mode 100644 index 0000000..81d68d4 --- /dev/null +++ b/CanFly/UI/GuidePanel/BaseGuideControl.cs @@ -0,0 +1,158 @@ +using CanFly.Canvas.Shape; +using CanFly.Canvas.UI; +using CanFly.Helper; +using HalconDotNet; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + + + +namespace CanFly.UI.GuidePanel +{ + + public class BaseGuideControl : UserControl + { + public Action? OnControlCloseEvent; + + public event Action OnDataPassed; + + + private string _currentImageFile; + + public string CurrentImageFile; + + + protected string _hScriptsDir = Path.Combine(Environment.CurrentDirectory, "hscripts"); + + protected HObject? hImage = null; + + protected FlyCanvas _canvas; + + private HDevEngineTool? tool = null; + + + + public void DataToTriggerEvent(string input,string output) + { + + OnDataPassed?.Invoke(input, output); + } + + protected virtual void UpdateShape(FlyShape shape) + { + throw new NotImplementedException(); + } + + protected virtual string GetScriptFileName() + { + throw new NotImplementedException(); + } + + + + /// + /// 执行Halcon脚本 + /// + /// 输入图像 + /// 输入参数 + /// 输出参数 + protected void ExecuteHScript( + Dictionary inputImg, + Dictionary inputDic, + List outputParamKeys, + Action? exceptionHandler = null) + { + + string filePath = Path.Combine(_hScriptsDir, GetScriptFileName()); + if (!File.Exists(filePath)) + { + MessageBox.Show($"文件 {filePath} 不存在"); + return; + } + + try + { + if (tool == null) + { + tool = new HDevEngineTool(_hScriptsDir); + tool.LoadProcedure(Path.GetFileNameWithoutExtension(GetScriptFileName())); + } + + + + //tool.InputImageDic["INPUT_Image"] = hImage; + //tool.InputTupleDic["XCenter"] = _x; + //tool.InputTupleDic["YCenter"] = _y; + //tool.InputTupleDic["Radius"] = _r; + + tool.InputImageDic = inputImg; + tool.InputTupleDic = inputDic; + + + Dictionary outputParams = new Dictionary(); + + + if (!tool.RunProcedure(out string error, out int timeElasped)) + { + OnExecuteHScriptResult(false, outputParams, timeElasped); + return; + } + + for (int i = 0; i < outputParamKeys.Count; i++) + { + string k = outputParamKeys[i]; + outputParams[k] = tool.GetResultTuple(k); + } + + OnExecuteHScriptResult(true, outputParams, timeElasped); + } + catch (Exception ex) + { + exceptionHandler?.Invoke(ex); + } + finally + { + hImage?.Dispose(); + hImage = null; + } + + } + + + + /// + /// Halcon脚本执行结果回调函数,重写该方法以自行处理算法执行结果 + /// + /// 算法执行是否成功 + /// 算法输出结果 + /// 算法耗时,单位:ms + protected virtual void OnExecuteHScriptResult(bool success, Dictionary resultDic, int timeElasped) + { + throw new NotImplementedException(); + } + + + protected void OpenImageFile(Action callback) + { + OpenFileDialog ofd = new OpenFileDialog(); + ofd.Filter = "图像文件|*.jpg;*.jpeg;*.png"; + ofd.Multiselect = false; + if (ofd.ShowDialog() == DialogResult.OK) + { + CurrentImageFile = ofd.FileName; + Bitmap bitmap = (Bitmap)Image.FromFile(CurrentImageFile); + callback?.Invoke(bitmap); + } + } + + + protected void OnControlClose() + { + OnControlCloseEvent?.Invoke(); + } + } +} diff --git a/CanFly/UI/GuidePanel/BaseGuideControl.resx b/CanFly/UI/GuidePanel/BaseGuideControl.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/CanFly/UI/GuidePanel/BaseGuideControl.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/CanFly/UI/GuidePanel/CtrlTitleBar.Designer.cs b/CanFly/UI/GuidePanel/CtrlTitleBar.Designer.cs new file mode 100644 index 0000000..dd63885 --- /dev/null +++ b/CanFly/UI/GuidePanel/CtrlTitleBar.Designer.cs @@ -0,0 +1,77 @@ +namespace CanFly.UI.GuidePanel +{ + partial class CtrlTitleBar + { + /// + /// 必需的设计器变量。 + /// + private System.ComponentModel.IContainer components = null; + + /// + /// 清理所有正在使用的资源。 + /// + /// 如果应释放托管资源,为 true;否则为 false。 + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region 组件设计器生成的代码 + + /// + /// 设计器支持所需的方法 - 不要修改 + /// 使用代码编辑器修改此方法的内容。 + /// + private void InitializeComponent() + { + btnClose = new PictureBox(); + j = new Label(); + ((System.ComponentModel.ISupportInitialize)btnClose).BeginInit(); + SuspendLayout(); + // + // btnClose + // + btnClose.Dock = DockStyle.Right; + btnClose.Image = XKRS.CanFly.Properties.Resources.Close; + btnClose.Location = new Point(516, 3); + btnClose.Name = "btnClose"; + btnClose.Size = new Size(30, 30); + btnClose.SizeMode = PictureBoxSizeMode.StretchImage; + btnClose.TabIndex = 1; + btnClose.TabStop = false; + btnClose.Click += btnClose_Click; + // + // j + // + j.Dock = DockStyle.Fill; + j.Font = new Font("Microsoft YaHei UI", 12F, FontStyle.Bold, GraphicsUnit.Point); + j.Location = new Point(3, 3); + j.Name = "j"; + j.Size = new Size(513, 30); + j.TabIndex = 2; + j.Text = "标题"; + j.TextAlign = ContentAlignment.MiddleLeft; + // + // CtrlTitleBar + // + AutoScaleDimensions = new SizeF(7F, 17F); + AutoScaleMode = AutoScaleMode.Font; + Controls.Add(j); + Controls.Add(btnClose); + MinimumSize = new Size(0, 36); + Name = "CtrlTitleBar"; + Padding = new Padding(3); + Size = new Size(549, 36); + ((System.ComponentModel.ISupportInitialize)btnClose).EndInit(); + ResumeLayout(false); + } + + #endregion + private PictureBox btnClose; + private Label j; + } +} diff --git a/CanFly/UI/GuidePanel/CtrlTitleBar.cs b/CanFly/UI/GuidePanel/CtrlTitleBar.cs new file mode 100644 index 0000000..a82f406 --- /dev/null +++ b/CanFly/UI/GuidePanel/CtrlTitleBar.cs @@ -0,0 +1,38 @@ +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; + +namespace CanFly.UI.GuidePanel +{ + public partial class CtrlTitleBar : UserControl + { + public event Action? OnCloseClicked; + + + + [DisplayName("Title")] + public string Title + { + get { return this.j.Text; } + set { this.j.Text = value; } + } + + + public CtrlTitleBar() + { + InitializeComponent(); + this.Dock = DockStyle.Top; + } + + private void btnClose_Click(object sender, EventArgs e) + { + OnCloseClicked?.Invoke(); + } + } +} diff --git a/CanFly/UI/GuidePanel/CtrlTitleBar.resx b/CanFly/UI/GuidePanel/CtrlTitleBar.resx new file mode 100644 index 0000000..8b2ff64 --- /dev/null +++ b/CanFly/UI/GuidePanel/CtrlTitleBar.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/CanFly/UI/GuidePanel/GuideCircleCtrl.Designer.cs b/CanFly/UI/GuidePanel/GuideCircleCtrl.Designer.cs new file mode 100644 index 0000000..73cfadc --- /dev/null +++ b/CanFly/UI/GuidePanel/GuideCircleCtrl.Designer.cs @@ -0,0 +1,364 @@ +namespace CanFly.UI.GuidePanel +{ + partial class GuideCircleCtrl + { + /// + /// 必需的设计器变量。 + /// + private System.ComponentModel.IContainer components = null; + + /// + /// 清理所有正在使用的资源。 + /// + /// 如果应释放托管资源,为 true;否则为 false。 + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region 组件设计器生成的代码 + + /// + /// 设计器支持所需的方法 - 不要修改 + /// 使用代码编辑器修改此方法的内容。 + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(GuideCircleCtrl)); + splitContainer = new SplitContainer(); + panel1 = new Panel(); + canvas = new Canvas.UI.FlyCanvas(); + statusStrip1 = new StatusStrip(); + lblStatus = new ToolStripStatusLabel(); + btnClose = new PictureBox(); + label4 = new Label(); + btnExecute = new Button(); + lblElapsed = new Label(); + ctrlTitleBar = new CtrlTitleBar(); + groupBox1 = new GroupBox(); + label1 = new Label(); + label2 = new Label(); + label3 = new Label(); + tbR = new TextBox(); + tbY = new TextBox(); + tbX = new TextBox(); + btnLoadImage = new Button(); + btnCreateCircle = new Button(); + btnSave = new Button(); + label6 = new Label(); + lblResult = new Label(); + panelGuide = new Panel(); + ((System.ComponentModel.ISupportInitialize)splitContainer).BeginInit(); + splitContainer.Panel1.SuspendLayout(); + splitContainer.Panel2.SuspendLayout(); + splitContainer.SuspendLayout(); + panel1.SuspendLayout(); + statusStrip1.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)btnClose).BeginInit(); + groupBox1.SuspendLayout(); + panelGuide.SuspendLayout(); + SuspendLayout(); + // + // splitContainer + // + splitContainer.Dock = DockStyle.Fill; + splitContainer.Location = new Point(0, 0); + splitContainer.Name = "splitContainer"; + // + // splitContainer.Panel1 + // + splitContainer.Panel1.Controls.Add(panelGuide); + splitContainer.Panel1MinSize = 150; + // + // splitContainer.Panel2 + // + splitContainer.Panel2.Controls.Add(panel1); + splitContainer.Size = new Size(1280, 640); + splitContainer.SplitterDistance = 200; + splitContainer.TabIndex = 12; + // + // panel1 + // + panel1.BorderStyle = BorderStyle.FixedSingle; + panel1.Controls.Add(canvas); + panel1.Controls.Add(statusStrip1); + panel1.Dock = DockStyle.Fill; + panel1.Location = new Point(0, 0); + panel1.Name = "panel1"; + panel1.Size = new Size(1076, 640); + panel1.TabIndex = 1; + // + // canvas + // + canvas.AllowMultiSelect = false; + canvas.CreateMode = Canvas.Shape.ShapeTypeEnum.Polygon; + canvas.Dock = DockStyle.Fill; + canvas.Enabled = false; + canvas.FillDrawing = false; + canvas.Location = new Point(0, 0); + canvas.Margin = new Padding(2); + canvas.Name = "canvas"; + canvas.OutsideShapes = (List)resources.GetObject("canvas.OutsideShapes"); + canvas.Scale = 1F; + canvas.Shapes = (List)resources.GetObject("canvas.Shapes"); + canvas.Size = new Size(1074, 616); + canvas.TabIndex = 2; + // + // statusStrip1 + // + statusStrip1.Items.AddRange(new ToolStripItem[] { lblStatus }); + statusStrip1.Location = new Point(0, 616); + statusStrip1.Name = "statusStrip1"; + statusStrip1.Size = new Size(1074, 22); + statusStrip1.TabIndex = 1; + statusStrip1.Text = "statusStrip1"; + // + // lblStatus + // + lblStatus.Name = "lblStatus"; + lblStatus.Size = new Size(44, 17); + lblStatus.Text = " "; + // + // btnClose + // + btnClose.Anchor = AnchorStyles.Top | AnchorStyles.Right; + btnClose.Image = XKRS.CanFly.Properties.Resources.Close; + btnClose.InitialImage = XKRS.CanFly.Properties.Resources.Close; + btnClose.Location = new Point(1102, 3); + btnClose.Name = "btnClose"; + btnClose.Size = new Size(33, 33); + btnClose.SizeMode = PictureBoxSizeMode.StretchImage; + btnClose.TabIndex = 5; + btnClose.TabStop = false; + btnClose.Click += btnClose_Click; + // + // label4 + // + label4.AutoSize = true; + label4.Location = new Point(6, 307); + label4.Name = "label4"; + label4.Size = new Size(44, 17); + label4.TabIndex = 3; + label4.Text = "耗时:"; + // + // btnExecute + // + btnExecute.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; + btnExecute.Location = new Point(6, 272); + btnExecute.Name = "btnExecute"; + btnExecute.Size = new Size(186, 32); + btnExecute.TabIndex = 2; + btnExecute.Text = "执行"; + btnExecute.UseVisualStyleBackColor = true; + btnExecute.Click += btnExecute_Click; + // + // lblElapsed + // + lblElapsed.AutoSize = true; + lblElapsed.Location = new Point(56, 307); + lblElapsed.Name = "lblElapsed"; + lblElapsed.Size = new Size(32, 17); + lblElapsed.TabIndex = 4; + lblElapsed.Text = "0ms"; + // + // ctrlTitleBar + // + ctrlTitleBar.Dock = DockStyle.Top; + ctrlTitleBar.Location = new Point(0, 0); + ctrlTitleBar.MinimumSize = new Size(0, 36); + ctrlTitleBar.Name = "ctrlTitleBar"; + ctrlTitleBar.Padding = new Padding(3); + ctrlTitleBar.Size = new Size(198, 36); + ctrlTitleBar.TabIndex = 11; + ctrlTitleBar.Title = "圆形测量"; + // + // groupBox1 + // + groupBox1.Controls.Add(tbX); + groupBox1.Controls.Add(tbY); + groupBox1.Controls.Add(tbR); + groupBox1.Controls.Add(label3); + groupBox1.Controls.Add(label2); + groupBox1.Controls.Add(label1); + groupBox1.Dock = DockStyle.Top; + groupBox1.Location = new Point(0, 36); + groupBox1.Name = "groupBox1"; + groupBox1.Size = new Size(198, 116); + groupBox1.TabIndex = 12; + groupBox1.TabStop = false; + groupBox1.Text = "圆参数"; + // + // label1 + // + label1.AutoSize = true; + label1.Location = new Point(6, 25); + label1.Name = "label1"; + label1.Size = new Size(19, 17); + label1.TabIndex = 0; + label1.Text = "X:"; + // + // label2 + // + label2.AutoSize = true; + label2.Location = new Point(6, 54); + label2.Name = "label2"; + label2.Size = new Size(18, 17); + label2.TabIndex = 1; + label2.Text = "Y:"; + // + // label3 + // + label3.AutoSize = true; + label3.Location = new Point(3, 83); + label3.Name = "label3"; + label3.Size = new Size(44, 17); + label3.TabIndex = 2; + label3.Text = "半径:"; + // + // tbR + // + tbR.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; + tbR.Location = new Point(56, 80); + tbR.Name = "tbR"; + tbR.Size = new Size(136, 23); + tbR.TabIndex = 3; + // + // tbY + // + tbY.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; + tbY.Location = new Point(56, 51); + tbY.Name = "tbY"; + tbY.Size = new Size(136, 23); + tbY.TabIndex = 4; + // + // tbX + // + tbX.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; + tbX.Location = new Point(56, 22); + tbX.Name = "tbX"; + tbX.Size = new Size(136, 23); + tbX.TabIndex = 5; + // + // btnLoadImage + // + btnLoadImage.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; + btnLoadImage.Location = new Point(6, 158); + btnLoadImage.Name = "btnLoadImage"; + btnLoadImage.Size = new Size(186, 32); + btnLoadImage.TabIndex = 13; + btnLoadImage.Text = "打开图片"; + btnLoadImage.UseVisualStyleBackColor = true; + btnLoadImage.Click += btnLoadImage_Click; + // + // btnCreateCircle + // + btnCreateCircle.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; + btnCreateCircle.Location = new Point(6, 196); + btnCreateCircle.Name = "btnCreateCircle"; + btnCreateCircle.Size = new Size(186, 32); + btnCreateCircle.TabIndex = 14; + btnCreateCircle.Text = "创建圆形"; + btnCreateCircle.UseVisualStyleBackColor = true; + btnCreateCircle.Click += btnCreateCircle_Click; + // + // btnSave + // + btnSave.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; + btnSave.Location = new Point(9, 397); + btnSave.Name = "btnSave"; + btnSave.Size = new Size(186, 32); + btnSave.TabIndex = 15; + btnSave.Text = "保存数据"; + btnSave.UseVisualStyleBackColor = true; + btnSave.Click += btnSave_Click; + // + // label6 + // + label6.AutoSize = true; + label6.Location = new Point(6, 338); + label6.Name = "label6"; + label6.Size = new Size(44, 17); + label6.TabIndex = 16; + label6.Text = "结果:"; + // + // lblResult + // + lblResult.AutoSize = true; + lblResult.Location = new Point(56, 338); + lblResult.Name = "lblResult"; + lblResult.Size = new Size(20, 17); + lblResult.TabIndex = 17; + lblResult.Text = "无"; + // + // panelGuide + // + panelGuide.BorderStyle = BorderStyle.FixedSingle; + panelGuide.Controls.Add(lblResult); + panelGuide.Controls.Add(label6); + panelGuide.Controls.Add(btnSave); + panelGuide.Controls.Add(btnCreateCircle); + panelGuide.Controls.Add(btnLoadImage); + panelGuide.Controls.Add(groupBox1); + panelGuide.Controls.Add(ctrlTitleBar); + panelGuide.Controls.Add(lblElapsed); + panelGuide.Controls.Add(btnExecute); + panelGuide.Controls.Add(label4); + panelGuide.Dock = DockStyle.Fill; + panelGuide.Location = new Point(0, 0); + panelGuide.Name = "panelGuide"; + panelGuide.Size = new Size(200, 640); + panelGuide.TabIndex = 0; + // + // GuideCircleCtrl + // + Controls.Add(splitContainer); + Controls.Add(btnClose); + Name = "GuideCircleCtrl"; + Size = new Size(1280, 640); + splitContainer.Panel1.ResumeLayout(false); + splitContainer.Panel2.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)splitContainer).EndInit(); + splitContainer.ResumeLayout(false); + panel1.ResumeLayout(false); + panel1.PerformLayout(); + statusStrip1.ResumeLayout(false); + statusStrip1.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)btnClose).EndInit(); + groupBox1.ResumeLayout(false); + groupBox1.PerformLayout(); + panelGuide.ResumeLayout(false); + panelGuide.PerformLayout(); + ResumeLayout(false); + } + + #endregion + + private SplitContainer splitContainer; + private Panel panel1; + private Canvas.UI.FlyCanvas canvas; + private StatusStrip statusStrip1; + private ToolStripStatusLabel lblStatus; + private PictureBox btnClose; + private Panel panelGuide; + private Label lblResult; + private Label label6; + private Button btnSave; + private Button btnCreateCircle; + private Button btnLoadImage; + private GroupBox groupBox1; + private TextBox tbX; + private TextBox tbY; + private TextBox tbR; + private Label label3; + private Label label2; + private Label label1; + private CtrlTitleBar ctrlTitleBar; + private Label lblElapsed; + private Button btnExecute; + private Label label4; + } +} diff --git a/CanFly/UI/GuidePanel/GuideCircleCtrl.cs b/CanFly/UI/GuidePanel/GuideCircleCtrl.cs new file mode 100644 index 0000000..7d54438 --- /dev/null +++ b/CanFly/UI/GuidePanel/GuideCircleCtrl.cs @@ -0,0 +1,359 @@ +using CanFly.Canvas.Shape; +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 CanFly.Canvas.Helper; +using CanFly.Helper; +using HalconDotNet; +using System.Diagnostics; +using CanFly.Canvas.UI; + + +namespace CanFly.UI.GuidePanel +{ + public partial class GuideCircleCtrl : BaseGuideControl + { + + private float _x; + private float _y; + private float _r; + private FlyShape? _circle; + + + protected override string GetScriptFileName() => "CircleMeasure.hdvp"; + + + + + public GuideCircleCtrl() + { + InitializeComponent(); + + + this.canvas.mouseMoved += Canvas_mouseMoved; + this.canvas.OnShapeUpdateEvent += UpdateShape; + this.canvas.selectionChanged += Canvas_selectionChanged; + + this.canvas.OnShapeMoving += Canvas_OnShapeMoving; + this.canvas.newShape += Canvas_newShape; + + this.ctrlTitleBar.OnCloseClicked += OnControlClose; + } + + + + protected override void UpdateShape(FlyShape shape) + { + this._circle = shape; + + _x = shape.Points[0].X; + _y = shape.Points[0].Y; + _r = PointHelper.Distance(shape.Points[0], shape.Points[1]); + + this.tbX.Text = shape.Points[0].X.ToString("F3"); + this.tbY.Text = shape.Points[0].Y.ToString("F3"); + this.tbR.Text = _r.ToString("F3"); + } + + + + + private void btnExecute_Click(object sender, EventArgs e) + { + if (this.canvas.pixmap == null) + { + MessageBox.Show("请先打开图片"); + return; + } + if(this.tbX.Text.Trim().Length == 0) + { + MessageBox.Show("请先创建圆形"); + return; + } + + + this.canvas.OutsideShapes.Clear(); + this.canvas.Invalidate(); + + flag = new List(); + x = new List(); + y = new List(); + r = new List(); + Dictionary inputImg = new Dictionary(); + + if (hImage == null) + { + HOperatorSet.ReadImage(out hImage, CurrentImageFile); + } + inputImg["INPUT_Image"] = hImage; + + Dictionary inputPara = new Dictionary(); + + + inputPara["XCenter"] = _x; + inputPara["YCenter"] = _y; + inputPara["Radius"] = _r; + + + List outputKeys = new List() + { + "OUTPUT_PreTreatedImage", + "OUTPUT_Flag", + "RXCenter", + "RYCenter", + "RRadius" + }; + + ExecuteHScript( + inputImg, + inputPara, + outputKeys); + + } + List flag = new List(), x=new List(),y=new List(),r=new List(); + + protected override void OnExecuteHScriptResult( + bool success, + Dictionary resultDic, + int timeElasped) + { + if (!success) + { + return; + } + + + /* + "OUTPUT_Flag", + "RXCenter", + "RYCenter", + "RRadius" + */ + + //取图????? + + + + flag = resultDic["OUTPUT_Flag"].HTupleToDouble(); + x = resultDic["RXCenter"].HTupleToDouble(); + y = resultDic["RYCenter"].HTupleToDouble(); + r = resultDic["RRadius"].HTupleToDouble(); + + + + + + + + + + if (flag.Count > 0) + { + lblResult.Text = flag[0].ToString(); + + } + else + { + lblResult.Text = "无"; + } + if (flag.Count > 0 && x.Count > 0 && y.Count > 0 && r.Count > 0) + { + + //detectResult.VisionImageSet.MLImage = resultDic["RRadius"].GetResultObject("OUTPUT_PreTreatedImage"); + this.canvas.DrawCircle(new PointF((float)x[0], (float)y[0]), (float)r[0]); + lblElapsed.Text = $"{timeElasped} ms"; + } + } + + + + + private void Test() + { + string filePath = Path.Combine(_hScriptsDir, GetScriptFileName()); + if (!File.Exists(filePath)) + { + MessageBox.Show($"文件 {filePath} 不存在"); + return; + } + + + try + { + HDevEngineTool tool = new HDevEngineTool(_hScriptsDir); + tool.LoadProcedure(Path.GetFileNameWithoutExtension(GetScriptFileName())); + + + if (hImage == null) + { + HOperatorSet.ReadImage(out hImage, CurrentImageFile); + } + + tool.InputImageDic["INPUT_Image"] = hImage; + tool.InputTupleDic["XCenter"] = _x; + tool.InputTupleDic["YCenter"] = _y; + tool.InputTupleDic["Radius"] = _r; + + + + if (!tool.RunProcedure(out string error, out int timeElasped)) + { + throw new Exception(); + } + + HTuple hFlag = tool.GetResultTuple("OUTPUT_Flag"); + + var flag = tool.GetResultTuple("OUTPUT_Flag").HTupleToDouble(); + List x = tool.GetResultTuple("RXCenter").HTupleToDouble(); + var y = tool.GetResultTuple("RYCenter").HTupleToDouble(); + var r = tool.GetResultTuple("RRadius").HTupleToDouble(); + if (flag.Count > 0) + { + lblResult.Text = flag[0].ToString(); + + } + else + { + lblResult.Text = "无"; + } + if (flag.Count > 0 && x.Count > 0 && y.Count > 0 && r.Count > 0) + { + this.canvas.DrawCircle(new PointF((float)x[0], (float)y[0]), (float)r[0]); + lblElapsed.Text = $"{timeElasped} ms"; + } + + // + Debug.WriteLine(""); + } + catch (Exception) + { + throw; + } + finally + { + hImage?.Dispose(); + hImage = null; + } + + + } + + + + private void btnClose_Click(object sender, EventArgs e) + { + OnControlCloseEvent?.Invoke(); + } + + private void btnLoadImage_Click(object sender, EventArgs e) + { + OpenImageFile(bitmap => + { + this.canvas.LoadPixmap(bitmap); + this.canvas.Enabled = true; + }); + } + + + + + private void Canvas_mouseMoved(PointF pos) + { + if (InvokeRequired) + { + Invoke(Canvas_mouseMoved, pos); + return; + } + + lblStatus.Text = $"X:{pos.X}, Y:{pos.Y}"; + + } + + + + + private void Canvas_selectionChanged(List shapes) + { + //if (shapes.Count != 1) + //{ + // // panelGuide.Controls.Clear(); + // return; + //} + //SwitchGuideForm(shapes[0].ShapeType); + // Canvas_OnShapeUpdateEvent(shapes[0]); + + if (shapes.Count != 1) + { + return; + } + UpdateShape(shapes[0]); + + } + + + private void Canvas_OnShapeMoving(List shapes) + { + if (shapes.Count != 1) + { + return; + } + + UpdateShape(shapes[0]); + } + + private void btnCreateCircle_Click(object sender, EventArgs e) + { + if (this.canvas.pixmap == null) + { + MessageBox.Show("请先打开图片"); + return; + } + this.tbX.Text = string.Empty; + this.tbY.Text = string.Empty; + this.tbR.Text = string.Empty; + this.canvas.Shapes.Clear(); + this.canvas.Invalidate(); + this.canvas.StartDraw(ShapeTypeEnum.Circle); + this.canvas.Enabled = true; + } + + + + private void Canvas_newShape() + { + + this.canvas.StopDraw(); + } + + private void btnSave_Click(object sender, EventArgs e) + { + if (lblResult.Text.Equals("无")) + { + MessageBox.Show("请先进行绘制"); + return; + } + if(lblResult.Text != "0") + { + MessageBox.Show("测量计算错误,无法保存"); + return; + } + + //List x = tool.GetResultTuple("RXCenter").HTupleToDouble(); + //var y = tool.GetResultTuple("RYCenter").HTupleToDouble(); + //var r = tool.GetResultTuple("RRadius").HTupleToDouble(); + //tool.InputTupleDic["XCenter"] = _x; + //tool.InputTupleDic["YCenter"] = _y; + //tool.InputTupleDic["Radius"] = _r; + string inputput = $"XCenter:{string.Join(";", _x)};YCenter:{string.Join(";", _y)};RRadius:{string.Join(";", _r)}"; + string output = $"RXCenter:{string.Join(";", x[0])};RYCenter:{string.Join(";", y[0])};RRadius:{string.Join(";", r[0])}"; + + DataToTriggerEvent(inputput,output); + } + } +} diff --git a/CanFly/UI/GuidePanel/GuideCircleCtrl.resx b/CanFly/UI/GuidePanel/GuideCircleCtrl.resx new file mode 100644 index 0000000..097e294 --- /dev/null +++ b/CanFly/UI/GuidePanel/GuideCircleCtrl.resx @@ -0,0 +1,145 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + AAEAAAD/////AQAAAAAAAAAMAgAAAERDYW5GbHkuQ2FudmFzLCBWZXJzaW9uPTEuMC4wLjAsIEN1bHR1 + cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49bnVsbAQBAAAAdlN5c3RlbS5Db2xsZWN0aW9ucy5HZW5l + cmljLkxpc3RgMVtbQ2FuRmx5LkNhbnZhcy5TaGFwZS5GbHlTaGFwZSwgQ2FuRmx5LkNhbnZhcywgQ3Vs + dHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1udWxsXV0DAAAABl9pdGVtcwVfc2l6ZQhfdmVyc2lv + bgQAAB5DYW5GbHkuQ2FudmFzLlNoYXBlLkZseVNoYXBlW10CAAAACAgJAwAAAAAAAAAAAAAADAQAAAAz + Q2FuRmx5LkNhbnZhcywgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1udWxsBwMAAAAAAQAA + AAAAAAAEHENhbkZseS5DYW52YXMuU2hhcGUuRmx5U2hhcGUEAAAACw== + + + + + AAEAAAD/////AQAAAAAAAAAMAgAAAERDYW5GbHkuQ2FudmFzLCBWZXJzaW9uPTEuMC4wLjAsIEN1bHR1 + cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49bnVsbAQBAAAAdlN5c3RlbS5Db2xsZWN0aW9ucy5HZW5l + cmljLkxpc3RgMVtbQ2FuRmx5LkNhbnZhcy5TaGFwZS5GbHlTaGFwZSwgQ2FuRmx5LkNhbnZhcywgQ3Vs + dHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1udWxsXV0DAAAABl9pdGVtcwVfc2l6ZQhfdmVyc2lv + bgQAAB5DYW5GbHkuQ2FudmFzLlNoYXBlLkZseVNoYXBlW10CAAAACAgJAwAAAAAAAAAAAAAADAQAAAAz + Q2FuRmx5LkNhbnZhcywgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1udWxsBwMAAAAAAQAA + AAAAAAAEHENhbkZseS5DYW52YXMuU2hhcGUuRmx5U2hhcGUEAAAACw== + + + + 17, 17 + + \ No newline at end of file diff --git a/CanFly/UI/GuidePanel/GuideHeightCtrl.Designer.cs b/CanFly/UI/GuidePanel/GuideHeightCtrl.Designer.cs new file mode 100644 index 0000000..bf3bc74 --- /dev/null +++ b/CanFly/UI/GuidePanel/GuideHeightCtrl.Designer.cs @@ -0,0 +1,446 @@ +namespace CanFly.UI.GuidePanel +{ + partial class GuideHeightCtrl + { + /// + /// 必需的设计器变量。 + /// + private System.ComponentModel.IContainer components = null; + + /// + /// 清理所有正在使用的资源。 + /// + /// 如果应释放托管资源,为 true;否则为 false。 + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region 组件设计器生成的代码 + + /// + /// 设计器支持所需的方法 - 不要修改 + /// 使用代码编辑器修改此方法的内容。 + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(GuideHeightCtrl)); + lblElapsed = new Label(); + label4 = new Label(); + splitContainer = new SplitContainer(); + panelGuide = new Panel(); + btnSave = new Button(); + lblResult = new Label(); + label1 = new Label(); + btnCreateLine = new Button(); + btnLoadImage = new Button(); + label9 = new Label(); + btnExecute = new Button(); + label10 = new Label(); + groupBox2 = new GroupBox(); + tbheight = new TextBox(); + lbheight = new Label(); + tbwidth = new TextBox(); + label2 = new Label(); + tbLineX2 = new TextBox(); + label8 = new Label(); + tbLineY2 = new TextBox(); + label5 = new Label(); + tbLineX1 = new TextBox(); + tbLineY1 = new TextBox(); + label6 = new Label(); + label7 = new Label(); + ctrlTitleBar = new CtrlTitleBar(); + panel1 = new Panel(); + canvas = new Canvas.UI.FlyCanvas(); + statusStrip1 = new StatusStrip(); + lblStatus = new ToolStripStatusLabel(); + ((System.ComponentModel.ISupportInitialize)splitContainer).BeginInit(); + splitContainer.Panel1.SuspendLayout(); + splitContainer.Panel2.SuspendLayout(); + splitContainer.SuspendLayout(); + panelGuide.SuspendLayout(); + groupBox2.SuspendLayout(); + panel1.SuspendLayout(); + statusStrip1.SuspendLayout(); + SuspendLayout(); + // + // lblElapsed + // + lblElapsed.AutoSize = true; + lblElapsed.Location = new Point(50, 328); + lblElapsed.Name = "lblElapsed"; + lblElapsed.Size = new Size(32, 17); + lblElapsed.TabIndex = 9; + lblElapsed.Text = "0ms"; + // + // label4 + // + label4.AutoSize = true; + label4.Location = new Point(0, 328); + label4.Name = "label4"; + label4.Size = new Size(44, 17); + label4.TabIndex = 8; + label4.Text = "耗时:"; + // + // splitContainer + // + splitContainer.Dock = DockStyle.Fill; + splitContainer.Location = new Point(0, 0); + splitContainer.Name = "splitContainer"; + // + // splitContainer.Panel1 + // + splitContainer.Panel1.Controls.Add(panelGuide); + splitContainer.Panel1MinSize = 150; + // + // splitContainer.Panel2 + // + splitContainer.Panel2.Controls.Add(panel1); + splitContainer.Size = new Size(1280, 640); + splitContainer.SplitterDistance = 200; + splitContainer.TabIndex = 11; + // + // panelGuide + // + panelGuide.BorderStyle = BorderStyle.FixedSingle; + panelGuide.Controls.Add(btnSave); + panelGuide.Controls.Add(lblResult); + panelGuide.Controls.Add(label1); + panelGuide.Controls.Add(btnCreateLine); + panelGuide.Controls.Add(btnLoadImage); + panelGuide.Controls.Add(label9); + panelGuide.Controls.Add(btnExecute); + panelGuide.Controls.Add(label10); + panelGuide.Controls.Add(groupBox2); + panelGuide.Controls.Add(ctrlTitleBar); + panelGuide.Dock = DockStyle.Fill; + panelGuide.Location = new Point(0, 0); + panelGuide.Name = "panelGuide"; + panelGuide.Size = new Size(200, 640); + panelGuide.TabIndex = 0; + // + // btnSave + // + btnSave.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; + btnSave.Location = new Point(2, 419); + btnSave.Name = "btnSave"; + btnSave.Size = new Size(186, 32); + btnSave.TabIndex = 23; + btnSave.Text = "保存数据"; + btnSave.UseVisualStyleBackColor = true; + btnSave.Click += btnSave_Click; + // + // lblResult + // + lblResult.AutoSize = true; + lblResult.Location = new Point(59, 354); + lblResult.Name = "lblResult"; + lblResult.Size = new Size(20, 17); + lblResult.TabIndex = 22; + lblResult.Text = "无"; + // + // label1 + // + label1.AutoSize = true; + label1.Location = new Point(9, 354); + label1.Name = "label1"; + label1.Size = new Size(44, 17); + label1.TabIndex = 21; + label1.Text = "结果:"; + // + // btnCreateLine + // + btnCreateLine.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; + btnCreateLine.Location = new Point(9, 252); + btnCreateLine.Name = "btnCreateLine"; + btnCreateLine.Size = new Size(186, 32); + btnCreateLine.TabIndex = 20; + btnCreateLine.Text = "创建矩形"; + btnCreateLine.UseVisualStyleBackColor = true; + btnCreateLine.Click += btnCreateLine_Click; + // + // btnLoadImage + // + btnLoadImage.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; + btnLoadImage.Location = new Point(6, 214); + btnLoadImage.Name = "btnLoadImage"; + btnLoadImage.Size = new Size(186, 32); + btnLoadImage.TabIndex = 18; + btnLoadImage.Text = "打开图片"; + btnLoadImage.UseVisualStyleBackColor = true; + btnLoadImage.Click += btnLoadImage_Click; + // + // label9 + // + label9.AutoSize = true; + label9.Location = new Point(59, 325); + label9.Name = "label9"; + label9.Size = new Size(32, 17); + label9.TabIndex = 17; + label9.Text = "0ms"; + // + // btnExecute + // + btnExecute.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; + btnExecute.Location = new Point(9, 290); + btnExecute.Name = "btnExecute"; + btnExecute.Size = new Size(186, 32); + btnExecute.TabIndex = 15; + btnExecute.Text = "执行"; + btnExecute.UseVisualStyleBackColor = true; + btnExecute.Click += btnExecute_Click; + // + // label10 + // + label10.AutoSize = true; + label10.Location = new Point(9, 325); + label10.Name = "label10"; + label10.Size = new Size(44, 17); + label10.TabIndex = 16; + label10.Text = "耗时:"; + // + // groupBox2 + // + groupBox2.Controls.Add(tbheight); + groupBox2.Controls.Add(lbheight); + groupBox2.Controls.Add(tbwidth); + groupBox2.Controls.Add(label2); + groupBox2.Controls.Add(tbLineX2); + groupBox2.Controls.Add(label8); + groupBox2.Controls.Add(tbLineY2); + groupBox2.Controls.Add(label5); + groupBox2.Controls.Add(tbLineX1); + groupBox2.Controls.Add(tbLineY1); + groupBox2.Controls.Add(label6); + groupBox2.Controls.Add(label7); + groupBox2.Dock = DockStyle.Top; + groupBox2.Location = new Point(0, 36); + groupBox2.Name = "groupBox2"; + groupBox2.Size = new Size(198, 172); + groupBox2.TabIndex = 13; + groupBox2.TabStop = false; + groupBox2.Text = "线参数"; + // + // tbheight + // + tbheight.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; + tbheight.Location = new Point(126, 140); + tbheight.Name = "tbheight"; + tbheight.Size = new Size(66, 23); + tbheight.TabIndex = 13; + // + // lbheight + // + lbheight.AutoSize = true; + lbheight.Location = new Point(97, 143); + lbheight.Name = "lbheight"; + lbheight.Size = new Size(23, 17); + lbheight.TabIndex = 12; + lbheight.Text = "高:"; + // + // tbwidth + // + tbwidth.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; + tbwidth.Location = new Point(27, 140); + tbwidth.Name = "tbwidth"; + tbwidth.Size = new Size(64, 23); + tbwidth.TabIndex = 11; + // + // label2 + // + label2.AutoSize = true; + label2.Location = new Point(6, 143); + label2.Name = "label2"; + label2.Size = new Size(23, 17); + label2.TabIndex = 10; + label2.Text = "宽:"; + // + // tbLineX2 + // + tbLineX2.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; + tbLineX2.Location = new Point(56, 80); + tbLineX2.Name = "tbLineX2"; + tbLineX2.Size = new Size(136, 23); + tbLineX2.TabIndex = 9; + // + // label8 + // + label8.AutoSize = true; + label8.Location = new Point(6, 83); + label8.Name = "label8"; + label8.Size = new Size(26, 17); + label8.TabIndex = 8; + label8.Text = "X2:"; + // + // tbLineY2 + // + tbLineY2.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; + tbLineY2.Location = new Point(56, 109); + tbLineY2.Name = "tbLineY2"; + tbLineY2.Size = new Size(136, 23); + tbLineY2.TabIndex = 7; + // + // label5 + // + label5.AutoSize = true; + label5.Location = new Point(6, 112); + label5.Name = "label5"; + label5.Size = new Size(25, 17); + label5.TabIndex = 6; + label5.Text = "Y2:"; + // + // tbLineX1 + // + tbLineX1.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; + tbLineX1.Location = new Point(56, 22); + tbLineX1.Name = "tbLineX1"; + tbLineX1.Size = new Size(136, 23); + tbLineX1.TabIndex = 5; + tbLineX1.TextChanged += tbLineX1_TextChanged; + // + // tbLineY1 + // + tbLineY1.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; + tbLineY1.Location = new Point(56, 51); + tbLineY1.Name = "tbLineY1"; + tbLineY1.Size = new Size(136, 23); + tbLineY1.TabIndex = 4; + // + // label6 + // + label6.AutoSize = true; + label6.Location = new Point(6, 54); + label6.Name = "label6"; + label6.Size = new Size(25, 17); + label6.TabIndex = 1; + label6.Text = "Y1:"; + // + // label7 + // + label7.AutoSize = true; + label7.Location = new Point(6, 25); + label7.Name = "label7"; + label7.Size = new Size(26, 17); + label7.TabIndex = 0; + label7.Text = "X1:"; + // + // ctrlTitleBar + // + ctrlTitleBar.Dock = DockStyle.Top; + ctrlTitleBar.Location = new Point(0, 0); + ctrlTitleBar.MinimumSize = new Size(0, 36); + ctrlTitleBar.Name = "ctrlTitleBar"; + ctrlTitleBar.Padding = new Padding(3); + ctrlTitleBar.Size = new Size(198, 36); + ctrlTitleBar.TabIndex = 11; + ctrlTitleBar.Title = "高度测量"; + // + // panel1 + // + panel1.BorderStyle = BorderStyle.FixedSingle; + panel1.Controls.Add(canvas); + panel1.Controls.Add(statusStrip1); + panel1.Dock = DockStyle.Fill; + panel1.Location = new Point(0, 0); + panel1.Name = "panel1"; + panel1.Size = new Size(1076, 640); + panel1.TabIndex = 1; + // + // canvas + // + canvas.AllowMultiSelect = false; + canvas.CreateMode = Canvas.Shape.ShapeTypeEnum.Polygon; + canvas.Dock = DockStyle.Fill; + canvas.Enabled = false; + canvas.FillDrawing = false; + canvas.Location = new Point(0, 0); + canvas.Margin = new Padding(2); + canvas.Name = "canvas"; + canvas.OutsideShapes = (List)resources.GetObject("canvas.OutsideShapes"); + canvas.Scale = 1F; + canvas.Shapes = (List)resources.GetObject("canvas.Shapes"); + canvas.Size = new Size(1074, 616); + canvas.TabIndex = 2; + // + // statusStrip1 + // + statusStrip1.Items.AddRange(new ToolStripItem[] { lblStatus }); + statusStrip1.Location = new Point(0, 616); + statusStrip1.Name = "statusStrip1"; + statusStrip1.Size = new Size(1074, 22); + statusStrip1.TabIndex = 1; + statusStrip1.Text = "statusStrip1"; + // + // lblStatus + // + lblStatus.Name = "lblStatus"; + lblStatus.Size = new Size(44, 17); + lblStatus.Text = " "; + // + // GuideHeightCtrl + // + AutoScaleDimensions = new SizeF(7F, 17F); + AutoScaleMode = AutoScaleMode.Font; + Controls.Add(splitContainer); + Controls.Add(lblElapsed); + Controls.Add(label4); + Name = "GuideHeightCtrl"; + Size = new Size(1280, 640); + Load += GuideLineCircleCtrl_Load; + splitContainer.Panel1.ResumeLayout(false); + splitContainer.Panel2.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)splitContainer).EndInit(); + splitContainer.ResumeLayout(false); + panelGuide.ResumeLayout(false); + panelGuide.PerformLayout(); + groupBox2.ResumeLayout(false); + groupBox2.PerformLayout(); + panel1.ResumeLayout(false); + panel1.PerformLayout(); + statusStrip1.ResumeLayout(false); + statusStrip1.PerformLayout(); + ResumeLayout(false); + PerformLayout(); + } + + #endregion + + private Label lblElapsed; + private Label label4; + + private SplitContainer splitContainer; + private Panel panelGuide; + private Panel panel1; + private Canvas.UI.FlyCanvas canvas; + private StatusStrip statusStrip1; + private ToolStripStatusLabel lblStatus; + private GroupBox groupBox2; + private TextBox tbLineX2; + private Label label8; + private TextBox tbLineY2; + private Label label5; + private TextBox tbLineX1; + private TextBox tbLineY1; + private Label label6; + private Label label7; + private CtrlTitleBar ctrlTitleBar; + private Button btnLoadImage; + private Label label9; + private Button btnExecute; + private Label label10; + private Button btnCreateLine; + private TextBox tbRectWidth1; + private Label lblResult; + private Label label1; + private Button btnSave; + private TextBox tbheight; + private Label lbheight; + private TextBox tbwidth; + private Label label2; + } +} diff --git a/CanFly/UI/GuidePanel/GuideHeightCtrl.cs b/CanFly/UI/GuidePanel/GuideHeightCtrl.cs new file mode 100644 index 0000000..c8eeb95 --- /dev/null +++ b/CanFly/UI/GuidePanel/GuideHeightCtrl.cs @@ -0,0 +1,346 @@ +using CanFly.Canvas.Helper; +using CanFly.Canvas.Shape; +using CanFly.Canvas.UI; +using CanFly.Helper; +using HalconDotNet; +using OpenCvSharp; +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; + +namespace CanFly.UI.GuidePanel +{ + public partial class GuideHeightCtrl : BaseGuideControl + { + + + + private FlyShape? _line; + + + private float _lineX1; + private float _lineY1; + private float _lineX2; + private float _lineY2; + float width, height; + private float _lineWidth; + private PointF[] _rectPoints = new PointF[4]; + //private float _LineLX=new float(); + //private float _LineLY =new float(); + //private float _LineRX =new float(); + //private float _LineRY =new float(); + + + + + + protected override string GetScriptFileName() => "HeightMeasure.hdvp"; + + + + public GuideHeightCtrl() + { + InitializeComponent(); + + this.canvas.mouseMoved += Canvas_mouseMoved; + this.canvas.OnShapeUpdateEvent += UpdateShape; + this.canvas.selectionChanged += Canvas_selectionChanged; + + this.canvas.OnShapeMoving += Canvas_OnShapeMoving; + this.canvas.newShape += Canvas_newShape; + + this.ctrlTitleBar.OnCloseClicked += OnControlClose; + + + + } + + + + protected override void UpdateShape(FlyShape shape) + { + switch (shape.ShapeType) + { + case ShapeTypeEnum.Rectangle: + this._line = shape; + + var pts = this._line.Points; + + _lineX1 = pts[0].X; + _lineY1 = pts[0].Y; + _lineX2 = pts[1].X; + _lineY2 = pts[1].Y; + _lineWidth = shape.LineVirtualRectWidth; + _rectPoints = shape.LineVirtualRectPoints; + //_LineLX = (shape.LineVirtualRectPoints[0].X + shape.LineVirtualRectPoints[3].X) / 2; + //_LineLY = (shape.LineVirtualRectPoints[0].Y + shape.LineVirtualRectPoints[3].Y) / 2; + //_LineRX = (shape.LineVirtualRectPoints[1].X + shape.LineVirtualRectPoints[2].X) / 2; + //_LineRY = (shape.LineVirtualRectPoints[1].Y + shape.LineVirtualRectPoints[2].Y) / 2; + + width = Math.Abs(_lineX2 - _lineX1); + height = Math.Abs(_lineY2 - _lineY1); + + + tbLineX1.Text = _lineX1.ToString("F3"); + tbLineY1.Text = _lineY1.ToString("F3"); + tbLineX2.Text = _lineX2.ToString("F3"); + tbLineY2.Text = _lineY2.ToString("F3"); + tbwidth.Text = width.ToString(); + tbheight.Text = height.ToString(); + // NumRectWidth1.Value = (decimal)_lineWidth; + break; + + default: + break; + } + } + + + + + + private void GuideLineCircleCtrl_Load(object sender, EventArgs e) + { + + + + } + + + + + private void Canvas_mouseMoved(PointF pos) + { + if (InvokeRequired) + { + Invoke(Canvas_mouseMoved, pos); + return; + } + + lblStatus.Text = $"X:{pos.X}, Y:{pos.Y}"; + + } + + + + + private void Canvas_selectionChanged(List shapes) + { + //if (shapes.Count != 1) + //{ + // // panelGuide.Controls.Clear(); + // return; + //} + //SwitchGuideForm(shapes[0].ShapeType); + // Canvas_OnShapeUpdateEvent(shapes[0]); + + if (shapes.Count != 1) + { + return; + } + UpdateShape(shapes[0]); + + } + + + + private void Canvas_OnShapeMoving(List shapes) + { + if (shapes.Count != 1) + { + return; + } + + UpdateShape(shapes[0]); + } + + + + + + + + private void btnCreateLine_Click(object sender, EventArgs e) + { + if (this.canvas.pixmap == null) + { + MessageBox.Show("请先打开图片"); + return; + } + tbLineX1.Text = string.Empty; + tbLineY1.Text = string.Empty; + tbLineX2.Text = string.Empty; + tbLineY2.Text = string.Empty; ; + tbwidth.Text = string.Empty; ; + tbheight.Text = string.Empty; ; + this.canvas.Shapes.RemoveAll(shp => shp.ShapeType == ShapeTypeEnum.Rectangle); + this.canvas.Invalidate(); + this.canvas.StartDraw(ShapeTypeEnum.Rectangle); + + } + + + + private void btnLoadImage_Click(object sender, EventArgs e) + { + OpenImageFile(bitmap => + { + this.canvas.LoadPixmap(bitmap); + this.canvas.Enabled = true; + + + }); + } + + + private void Canvas_newShape() + { + this.canvas.StopDraw(); + } + + private void btnExecute_Click(object sender, EventArgs e) + { + if (this.canvas.pixmap == null) + { + MessageBox.Show("请先打开图片"); + return; + } + if (this.tbLineX1.Text.Trim().Length == 0) + { + MessageBox.Show("请先创建矩形"); + return; + } + this.canvas.OutsideShapes.Clear(); + this.canvas.Invalidate(); + + + flag = new List(); + + Line1Para = new List(); + Line2Para = new List(); + iHeight = new List(); + Dictionary inputImg = new Dictionary(); + + if (hImage == null) + { + HOperatorSet.ReadImage(out hImage, CurrentImageFile); + } + inputImg["INPUT_Image"] = hImage; + + + Dictionary inputPara = new Dictionary(); + + + inputPara["row"] = _lineY1; + inputPara["column"] = _lineX1; + inputPara["Width"] = width; + inputPara["Height"] = height; + + + + List outputKeys = new List() + { + "OUTPUT_PreTreatedImage", + "OUTPUT_Flag", + + "Line1Para", + "Line2Para", + "iHeight" + }; + + ExecuteHScript( + inputImg, + inputPara, + outputKeys); + + } + + + List flag = new List(); + List Line1Para = new List(); + List Line2Para = new List(); + + List iHeight = new List(); + + + protected override void OnExecuteHScriptResult( + bool success, + Dictionary resultDic, + int timeElasped) + { + if (!success) + { + return; + } + + + /* + "OUTPUT_Flag", + "RXCenter", + "RYCenter", + "RRadius" + */ + + flag = resultDic["OUTPUT_Flag"].HTupleToDouble(); + + Line1Para = resultDic["Line1Para"].HTupleToDouble(); + Line2Para = resultDic["Line2Para"].HTupleToDouble(); + // EndRow = resultDic["EndRow"].HTupleToDouble(); + //EndCloumn = resultDic["EndColumn"].HTupleToDouble(); + iHeight = resultDic["iHeight"].HTupleToDouble(); + + if (flag.Count > 0) + { + lblResult.Text = flag[0].ToString(); + + } + else + { + lblResult.Text = "无"; + } + if (flag.Count > 0 && Line1Para.Count == 4 && Line2Para.Count == 4 && iHeight.Count > 0) + { + float width = 0; + this.canvas.DrawLine(new PointF((float)Line1Para[1], (float)Line1Para[0]), new PointF((float)Line1Para[3], (float)Line1Para[2]), 0); + this.canvas.DrawLine(new PointF((float)Line2Para[1], (float)Line2Para[0]), new PointF((float)Line2Para[3], (float)Line2Para[2]), 0); + this.canvas.Invalidate(); + lblElapsed.Text = $"{timeElasped} ms"; + } + } + + + + private void btnSave_Click(object sender, EventArgs e) + { + if (lblResult.Text.Equals("无")) + { + MessageBox.Show("请先进行绘制"); + return; + } + if (lblResult.Text != "0") + { + MessageBox.Show("测量计算错误,无法保存"); + return; + } + + + + string input = $"row:{string.Join(";", _lineY1)};column:{string.Join(";", _lineX1)};" + + $"Width:{string.Join(";", width)};Height:{string.Join(";", height)}"; + + string output = $"iHeight:{string.Join(";", iHeight[0])}"; + DataToTriggerEvent(input, output); + } + + private void tbLineX1_TextChanged(object sender, EventArgs e) + { + + } + } +} diff --git a/CanFly/UI/GuidePanel/GuideHeightCtrl.resx b/CanFly/UI/GuidePanel/GuideHeightCtrl.resx new file mode 100644 index 0000000..ad76d1e --- /dev/null +++ b/CanFly/UI/GuidePanel/GuideHeightCtrl.resx @@ -0,0 +1,145 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + AAEAAAD/////AQAAAAAAAAAMAgAAAERDYW5GbHkuQ2FudmFzLCBWZXJzaW9uPTEuMC4wLjAsIEN1bHR1 + cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49bnVsbAQBAAAAdlN5c3RlbS5Db2xsZWN0aW9ucy5HZW5l + cmljLkxpc3RgMVtbQ2FuRmx5LkNhbnZhcy5TaGFwZS5GbHlTaGFwZSwgQ2FuRmx5LkNhbnZhcywgQ3Vs + dHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1udWxsXV0DAAAABl9pdGVtcwVfc2l6ZQhfdmVyc2lv + bgQAAB5DYW5GbHkuQ2FudmFzLlNoYXBlLkZseVNoYXBlW10CAAAACAgJAwAAAAAAAAAAAAAADAQAAAAz + Q2FuRmx5LkNhbnZhcywgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1udWxsBwMAAAAAAQAA + AAAAAAAEHENhbkZseS5DYW52YXMuU2hhcGUuRmx5U2hhcGUEAAAACw== + + + + + AAEAAAD/////AQAAAAAAAAAMAgAAAERDYW5GbHkuQ2FudmFzLCBWZXJzaW9uPTEuMC4wLjAsIEN1bHR1 + cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49bnVsbAQBAAAAdlN5c3RlbS5Db2xsZWN0aW9ucy5HZW5l + cmljLkxpc3RgMVtbQ2FuRmx5LkNhbnZhcy5TaGFwZS5GbHlTaGFwZSwgQ2FuRmx5LkNhbnZhcywgQ3Vs + dHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1udWxsXV0DAAAABl9pdGVtcwVfc2l6ZQhfdmVyc2lv + bgQAAB5DYW5GbHkuQ2FudmFzLlNoYXBlLkZseVNoYXBlW10CAAAACAgJAwAAAAAAAAAAAAAADAQAAAAz + Q2FuRmx5LkNhbnZhcywgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1udWxsBwMAAAAAAQAA + AAAAAAAEHENhbkZseS5DYW52YXMuU2hhcGUuRmx5U2hhcGUEAAAACw== + + + + 17, 17 + + \ No newline at end of file diff --git a/CanFly/UI/GuidePanel/GuideLineCircleCtrl.Designer.cs b/CanFly/UI/GuidePanel/GuideLineCircleCtrl.Designer.cs new file mode 100644 index 0000000..7cc0816 --- /dev/null +++ b/CanFly/UI/GuidePanel/GuideLineCircleCtrl.Designer.cs @@ -0,0 +1,550 @@ +namespace CanFly.UI.GuidePanel +{ + partial class GuideLineCircleCtrl + { + /// + /// 必需的设计器变量。 + /// + private System.ComponentModel.IContainer components = null; + + /// + /// 清理所有正在使用的资源。 + /// + /// 如果应释放托管资源,为 true;否则为 false。 + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region 组件设计器生成的代码 + + /// + /// 设计器支持所需的方法 - 不要修改 + /// 使用代码编辑器修改此方法的内容。 + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(GuideLineCircleCtrl)); + lblElapsed = new Label(); + label4 = new Label(); + splitContainer = new SplitContainer(); + panelGuide = new Panel(); + lblDistance = new Label(); + label17 = new Label(); + lblResult = new Label(); + label15 = new Label(); + btnCreateLine = new Button(); + btnCreateCircle = new Button(); + btnLoadImage = new Button(); + label9 = new Label(); + btnExecute = new Button(); + label10 = new Label(); + groupBox2 = new GroupBox(); + NumRectWidth1 = new NumericUpDown(); + label11 = new Label(); + tbLineX2 = new TextBox(); + label8 = new Label(); + tbLineY2 = new TextBox(); + label5 = new Label(); + tbLineX1 = new TextBox(); + tbLineY1 = new TextBox(); + label6 = new Label(); + label7 = new Label(); + groupBox1 = new GroupBox(); + tbCircleX = new TextBox(); + tbCircleY = new TextBox(); + tbCircleR = new TextBox(); + label3 = new Label(); + label2 = new Label(); + label1 = new Label(); + ctrlTitleBar = new CtrlTitleBar(); + panel1 = new Panel(); + canvas = new Canvas.UI.FlyCanvas(); + statusStrip1 = new StatusStrip(); + lblStatus = new ToolStripStatusLabel(); + btnSave = new Button(); + ((System.ComponentModel.ISupportInitialize)splitContainer).BeginInit(); + splitContainer.Panel1.SuspendLayout(); + splitContainer.Panel2.SuspendLayout(); + splitContainer.SuspendLayout(); + panelGuide.SuspendLayout(); + groupBox2.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)NumRectWidth1).BeginInit(); + groupBox1.SuspendLayout(); + panel1.SuspendLayout(); + statusStrip1.SuspendLayout(); + SuspendLayout(); + // + // lblElapsed + // + lblElapsed.AutoSize = true; + lblElapsed.Location = new Point(50, 328); + lblElapsed.Name = "lblElapsed"; + lblElapsed.Size = new Size(32, 17); + lblElapsed.TabIndex = 9; + lblElapsed.Text = "0ms"; + // + // label4 + // + label4.AutoSize = true; + label4.Location = new Point(0, 328); + label4.Name = "label4"; + label4.Size = new Size(44, 17); + label4.TabIndex = 8; + label4.Text = "耗时:"; + // + // splitContainer + // + splitContainer.Dock = DockStyle.Fill; + splitContainer.Location = new Point(0, 0); + splitContainer.Name = "splitContainer"; + // + // splitContainer.Panel1 + // + splitContainer.Panel1.Controls.Add(panelGuide); + splitContainer.Panel1MinSize = 150; + // + // splitContainer.Panel2 + // + splitContainer.Panel2.Controls.Add(panel1); + splitContainer.Size = new Size(1280, 640); + splitContainer.SplitterDistance = 200; + splitContainer.TabIndex = 11; + // + // panelGuide + // + panelGuide.BorderStyle = BorderStyle.FixedSingle; + panelGuide.Controls.Add(btnSave); + panelGuide.Controls.Add(lblDistance); + panelGuide.Controls.Add(label17); + panelGuide.Controls.Add(lblResult); + panelGuide.Controls.Add(label15); + panelGuide.Controls.Add(btnCreateLine); + panelGuide.Controls.Add(btnCreateCircle); + panelGuide.Controls.Add(btnLoadImage); + panelGuide.Controls.Add(label9); + panelGuide.Controls.Add(btnExecute); + panelGuide.Controls.Add(label10); + panelGuide.Controls.Add(groupBox2); + panelGuide.Controls.Add(groupBox1); + panelGuide.Controls.Add(ctrlTitleBar); + panelGuide.Dock = DockStyle.Fill; + panelGuide.Location = new Point(0, 0); + panelGuide.Name = "panelGuide"; + panelGuide.Size = new Size(200, 640); + panelGuide.TabIndex = 0; + // + // lblDistance + // + lblDistance.AutoSize = true; + lblDistance.Location = new Point(54, 505); + lblDistance.Name = "lblDistance"; + lblDistance.Size = new Size(15, 17); + lblDistance.TabIndex = 29; + lblDistance.Text = "0"; + // + // label17 + // + label17.AutoSize = true; + label17.Location = new Point(6, 505); + label17.Name = "label17"; + label17.Size = new Size(44, 17); + label17.TabIndex = 28; + label17.Text = "距离:"; + // + // lblResult + // + lblResult.AutoSize = true; + lblResult.Location = new Point(54, 479); + lblResult.Name = "lblResult"; + lblResult.Size = new Size(20, 17); + lblResult.TabIndex = 27; + lblResult.Text = "无"; + // + // label15 + // + label15.AutoSize = true; + label15.Location = new Point(6, 479); + label15.Name = "label15"; + label15.Size = new Size(44, 17); + label15.TabIndex = 26; + label15.Text = "结果:"; + // + // btnCreateLine + // + btnCreateLine.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; + btnCreateLine.Location = new Point(6, 406); + btnCreateLine.Name = "btnCreateLine"; + btnCreateLine.Size = new Size(186, 32); + btnCreateLine.TabIndex = 20; + btnCreateLine.Text = "创建直线"; + btnCreateLine.UseVisualStyleBackColor = true; + btnCreateLine.Click += btnCreateLine_Click; + // + // btnCreateCircle + // + btnCreateCircle.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; + btnCreateCircle.Location = new Point(6, 368); + btnCreateCircle.Name = "btnCreateCircle"; + btnCreateCircle.Size = new Size(186, 32); + btnCreateCircle.TabIndex = 19; + btnCreateCircle.Text = "创建圆形"; + btnCreateCircle.UseVisualStyleBackColor = true; + btnCreateCircle.Click += btnCreateCircle_Click; + // + // btnLoadImage + // + btnLoadImage.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; + btnLoadImage.Location = new Point(6, 330); + btnLoadImage.Name = "btnLoadImage"; + btnLoadImage.Size = new Size(186, 32); + btnLoadImage.TabIndex = 18; + btnLoadImage.Text = "打开图片"; + btnLoadImage.UseVisualStyleBackColor = true; + btnLoadImage.Click += btnLoadImage_Click; + // + // label9 + // + label9.AutoSize = true; + label9.Location = new Point(56, 525); + label9.Name = "label9"; + label9.Size = new Size(32, 17); + label9.TabIndex = 17; + label9.Text = "0ms"; + // + // btnExecute + // + btnExecute.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; + btnExecute.Location = new Point(6, 444); + btnExecute.Name = "btnExecute"; + btnExecute.Size = new Size(186, 32); + btnExecute.TabIndex = 15; + btnExecute.Text = "执行"; + btnExecute.UseVisualStyleBackColor = true; + btnExecute.Click += btnExecute_Click; + // + // label10 + // + label10.AutoSize = true; + label10.Location = new Point(6, 525); + label10.Name = "label10"; + label10.Size = new Size(44, 17); + label10.TabIndex = 16; + label10.Text = "耗时:"; + // + // groupBox2 + // + groupBox2.Controls.Add(NumRectWidth1); + groupBox2.Controls.Add(label11); + groupBox2.Controls.Add(tbLineX2); + groupBox2.Controls.Add(label8); + groupBox2.Controls.Add(tbLineY2); + groupBox2.Controls.Add(label5); + groupBox2.Controls.Add(tbLineX1); + groupBox2.Controls.Add(tbLineY1); + groupBox2.Controls.Add(label6); + groupBox2.Controls.Add(label7); + groupBox2.Dock = DockStyle.Top; + groupBox2.Location = new Point(0, 152); + groupBox2.Name = "groupBox2"; + groupBox2.Size = new Size(198, 172); + groupBox2.TabIndex = 13; + groupBox2.TabStop = false; + groupBox2.Text = "线参数"; + // + // NumRectWidth1 + // + NumRectWidth1.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; + NumRectWidth1.Location = new Point(56, 138); + NumRectWidth1.Maximum = new decimal(new int[] { 9000, 0, 0, 0 }); + NumRectWidth1.Minimum = new decimal(new int[] { 1, 0, 0, 0 }); + NumRectWidth1.Name = "NumRectWidth1"; + NumRectWidth1.Size = new Size(136, 23); + NumRectWidth1.TabIndex = 13; + NumRectWidth1.Value = new decimal(new int[] { 1, 0, 0, 0 }); + // + // label11 + // + label11.AutoSize = true; + label11.Location = new Point(6, 140); + label11.Name = "label11"; + label11.Size = new Size(35, 17); + label11.TabIndex = 12; + label11.Text = "宽度:"; + // + // tbLineX2 + // + tbLineX2.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; + tbLineX2.Location = new Point(56, 80); + tbLineX2.Name = "tbLineX2"; + tbLineX2.Size = new Size(136, 23); + tbLineX2.TabIndex = 9; + // + // label8 + // + label8.AutoSize = true; + label8.Location = new Point(6, 83); + label8.Name = "label8"; + label8.Size = new Size(26, 17); + label8.TabIndex = 8; + label8.Text = "X2:"; + // + // tbLineY2 + // + tbLineY2.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; + tbLineY2.Location = new Point(56, 109); + tbLineY2.Name = "tbLineY2"; + tbLineY2.Size = new Size(136, 23); + tbLineY2.TabIndex = 7; + // + // label5 + // + label5.AutoSize = true; + label5.Location = new Point(6, 112); + label5.Name = "label5"; + label5.Size = new Size(25, 17); + label5.TabIndex = 6; + label5.Text = "Y2:"; + // + // tbLineX1 + // + tbLineX1.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; + tbLineX1.Location = new Point(56, 22); + tbLineX1.Name = "tbLineX1"; + tbLineX1.Size = new Size(136, 23); + tbLineX1.TabIndex = 5; + // + // tbLineY1 + // + tbLineY1.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; + tbLineY1.Location = new Point(56, 51); + tbLineY1.Name = "tbLineY1"; + tbLineY1.Size = new Size(136, 23); + tbLineY1.TabIndex = 4; + // + // label6 + // + label6.AutoSize = true; + label6.Location = new Point(6, 54); + label6.Name = "label6"; + label6.Size = new Size(25, 17); + label6.TabIndex = 1; + label6.Text = "Y1:"; + // + // label7 + // + label7.AutoSize = true; + label7.Location = new Point(6, 25); + label7.Name = "label7"; + label7.Size = new Size(26, 17); + label7.TabIndex = 0; + label7.Text = "X1:"; + // + // groupBox1 + // + groupBox1.Controls.Add(tbCircleX); + groupBox1.Controls.Add(tbCircleY); + groupBox1.Controls.Add(tbCircleR); + groupBox1.Controls.Add(label3); + groupBox1.Controls.Add(label2); + groupBox1.Controls.Add(label1); + groupBox1.Dock = DockStyle.Top; + groupBox1.Location = new Point(0, 36); + groupBox1.Name = "groupBox1"; + groupBox1.Size = new Size(198, 116); + groupBox1.TabIndex = 12; + groupBox1.TabStop = false; + groupBox1.Text = "圆参数"; + // + // tbCircleX + // + tbCircleX.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; + tbCircleX.Location = new Point(56, 22); + tbCircleX.Name = "tbCircleX"; + tbCircleX.Size = new Size(136, 23); + tbCircleX.TabIndex = 5; + // + // tbCircleY + // + tbCircleY.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; + tbCircleY.Location = new Point(56, 51); + tbCircleY.Name = "tbCircleY"; + tbCircleY.Size = new Size(136, 23); + tbCircleY.TabIndex = 4; + // + // tbCircleR + // + tbCircleR.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; + tbCircleR.Location = new Point(56, 80); + tbCircleR.Name = "tbCircleR"; + tbCircleR.Size = new Size(136, 23); + tbCircleR.TabIndex = 3; + // + // label3 + // + label3.AutoSize = true; + label3.Location = new Point(3, 83); + label3.Name = "label3"; + label3.Size = new Size(44, 17); + label3.TabIndex = 2; + label3.Text = "半径:"; + // + // label2 + // + label2.AutoSize = true; + label2.Location = new Point(6, 54); + label2.Name = "label2"; + label2.Size = new Size(18, 17); + label2.TabIndex = 1; + label2.Text = "Y:"; + // + // label1 + // + label1.AutoSize = true; + label1.Location = new Point(6, 25); + label1.Name = "label1"; + label1.Size = new Size(19, 17); + label1.TabIndex = 0; + label1.Text = "X:"; + // + // ctrlTitleBar + // + ctrlTitleBar.Dock = DockStyle.Top; + ctrlTitleBar.Location = new Point(0, 0); + ctrlTitleBar.MinimumSize = new Size(0, 36); + ctrlTitleBar.Name = "ctrlTitleBar"; + ctrlTitleBar.Padding = new Padding(3); + ctrlTitleBar.Size = new Size(198, 36); + ctrlTitleBar.TabIndex = 11; + ctrlTitleBar.Title = "线圆测量"; + // + // panel1 + // + panel1.BorderStyle = BorderStyle.FixedSingle; + panel1.Controls.Add(canvas); + panel1.Controls.Add(statusStrip1); + panel1.Dock = DockStyle.Fill; + panel1.Location = new Point(0, 0); + panel1.Name = "panel1"; + panel1.Size = new Size(1076, 640); + panel1.TabIndex = 1; + // + // canvas + // + canvas.AllowMultiSelect = false; + canvas.CreateMode = Canvas.Shape.ShapeTypeEnum.Polygon; + canvas.Dock = DockStyle.Fill; + canvas.Enabled = false; + canvas.FillDrawing = false; + canvas.Location = new Point(0, 0); + canvas.Margin = new Padding(2); + canvas.Name = "canvas"; + canvas.OutsideShapes = (List)resources.GetObject("canvas.OutsideShapes"); + canvas.Scale = 1F; + canvas.Shapes = (List)resources.GetObject("canvas.Shapes"); + canvas.Size = new Size(1074, 616); + canvas.TabIndex = 2; + // + // statusStrip1 + // + statusStrip1.Items.AddRange(new ToolStripItem[] { lblStatus }); + statusStrip1.Location = new Point(0, 616); + statusStrip1.Name = "statusStrip1"; + statusStrip1.Size = new Size(1074, 22); + statusStrip1.TabIndex = 1; + statusStrip1.Text = "statusStrip1"; + // + // lblStatus + // + lblStatus.Name = "lblStatus"; + lblStatus.Size = new Size(44, 17); + lblStatus.Text = " "; + // + // btnSave + // + btnSave.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; + btnSave.Location = new Point(6, 545); + btnSave.Name = "btnSave"; + btnSave.Size = new Size(186, 32); + btnSave.TabIndex = 30; + btnSave.Text = "保存数据"; + btnSave.UseVisualStyleBackColor = true; + btnSave.Click += btnSave_Click; + // + // GuideLineCircleCtrl + // + AutoScaleDimensions = new SizeF(7F, 17F); + AutoScaleMode = AutoScaleMode.Font; + Controls.Add(splitContainer); + Controls.Add(lblElapsed); + Controls.Add(label4); + Name = "GuideLineCircleCtrl"; + Size = new Size(1280, 640); + Load += GuideLineCircleCtrl_Load; + splitContainer.Panel1.ResumeLayout(false); + splitContainer.Panel2.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)splitContainer).EndInit(); + splitContainer.ResumeLayout(false); + panelGuide.ResumeLayout(false); + panelGuide.PerformLayout(); + groupBox2.ResumeLayout(false); + groupBox2.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)NumRectWidth1).EndInit(); + groupBox1.ResumeLayout(false); + groupBox1.PerformLayout(); + panel1.ResumeLayout(false); + panel1.PerformLayout(); + statusStrip1.ResumeLayout(false); + statusStrip1.PerformLayout(); + ResumeLayout(false); + PerformLayout(); + } + + #endregion + + private Label lblElapsed; + private Label label4; + + private SplitContainer splitContainer; + private Panel panelGuide; + private Panel panel1; + private Canvas.UI.FlyCanvas canvas; + private StatusStrip statusStrip1; + private ToolStripStatusLabel lblStatus; + private GroupBox groupBox2; + private TextBox tbLineX2; + private Label label8; + private TextBox tbLineY2; + private Label label5; + private TextBox tbLineX1; + private TextBox tbLineY1; + private Label label6; + private Label label7; + private GroupBox groupBox1; + private TextBox tbCircleX; + private TextBox tbCircleY; + private TextBox tbCircleR; + private Label label3; + private Label label2; + private Label label1; + private CtrlTitleBar ctrlTitleBar; + private Button btnCreateCircle; + private Button btnLoadImage; + private Label label9; + private Button btnExecute; + private Label label10; + private Button btnCreateLine; + private TextBox tbRectWidth1; + private Label label11; + private NumericUpDown NumRectWidth1; + private Label lblDistance; + private Label label17; + private Label lblResult; + private Label label15; + private Button btnSave; + } +} diff --git a/CanFly/UI/GuidePanel/GuideLineCircleCtrl.cs b/CanFly/UI/GuidePanel/GuideLineCircleCtrl.cs new file mode 100644 index 0000000..860a24c --- /dev/null +++ b/CanFly/UI/GuidePanel/GuideLineCircleCtrl.cs @@ -0,0 +1,449 @@ +using CanFly.Canvas.Helper; +using CanFly.Canvas.Shape; +using CanFly.Canvas.UI; +using CanFly.Helper; +using HalconDotNet; +using OpenCvSharp; +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; + + +namespace CanFly.UI.GuidePanel +{ + public partial class GuideLineCircleCtrl : BaseGuideControl + { + + + private FlyShape? _circle; + private FlyShape? _line; + + + private float _lineX1; + private float _lineY1; + private float _lineX2; + private float _lineY2; + private float _lineWidth; + + + private float _circleX; + private float _circleY; + private float _circleR; + + + + + protected override string GetScriptFileName() => "LineToCircle.hdvp"; + + + + public GuideLineCircleCtrl() + { + InitializeComponent(); + + this.canvas.mouseMoved += Canvas_mouseMoved; + this.canvas.OnShapeUpdateEvent += UpdateShape; + this.canvas.selectionChanged += Canvas_selectionChanged; + + this.canvas.OnShapeMoving += Canvas_OnShapeMoving; + this.canvas.newShape += Canvas_newShape; + + this.ctrlTitleBar.OnCloseClicked += OnControlClose; + + NumRectWidth1.ValueChanged -= NumRectWidth1_ValueChanged; + NumRectWidth1.Value = 40; + NumRectWidth1.ValueChanged += NumRectWidth1_ValueChanged; + + } + + + + protected override void UpdateShape(FlyShape shape) + { + switch (shape.ShapeType) + { + case ShapeTypeEnum.Line: + this._line = shape; + _line.IsDrawLineVirtualRect = true; + var pts = this._line.Points; + + _lineX1 = pts[0].X; + _lineY1 = pts[0].Y; + _lineX2 = pts[1].X; + _lineY2 = pts[1].Y; + _lineWidth = shape.LineVirtualRectWidth; + + tbLineX1.Text = _lineX1.ToString("F3"); + tbLineY1.Text = _lineY1.ToString("F3"); + tbLineX2.Text = _lineX2.ToString("F3"); + tbLineY2.Text = _lineY2.ToString("F3"); + // NumRectWidth1.Value = (decimal)_lineWidth; + break; + case ShapeTypeEnum.Circle: + this._circle = shape; + + _circleX = shape.Points[0].X; + _circleY = shape.Points[0].Y; + _circleR = PointHelper.Distance(shape.Points[0], shape.Points[1]); + + this.tbCircleX.Text = _circleX.ToString("F3"); + this.tbCircleY.Text = _circleY.ToString("F3"); + this.tbCircleR.Text = _circleR.ToString("F3"); + + break; + default: + break; + } + } + + + + + + private void GuideLineCircleCtrl_Load(object sender, EventArgs e) + { + + + + } + + + + + private void Canvas_mouseMoved(PointF pos) + { + if (InvokeRequired) + { + Invoke(Canvas_mouseMoved, pos); + return; + } + + lblStatus.Text = $"X:{pos.X}, Y:{pos.Y}"; + + } + + + + + private void Canvas_selectionChanged(List shapes) + { + //if (shapes.Count != 1) + //{ + // // panelGuide.Controls.Clear(); + // return; + //} + //SwitchGuideForm(shapes[0].ShapeType); + // Canvas_OnShapeUpdateEvent(shapes[0]); + + if (shapes.Count != 1) + { + return; + } + UpdateShape(shapes[0]); + + } + + + + private void Canvas_OnShapeMoving(List shapes) + { + if (shapes.Count != 1) + { + return; + } + + UpdateShape(shapes[0]); + } + + + + private void btnCreateCircle_Click(object sender, EventArgs e) + { + if (this.canvas.pixmap == null) + { + MessageBox.Show("请先打开图片"); + return; + } + this.tbCircleX.Text = string.Empty; + this.tbCircleY.Text = string.Empty; + this.tbCircleR.Text = string.Empty; + this.canvas.Shapes.RemoveAll(shp => shp.ShapeType == ShapeTypeEnum.Circle); + + this.canvas.Invalidate(); + this.canvas.StartDraw(ShapeTypeEnum.Circle); + } + + + + private void btnCreateLine_Click(object sender, EventArgs e) + { + if (this.canvas.pixmap == null) + { + MessageBox.Show("请先打开图片"); + return; + } + tbLineX1.Text = string.Empty; + tbLineY1.Text = string.Empty; + tbLineX2.Text = string.Empty; + tbLineY2.Text = string.Empty; + + this.canvas.Shapes.RemoveAll(shp => shp.ShapeType == ShapeTypeEnum.Line); + this.canvas.Invalidate(); + this.canvas.StartDraw(ShapeTypeEnum.Line); + + } + + + + private void btnLoadImage_Click(object sender, EventArgs e) + { + OpenImageFile(bitmap => + { + this.canvas.LoadPixmap(bitmap); + this.canvas.Enabled = true; + + + }); + } + + + private void Canvas_newShape() + { + this.canvas.StopDraw(); + } + + + + string strarrayX=string.Empty; + string strarrayY=string.Empty; + private void btnExecute_Click(object sender, EventArgs e) + { + + if (this.canvas.pixmap == null) + { + MessageBox.Show("请先打开图片"); + return; + } + if (this.tbLineX1.Text.Trim().Length == 0) + { + MessageBox.Show("请先创建直线"); + return; + } + if (this.tbLineX1.Text.Trim().Length == 0) + { + MessageBox.Show("请先创建圆形"); + return; + } + + this.canvas.OutsideShapes.Clear(); + this.canvas.Invalidate(); + + flag = new List(); + Distance = new List(); + fRowCenter = new List(); + fColCenter = new List(); + fRadius = new List(); + RowBegin = new List(); + ColBegin = new List(); + RowEnd = new List(); + ColEnd = new List(); + Dictionary inputImg = new Dictionary(); + + if (hImage == null) + { + HOperatorSet.ReadImage(out hImage, CurrentImageFile); + } + inputImg["INPUT_Image"] = hImage; + + Dictionary inputPara = new Dictionary(); + + PointF[] Points = this._line.LineVirtualRectPoints; + PointF Point1 = Points[0]; + PointF Point2 = Points[1]; + PointF Point3 = Points[2]; + PointF Point4 = Points[3]; + PointF Point5 = Points[0]; + + float x1 = Point1.X; + float y1 = Point1.Y; + + float x2 = Point2.X; + float y2 = Point2.Y; + + float x3 = Point3.X; + float y3 = Point3.Y; + + float x4 = Point4.X; + float y4 = Point4.Y; + + float x5 = Point5.X; + float y5 = Point5.Y; + + + float[] arrayX = new float[] { x1, x2, x3, x4, x5 }; + HTuple hTupleArrayX = new HTuple(arrayX); + + float[] arrayY = new float[] { y1, y2, y3, y4, y5 }; + HTuple hTupleArrayY = new HTuple(arrayY); + + strarrayX=string.Join(",", arrayX); + strarrayY=string.Join(",", arrayY); + + inputPara["LX"] = _lineX1; + inputPara["LY"] = _lineY1; + inputPara["RX"] = _lineX2; + inputPara["RY"] = _lineY2; + inputPara["XCenter"] = _circleX; + inputPara["YCenter"] = _circleY; + inputPara["Radius"] = _circleR; + inputPara["Line_XRect"] = hTupleArrayX; + inputPara["Line_YRect"] = hTupleArrayY; + + + + List outputKeys = new List() + { + "OUTPUT_Flag", + "distance", + "fRowCenter", + "fColCenter", + "fRadius", + "RowBegin", + "ColBegin", + "RowEnd", + "ColEnd" + }; + + ExecuteHScript( + inputImg, + inputPara, + outputKeys); + + } + List flag = new List(); + List Distance = new List(); + List fRowCenter = new List(); + List fColCenter = new List(); + List fRadius = new List(); + List RowBegin = new List(); + List ColBegin = new List(); + List RowEnd = new List(); + List ColEnd = new List(); + protected override void OnExecuteHScriptResult( + bool success, + Dictionary resultDic, + int timeElasped) + { + if (!success) + { + return; + } + + //"OUTPUT_Flag", + // "distance", + // "fRowCenter", + // "fColCenter", + // "fRadius", + // "RowBegin", + // "ColBegin", + // "RowEnd", + // "ColEnd" + + flag = resultDic["OUTPUT_Flag"].HTupleToDouble(); + Distance = resultDic["distance"].HTupleToDouble(); + fRowCenter = resultDic["fRowCenter"].HTupleToDouble(); + fColCenter = resultDic["fColCenter"].HTupleToDouble(); + fRadius = resultDic["fRadius"].HTupleToDouble(); + RowBegin = resultDic["RowBegin"].HTupleToDouble(); + ColBegin = resultDic["ColBegin"].HTupleToDouble(); + RowEnd = resultDic["RowEnd"].HTupleToDouble(); + ColEnd = resultDic["ColEnd"].HTupleToDouble(); + + + if (flag.Count > 0) + { + lblResult.Text = flag[0].ToString(); + + } + else + { + lblResult.Text = "无"; + } + if (Distance.Count > 0) + { + lblDistance.Text = Distance[0].ToString(); + } + else + { + lblDistance.Text = "0"; + } + + if (flag.Count > 0 && Distance.Count > 0 && fRowCenter.Count > 0 && fColCenter.Count > 0 && fRadius.Count > 0 && RowBegin.Count > 0 && ColBegin.Count > 0 && RowEnd.Count > 0 && ColEnd.Count > 0) + { + float width = 0; + this.canvas.DrawLine(new PointF((float)ColBegin[0], (float)RowBegin[0]), new PointF((float)ColEnd[0], (float)RowEnd[0]), width); + this.canvas.DrawCircle(new PointF((float)fColCenter[0], (float)fRowCenter[0]), (float)fRadius[0]); + + this.canvas.Invalidate(); + lblElapsed.Text = $"{timeElasped} ms"; + } + } + + + + + + + private void NumRectWidth1_ValueChanged(object sender, EventArgs e) + { + if (_line != null) + { + //_line1.IsDrawLineVirtualRect = true; + _line.LineVirtualRectWidth = (float)NumRectWidth1.Value; + UpdateShape(_line); + this.canvas.Invalidate(); + } + } + + private void btnSave_Click(object sender, EventArgs e) + { + if (lblResult.Text.Equals("无")) + { + MessageBox.Show("请先进行绘制"); + return; + } + if (lblResult.Text != "0") + { + MessageBox.Show("测量计算错误,无法保存"); + return; + } + + + + + + string input = $"LX:{_lineX1};" + + $"LY:{_lineY1};" + + $"RX:{_lineX2};" + + $"RY:{_lineY2};" + + $"XCenter:{_circleX};" + + $"YCenter:{_circleY};" + + $"Radius:{_circleR};" + + $"Line_XRect:{strarrayX};"+ + $"Line_YRect:{strarrayY}"; + + + + + string result = $"distance:{Distance[0]};"; + DataToTriggerEvent(input, result); + + } + } +} diff --git a/CanFly/UI/GuidePanel/GuideLineCircleCtrl.resx b/CanFly/UI/GuidePanel/GuideLineCircleCtrl.resx new file mode 100644 index 0000000..097e294 --- /dev/null +++ b/CanFly/UI/GuidePanel/GuideLineCircleCtrl.resx @@ -0,0 +1,145 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + AAEAAAD/////AQAAAAAAAAAMAgAAAERDYW5GbHkuQ2FudmFzLCBWZXJzaW9uPTEuMC4wLjAsIEN1bHR1 + cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49bnVsbAQBAAAAdlN5c3RlbS5Db2xsZWN0aW9ucy5HZW5l + cmljLkxpc3RgMVtbQ2FuRmx5LkNhbnZhcy5TaGFwZS5GbHlTaGFwZSwgQ2FuRmx5LkNhbnZhcywgQ3Vs + dHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1udWxsXV0DAAAABl9pdGVtcwVfc2l6ZQhfdmVyc2lv + bgQAAB5DYW5GbHkuQ2FudmFzLlNoYXBlLkZseVNoYXBlW10CAAAACAgJAwAAAAAAAAAAAAAADAQAAAAz + Q2FuRmx5LkNhbnZhcywgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1udWxsBwMAAAAAAQAA + AAAAAAAEHENhbkZseS5DYW52YXMuU2hhcGUuRmx5U2hhcGUEAAAACw== + + + + + AAEAAAD/////AQAAAAAAAAAMAgAAAERDYW5GbHkuQ2FudmFzLCBWZXJzaW9uPTEuMC4wLjAsIEN1bHR1 + cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49bnVsbAQBAAAAdlN5c3RlbS5Db2xsZWN0aW9ucy5HZW5l + cmljLkxpc3RgMVtbQ2FuRmx5LkNhbnZhcy5TaGFwZS5GbHlTaGFwZSwgQ2FuRmx5LkNhbnZhcywgQ3Vs + dHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1udWxsXV0DAAAABl9pdGVtcwVfc2l6ZQhfdmVyc2lv + bgQAAB5DYW5GbHkuQ2FudmFzLlNoYXBlLkZseVNoYXBlW10CAAAACAgJAwAAAAAAAAAAAAAADAQAAAAz + Q2FuRmx5LkNhbnZhcywgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1udWxsBwMAAAAAAQAA + AAAAAAAEHENhbkZseS5DYW52YXMuU2hhcGUuRmx5U2hhcGUEAAAACw== + + + + 17, 17 + + \ No newline at end of file diff --git a/CanFly/UI/GuidePanel/GuideLineCtrl.Designer.cs b/CanFly/UI/GuidePanel/GuideLineCtrl.Designer.cs new file mode 100644 index 0000000..85a5ddf --- /dev/null +++ b/CanFly/UI/GuidePanel/GuideLineCtrl.Designer.cs @@ -0,0 +1,427 @@ +namespace CanFly.UI.GuidePanel +{ + partial class GuideLineCtrl + { + /// + /// 必需的设计器变量。 + /// + private System.ComponentModel.IContainer components = null; + + /// + /// 清理所有正在使用的资源。 + /// + /// 如果应释放托管资源,为 true;否则为 false。 + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region 组件设计器生成的代码 + + /// + /// 设计器支持所需的方法 - 不要修改 + /// 使用代码编辑器修改此方法的内容。 + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(GuideLineCtrl)); + lblElapsed = new Label(); + label4 = new Label(); + splitContainer = new SplitContainer(); + panelGuide = new Panel(); + btnSave = new Button(); + lblResult = new Label(); + label1 = new Label(); + btnCreateLine = new Button(); + btnLoadImage = new Button(); + label9 = new Label(); + btnExecute = new Button(); + label10 = new Label(); + groupBox2 = new GroupBox(); + NumRectWidth1 = new NumericUpDown(); + label11 = new Label(); + tbLineX2 = new TextBox(); + label8 = new Label(); + tbLineY2 = new TextBox(); + label5 = new Label(); + tbLineX1 = new TextBox(); + tbLineY1 = new TextBox(); + label6 = new Label(); + label7 = new Label(); + ctrlTitleBar = new CtrlTitleBar(); + panel1 = new Panel(); + canvas = new Canvas.UI.FlyCanvas(); + statusStrip1 = new StatusStrip(); + lblStatus = new ToolStripStatusLabel(); + ((System.ComponentModel.ISupportInitialize)splitContainer).BeginInit(); + splitContainer.Panel1.SuspendLayout(); + splitContainer.Panel2.SuspendLayout(); + splitContainer.SuspendLayout(); + panelGuide.SuspendLayout(); + groupBox2.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)NumRectWidth1).BeginInit(); + panel1.SuspendLayout(); + statusStrip1.SuspendLayout(); + SuspendLayout(); + // + // lblElapsed + // + lblElapsed.AutoSize = true; + lblElapsed.Location = new Point(50, 328); + lblElapsed.Name = "lblElapsed"; + lblElapsed.Size = new Size(32, 17); + lblElapsed.TabIndex = 9; + lblElapsed.Text = "0ms"; + // + // label4 + // + label4.AutoSize = true; + label4.Location = new Point(0, 328); + label4.Name = "label4"; + label4.Size = new Size(44, 17); + label4.TabIndex = 8; + label4.Text = "耗时:"; + // + // splitContainer + // + splitContainer.Dock = DockStyle.Fill; + splitContainer.Location = new Point(0, 0); + splitContainer.Name = "splitContainer"; + // + // splitContainer.Panel1 + // + splitContainer.Panel1.Controls.Add(panelGuide); + splitContainer.Panel1MinSize = 150; + // + // splitContainer.Panel2 + // + splitContainer.Panel2.Controls.Add(panel1); + splitContainer.Size = new Size(1280, 640); + splitContainer.SplitterDistance = 200; + splitContainer.TabIndex = 11; + // + // panelGuide + // + panelGuide.BorderStyle = BorderStyle.FixedSingle; + panelGuide.Controls.Add(btnSave); + panelGuide.Controls.Add(lblResult); + panelGuide.Controls.Add(label1); + panelGuide.Controls.Add(btnCreateLine); + panelGuide.Controls.Add(btnLoadImage); + panelGuide.Controls.Add(label9); + panelGuide.Controls.Add(btnExecute); + panelGuide.Controls.Add(label10); + panelGuide.Controls.Add(groupBox2); + panelGuide.Controls.Add(ctrlTitleBar); + panelGuide.Dock = DockStyle.Fill; + panelGuide.Location = new Point(0, 0); + panelGuide.Name = "panelGuide"; + panelGuide.Size = new Size(200, 640); + panelGuide.TabIndex = 0; + // + // btnSave + // + btnSave.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; + btnSave.Location = new Point(6, 390); + btnSave.Name = "btnSave"; + btnSave.Size = new Size(186, 32); + btnSave.TabIndex = 23; + btnSave.Text = "保存数据"; + btnSave.UseVisualStyleBackColor = true; + btnSave.Click += btnSave_Click; + // + // lblResult + // + lblResult.AutoSize = true; + lblResult.Location = new Point(59, 354); + lblResult.Name = "lblResult"; + lblResult.Size = new Size(20, 17); + lblResult.TabIndex = 22; + lblResult.Text = "无"; + // + // label1 + // + label1.AutoSize = true; + label1.Location = new Point(9, 354); + label1.Name = "label1"; + label1.Size = new Size(44, 17); + label1.TabIndex = 21; + label1.Text = "结果:"; + // + // btnCreateLine + // + btnCreateLine.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; + btnCreateLine.Location = new Point(9, 252); + btnCreateLine.Name = "btnCreateLine"; + btnCreateLine.Size = new Size(186, 32); + btnCreateLine.TabIndex = 20; + btnCreateLine.Text = "创建直线"; + btnCreateLine.UseVisualStyleBackColor = true; + btnCreateLine.Click += btnCreateLine_Click; + // + // btnLoadImage + // + btnLoadImage.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; + btnLoadImage.Location = new Point(6, 214); + btnLoadImage.Name = "btnLoadImage"; + btnLoadImage.Size = new Size(186, 32); + btnLoadImage.TabIndex = 18; + btnLoadImage.Text = "打开图片"; + btnLoadImage.UseVisualStyleBackColor = true; + btnLoadImage.Click += btnLoadImage_Click; + // + // label9 + // + label9.AutoSize = true; + label9.Location = new Point(59, 325); + label9.Name = "label9"; + label9.Size = new Size(32, 17); + label9.TabIndex = 17; + label9.Text = "0ms"; + // + // btnExecute + // + btnExecute.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; + btnExecute.Location = new Point(9, 290); + btnExecute.Name = "btnExecute"; + btnExecute.Size = new Size(186, 32); + btnExecute.TabIndex = 15; + btnExecute.Text = "执行"; + btnExecute.UseVisualStyleBackColor = true; + btnExecute.Click += btnExecute_Click; + // + // label10 + // + label10.AutoSize = true; + label10.Location = new Point(9, 325); + label10.Name = "label10"; + label10.Size = new Size(44, 17); + label10.TabIndex = 16; + label10.Text = "耗时:"; + // + // groupBox2 + // + groupBox2.Controls.Add(NumRectWidth1); + groupBox2.Controls.Add(label11); + groupBox2.Controls.Add(tbLineX2); + groupBox2.Controls.Add(label8); + groupBox2.Controls.Add(tbLineY2); + groupBox2.Controls.Add(label5); + groupBox2.Controls.Add(tbLineX1); + groupBox2.Controls.Add(tbLineY1); + groupBox2.Controls.Add(label6); + groupBox2.Controls.Add(label7); + groupBox2.Dock = DockStyle.Top; + groupBox2.Location = new Point(0, 36); + groupBox2.Name = "groupBox2"; + groupBox2.Size = new Size(198, 172); + groupBox2.TabIndex = 13; + groupBox2.TabStop = false; + groupBox2.Text = "线参数"; + // + // NumRectWidth1 + // + NumRectWidth1.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; + NumRectWidth1.Location = new Point(56, 138); + NumRectWidth1.Maximum = new decimal(new int[] { 9000, 0, 0, 0 }); + NumRectWidth1.Minimum = new decimal(new int[] { 1, 0, 0, 0 }); + NumRectWidth1.Name = "NumRectWidth1"; + NumRectWidth1.Size = new Size(136, 23); + NumRectWidth1.TabIndex = 13; + NumRectWidth1.Value = new decimal(new int[] { 1, 0, 0, 0 }); + // + // label11 + // + label11.AutoSize = true; + label11.Location = new Point(6, 140); + label11.Name = "label11"; + label11.Size = new Size(35, 17); + label11.TabIndex = 12; + label11.Text = "宽度:"; + // + // tbLineX2 + // + tbLineX2.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; + tbLineX2.Location = new Point(56, 80); + tbLineX2.Name = "tbLineX2"; + tbLineX2.Size = new Size(136, 23); + tbLineX2.TabIndex = 9; + // + // label8 + // + label8.AutoSize = true; + label8.Location = new Point(6, 83); + label8.Name = "label8"; + label8.Size = new Size(26, 17); + label8.TabIndex = 8; + label8.Text = "X2:"; + // + // tbLineY2 + // + tbLineY2.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; + tbLineY2.Location = new Point(56, 109); + tbLineY2.Name = "tbLineY2"; + tbLineY2.Size = new Size(136, 23); + tbLineY2.TabIndex = 7; + // + // label5 + // + label5.AutoSize = true; + label5.Location = new Point(6, 112); + label5.Name = "label5"; + label5.Size = new Size(25, 17); + label5.TabIndex = 6; + label5.Text = "Y2:"; + // + // tbLineX1 + // + tbLineX1.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; + tbLineX1.Location = new Point(56, 22); + tbLineX1.Name = "tbLineX1"; + tbLineX1.Size = new Size(136, 23); + tbLineX1.TabIndex = 5; + // + // tbLineY1 + // + tbLineY1.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; + tbLineY1.Location = new Point(56, 51); + tbLineY1.Name = "tbLineY1"; + tbLineY1.Size = new Size(136, 23); + tbLineY1.TabIndex = 4; + // + // label6 + // + label6.AutoSize = true; + label6.Location = new Point(6, 54); + label6.Name = "label6"; + label6.Size = new Size(25, 17); + label6.TabIndex = 1; + label6.Text = "Y1:"; + // + // label7 + // + label7.AutoSize = true; + label7.Location = new Point(6, 25); + label7.Name = "label7"; + label7.Size = new Size(26, 17); + label7.TabIndex = 0; + label7.Text = "X1:"; + // + // ctrlTitleBar + // + ctrlTitleBar.Dock = DockStyle.Top; + ctrlTitleBar.Location = new Point(0, 0); + ctrlTitleBar.MinimumSize = new Size(0, 36); + ctrlTitleBar.Name = "ctrlTitleBar"; + ctrlTitleBar.Padding = new Padding(3); + ctrlTitleBar.Size = new Size(198, 36); + ctrlTitleBar.TabIndex = 11; + ctrlTitleBar.Title = "直线测量"; + // + // panel1 + // + panel1.BorderStyle = BorderStyle.FixedSingle; + panel1.Controls.Add(canvas); + panel1.Controls.Add(statusStrip1); + panel1.Dock = DockStyle.Fill; + panel1.Location = new Point(0, 0); + panel1.Name = "panel1"; + panel1.Size = new Size(1076, 640); + panel1.TabIndex = 1; + // + // canvas + // + canvas.AllowMultiSelect = false; + canvas.CreateMode = Canvas.Shape.ShapeTypeEnum.Polygon; + canvas.Dock = DockStyle.Fill; + canvas.Enabled = false; + canvas.FillDrawing = false; + canvas.Location = new Point(0, 0); + canvas.Margin = new Padding(2); + canvas.Name = "canvas"; + canvas.OutsideShapes = (List)resources.GetObject("canvas.OutsideShapes"); + canvas.Scale = 1F; + canvas.Shapes = (List)resources.GetObject("canvas.Shapes"); + canvas.Size = new Size(1074, 616); + canvas.TabIndex = 2; + // + // statusStrip1 + // + statusStrip1.Items.AddRange(new ToolStripItem[] { lblStatus }); + statusStrip1.Location = new Point(0, 616); + statusStrip1.Name = "statusStrip1"; + statusStrip1.Size = new Size(1074, 22); + statusStrip1.TabIndex = 1; + statusStrip1.Text = "statusStrip1"; + // + // lblStatus + // + lblStatus.Name = "lblStatus"; + lblStatus.Size = new Size(44, 17); + lblStatus.Text = " "; + // + // GuideLineCtrl + // + AutoScaleDimensions = new SizeF(7F, 17F); + AutoScaleMode = AutoScaleMode.Font; + Controls.Add(splitContainer); + Controls.Add(lblElapsed); + Controls.Add(label4); + Name = "GuideLineCtrl"; + Size = new Size(1280, 640); + Load += GuideLineCircleCtrl_Load; + splitContainer.Panel1.ResumeLayout(false); + splitContainer.Panel2.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)splitContainer).EndInit(); + splitContainer.ResumeLayout(false); + panelGuide.ResumeLayout(false); + panelGuide.PerformLayout(); + groupBox2.ResumeLayout(false); + groupBox2.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)NumRectWidth1).EndInit(); + panel1.ResumeLayout(false); + panel1.PerformLayout(); + statusStrip1.ResumeLayout(false); + statusStrip1.PerformLayout(); + ResumeLayout(false); + PerformLayout(); + } + + #endregion + + private Label lblElapsed; + private Label label4; + + private SplitContainer splitContainer; + private Panel panelGuide; + private Panel panel1; + private Canvas.UI.FlyCanvas canvas; + private StatusStrip statusStrip1; + private ToolStripStatusLabel lblStatus; + private GroupBox groupBox2; + private TextBox tbLineX2; + private Label label8; + private TextBox tbLineY2; + private Label label5; + private TextBox tbLineX1; + private TextBox tbLineY1; + private Label label6; + private Label label7; + private CtrlTitleBar ctrlTitleBar; + private Button btnLoadImage; + private Label label9; + private Button btnExecute; + private Label label10; + private Button btnCreateLine; + private TextBox tbRectWidth1; + private Label label11; + private NumericUpDown NumRectWidth1; + private Label lblResult; + private Label label1; + private Button btnSave; + } +} diff --git a/CanFly/UI/GuidePanel/GuideLineCtrl.cs b/CanFly/UI/GuidePanel/GuideLineCtrl.cs new file mode 100644 index 0000000..501cb5a --- /dev/null +++ b/CanFly/UI/GuidePanel/GuideLineCtrl.cs @@ -0,0 +1,387 @@ +using CanFly.Canvas.Helper; +using CanFly.Canvas.Shape; +using CanFly.Canvas.UI; +using CanFly.Helper; +using HalconDotNet; +using OpenCvSharp; +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; + +namespace CanFly.UI.GuidePanel +{ + public partial class GuideLineCtrl : BaseGuideControl + { + + + + private FlyShape? _line; + + + private float _lineX1; + private float _lineY1; + private float _lineX2; + private float _lineY2; + private float _lineWidth; + private PointF[] _rectPoints = new PointF[4]; + //private float _LineLX=new float(); + //private float _LineLY =new float(); + //private float _LineRX =new float(); + //private float _LineRY =new float(); + + + + + + protected override string GetScriptFileName() => "Line_detect.hdvp"; + + + + public GuideLineCtrl() + { + InitializeComponent(); + + this.canvas.mouseMoved += Canvas_mouseMoved; + this.canvas.OnShapeUpdateEvent += UpdateShape; + this.canvas.selectionChanged += Canvas_selectionChanged; + + this.canvas.OnShapeMoving += Canvas_OnShapeMoving; + this.canvas.newShape += Canvas_newShape; + + this.ctrlTitleBar.OnCloseClicked += OnControlClose; + + NumRectWidth1.ValueChanged -= NumRectWidth1_ValueChanged; + NumRectWidth1.Value = 40; + NumRectWidth1.ValueChanged += NumRectWidth1_ValueChanged; + + } + + + + protected override void UpdateShape(FlyShape shape) + { + switch (shape.ShapeType) + { + case ShapeTypeEnum.Line: + this._line = shape; + _line.IsDrawLineVirtualRect = true; + var pts = this._line.Points; + + _lineX1 = pts[0].X; + _lineY1 = pts[0].Y; + _lineX2 = pts[1].X; + _lineY2 = pts[1].Y; + _lineWidth = shape.LineVirtualRectWidth; + _rectPoints = shape.LineVirtualRectPoints; + //_LineLX = (shape.LineVirtualRectPoints[0].X + shape.LineVirtualRectPoints[3].X) / 2; + //_LineLY = (shape.LineVirtualRectPoints[0].Y + shape.LineVirtualRectPoints[3].Y) / 2; + //_LineRX = (shape.LineVirtualRectPoints[1].X + shape.LineVirtualRectPoints[2].X) / 2; + //_LineRY = (shape.LineVirtualRectPoints[1].Y + shape.LineVirtualRectPoints[2].Y) / 2; + + tbLineX1.Text = _lineX1.ToString("F3"); + tbLineY1.Text = _lineY1.ToString("F3"); + tbLineX2.Text = _lineX2.ToString("F3"); + tbLineY2.Text = _lineY2.ToString("F3"); + // NumRectWidth1.Value = (decimal)_lineWidth; + break; + + default: + break; + } + } + + + + + + private void GuideLineCircleCtrl_Load(object sender, EventArgs e) + { + + + + } + + + + + private void Canvas_mouseMoved(PointF pos) + { + if (InvokeRequired) + { + Invoke(Canvas_mouseMoved, pos); + return; + } + + lblStatus.Text = $"X:{pos.X}, Y:{pos.Y}"; + + } + + + + + private void Canvas_selectionChanged(List shapes) + { + //if (shapes.Count != 1) + //{ + // // panelGuide.Controls.Clear(); + // return; + //} + //SwitchGuideForm(shapes[0].ShapeType); + // Canvas_OnShapeUpdateEvent(shapes[0]); + + if (shapes.Count != 1) + { + return; + } + UpdateShape(shapes[0]); + + } + + + + private void Canvas_OnShapeMoving(List shapes) + { + if (shapes.Count != 1) + { + return; + } + + UpdateShape(shapes[0]); + } + + + + + + + + private void btnCreateLine_Click(object sender, EventArgs e) + { + if (this.canvas.pixmap == null) + { + MessageBox.Show("请先打开图片"); + return; + } + + tbLineX1.Text = string.Empty; + tbLineY1.Text = string.Empty; + tbLineX2.Text = string.Empty; + tbLineY2.Text = string.Empty; + + + this.canvas.Shapes.RemoveAll(shp => shp.ShapeType == ShapeTypeEnum.Line); + this.canvas.Invalidate(); + this.canvas.StartDraw(ShapeTypeEnum.Line); + + } + + + + private void btnLoadImage_Click(object sender, EventArgs e) + { + OpenImageFile(bitmap => + { + this.canvas.LoadPixmap(bitmap); + this.canvas.Enabled = true; + + + }); + } + + + private void Canvas_newShape() + { + this.canvas.StopDraw(); + } + string strarrayX = string.Empty; + string strarrayY = string.Empty; + private void btnExecute_Click(object sender, EventArgs e) + { + if (this.canvas.pixmap == null) + { + MessageBox.Show("请先打开图片"); + return; + } + if (this.tbLineX1.Text.Trim().Length == 0) + { + MessageBox.Show("请先创建直线"); + return; + } + this.canvas.OutsideShapes.Clear(); + this.canvas.Invalidate(); + + + flag = new List(); + RowBegin = new List(); + ColBegin = new List(); + RowEnd = new List(); + ColEnd = new List(); + Dictionary inputImg = new Dictionary(); + + if (hImage == null) + { + HOperatorSet.ReadImage(out hImage, CurrentImageFile); + } + inputImg["INPUT_Image"] = hImage; + // 创建一维数组 + + Dictionary inputPara = new Dictionary(); + + // 获取矩形的 4 个点 + PointF[] Points = this._line.LineVirtualRectPoints; + PointF Point1 = Points[0]; + PointF Point2 = Points[1]; + PointF Point3 = Points[2]; + PointF Point4 = Points[3]; + PointF Point5 = Points[0]; + + float x1 = Point1.X; + float y1 = Point1.Y; + + float x2 = Point2.X; + float y2 = Point2.Y; + + float x3 = Point3.X; + float y3 = Point3.Y; + + float x4 = Point4.X; + float y4 = Point4.Y; + + float x5 = Point5.X; + float y5 = Point5.Y; + + + float[] arrayX = new float[] { x1, x2, x3, x4, x5 }; + HTuple hTupleArrayX = new HTuple(arrayX); + + float[] arrayY = new float[] { y1, y2, y3, y4, y5 }; + HTuple hTupleArrayY = new HTuple(arrayY); + + strarrayX = string.Join(",", arrayX); + strarrayY = string.Join(",", arrayY); + + inputPara["LX"] = _lineX1; + inputPara["LY"] = _lineY1; + inputPara["RX"] = _lineX2; + inputPara["RY"] = _lineY2; + inputPara["XRect"] = hTupleArrayX; + inputPara["YRect"] = hTupleArrayY; + + + + List outputKeys = new List() + { + "OUTPUT_Flag", + "RowBegin", + "ColBegin", + "RowEnd", + "ColEnd" + }; + + ExecuteHScript( + inputImg, + inputPara, + outputKeys); + + } + + + List flag = new List(); + List RowBegin = new List(); + List ColBegin = new List(); + List RowEnd = new List(); + List ColEnd = new List(); + + + protected override void OnExecuteHScriptResult( + bool success, + Dictionary resultDic, + int timeElasped) + { + if (!success) + { + return; + } + + + /* + "OUTPUT_Flag", + "RXCenter", + "RYCenter", + "RRadius" + */ + + flag = resultDic["OUTPUT_Flag"].HTupleToDouble(); + RowBegin = resultDic["RowBegin"].HTupleToDouble(); + ColBegin = resultDic["ColBegin"].HTupleToDouble(); + RowEnd = resultDic["RowEnd"].HTupleToDouble(); + ColEnd = resultDic["ColEnd"].HTupleToDouble(); + if (flag.Count > 0) + { + lblResult.Text = flag[0].ToString(); + + } + else + { + lblResult.Text = "无"; + } + if (flag.Count > 0 && RowBegin.Count > 0 && ColBegin.Count > 0 && RowEnd.Count > 0 && ColEnd.Count > 0) + { + float width = 0; + this.canvas.DrawLine(new PointF((float)ColBegin[0], (float)RowBegin[0]), new PointF((float)ColEnd[0], (float)RowEnd[0]), width); + this.canvas.Invalidate(); + lblElapsed.Text = $"{timeElasped} ms"; + } + } + + + private void NumRectWidth1_ValueChanged(object sender, EventArgs e) + { + if (_line != null) + { + //_line1.IsDrawLineVirtualRect = true; + _line.LineVirtualRectWidth = (float)NumRectWidth1.Value; + UpdateShape(_line); + this.canvas.Invalidate(); + } + } + + private void btnSave_Click(object sender, EventArgs e) + { + if (lblResult.Text.Equals("无")) + { + MessageBox.Show("请先进行绘制"); + return; + } + if (lblResult.Text != "0") + { + MessageBox.Show("测量计算错误,无法保存"); + return; + } + //flag = resultDic["OUTPUT_Flag"].HTupleToDouble(); + //RowBegin = resultDic["RowBegin"].HTupleToDouble(); + //ColBegin = resultDic["ColBegin"].HTupleToDouble(); + //RowEnd = resultDic["RowEnd"].HTupleToDouble(); + //ColEnd = resultDic["ColEnd"].HTupleToDouble(); + + + string input = $"LX:{_lineX1};" + + $"LY:{_lineY1};" + + $"RX:{_lineX2};" + + $"RY:{_lineY2};" + + $"Line_XRect:{strarrayX};" + + $"Line_YRect:{strarrayY}"; + + + string result = $"RowBegin:{string.Join(";", RowBegin[0])};ColBegin:{string.Join(";", ColBegin[0])};RowEnd:{string.Join(";", RowEnd[0])};ColEnd:{string.Join(";", ColEnd[0])}"; + + DataToTriggerEvent(input, result); + } + } +} diff --git a/CanFly/UI/GuidePanel/GuideLineCtrl.resx b/CanFly/UI/GuidePanel/GuideLineCtrl.resx new file mode 100644 index 0000000..097e294 --- /dev/null +++ b/CanFly/UI/GuidePanel/GuideLineCtrl.resx @@ -0,0 +1,145 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + AAEAAAD/////AQAAAAAAAAAMAgAAAERDYW5GbHkuQ2FudmFzLCBWZXJzaW9uPTEuMC4wLjAsIEN1bHR1 + cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49bnVsbAQBAAAAdlN5c3RlbS5Db2xsZWN0aW9ucy5HZW5l + cmljLkxpc3RgMVtbQ2FuRmx5LkNhbnZhcy5TaGFwZS5GbHlTaGFwZSwgQ2FuRmx5LkNhbnZhcywgQ3Vs + dHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1udWxsXV0DAAAABl9pdGVtcwVfc2l6ZQhfdmVyc2lv + bgQAAB5DYW5GbHkuQ2FudmFzLlNoYXBlLkZseVNoYXBlW10CAAAACAgJAwAAAAAAAAAAAAAADAQAAAAz + Q2FuRmx5LkNhbnZhcywgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1udWxsBwMAAAAAAQAA + AAAAAAAEHENhbkZseS5DYW52YXMuU2hhcGUuRmx5U2hhcGUEAAAACw== + + + + + AAEAAAD/////AQAAAAAAAAAMAgAAAERDYW5GbHkuQ2FudmFzLCBWZXJzaW9uPTEuMC4wLjAsIEN1bHR1 + cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49bnVsbAQBAAAAdlN5c3RlbS5Db2xsZWN0aW9ucy5HZW5l + cmljLkxpc3RgMVtbQ2FuRmx5LkNhbnZhcy5TaGFwZS5GbHlTaGFwZSwgQ2FuRmx5LkNhbnZhcywgQ3Vs + dHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1udWxsXV0DAAAABl9pdGVtcwVfc2l6ZQhfdmVyc2lv + bgQAAB5DYW5GbHkuQ2FudmFzLlNoYXBlLkZseVNoYXBlW10CAAAACAgJAwAAAAAAAAAAAAAADAQAAAAz + Q2FuRmx5LkNhbnZhcywgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1udWxsBwMAAAAAAQAA + AAAAAAAEHENhbkZseS5DYW52YXMuU2hhcGUuRmx5U2hhcGUEAAAACw== + + + + 17, 17 + + \ No newline at end of file diff --git a/CanFly/UI/GuidePanel/GuideLineLineCtrl.Designer.cs b/CanFly/UI/GuidePanel/GuideLineLineCtrl.Designer.cs new file mode 100644 index 0000000..a451bdf --- /dev/null +++ b/CanFly/UI/GuidePanel/GuideLineLineCtrl.Designer.cs @@ -0,0 +1,570 @@ +namespace CanFly.UI.GuidePanel +{ + partial class GuideLineLineCtrl + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(GuideLineLineCtrl)); + lblStatus = new ToolStripStatusLabel(); + panel1 = new Panel(); + canvas = new Canvas.UI.FlyCanvas(); + statusStrip1 = new StatusStrip(); + ctrlTitleBar = new CtrlTitleBar(); + tbLine1X2 = new TextBox(); + label8 = new Label(); + tbLine1Y2 = new TextBox(); + label5 = new Label(); + label10 = new Label(); + tbLine1X1 = new TextBox(); + tbLine1Y1 = new TextBox(); + label6 = new Label(); + label7 = new Label(); + btnLoadImage = new Button(); + label9 = new Label(); + btnExecute = new Button(); + panelGuide = new Panel(); + lblDistance = new Label(); + label17 = new Label(); + lblResult = new Label(); + label15 = new Label(); + groupBox3 = new GroupBox(); + NumRectWidth2 = new NumericUpDown(); + label2 = new Label(); + tbLine2X2 = new TextBox(); + label11 = new Label(); + tbLine2Y2 = new TextBox(); + label12 = new Label(); + tbLine2X1 = new TextBox(); + tbLine2Y1 = new TextBox(); + label13 = new Label(); + label14 = new Label(); + groupBox2 = new GroupBox(); + NumRectWidth1 = new NumericUpDown(); + label1 = new Label(); + splitContainer = new SplitContainer(); + lblElapsed = new Label(); + label4 = new Label(); + btnSave = new Button(); + panel1.SuspendLayout(); + statusStrip1.SuspendLayout(); + panelGuide.SuspendLayout(); + groupBox3.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)NumRectWidth2).BeginInit(); + groupBox2.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)NumRectWidth1).BeginInit(); + ((System.ComponentModel.ISupportInitialize)splitContainer).BeginInit(); + splitContainer.Panel1.SuspendLayout(); + splitContainer.Panel2.SuspendLayout(); + splitContainer.SuspendLayout(); + SuspendLayout(); + // + // lblStatus + // + lblStatus.Name = "lblStatus"; + lblStatus.Size = new Size(44, 17); + lblStatus.Text = " "; + // + // panel1 + // + panel1.BorderStyle = BorderStyle.FixedSingle; + panel1.Controls.Add(canvas); + panel1.Controls.Add(statusStrip1); + panel1.Dock = DockStyle.Fill; + panel1.Location = new Point(0, 0); + panel1.Name = "panel1"; + panel1.Size = new Size(1076, 640); + panel1.TabIndex = 1; + // + // canvas + // + canvas.AllowMultiSelect = false; + canvas.CreateMode = Canvas.Shape.ShapeTypeEnum.Polygon; + canvas.Dock = DockStyle.Fill; + canvas.Enabled = false; + canvas.FillDrawing = false; + canvas.Location = new Point(0, 0); + canvas.Margin = new Padding(2); + canvas.Name = "canvas"; + canvas.OutsideShapes = (List)resources.GetObject("canvas.OutsideShapes"); + canvas.Scale = 1F; + canvas.Shapes = (List)resources.GetObject("canvas.Shapes"); + canvas.Size = new Size(1074, 616); + canvas.TabIndex = 2; + // + // statusStrip1 + // + statusStrip1.Items.AddRange(new ToolStripItem[] { lblStatus }); + statusStrip1.Location = new Point(0, 616); + statusStrip1.Name = "statusStrip1"; + statusStrip1.Size = new Size(1074, 22); + statusStrip1.TabIndex = 1; + statusStrip1.Text = "statusStrip1"; + // + // ctrlTitleBar + // + ctrlTitleBar.Dock = DockStyle.Top; + ctrlTitleBar.Location = new Point(0, 0); + ctrlTitleBar.MinimumSize = new Size(0, 36); + ctrlTitleBar.Name = "ctrlTitleBar"; + ctrlTitleBar.Padding = new Padding(3); + ctrlTitleBar.Size = new Size(198, 36); + ctrlTitleBar.TabIndex = 11; + ctrlTitleBar.Title = "线线测量"; + // + // tbLine1X2 + // + tbLine1X2.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; + tbLine1X2.Location = new Point(56, 80); + tbLine1X2.Name = "tbLine1X2"; + tbLine1X2.Size = new Size(134, 23); + tbLine1X2.TabIndex = 9; + // + // label8 + // + label8.AutoSize = true; + label8.Location = new Point(6, 83); + label8.Name = "label8"; + label8.Size = new Size(26, 17); + label8.TabIndex = 8; + label8.Text = "X2:"; + // + // tbLine1Y2 + // + tbLine1Y2.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; + tbLine1Y2.Location = new Point(56, 109); + tbLine1Y2.Name = "tbLine1Y2"; + tbLine1Y2.Size = new Size(134, 23); + tbLine1Y2.TabIndex = 7; + // + // label5 + // + label5.AutoSize = true; + label5.Location = new Point(6, 112); + label5.Name = "label5"; + label5.Size = new Size(25, 17); + label5.TabIndex = 6; + label5.Text = "Y2:"; + // + // label10 + // + label10.AutoSize = true; + label10.Location = new Point(6, 521); + label10.Name = "label10"; + label10.Size = new Size(44, 17); + label10.TabIndex = 16; + label10.Text = "耗时:"; + // + // tbLine1X1 + // + tbLine1X1.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; + tbLine1X1.Location = new Point(56, 22); + tbLine1X1.Name = "tbLine1X1"; + tbLine1X1.Size = new Size(134, 23); + tbLine1X1.TabIndex = 5; + // + // tbLine1Y1 + // + tbLine1Y1.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; + tbLine1Y1.Location = new Point(56, 51); + tbLine1Y1.Name = "tbLine1Y1"; + tbLine1Y1.Size = new Size(134, 23); + tbLine1Y1.TabIndex = 4; + // + // label6 + // + label6.AutoSize = true; + label6.Location = new Point(6, 54); + label6.Name = "label6"; + label6.Size = new Size(25, 17); + label6.TabIndex = 1; + label6.Text = "Y1:"; + // + // label7 + // + label7.AutoSize = true; + label7.Location = new Point(6, 25); + label7.Name = "label7"; + label7.Size = new Size(26, 17); + label7.TabIndex = 0; + label7.Text = "X1:"; + // + // btnLoadImage + // + btnLoadImage.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; + btnLoadImage.Location = new Point(6, 394); + btnLoadImage.Name = "btnLoadImage"; + btnLoadImage.Size = new Size(184, 32); + btnLoadImage.TabIndex = 18; + btnLoadImage.Text = "打开图片"; + btnLoadImage.UseVisualStyleBackColor = true; + btnLoadImage.Click += btnLoadImage_Click; + // + // label9 + // + label9.AutoSize = true; + label9.Location = new Point(54, 521); + label9.Name = "label9"; + label9.Size = new Size(32, 17); + label9.TabIndex = 17; + label9.Text = "0ms"; + // + // btnExecute + // + btnExecute.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; + btnExecute.Location = new Point(5, 432); + btnExecute.Name = "btnExecute"; + btnExecute.Size = new Size(184, 32); + btnExecute.TabIndex = 15; + btnExecute.Text = "执行"; + btnExecute.UseVisualStyleBackColor = true; + btnExecute.Click += btnExecute_Click; + // + // panelGuide + // + panelGuide.BorderStyle = BorderStyle.FixedSingle; + panelGuide.Controls.Add(btnSave); + panelGuide.Controls.Add(lblDistance); + panelGuide.Controls.Add(label17); + panelGuide.Controls.Add(lblResult); + panelGuide.Controls.Add(label15); + panelGuide.Controls.Add(groupBox3); + panelGuide.Controls.Add(btnLoadImage); + panelGuide.Controls.Add(label9); + panelGuide.Controls.Add(btnExecute); + panelGuide.Controls.Add(label10); + panelGuide.Controls.Add(groupBox2); + panelGuide.Controls.Add(ctrlTitleBar); + panelGuide.Dock = DockStyle.Fill; + panelGuide.Location = new Point(0, 0); + panelGuide.Name = "panelGuide"; + panelGuide.Size = new Size(200, 640); + panelGuide.TabIndex = 0; + // + // lblDistance + // + lblDistance.AutoSize = true; + lblDistance.Location = new Point(54, 493); + lblDistance.Name = "lblDistance"; + lblDistance.Size = new Size(15, 17); + lblDistance.TabIndex = 25; + lblDistance.Text = "0"; + // + // label17 + // + label17.AutoSize = true; + label17.Location = new Point(6, 493); + label17.Name = "label17"; + label17.Size = new Size(44, 17); + label17.TabIndex = 24; + label17.Text = "距离:"; + // + // lblResult + // + lblResult.AutoSize = true; + lblResult.Location = new Point(54, 467); + lblResult.Name = "lblResult"; + lblResult.Size = new Size(20, 17); + lblResult.TabIndex = 23; + lblResult.Text = "无"; + // + // label15 + // + label15.AutoSize = true; + label15.Location = new Point(6, 467); + label15.Name = "label15"; + label15.Size = new Size(44, 17); + label15.TabIndex = 22; + label15.Text = "结果:"; + // + // groupBox3 + // + groupBox3.Controls.Add(NumRectWidth2); + groupBox3.Controls.Add(label2); + groupBox3.Controls.Add(tbLine2X2); + groupBox3.Controls.Add(label11); + groupBox3.Controls.Add(tbLine2Y2); + groupBox3.Controls.Add(label12); + groupBox3.Controls.Add(tbLine2X1); + groupBox3.Controls.Add(tbLine2Y1); + groupBox3.Controls.Add(label13); + groupBox3.Controls.Add(label14); + groupBox3.Dock = DockStyle.Top; + groupBox3.Location = new Point(0, 216); + groupBox3.Name = "groupBox3"; + groupBox3.Size = new Size(198, 172); + groupBox3.TabIndex = 21; + groupBox3.TabStop = false; + groupBox3.Text = "线2参数"; + // + // NumRectWidth2 + // + NumRectWidth2.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; + NumRectWidth2.Location = new Point(53, 138); + NumRectWidth2.Maximum = new decimal(new int[] { 9000, 0, 0, 0 }); + NumRectWidth2.Minimum = new decimal(new int[] { 1, 0, 0, 0 }); + NumRectWidth2.Name = "NumRectWidth2"; + NumRectWidth2.Size = new Size(136, 23); + NumRectWidth2.TabIndex = 13; + NumRectWidth2.Value = new decimal(new int[] { 1, 0, 0, 0 }); + // + // label2 + // + label2.AutoSize = true; + label2.Location = new Point(6, 140); + label2.Name = "label2"; + label2.Size = new Size(35, 17); + label2.TabIndex = 12; + label2.Text = "宽度:"; + // + // tbLine2X2 + // + tbLine2X2.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; + tbLine2X2.Location = new Point(56, 80); + tbLine2X2.Name = "tbLine2X2"; + tbLine2X2.Size = new Size(134, 23); + tbLine2X2.TabIndex = 9; + // + // label11 + // + label11.AutoSize = true; + label11.Location = new Point(6, 83); + label11.Name = "label11"; + label11.Size = new Size(26, 17); + label11.TabIndex = 8; + label11.Text = "X2:"; + // + // tbLine2Y2 + // + tbLine2Y2.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; + tbLine2Y2.Location = new Point(56, 109); + tbLine2Y2.Name = "tbLine2Y2"; + tbLine2Y2.Size = new Size(136, 23); + tbLine2Y2.TabIndex = 7; + // + // label12 + // + label12.AutoSize = true; + label12.Location = new Point(6, 112); + label12.Name = "label12"; + label12.Size = new Size(25, 17); + label12.TabIndex = 6; + label12.Text = "Y2:"; + // + // tbLine2X1 + // + tbLine2X1.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; + tbLine2X1.Location = new Point(56, 22); + tbLine2X1.Name = "tbLine2X1"; + tbLine2X1.Size = new Size(134, 23); + tbLine2X1.TabIndex = 5; + // + // tbLine2Y1 + // + tbLine2Y1.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; + tbLine2Y1.Location = new Point(56, 51); + tbLine2Y1.Name = "tbLine2Y1"; + tbLine2Y1.Size = new Size(134, 23); + tbLine2Y1.TabIndex = 4; + // + // label13 + // + label13.AutoSize = true; + label13.Location = new Point(6, 54); + label13.Name = "label13"; + label13.Size = new Size(25, 17); + label13.TabIndex = 1; + label13.Text = "Y1:"; + // + // label14 + // + label14.AutoSize = true; + label14.Location = new Point(6, 25); + label14.Name = "label14"; + label14.Size = new Size(26, 17); + label14.TabIndex = 0; + label14.Text = "X1:"; + // + // groupBox2 + // + groupBox2.Controls.Add(NumRectWidth1); + groupBox2.Controls.Add(label1); + groupBox2.Controls.Add(tbLine1X2); + groupBox2.Controls.Add(label8); + groupBox2.Controls.Add(tbLine1Y2); + groupBox2.Controls.Add(label5); + groupBox2.Controls.Add(tbLine1X1); + groupBox2.Controls.Add(tbLine1Y1); + groupBox2.Controls.Add(label6); + groupBox2.Controls.Add(label7); + groupBox2.Dock = DockStyle.Top; + groupBox2.Location = new Point(0, 36); + groupBox2.Name = "groupBox2"; + groupBox2.Size = new Size(198, 180); + groupBox2.TabIndex = 13; + groupBox2.TabStop = false; + groupBox2.Text = "线1参数"; + // + // NumRectWidth1 + // + NumRectWidth1.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; + NumRectWidth1.Location = new Point(54, 138); + NumRectWidth1.Maximum = new decimal(new int[] { 9000, 0, 0, 0 }); + NumRectWidth1.Minimum = new decimal(new int[] { 1, 0, 0, 0 }); + NumRectWidth1.Name = "NumRectWidth1"; + NumRectWidth1.Size = new Size(135, 23); + NumRectWidth1.TabIndex = 11; + NumRectWidth1.Value = new decimal(new int[] { 1, 0, 0, 0 }); + // + // label1 + // + label1.AutoSize = true; + label1.Location = new Point(6, 140); + label1.Name = "label1"; + label1.Size = new Size(35, 17); + label1.TabIndex = 10; + label1.Text = "宽度:"; + // + // splitContainer + // + splitContainer.Dock = DockStyle.Fill; + splitContainer.Location = new Point(0, 0); + splitContainer.Name = "splitContainer"; + // + // splitContainer.Panel1 + // + splitContainer.Panel1.Controls.Add(panelGuide); + splitContainer.Panel1MinSize = 150; + // + // splitContainer.Panel2 + // + splitContainer.Panel2.Controls.Add(panel1); + splitContainer.Size = new Size(1280, 640); + splitContainer.SplitterDistance = 200; + splitContainer.TabIndex = 11; + // + // lblElapsed + // + lblElapsed.AutoSize = true; + lblElapsed.Location = new Point(50, 328); + lblElapsed.Name = "lblElapsed"; + lblElapsed.Size = new Size(32, 17); + lblElapsed.TabIndex = 13; + lblElapsed.Text = "0ms"; + // + // label4 + // + label4.AutoSize = true; + label4.Location = new Point(0, 328); + label4.Name = "label4"; + label4.Size = new Size(44, 17); + label4.TabIndex = 12; + label4.Text = "耗时:"; + // + // btnSave + // + btnSave.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; + btnSave.Location = new Point(3, 541); + btnSave.Name = "btnSave"; + btnSave.Size = new Size(186, 32); + btnSave.TabIndex = 26; + btnSave.Text = "保存数据"; + btnSave.UseVisualStyleBackColor = true; + btnSave.Click += btnSave_Click; + // + // GuideLineLineCtrl + // + AutoScaleDimensions = new SizeF(7F, 17F); + AutoScaleMode = AutoScaleMode.Font; + Controls.Add(splitContainer); + Controls.Add(lblElapsed); + Controls.Add(label4); + Name = "GuideLineLineCtrl"; + Size = new Size(1280, 640); + panel1.ResumeLayout(false); + panel1.PerformLayout(); + statusStrip1.ResumeLayout(false); + statusStrip1.PerformLayout(); + panelGuide.ResumeLayout(false); + panelGuide.PerformLayout(); + groupBox3.ResumeLayout(false); + groupBox3.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)NumRectWidth2).EndInit(); + groupBox2.ResumeLayout(false); + groupBox2.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)NumRectWidth1).EndInit(); + splitContainer.Panel1.ResumeLayout(false); + splitContainer.Panel2.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)splitContainer).EndInit(); + splitContainer.ResumeLayout(false); + ResumeLayout(false); + PerformLayout(); + } + + #endregion + + private ToolStripStatusLabel lblStatus; + private Panel panel1; + private Canvas.UI.FlyCanvas canvas; + private StatusStrip statusStrip1; + private CtrlTitleBar ctrlTitleBar; + private TextBox tbLine1X2; + private Label label8; + private TextBox tbLine1Y2; + private Label label5; + private Label label10; + private TextBox tbLine1X1; + private TextBox tbLine1Y1; + private Label label6; + private Label label7; + private Button btnLoadImage; + private Label label9; + private Button btnExecute; + private Panel panelGuide; + private GroupBox groupBox2; + private SplitContainer splitContainer; + private Label lblElapsed; + private Label label4; + private GroupBox groupBox3; + private TextBox tbLine2X2; + private Label label11; + private TextBox tbLine2Y2; + private Label label12; + private TextBox tbLine2X1; + private TextBox tbLine2Y1; + private Label label13; + private Label label14; + private Label label1; + private Label label2; + private NumericUpDown NumRectWidth2; + private NumericUpDown NumRectWidth1; + private Label lblDistance; + private Label label17; + private Label lblResult; + private Label label15; + private Button btnSave; + } +} \ No newline at end of file diff --git a/CanFly/UI/GuidePanel/GuideLineLineCtrl.cs b/CanFly/UI/GuidePanel/GuideLineLineCtrl.cs new file mode 100644 index 0000000..140bb8d --- /dev/null +++ b/CanFly/UI/GuidePanel/GuideLineLineCtrl.cs @@ -0,0 +1,526 @@ +using CanFly.Canvas.Helper; +using CanFly.Canvas.Shape; +using CanFly.Helper; +using HalconDotNet; +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; + +namespace CanFly.UI.GuidePanel +{ + public partial class GuideLineLineCtrl : BaseGuideControl + { + private FlyShape? _line1; + private FlyShape? _line2; + + private float _line1X1; + private float _line1Y1; + private float _line1X2; + private float _line1Y2; + private float _lineWidth; + + private float _line2X1; + private float _line2Y1; + private float _line2X2; + private float _line2Y2; + private float _line2Width; + + protected override string GetScriptFileName() => "LineToLine.hdvp"; + + + public GuideLineLineCtrl() + { + InitializeComponent(); + this.canvas.mouseMoved += Canvas_mouseMoved; + this.canvas.OnShapeUpdateEvent += UpdateShape; + this.canvas.selectionChanged += Canvas_selectionChanged; + + this.canvas.OnShapeMoving += Canvas_OnShapeMoving; + this.canvas.newShape += Canvas_newShape; + + this.ctrlTitleBar.OnCloseClicked += OnControlClose; + NumRectWidth1.ValueChanged -= NumRectWidth1_ValueChanged; + NumRectWidth1.Value = 40; + NumRectWidth1.ValueChanged += NumRectWidth1_ValueChanged; + + NumRectWidth2.ValueChanged -= NumericUpDown2_ValueChanged; + NumRectWidth2.Value = 40; + NumRectWidth2.ValueChanged += NumericUpDown2_ValueChanged; + + } + protected override void UpdateShape(FlyShape shape) + { + switch (shape.ShapeType) + { + case ShapeTypeEnum.Line: + // 判断是否为第一条直线或第二条直线 + if (_line1 == shape) + { + //_line1 = shape; + var pts1 = _line1.Points; + _line1X1 = pts1[0].X; + _line1Y1 = pts1[0].Y; + _line1X2 = pts1[1].X; + _line1Y2 = pts1[1].Y; + _lineWidth = _line1.LineVirtualRectWidth; + + tbLine1X1.Text = _line1X1.ToString("F3"); + tbLine1Y1.Text = _line1Y1.ToString("F3"); + tbLine1X2.Text = _line1X2.ToString("F3"); + tbLine1Y2.Text = _line1Y2.ToString("F3"); + //NumRectWidth1.Value = (decimal)_lineWidth; + } + else + { + //_line2 = shape; + var pts2 = _line2.Points; + _line2X1 = pts2[0].X; + _line2Y1 = pts2[0].Y; + _line2X2 = pts2[1].X; + _line2Y2 = pts2[1].Y; + _line2Width = _line2.LineVirtualRectWidth; + + tbLine2X1.Text = _line2X1.ToString("F3"); + tbLine2Y1.Text = _line2Y1.ToString("F3"); + tbLine2X2.Text = _line2X2.ToString("F3"); + tbLine2Y2.Text = _line2Y2.ToString("F3"); + // NumRectWidth2.Value = (decimal)_line2Width; + } + + break; + + default: + break; + } + } + + + + + + private void GuideLineCircleCtrl_Load(object sender, EventArgs e) + { + + + + } + + + + + private void Canvas_mouseMoved(PointF pos) + { + if (InvokeRequired) + { + Invoke(Canvas_mouseMoved, pos); + return; + } + + lblStatus.Text = $"X:{pos.X}, Y:{pos.Y}"; + + } + + + + + private void Canvas_selectionChanged(List shapes) + { + //if (shapes.Count != 1) + //{ + // // panelGuide.Controls.Clear(); + // return; + //} + //SwitchGuideForm(shapes[0].ShapeType); + // Canvas_OnShapeUpdateEvent(shapes[0]); + + if (shapes.Count != 1) + { + return; + } + UpdateShape(shapes[0]); + + } + + + + private void Canvas_OnShapeMoving(List shapes) + { + if (shapes.Count != 1) + { + return; + } + + UpdateShape(shapes[0]); + } + private void Canvas_newShape() + { + // 自动切换到下一条直线绘制 + if (_line1 == null) + { + _line1 = this.canvas.Shapes.LastOrDefault(shp => shp.ShapeType == ShapeTypeEnum.Line); + } + else if (_line2 == null) + { + _line2 = this.canvas.Shapes.LastOrDefault(shp => shp.ShapeType == ShapeTypeEnum.Line); + } + + // 停止绘制模式,用户可以根据需要重新启用 + this.canvas.StopDraw(); + //this.canvas.StopDraw(); + } + + private void btnCreateLineOne_Click(object sender, EventArgs e) + { + // this.canvas.Shapes.RemoveAll(shp => shp == _line1); // 移除第一条直线 + this._line1 = null; + this.canvas.Invalidate(); + this.canvas.StartDraw(ShapeTypeEnum.Line); // 启动绘制模式 + this.canvas.Enabled = true; + } + + private void btnCreateLineTwo_Click(object sender, EventArgs e) + { + // this.canvas.Shapes.RemoveAll(shp => shp == _line2); // 移除第二条直线 + this._line2 = null; + this.canvas.Invalidate(); + this.canvas.StartDraw(ShapeTypeEnum.Line); // 启动绘制模式 + this.canvas.Enabled = true; + } + + private void btnExecute_Click(object sender, EventArgs e) + { + if (this.canvas.pixmap == null) + { + MessageBox.Show("请先打开图片"); + return; + } + + this.canvas.OutsideShapes.Clear(); + this.canvas.Invalidate(); + + flag = new List(); + Distance = new List(); + Line1_RowBegin = new List(); + Line1_ColBegin = new List(); + Line1_RowEnd = new List(); + Line1_ColEnd = new List(); + Line2_RowBegin = new List(); + Line2_ColBegin = new List(); + Line2_RowEnd = new List(); + Line2_ColEnd = new List(); + Dictionary inputImg = new Dictionary(); + + if (hImage == null) + { + HOperatorSet.ReadImage(out hImage, CurrentImageFile); + } + inputImg["INPUT_Image"] = hImage; + + Dictionary inputPara = new Dictionary(); + + + // 获取矩形的 4 个点 + PointF[] Points = this._line1.LineVirtualRectPoints; + if (Points.Count() < 4) + { + return; + } + PointF Point1 = Points[0]; + PointF Point2 = Points[1]; + PointF Point3 = Points[2]; + PointF Point4 = Points[3]; + PointF Point5 = Points[0]; + + float x1 = Point1.X; + float y1 = Point1.Y; + + float x2 = Point2.X; + float y2 = Point2.Y; + + float x3 = Point3.X; + float y3 = Point3.Y; + + float x4 = Point4.X; + float y4 = Point4.Y; + + float x5 = Point5.X; + float y5 = Point5.Y; + + + float[] array1X = new float[] { x1, x2, x3, x4, x5 }; + HTuple hTupleArray1X = new HTuple(array1X); + + float[] array1Y = new float[] { y1, y2, y3, y4, y5 }; + HTuple hTupleArray1Y = new HTuple(array1Y); + + + strarray1X = string.Join(",", array1X); + strarray1Y = string.Join(",", array1Y); + + + // 获取矩形的 4 个点 + PointF[] Points2 = this._line2.LineVirtualRectPoints; + if (Points2.Count() < 4) + { + return; + } + PointF Point21 = Points2[0]; + PointF Point22 = Points2[1]; + PointF Point23 = Points2[2]; + PointF Point24 = Points2[3]; + PointF Point25 = Points2[0]; + + float x21 = Point21.X; + float y21 = Point21.Y; + + float x22 = Point22.X; + float y22 = Point22.Y; + + float x23 = Point23.X; + float y23 = Point23.Y; + + float x24 = Point24.X; + float y24 = Point24.Y; + + float x25 = Point25.X; + float y25 = Point25.Y; + + + float[] array2X = new float[] { x21, x22, x23, x24, x25 }; + HTuple hTupleArray2X = new HTuple(array2X); + + float[] array2Y = new float[] { y21, y22, y23, y24, y25 }; + HTuple hTupleArray2Y = new HTuple(array2Y); + + + strarray2X = string.Join(",", array2X); + strarray2Y = string.Join(",", array2Y); + + inputPara["Line1_LX"] = _line1X1; + inputPara["Line1_LY"] = _line1Y1; + inputPara["Line1_RX"] = _line1X2; + inputPara["Line1_RY"] = _line1Y2; + + inputPara["Line2_LX"] = _line2X1; + inputPara["Line2_LY"] = _line2Y1; + inputPara["Line2_RX"] = _line2X2; + inputPara["Line2_RY"] = _line2Y2; + + + + inputPara["Line1_XRect"] = hTupleArray1X; + inputPara["Line1_YRect"] = hTupleArray1Y; + + inputPara["Line2_XRect"] = hTupleArray2X; + inputPara["Line2_YRect"] = hTupleArray2Y; + + List outputKeys = new List() + { + "OUTPUT_Flag", + "Distance", + "Line1_RowBegin", + "Line1_ColBegin", + "Line1_RowEnd", + "Line1_ColEnd", + "Line2_RowBegin", + "Line2_ColBegin", + "Line2_RowEnd", + "Line2_ColEnd" + + }; + + ExecuteHScript( + inputImg, + inputPara, + outputKeys); + } + + + private void btnLoadImage_Click(object sender, EventArgs e) + { + OpenImageFile(bitmap => + { + this.canvas.LoadPixmap(bitmap); + this.canvas.Enabled = true; + _line1 = new FlyShape(); + _line2 = new FlyShape(); + _line1.AddPoint(new Point(10, 10)); + _line1.AddPoint(new Point(50, 10)); + _line2.AddPoint(new Point(10, 20)); + _line2.AddPoint(new Point(60, 20)); + _line1.ShapeType = ShapeTypeEnum.Line; + _line2.ShapeType = ShapeTypeEnum.Line; + + _line1.IsDrawLineVirtualRect = true; + _line1.LineVirtualRectWidth = 40; + _line2.IsDrawLineVirtualRect = true; + _line2.LineVirtualRectWidth = 40; + + canvas.Shapes.Add(_line1); + canvas.Shapes.Add(_line2); + canvas.Invalidate(); + + UpdateShape(_line1); + UpdateShape(_line2); + }); + } + string strarray1X = string.Empty; + string strarray1Y = string.Empty; + string strarray2X = string.Empty; + string strarray2Y = string.Empty; + List flag =new List(); + List Distance = new List(); + List Line1_RowBegin = new List(); + List Line1_ColBegin = new List(); + List Line1_RowEnd = new List(); + List Line1_ColEnd = new List(); + List Line2_RowBegin = new List(); + List Line2_ColBegin = new List(); + List Line2_RowEnd = new List(); + List Line2_ColEnd = new List(); + protected override void OnExecuteHScriptResult( + bool success, + Dictionary resultDic, + int timeElasped) + { + if (!success) + { + return; + } + + //"OUTPUT_Flag", + // "Distance", + // "Line1_RowBegin", + // "Line1_ColBegin", + // "Line1_RowEnd", + // "Line1_ColEnd", + // "Line2_RowBegin", + // "Line2_ColBegin", + // "Line2_RowEnd", + // "Line2_ColEnd" + + + flag = resultDic["OUTPUT_Flag"].HTupleToDouble(); + Distance = resultDic["Distance"].HTupleToDouble(); + Line1_RowBegin = resultDic["Line1_RowBegin"].HTupleToDouble(); + Line1_ColBegin = resultDic["Line1_ColBegin"].HTupleToDouble(); + Line1_RowEnd = resultDic["Line1_RowEnd"].HTupleToDouble(); + Line1_ColEnd = resultDic["Line1_ColEnd"].HTupleToDouble(); + Line2_RowBegin = resultDic["Line2_RowBegin"].HTupleToDouble(); + Line2_ColBegin = resultDic["Line2_ColBegin"].HTupleToDouble(); + Line2_RowEnd = resultDic["Line2_RowEnd"].HTupleToDouble(); + Line2_ColEnd = resultDic["Line2_ColEnd"].HTupleToDouble(); + + if (flag.Count > 0) + { + lblResult.Text = flag[0].ToString(); + + } + else + { + lblResult.Text = "无"; + } + if (Distance.Count > 0) + { + lblDistance.Text = Distance[0].ToString(); + } + else + { + lblDistance.Text = "0"; + } + + if (flag.Count > 0 && Distance.Count > 0 && Line1_RowBegin.Count > 0 && Line1_ColBegin.Count > 0 && Line1_RowEnd.Count > 0 && Line1_ColEnd.Count > 0 && Line2_RowBegin.Count > 0 && Line2_ColBegin.Count > 0 && Line2_RowEnd.Count > 0 && Line2_ColEnd.Count > 0) + { + float width = 0; + this.canvas.DrawLine(new PointF((float)Line1_ColBegin[0], (float)Line1_RowBegin[0]), new PointF((float)Line1_ColEnd[0], (float)Line1_RowEnd[0]), width); + this.canvas.DrawLine(new PointF((float)Line2_ColBegin[0], (float)Line2_RowBegin[0]), new PointF((float)Line2_ColEnd[0], (float)Line2_RowEnd[0]), width); + this.canvas.Invalidate(); + lblElapsed.Text = $"{timeElasped} ms"; + } + } + + private void NumRectWidth1_ValueChanged(object sender, EventArgs e) + { + if (_line1 != null) + { + //_line1.IsDrawLineVirtualRect = true; + _line1.LineVirtualRectWidth = (float)NumRectWidth1.Value; + UpdateShape(_line1); + this.canvas.Invalidate(); + } + } + + private void NumericUpDown2_ValueChanged(object sender, EventArgs e) + { + if (_line2 != null) + { + // _line2.IsDrawLineVirtualRect = true; + _line2.LineVirtualRectWidth = (float)NumRectWidth2.Value; + UpdateShape(_line2); + this.canvas.Invalidate(); + } + } + + private void btnSave_Click(object sender, EventArgs e) + { + if (lblResult.Text.Equals("无")) + { + MessageBox.Show("请先进行绘制"); + return; + } + if (lblResult.Text != "0") + { + MessageBox.Show("测量计算错误,无法保存"); + return; + } + + + + //inputPara["Line1_LX"] = _line1X1; + //inputPara["Line1_LY"] = _line1Y1; + //inputPara["Line1_RX"] = _line1X2; + //inputPara["Line1_RY"] = _line1Y2; + + //inputPara["Line2_LX"] = _line2X1; + //inputPara["Line2_LY"] = _line2Y1; + //inputPara["Line2_RX"] = _line2X2; + //inputPara["Line2_RY"] = _line2Y2; + + + + //inputPara["Line1_XRect"] = hTupleArray1X; + //inputPara["Line1_YRect"] = hTupleArray1Y; + + //inputPara["Line2_XRect"] = hTupleArray2X; + //inputPara["Line2_YRect"] = hTupleArray2Y; + + + string input = $"Line1_LX:{_line1X1};" + + $"Line1_LY:{_line1Y1};" + + $"Line1_RX:{_line1X2};" + + $"Line1_RY:{_line1Y2};" + + $"Line2_LX:{_line2X1};" + + $"Line2_LY:{_line2Y1};" + + $"Line2_RX:{_line2X2};" + + $"Line2_RY:{_line2Y2};" + + $"Line1_XRect:{strarray1X};" + + $"Line1_YRect:{strarray1Y};" + + $"Line2_XRect:{strarray2X};" + + $"Line2_YRect:{strarray2Y}" + ; + + + string result = $"Distance:{Distance[0]}"; + + + DataToTriggerEvent(input, result); + + } + } +} diff --git a/CanFly/UI/GuidePanel/GuideLineLineCtrl.resx b/CanFly/UI/GuidePanel/GuideLineLineCtrl.resx new file mode 100644 index 0000000..097e294 --- /dev/null +++ b/CanFly/UI/GuidePanel/GuideLineLineCtrl.resx @@ -0,0 +1,145 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + AAEAAAD/////AQAAAAAAAAAMAgAAAERDYW5GbHkuQ2FudmFzLCBWZXJzaW9uPTEuMC4wLjAsIEN1bHR1 + cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49bnVsbAQBAAAAdlN5c3RlbS5Db2xsZWN0aW9ucy5HZW5l + cmljLkxpc3RgMVtbQ2FuRmx5LkNhbnZhcy5TaGFwZS5GbHlTaGFwZSwgQ2FuRmx5LkNhbnZhcywgQ3Vs + dHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1udWxsXV0DAAAABl9pdGVtcwVfc2l6ZQhfdmVyc2lv + bgQAAB5DYW5GbHkuQ2FudmFzLlNoYXBlLkZseVNoYXBlW10CAAAACAgJAwAAAAAAAAAAAAAADAQAAAAz + Q2FuRmx5LkNhbnZhcywgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1udWxsBwMAAAAAAQAA + AAAAAAAEHENhbkZseS5DYW52YXMuU2hhcGUuRmx5U2hhcGUEAAAACw== + + + + + AAEAAAD/////AQAAAAAAAAAMAgAAAERDYW5GbHkuQ2FudmFzLCBWZXJzaW9uPTEuMC4wLjAsIEN1bHR1 + cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49bnVsbAQBAAAAdlN5c3RlbS5Db2xsZWN0aW9ucy5HZW5l + cmljLkxpc3RgMVtbQ2FuRmx5LkNhbnZhcy5TaGFwZS5GbHlTaGFwZSwgQ2FuRmx5LkNhbnZhcywgQ3Vs + dHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1udWxsXV0DAAAABl9pdGVtcwVfc2l6ZQhfdmVyc2lv + bgQAAB5DYW5GbHkuQ2FudmFzLlNoYXBlLkZseVNoYXBlW10CAAAACAgJAwAAAAAAAAAAAAAADAQAAAAz + Q2FuRmx5LkNhbnZhcywgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1udWxsBwMAAAAAAQAA + AAAAAAAEHENhbkZseS5DYW52YXMuU2hhcGUuRmx5U2hhcGUEAAAACw== + + + + 17, 17 + + \ No newline at end of file diff --git a/CanFly/Util/FormUtils.cs b/CanFly/Util/FormUtils.cs new file mode 100644 index 0000000..c76bada --- /dev/null +++ b/CanFly/Util/FormUtils.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace CanFly.Util +{ + public static class FormUtils + { + + /// + /// 显示窗体 + /// + /// + /// + public static void ShowForm(this Panel panel, Form frm) + { + + try + { + frm.TopLevel = false; + panel.Controls.Clear(); + panel.Controls.Add(frm); + frm.Show(); + frm.Dock = DockStyle.Fill; + panel.Refresh(); + foreach (Control item in frm.Controls) + { + item.Focus(); + break; + } + } + catch (Exception ex) + { + throw ex; + } + + } + } +} diff --git a/CanFly/XKRS.CanFly.csproj b/CanFly/XKRS.CanFly.csproj new file mode 100644 index 0000000..bcae58e --- /dev/null +++ b/CanFly/XKRS.CanFly.csproj @@ -0,0 +1,61 @@ + + + + net8.0-windows + enable + enable + ..\ + output + true + true + AnyCPU;x64 + + + + + + + + + + + + + + + + + + + + + + + + + + + + ..\x64\Debug\halcondotnet.dll + + + ..\x64\Debug\hdevenginedotnet.dll + + + + + + True + True + Resources.resx + + + + + + ResXFileCodeGenerator + Resources.Designer.cs + + + + \ No newline at end of file diff --git a/DH.Commons/DetectionConfig.cs b/DH.Commons/DetectionConfig.cs index 5afce01..30cbe8f 100644 --- a/DH.Commons/DetectionConfig.cs +++ b/DH.Commons/DetectionConfig.cs @@ -6,6 +6,7 @@ using System.Text.RegularExpressions; using System.Text; using System.Drawing.Design; using AntdUI; +using static DH.Commons.Enums.EnumHelper; namespace DH.Commons.Enums @@ -736,6 +737,7 @@ namespace DH.Commons.Enums } + public string LabelId { get { return _labelId; } @@ -826,7 +828,125 @@ namespace DH.Commons.Enums } } + public class SizeTreatParam : NotifyProperty + { + private bool _selected = false; + + private bool _isEnable; + private string _preName; + private int _prePix; + + private SizeEnum _preType; + private string _resultShow; + private string _outResultShow; + + + private string _prePath; + + + public bool Selected + { + get { return _selected; } + set + { + if (_selected == value) return; + _selected = value; + OnPropertyChanged(nameof(Selected)); + } + } + + public bool IsEnable + { + get { return _isEnable; } + set + { + if (_isEnable == value) return; + _isEnable = value; + OnPropertyChanged(nameof(IsEnable)); + } + } + + public string PreName + { + get { return _preName; } + set + { + if (_preName == value) return; + _preName = value; + OnPropertyChanged(nameof(PreName)); + } + } + + public SizeEnum PreType + { + get { return _preType; } + set + { + if (_preType == value) return; + _preType = value; + OnPropertyChanged(nameof(PreType)); + } + } + + public int PrePix + { + get { return _prePix; } + set + { + if (_prePix.Equals(value)) return; + _prePix = value; + OnPropertyChanged(nameof(PrePix)); + } + } + + public string ResultShow + { + get { return _resultShow; } + set + { + if (_resultShow == value) return; + _resultShow = value; + OnPropertyChanged(nameof(ResultShow)); + } + + } + + public string OutResultShow + { + get { return _outResultShow; } + set + { + if (_outResultShow == value) return; + _outResultShow = value; + OnPropertyChanged(nameof(OutResultShow)); + } + } + + public string PrePath + { + get { return _prePath; } + set + { + if (_prePath.Equals(value)) return; + _prePath = value; + OnPropertyChanged(nameof(PrePath)); + } + } + + + private CellLink[] cellLinks; + public CellLink[] CellLinks + { + get { return cellLinks; } + set + { + if (cellLinks == value) return; + cellLinks = value; + OnPropertyChanged(nameof(CellLinks)); + } + } + } /// /// 识别目标定义 class:分类信息 Detection Segmentation:要识别的对象 /// diff --git a/DH.Commons/Helper/EnumHelper.cs b/DH.Commons/Helper/EnumHelper.cs index 32cc533..4883448 100644 --- a/DH.Commons/Helper/EnumHelper.cs +++ b/DH.Commons/Helper/EnumHelper.cs @@ -650,15 +650,15 @@ namespace DH.Commons.Enums public enum SizeEnum { [Description("圆形测量")] - Circle = 1, + 圆形测量 = 1, [Description("直线测量")] - Line = 2, + 直线测量 = 2, [Description("线线测量")] - LineLine = 3, + 线线测量 = 3, [Description("线圆测量")] - LineCircle = 4, + 线圆测量 = 4, [Description("高度测量")] - Height = 5, + 高度测量 = 5, } public enum MachineState diff --git a/DHSoftware.sln b/DHSoftware.sln index a4155f0..00408cf 100644 --- a/DHSoftware.sln +++ b/DHSoftware.sln @@ -33,6 +33,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DH.UI.Model.Winform", "DH.U EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DH.Devices.Vision", "DH.Devices.Vision\DH.Devices.Vision.csproj", "{5AD3A29E-149A-4C37-9548-7638A36C8175}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Size", "Size", "{048B30B5-D075-4CE0-BF9F-CB6152E6D376}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "XKRS.CanFly", "CanFly\XKRS.CanFly.csproj", "{1FB768DB-843E-4C67-96B9-7684CF890D89}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CanFly.Canvas", "CanFly.Canvas\CanFly.Canvas.csproj", "{EA7E228B-DB5C-4BF1-832B-D51B7F7D5F35}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -105,6 +111,22 @@ Global {5AD3A29E-149A-4C37-9548-7638A36C8175}.Release|Any CPU.Build.0 = Release|Any CPU {5AD3A29E-149A-4C37-9548-7638A36C8175}.Release|x64.ActiveCfg = Release|x64 {5AD3A29E-149A-4C37-9548-7638A36C8175}.Release|x64.Build.0 = Release|x64 + {1FB768DB-843E-4C67-96B9-7684CF890D89}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1FB768DB-843E-4C67-96B9-7684CF890D89}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1FB768DB-843E-4C67-96B9-7684CF890D89}.Debug|x64.ActiveCfg = Debug|x64 + {1FB768DB-843E-4C67-96B9-7684CF890D89}.Debug|x64.Build.0 = Debug|x64 + {1FB768DB-843E-4C67-96B9-7684CF890D89}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1FB768DB-843E-4C67-96B9-7684CF890D89}.Release|Any CPU.Build.0 = Release|Any CPU + {1FB768DB-843E-4C67-96B9-7684CF890D89}.Release|x64.ActiveCfg = Release|x64 + {1FB768DB-843E-4C67-96B9-7684CF890D89}.Release|x64.Build.0 = Release|x64 + {EA7E228B-DB5C-4BF1-832B-D51B7F7D5F35}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EA7E228B-DB5C-4BF1-832B-D51B7F7D5F35}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EA7E228B-DB5C-4BF1-832B-D51B7F7D5F35}.Debug|x64.ActiveCfg = Debug|x64 + {EA7E228B-DB5C-4BF1-832B-D51B7F7D5F35}.Debug|x64.Build.0 = Debug|x64 + {EA7E228B-DB5C-4BF1-832B-D51B7F7D5F35}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EA7E228B-DB5C-4BF1-832B-D51B7F7D5F35}.Release|Any CPU.Build.0 = Release|Any CPU + {EA7E228B-DB5C-4BF1-832B-D51B7F7D5F35}.Release|x64.ActiveCfg = Release|x64 + {EA7E228B-DB5C-4BF1-832B-D51B7F7D5F35}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -121,6 +143,8 @@ Global {A33108B6-2740-4D28-AD22-B280372980BE} = {0AB4BB9A-A861-4F80-B549-CD331490942B} {12CB9041-B1B1-41AE-B308-AABDACAA580E} = {3EAF3D9C-D3F9-4B6E-89DE-58F129CD1F4C} {5AD3A29E-149A-4C37-9548-7638A36C8175} = {F77AF94C-280D-44C5-B7C0-FC86AA9EC504} + {1FB768DB-843E-4C67-96B9-7684CF890D89} = {048B30B5-D075-4CE0-BF9F-CB6152E6D376} + {EA7E228B-DB5C-4BF1-832B-D51B7F7D5F35} = {048B30B5-D075-4CE0-BF9F-CB6152E6D376} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {6FC1A8DF-636E-434C-981E-10F20FAD723B} diff --git a/DHSoftware/DHSoftware.csproj b/DHSoftware/DHSoftware.csproj index 9e0432f..b04a06c 100644 --- a/DHSoftware/DHSoftware.csproj +++ b/DHSoftware/DHSoftware.csproj @@ -11,6 +11,8 @@ AnyCPU;x64 WinExe + + @@ -38,6 +40,7 @@ + diff --git a/DHSoftware/MainWindow.cs b/DHSoftware/MainWindow.cs index 92a919d..cf6233b 100644 --- a/DHSoftware/MainWindow.cs +++ b/DHSoftware/MainWindow.cs @@ -1020,9 +1020,10 @@ namespace DHSoftware listCamBase.Add(cam1); listCamBase.Add(cam2); - SettingWindow s = new SettingWindow(); - s.cameras = listCamBase; - s.Show(); + SettingWindow1 settingWindow = new SettingWindow1(); + settingWindow.Show(); + //s.cameras = listCamBase; + //s.Show(); } diff --git a/DHSoftware/Views/DetectControl.Designer.cs b/DHSoftware/Views/DetectControl.Designer.cs index 9d4d2f3..8dd5cd4 100644 --- a/DHSoftware/Views/DetectControl.Designer.cs +++ b/DHSoftware/Views/DetectControl.Designer.cs @@ -74,9 +74,18 @@ iptPath2 = new AntdUI.Input(); label8 = new AntdUI.Label(); tabPage3 = new AntdUI.TabPage(); + tabPage4 = new AntdUI.TabPage(); + switch8 = new AntdUI.Switch(); + btnSizeDel = new AntdUI.Button(); + btnSizeAdd = new AntdUI.Button(); + SizeTable = new AntdUI.Table(); + label17 = new AntdUI.Label(); + label18 = new AntdUI.Label(); tabs1.SuspendLayout(); tabPage1.SuspendLayout(); tabPage2.SuspendLayout(); + tabPage3.SuspendLayout(); + tabPage4.SuspendLayout(); SuspendLayout(); // // tabs1 @@ -89,10 +98,10 @@ tabs1.Pages.Add(tabPage1); tabs1.Pages.Add(tabPage2); tabs1.Pages.Add(tabPage3); - tabs1.SelectedIndex = 1; + tabs1.SelectedIndex = 2; tabs1.Size = new Size(915, 609); tabs1.Style = styleLine1; - tabs1.TabIndex = 2; + tabs1.TabIndex = 1; tabs1.Text = "tabs1"; // // tabPage1 @@ -110,9 +119,9 @@ tabPage1.Controls.Add(label2); tabPage1.Controls.Add(iptPath); tabPage1.Controls.Add(label1); - tabPage1.Location = new Point(-822, -575); + tabPage1.Location = new Point(-909, -575); tabPage1.Name = "tabPage1"; - tabPage1.Size = new Size(822, 575); + tabPage1.Size = new Size(909, 575); tabPage1.TabIndex = 0; tabPage1.Text = "预处理"; // @@ -276,11 +285,12 @@ tabPage2.Controls.Add(label7); tabPage2.Controls.Add(iptPath2); tabPage2.Controls.Add(label8); - tabPage2.Location = new Point(3, 31); + tabPage2.Location = new Point(-909, -575); tabPage2.Name = "tabPage2"; tabPage2.Size = new Size(909, 575); tabPage2.TabIndex = 1; tabPage2.Text = "模型检测"; + tabPage2.Click += tabPage2_Click; // // btnLableDelete // @@ -538,12 +548,86 @@ // // tabPage3 // - tabPage3.Location = new Point(0, 0); + tabPage3.Controls.Add(tabPage4); + tabPage3.Location = new Point(3, 31); tabPage3.Name = "tabPage3"; - tabPage3.Size = new Size(0, 0); - tabPage3.TabIndex = 2; + tabPage3.Size = new Size(909, 575); + tabPage3.TabIndex = 3; tabPage3.Text = "尺寸测量"; // + // tabPage4 + // + tabPage4.Controls.Add(switch8); + tabPage4.Controls.Add(btnSizeDel); + tabPage4.Controls.Add(btnSizeAdd); + tabPage4.Controls.Add(SizeTable); + tabPage4.Controls.Add(label17); + tabPage4.Controls.Add(label18); + tabPage4.Location = new Point(8, 8); + tabPage4.Name = "tabPage4"; + tabPage4.Size = new Size(909, 575); + tabPage4.TabIndex = 1; + tabPage4.Text = "预处理"; + // + // switch8 + // + switch8.CheckedText = "启用"; + switch8.Location = new Point(120, 33); + switch8.Name = "switch8"; + switch8.Size = new Size(82, 33); + switch8.TabIndex = 11; + switch8.UnCheckedText = "关闭"; + // + // btnSizeDel + // + btnSizeDel.BorderWidth = 2F; + btnSizeDel.Font = new Font("Microsoft YaHei UI", 9F, FontStyle.Regular, GraphicsUnit.Point, 134); + btnSizeDel.Ghost = true; + btnSizeDel.IconRatio = 0.8F; + btnSizeDel.IconSvg = resources.GetString("btnSizeDel.IconSvg"); + btnSizeDel.Location = new Point(747, 192); + btnSizeDel.Name = "btnSizeDel"; + btnSizeDel.Size = new Size(80, 38); + btnSizeDel.TabIndex = 10; + btnSizeDel.Text = "删除"; + // + // btnSizeAdd + // + btnSizeAdd.BorderWidth = 2F; + btnSizeAdd.Font = new Font("Microsoft YaHei UI", 9F, FontStyle.Regular, GraphicsUnit.Point, 134); + btnSizeAdd.Ghost = true; + btnSizeAdd.IconRatio = 0.8F; + btnSizeAdd.IconSvg = resources.GetString("btnSizeAdd.IconSvg"); + btnSizeAdd.Location = new Point(747, 148); + btnSizeAdd.Name = "btnSizeAdd"; + btnSizeAdd.Size = new Size(80, 38); + btnSizeAdd.TabIndex = 9; + btnSizeAdd.Text = "新增"; + // + // SizeTable + // + SizeTable.Location = new Point(38, 118); + SizeTable.Name = "SizeTable"; + SizeTable.Size = new Size(686, 402); + SizeTable.TabIndex = 8; + SizeTable.Text = "table1"; + // + // label17 + // + label17.Location = new Point(38, 89); + label17.Name = "label17"; + label17.Size = new Size(91, 23); + label17.TabIndex = 1; + label17.Text = "配 置"; + // + // label18 + // + label18.Location = new Point(38, 43); + label18.Name = "label18"; + label18.Size = new Size(91, 23); + label18.TabIndex = 3; + label18.Text = "状 态"; + // // DetectControl // AutoScaleDimensions = new SizeF(7F, 17F); @@ -554,6 +638,8 @@ tabs1.ResumeLayout(false); tabPage1.ResumeLayout(false); tabPage2.ResumeLayout(false); + tabPage3.ResumeLayout(false); + tabPage4.ResumeLayout(false); ResumeLayout(false); } @@ -603,5 +689,12 @@ private AntdUI.Table lableTable; private AntdUI.Button btnLableAdd; private AntdUI.Button btnLableDelete; + private AntdUI.TabPage tabPage4; + private AntdUI.Button btnSizeDel; + private AntdUI.Button btnSizeAdd; + private AntdUI.Table SizeTable; + private AntdUI.Label label17; + private AntdUI.Label label18; + private AntdUI.Switch switch8; } } diff --git a/DHSoftware/Views/DetectControl.cs b/DHSoftware/Views/DetectControl.cs index fbc6dcb..7f0e54c 100644 --- a/DHSoftware/Views/DetectControl.cs +++ b/DHSoftware/Views/DetectControl.cs @@ -12,6 +12,9 @@ using System.Xml.Linq; using AntdUI; using DH.Commons.Enums; using DH.Devices.Vision; +using XKRS.CanFly; +using static AntdUI.Table; +using static DH.Commons.Enums.EnumHelper; namespace DHSoftware.Views { @@ -20,7 +23,7 @@ namespace DHSoftware.Views Window window; public DetectControl(Window _window) { - window= _window; + window = _window; InitializeComponent(); //初始化表格列头 InitTableColumns(); @@ -48,6 +51,10 @@ namespace DHSoftware.Views btnLableDelete.Click += BtnLableDelete_Click; lableTable.CellButtonClick += LableTable_CellButtonClick; + btnSizeAdd.Click += BtnSizeAdd_Click; + btnSizeDel.Click += BtnSizeDelete_Click; + SizeTable.CellButtonClick += SizeTable_CellButtonClick; + } private void LableTable_CellButtonClick(object sender, TableButtonEventArgs e) @@ -84,6 +91,75 @@ namespace DHSoftware.Views } } + + private void SizeTable_CellButtonClick(object sender, TableButtonEventArgs e) + { + var buttontext = e.Btn.Text; + + if (e.Record is SizeTreatParam sizeTreat) + { + SizeParamLable = sizeTreat; + switch (buttontext) + { + //暂不支持进入整行编辑,只支持指定单元格编辑,推荐使用弹窗或抽屉编辑整行数据 + case "编辑": + var form = new SizeLabelEdit(window, SizeParamLable) { Size = new Size(500, 300) }; + AntdUI.Drawer.open(new AntdUI.Drawer.Config(window, form) + { + OnLoad = () => + { + AntdUI.Message.info(window, "进入编辑", autoClose: 1); + }, + OnClose = () => + { + AntdUI.Message.info(window, "结束编辑", autoClose: 1); + } + }); + break; + case "删除": + var result = Modal.open(window, "删除警告!", "确认要删除选择的数据吗?", TType.Warn); + if (result == DialogResult.OK) + SizeLableList.Remove(sizeTreat); + break; + case "进行测量": + var sizeType = ((int)SizeParamLable.PreType).ToString(); + + // 根据测量类型打开不同的窗口 + switch (sizeType) + { + case "1": + case "2": + case "3": + case "4": + case "5": + FrmMain3 frmMain3 = new FrmMain3(sizeType); + frmMain3.ShowDialog(); + if (!string.IsNullOrEmpty(frmMain3.inputtext)) + { + + sizeTreat.ResultShow = frmMain3.inputtext; + } + if (!string.IsNullOrEmpty(frmMain3.outtext)) + { + + + sizeTreat.OutResultShow = frmMain3.outtext; + } + break; + default: + MessageBox.Show("未定义的测量类型!"); + break; + } + + //使用clone可以防止table中的image被修改 + //Preview.open(new Preview.Config(window, (Image)SizeParamLable.CellImages[0].Image.Clone())); + break; + + } + } + } + + private void BtnLableDelete_Click(object? sender, EventArgs e) { if (DetectionLableList.Count == 0 || !DetectionLableList.Any(x => x.Selected)) @@ -111,7 +187,7 @@ namespace DHSoftware.Views private void BtnLableAdd_Click(object? sender, EventArgs e) { - DetectionLable detectionLable = new DetectionLable() + DetectionLable detectionLable = new DetectionLable() { CellLinks = new CellLink[] { new CellButton(Guid.NewGuid().ToString(),"编辑",TTypeMini.Primary), @@ -129,15 +205,65 @@ namespace DHSoftware.Views } } + private void BtnSizeDelete_Click(object? sender, EventArgs e) + { + if (SizeLableList.Count == 0 || !SizeLableList.Any(x => x.Selected)) + { + AntdUI.Message.warn(window, "请选择要删除的行!", autoClose: 3); + return; + } + + var result = Modal.open(window, "删除警告!", "确认要删除选择的数据吗?", TType.Warn); + if (result == DialogResult.OK) + { + // 使用反转for循环删除主列表中选中的项 + for (int i = SizeLableList.Count - 1; i >= 0; i--) + { + // 删除选中的主列表项 + if (SizeLableList[i].Selected) + { + SizeLableList.RemoveAt(i); + } + } + // 提示删除完成 + AntdUI.Message.success(window, "删除成功!", autoClose: 3); + } + } + + private void BtnSizeAdd_Click(object? sender, EventArgs e) + { + SizeTreatParam SizeParamLable = new SizeTreatParam() + { + //CellBadge = new CellBadge(SizeEnum.Circle.GetEnumDescription()), + CellLinks = new CellLink[] { + new CellButton(Guid.NewGuid().ToString(),"编辑",TTypeMini.Primary), + + new CellButton(Guid.NewGuid().ToString(),"删除",TTypeMini.Error), + new CellButton(Guid.NewGuid().ToString(),"进行测量",TTypeMini.Primary) + } + + + }; + var form = new SizeLabelEdit(window, SizeParamLable) { Size = new Size(450, 500) }; + AntdUI.Modal.open(new AntdUI.Modal.Config(window, "", form, TType.None) + { + BtnHeight = 0, + }); + if (form.submit) + { + SizeLableList.Add(SizeParamLable); + } + } + private void BtnPic_Click(object? sender, EventArgs e) { - + } List relatedCameras = new List(); private void BtnCorrelatedCamera_Click(object? sender, EventArgs e) { - + var form = new CorrelatedCameraEdit(window, relatedCameras) { Size = new Size(500, 400) }; @@ -179,8 +305,8 @@ namespace DHSoftware.Views control.BringToFront(); } } - } - } + } + } private bool Control_CloseChanged(object sender, EventArgs e) { @@ -272,6 +398,7 @@ namespace DHSoftware.Views { PreTreatParam preParam = new PreTreatParam() { + CellLinks = new CellLink[] { new CellButton(Guid.NewGuid().ToString(),"编辑",TTypeMini.Primary), new CellButton(Guid.NewGuid().ToString(),"删除",TTypeMini.Error), @@ -317,7 +444,7 @@ namespace DHSoftware.Views if (result == DialogResult.OK) PreTreatList.Remove(PreTreat); break; - + } } } @@ -325,15 +452,15 @@ namespace DHSoftware.Views private void PreTable_CellClick(object sender, TableClickEventArgs e) { } - - + + private void BtnPreDelete_Click(object? sender, EventArgs e) { if (PreTreatList.Count == 0 || !PreTreatList.Any(x => x.Selected)) { - AntdUI.Message.warn(window, "请选择要删除的行!", autoClose: 3); - return; + AntdUI.Message.warn(window, "请选择要删除的行!", autoClose: 3); + return; } var result = Modal.open(window, "删除警告!", "确认要删除选择的数据吗?", TType.Warn); @@ -376,9 +503,11 @@ namespace DHSoftware.Views AntList PreTreatList; AntList PreOutTreatList; AntList DetectionLableList; + AntList SizeLableList; PreTreatParam curPreTreat; PreTreatParam curPreOutTreat; DetectionLable curDetectionLable; + SizeTreatParam SizeParamLable; private void InitData() { PreTreatList = new AntList(); @@ -389,17 +518,20 @@ namespace DHSoftware.Views PreOutTable.Binding(PreOutTreatList); - + foreach (var item in MLModelTypes) { stDetectType.Items.Add(item.Key); } - DetectionLableList =new AntList(); + DetectionLableList = new AntList(); lableTable.Binding(DetectionLableList); + SizeLableList = new AntList(); + SizeTable.Binding(SizeLableList); + } private void InitTableColumns() @@ -429,6 +561,17 @@ namespace DHSoftware.Views new Column("ResultState", "结果", ColumnAlign.Center), new Column("CellLinks", "操作", ColumnAlign.Center) }; + + SizeTable.Columns = new ColumnCollection() { + new ColumnCheck("Selected"){Fixed = true}, + new ColumnSwitch("IsEnable", "是否启用", ColumnAlign.Center), + new Column("PreName", "测量名称",ColumnAlign.Center), + new Column("PreType", "测量类型", ColumnAlign.Center), + new Column("PrePix", "阈值", ColumnAlign.Center), + new Column("ResultShow", "输入参数", ColumnAlign.Center), + new Column("OutResultShow", "输出参数", ColumnAlign.Center), + new Column("CellLinks", "操作", ColumnAlign.Center) + }; } private void btnPath_Click(object? sender, EventArgs e) @@ -446,18 +589,24 @@ namespace DHSoftware.Views if (openFileDialog.ShowDialog() == DialogResult.OK) { string filePath = openFileDialog.FileName; - + iptPath.Text = filePath; - + } } } - + List> MLModelTypes = GetFilteredEnumDescriptionsAndValues(); + List> SizeEnum = GetFilteredEnumDescriptionsAndValues(); + + private void tabPage2_Click(object sender, EventArgs e) + { + + } public static List> GetFilteredEnumDescriptionsAndValues() where T : Enum { diff --git a/DHSoftware/Views/DetectControl.resx b/DHSoftware/Views/DetectControl.resx index 8dd9521..a0dc3a8 100644 --- a/DHSoftware/Views/DetectControl.resx +++ b/DHSoftware/Views/DetectControl.resx @@ -1,7 +1,7 @@  + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file