123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418 |
- using System;
- using System.Collections.Generic;
- //using System.Drawing;
- using System.Linq;
- using System.Text;
- using System.Threading.Tasks;
- using System.Windows;
- using System.Windows.Controls;
- using System.Windows.Media;
- using System.Windows.Shapes;
- namespace MeterVision.Mark
- {
- //水表图片标注管理
- public class MarkManager
- {
- private readonly Brush[] _brushes = new Brush[] { Brushes.Red, Brushes.Orange, Brushes.Yellow, Brushes.Green };
- //画布
- private Canvas _canvas;
- //最多4个点
- private List<Point> _points;
- //用来保存已绘制的图像
- private List<UIElement> _drawShapes;
- //要求的画点数(只有2、3、4三种情况)
- //1. 2个点取指针表第一个指针与最后一个指针的直线
- //2. 3个点取数字区域的选取
- //3. 4个点表盘区域的选取
- public int PointCount { get; private set; }
- //public int _curPointCount = 0;
- public bool IsMarking { get; private set; } //正在标注标记
- //标注完成事件
- public event Action<int, List<Point>, int> FinishMark;
- public event Action<string> MarkError;
- //记录临时直线图像
- private Point lastFixedPoint; //上一个按下的点
- private Line tempLine; //临时线
- private bool isFirstClick = true;
- public MarkManager(Canvas canvas)
- {
- _canvas = canvas;
- _points = new List<Point>();
- _drawShapes = new List<UIElement>();
- PointCount = 0;
- IsMarking = false;
- }
- //开始标注
- public void ReadyMark(int pointCount)
- {
- //删除所有绘制的形状,不能删除表盘图像
- foreach (var shape in _drawShapes)
- {
- _canvas.Children.Remove(shape);
- }
- _drawShapes.Clear();
- _points.Clear();
- PointCount = pointCount;
- IsMarking = true;
- //_curPointCount = 0;
- InitDrawTempLine(pointCount);
- }
- //删除临时线
- private void InitDrawTempLine(int pointCount)
- {
- isFirstClick = pointCount == 3 ? true : false;
- }
- //清除标注
- public void ClearMark()
- {
- ReadyMark(PointCount);
- //IsMarking = false;
- }
- public void InitMark()
- {
- ReadyMark(0);
- IsMarking = false;
- }
- public void StopMark()
- {
- IsMarking = false;
- }
- private void AddPoint(Point point)
- {
- int index = _points.Count;
- // 绘制点击点
- Ellipse pointEllipse = new Ellipse
- {
- Width = 5,
- Height = 5,
- Fill = _brushes[index]
- };
- Canvas.SetLeft(pointEllipse, point.X - 2.5); // 调整点的中心位置
- Canvas.SetTop(pointEllipse, point.Y - 2.5);
- _canvas.Children.Add(pointEllipse);
- _drawShapes.Add(pointEllipse);
- _points.Add(point);
- }
- //更新指定位置的点坐标及标注
- private void UpdatePoint(Point point, int position)
- {
- int index = _canvas.Children.IndexOf(_drawShapes[position - 1]);
- _canvas.Children.RemoveAt(index);
- Ellipse pointEllipse = new Ellipse
- {
- Width = 5,
- Height = 5,
- Fill = _brushes[position - 1]
- };
- Canvas.SetLeft(pointEllipse, point.X - 2.5); // 调整点的中心位置
- Canvas.SetTop(pointEllipse, point.Y - 2.5);
- _canvas.Children.Insert(index, pointEllipse);
- _drawShapes.RemoveAt(position - 1);
- _drawShapes.Insert(position - 1, pointEllipse);
- _points.RemoveAt(position - 1);
- _points.Insert(position - 1, point);
- }
- //点标注
- public void PointMark(Point point)
- {
- if (IsMarking && _points.Count < PointCount)
- {
- AddPoint(point);
- if (_points.Count == PointCount)
- {
- if (PointCount == 4)
- {
- //四点标表盘
- FourPoint_DrawRectangle();
- }
- else if (PointCount == 3)
- {
- //三点画矩形
- //删除画布中的直线元素(因为是临时的)
- for(int i= _canvas.Children.Count-1; i>=0;i--)
- {
- UIElement element = _canvas.Children[i];
- if (element is Line)
- {
- _canvas.Children.Remove(element);
- }
- }
- ThreePoint_DrawRectangle();
- }
- else if (PointCount == 2)
- {
- TwoPoint_DrawLine();
- }
- }//if _points.Count == PointCount
- else if(PointCount == 3 && _points.Count < PointCount)
- {
- if (isFirstClick)
- {
- //第一次电子,记录起点
- lastFixedPoint = point;
- isFirstClick = false;
- }
- else
- {
- //固定上一条线
- Line fixedLine = new Line
- {
- X1 = lastFixedPoint.X,
- Y1 = lastFixedPoint.Y,
- X2 = point.X,
- Y2 = point.Y,
- Stroke = Brushes.Red,
- StrokeThickness = 2
- };
- _canvas.Children.Add(fixedLine);
- //更新固定点
- lastFixedPoint = point;
- }
- //创建新的临时线(鼠标实时跟随)
- tempLine = new Line
- {
- X1 = lastFixedPoint.X,
- Y1 = lastFixedPoint.Y,
- X2 = lastFixedPoint.X,
- Y2 = lastFixedPoint.Y,
- Stroke = Brushes.Red,
- StrokeThickness = 2
- };
- _canvas.Children.Add(tempLine);
- }//else if
- }//if IsMarking
- }
- //画临时线
- public void MouseDrawLine(Point point)
- {
- //第一个点,第二个点后,要画临时线
- if(IsMarking && PointCount == 3 && _points.Count >0 && _points.Count <= 2 )
- {
- if (tempLine != null)
- {
- //Point currentPoint = e.GetPosition(MyCanvas);
- tempLine.X2 = point.X;
- tempLine.Y2 = point.Y;
- }
- }
- }
- // 判断三点是否共线
- private bool ArePointsCollinear(Point p1, Point p2, Point p3)
- {
- // 使用叉积判断三点是否共线
- double crossProduct = (p2.X - p1.X) * (p3.Y - p1.Y) - (p2.Y - p1.Y) * (p3.X - p1.X);
- return Math.Abs(crossProduct) < 0.0001;
- }
- //计算L12与L23的交点,作为新的第二个点
- private Point CalculatePerpendicularIntersection(Point p1, Point p2, Point p3)
- {
- double x1 = p1.X, y1 = p1.Y;
- double x2 = p2.X, y2 = p2.Y;
- double x3 = p3.X, y3 = p3.Y;
- // 计算L12的斜率
- double slopeL23 = (y3 - y2) / (x3 - x2);
- // 计算L23的斜率,L23垂直于L12,所以斜率为 -1 / slopeL12
- double slopeL12 = -1 / slopeL23;
- // L12的方程为:y = slopeL12 * x + b1
- double b1 = y1 - slopeL12 * x1;
- // L23的方程为:y = slopeL23 * x + b2
- double b2 = y3 - slopeL23 * x3;
- // 计算L12与L23的交点
- double intersectX = (b2 - b1) / (slopeL12 - slopeL23);
- double intersectY = slopeL12 * intersectX + b1;
- return new Point(intersectX, intersectY);
- }
- //计算矩形的第四个点
- private Point CalculateFourthPoint(Point p1, Point p2, Point p3)
- {
- // 计算从P1到P2的向量
- double dx1 = p2.X - p1.X;
- double dy1 = p2.Y - p1.Y;
- // 计算从P1到P3的向量
- double dx2 = p3.X - p1.X;
- double dy2 = p3.Y - p1.Y;
- // 通过平行四边形法则计算第四个点
- double x4 = p3.X - dx1;
- double y4 = p3.Y - dy1;
- return new Point(x4, y4);
- }
- // 绘制旋转矩形,连接四个顶点
- private void DrawRotatedRectangle(Point p1, Point p2, Point p3, Point p4)
- {
- // 绘制矩形的四条边
- Line line1 = new Line
- {
- X1 = p1.X,
- Y1 = p1.Y,
- X2 = p2.X,
- Y2 = p2.Y,
- Stroke = Brushes.Blue,
- StrokeThickness = 2
- };
- Line line2 = new Line
- {
- X1 = p2.X,
- Y1 = p2.Y,
- X2 = p3.X,
- Y2 = p3.Y,
- Stroke = Brushes.Blue,
- StrokeThickness = 2
- };
- Line line3 = new Line
- {
- X1 = p3.X,
- Y1 = p3.Y,
- X2 = p4.X,
- Y2 = p4.Y,
- Stroke = Brushes.Blue,
- StrokeThickness = 2
- };
- Line line4 = new Line
- {
- X1 = p4.X,
- Y1 = p4.Y,
- X2 = p1.X,
- Y2 = p1.Y,
- Stroke = Brushes.Blue,
- StrokeThickness = 2
- };
- _canvas.Children.Add(line1);
- _canvas.Children.Add(line2);
- _canvas.Children.Add(line3);
- _canvas.Children.Add(line4);
- _drawShapes.Add(line1);
- _drawShapes.Add(line2);
- _drawShapes.Add(line3);
- _drawShapes.Add(line4);
- }
- //三点画矩形
- private void ThreePoint_DrawRectangle()
- {
- //判断是否为三点共线
- if (ArePointsCollinear(_points[0], _points[1], _points[2]))
- {
- ReadyMark(PointCount);
- MarkError?.Invoke("三个点共线,无效的标注");
- return;
- }
- //计算新的第二个点
- Point newSecondPoint = CalculatePerpendicularIntersection(_points[0], _points[1], _points[2]);
- UpdatePoint(newSecondPoint, 2); //第2个位置更新
- //AddPoint(newSecondPoint);
- // 计算第四个点(矩形的另一个角)
- Point fourthPoint = CalculateFourthPoint(_points[0], newSecondPoint, _points[2]);
- AddPoint(fourthPoint); //增加第四个位置
- DrawRotatedRectangle(_points[0], newSecondPoint, _points[2], fourthPoint);
- IsMarking = false;
- FinishMark?.Invoke(3, _points, 0);
- }
- //四点标记表盘
- private void FourPoint_DrawRectangle()
- {
- //通过标记的四个点来计算矩形的坐标
- double xMin = Math.Min(Math.Min(_points[0].X, _points[1].X), Math.Min(_points[2].X, _points[3].X));
- double yMin = Math.Min(Math.Min(_points[0].Y, _points[1].Y), Math.Min(_points[2].Y, _points[3].Y));
- double xMax = Math.Max(Math.Max(_points[0].X, _points[1].X), Math.Max(_points[2].X, _points[3].X));
- double yMax = Math.Max(Math.Max(_points[0].Y, _points[1].Y), Math.Max(_points[2].Y, _points[3].Y));
- double width = Math.Abs(xMax - xMin);
- double height = Math.Abs(yMax - yMin);
- //画矩形
- var rectangle = new Rectangle
- {
- Stroke = Brushes.Blue,
- StrokeThickness = 2,
- Fill = Brushes.Transparent,
- Width = width,
- Height = height
- };
- _canvas.Children.Add(rectangle);
- Canvas.SetLeft(rectangle, xMin);
- Canvas.SetTop(rectangle, yMin);
- _drawShapes.Add(rectangle);
- List<Point> points = new List<Point>
- {
- new Point(xMin,yMin),new Point(xMax,yMax)
- };
- IsMarking = false;
- FinishMark?.Invoke(2, points, 0);
- }
- //2点标记直线
- private void TwoPoint_DrawLine()
- {
- Line line = new Line
- {
- X1 = _points[0].X,
- Y1 = _points[0].Y,
- X2 = _points[1].X,
- Y2 = _points[1].Y,
- Stroke = Brushes.Blue,
- StrokeThickness = 2
- };
- _canvas.Children.Add(line);
- _drawShapes.Add(line);
- IsMarking = false;
- FinishMark?.Invoke(3, _points, 0);
- }
- //-------------------------------------------------------------------------
- }
- }
|