using ComPDFKit.Tool.SettingParam; using System; using System.Collections.Generic; using System.Windows; using System.Windows.Controls; using System.Windows.Media; namespace ComPDFKit.Tool.DrawTool { public class PageSelectedRect : DrawingVisual { /// /// A method that repositions child elements /// public void Arrange() { foreach (Visual child in Children) { if (!(child is UIElement)) { continue; } UIElement checkChild = child as UIElement; try { double left = Canvas.GetLeft(checkChild); double top = Canvas.GetTop(checkChild); double width = (double)checkChild.GetValue(FrameworkElement.WidthProperty); double height = (double)checkChild.GetValue(FrameworkElement.HeightProperty); checkChild.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity)); checkChild.Arrange(new Rect( double.IsNaN(left) ? 0 : left, double.IsNaN(top) ? 0 : top, double.IsNaN(width) ? checkChild.DesiredSize.Width : width, double.IsNaN(height) ? checkChild.DesiredSize.Height : height)); } catch (Exception ex) { } } } protected DefaultDrawParam DrawParam = new DefaultDrawParam(); protected DrawingContext drawDC { get; set; } /// /// Data changing event /// public event EventHandler DataChanging; /// /// Data changed event /// public event EventHandler DataChanged; /// /// Minimum width of the rectangle /// protected int rectMinWidth { get; set; } = 10; /// /// Minimum height of the rectangle /// protected int rectMinHeight { get; set; } = 10; /// /// Identifies whether the mouse is pressed /// protected bool isMouseDown { get; set; } /// /// Current click hit control point /// protected PointControlType hitControlType { get; set; } /// /// Location information recorded when the mouse is pressed /// protected Point mouseDownPoint { get; set; } /// /// Current set ignore point /// protected List ignorePoints { get; set; } = new List(); /// /// Current control point coordinates /// protected List controlPoints { get; set; } = new List(); /// /// Move offset during movement /// protected Point moveOffset { get; set; } = new Point(0, 0); /// /// Current PDFVIewer actual display width /// protected double PDFViewerActualWidth { get; set; } = 0; /// /// Current PDFVIewer actual display height /// protected double PDFViewerActualHeight { get; set; } = 0; /// /// Current control point drawing style /// protected DrawPointType currentDrawPointType { get; set; } /// /// Current drag drawing style /// protected DrawMoveType currentDrawMoveType { get; set; } /// /// Control point size /// protected int pointSize { get; set; } = 4; /// /// Current drawing rectangle (calculated during operation) /// protected Rect drawRect { get; set; } = new Rect(0, 0, 0, 0); /// /// Draw border and content internal padding /// protected double rectPadding = 5; /// /// Cache the rectangle when the mouse is pressed /// protected Rect cacheRect { get; set; } = new Rect(0, 0, 0, 0); /// /// Current set drawing rectangle (original data) /// protected Rect setDrawRect { get; set; } = new Rect(0, 0, 0, 0); /// /// Maximum drawable range /// protected Rect maxRect { get; set; } = new Rect(0, 0, 0, 0); /// /// Mouse start drawing point /// protected Point mouseStartPoint { get; set; } /// /// Mouse end drawing point /// protected Point mouseEndPoint { get; set; } /// /// Identifies whether proportional scaling is required /// protected bool isProportionalScaling { get; set; } = false; /// /// Identifies whether to draw a hover state /// protected bool isHover = false; /// /// Identifies whether to draw a selected state /// protected bool isSelected = false; protected bool isDrawCreateSelected = false; public PageSelectedRect(DefaultDrawParam defaultDrawParam) { DrawParam = defaultDrawParam; currentDrawPointType = DrawPointType.Square; } public void SetIsHover(bool hover) { isHover = hover; } public bool GetIsHover() { return isHover; } public void SetIsSelected(bool selected) { isSelected = selected; } public bool GetIsSelected() { return isSelected; } /// /// Get the original set Rect, not the calculated filled /// /// /// The new rectangle to be set /// public Rect GetRect() { Rect rect = new Rect(drawRect.X + rectPadding, drawRect.Y + rectPadding, Math.Max(0, drawRect.Width - 2 * rectPadding), Math.Max(0, drawRect.Height - 2 * rectPadding)); return rect; } public void SetRect(Rect newRect) { newRect = new Rect(newRect.X - rectPadding, newRect.Y - rectPadding, newRect.Width + 2 * rectPadding, newRect.Height + 2 * rectPadding); setDrawRect = drawRect = newRect; } public void SetMaxRect(Rect rect) { maxRect = rect; } public Rect GetMaxRect() { return maxRect; } public void SetDrawMoveType(DrawMoveType drawType) { currentDrawMoveType = drawType; } public DrawMoveType GetDrawMoveType() { return currentDrawMoveType; } public void SetPDFViewerActualSize(double width, double height) { PDFViewerActualWidth = width; PDFViewerActualHeight = height; } public virtual void OnMouseLeftButtonDown(Point downPoint) { isMouseDown = true; hitControlType = PointControlType.None; mouseDownPoint = downPoint; moveOffset = new Point(0, 0); HitTestResult hitResult = VisualTreeHelper.HitTest(this, downPoint); if (hitResult != null && hitResult.VisualHit is DrawingVisual) { hitControlType = GetHitControlIndex(downPoint); if (hitControlType != PointControlType.None) { cacheRect = drawRect; } } } public virtual void OnMouseLeftButtonUp(Point upPoint) { if (isDrawCreateSelected) { Draw(); if ((int)upPoint.X != (int)mouseDownPoint.X || (int)upPoint.Y != (int)mouseDownPoint.Y) { InvokeDataChangEvent(true); } } else { if (isMouseDown && hitControlType != PointControlType.None) { isMouseDown = false; cacheRect = setDrawRect = drawRect; Draw(); if ((int)upPoint.X != (int)mouseDownPoint.X || (int)upPoint.Y != (int)mouseDownPoint.Y) { InvokeDataChangEvent(true); } } moveOffset = new Point(0, 0); } isDrawCreateSelected = false; } public virtual void OnMouseMove(Point mousePoint, out bool Tag, double width, double height) { Tag = false; Tag = isMouseDown; SetPDFViewerActualSize(width, height); if (isDrawCreateSelected) { mouseEndPoint = mousePoint; Draw(); } else { if (isMouseDown && hitControlType != PointControlType.None) { if (CalcHitPointMove(mousePoint)) { Draw(); if ((int)mousePoint.X != (int)mouseDownPoint.X || (int)mousePoint.Y != (int)mouseDownPoint.Y) { InvokeDataChangEvent(false); } } } } } public void CreateRect(Point downPoint, Point cropPoint, Rect maxRect, double width, double height) { mouseEndPoint = mouseStartPoint = downPoint; this.maxRect = maxRect; PDFViewerActualWidth = width; PDFViewerActualHeight = height; isDrawCreateSelected = true; } public void Draw() { if (isDrawCreateSelected) { CreateRect(); } else { EditRect(); } } private void CreateRect() { Dispatcher.Invoke(() => { drawDC = RenderOpen(); SolidColorBrush bgsolidColorBrush = DrawParam.PageSelectedBgBrush; Pen bgpen = DrawParam.PageSelectedRectLinePen; CombinedGeometry clipGeometry = new CombinedGeometry(); clipGeometry.Geometry1 = new RectangleGeometry() { Rect = maxRect }; clipGeometry.Geometry2 = new RectangleGeometry() { Rect = drawRect }; clipGeometry.GeometryCombineMode = GeometryCombineMode.Exclude; drawDC?.DrawGeometry(bgsolidColorBrush, bgpen, clipGeometry); SolidColorBrush solidColorBrush = DrawParam.PageSelectedRectFillBrush; Pen pen = DrawParam.PageSelectedRectLinePen; if (isProportionalScaling) { Point mouseOffset = (Point)(mouseStartPoint - mouseEndPoint); if (mouseOffset.X < 0) { if (mouseOffset.Y > 0) { mouseEndPoint = new Point(mouseEndPoint.X, mouseStartPoint.Y + mouseStartPoint.X - mouseEndPoint.X); } else { mouseEndPoint = new Point(mouseEndPoint.X, mouseStartPoint.Y + mouseEndPoint.X - mouseStartPoint.X); } } else { if (mouseOffset.Y > 0) { mouseEndPoint = new Point(mouseEndPoint.X, mouseStartPoint.Y + mouseEndPoint.X - mouseStartPoint.X); } else { mouseEndPoint = new Point(mouseEndPoint.X, mouseStartPoint.Y + mouseStartPoint.X - mouseEndPoint.X); } } } Rect rect = new Rect(mouseStartPoint, mouseEndPoint); double mLeft = rect.Left; double mRight = rect.Right; double mUp = rect.Top; double mDown = rect.Bottom; if (rect.Left < maxRect.Left) { mLeft = maxRect.Left; } if (rect.Right > maxRect.Right) { mRight = maxRect.Right; } if (rect.Top < maxRect.Top) { mUp = maxRect.Top; } if (rect.Bottom > maxRect.Bottom) { mDown = maxRect.Bottom; } Rect DPIRect = new Rect(mLeft, mUp, mRight - mLeft, mDown - mUp); int halfPenWidth = (int)Math.Ceiling(pen.Thickness / 2); double drawWidth = DPIRect.Width - halfPenWidth * 2; double drawHeight = DPIRect.Height - halfPenWidth * 2; if (drawWidth > 0 && drawHeight > 0) { drawRect = new Rect( (int)DPIRect.Left + halfPenWidth, (int)DPIRect.Top + halfPenWidth, (int)DPIRect.Width - halfPenWidth * 2, (int)DPIRect.Height - halfPenWidth * 2); drawDC?.DrawRectangle(solidColorBrush, pen, drawRect); CalcControlPoint(drawRect); SolidColorBrush PointBrush = DrawParam.PageSelectedPointBorderBrush; Pen PointPen = DrawParam.PageSelectedPointPen; GetPointBrushAndPen(ref PointBrush, ref PointPen); switch (currentDrawPointType) { case DrawPointType.Circle: DrawCirclePoint(drawDC, GetIgnorePoints(), pointSize, PointPen, PointBrush); break; case DrawPointType.Square: DrawSquarePoint(drawDC, GetIgnorePoints(), pointSize, PointPen, PointBrush); break; } } drawDC?.Close(); drawDC = null; }); } private void EditRect() { Dispatcher.Invoke(() => { drawDC = RenderOpen(); SolidColorBrush bgsolidColorBrush = DrawParam.PageSelectedBgBrush; Pen bgpen = DrawParam.PageSelectedRectLinePen; CombinedGeometry clipGeometry = new CombinedGeometry(); clipGeometry.Geometry1 = new RectangleGeometry() { Rect = maxRect }; clipGeometry.Geometry2 = new RectangleGeometry() { Rect = drawRect }; clipGeometry.GeometryCombineMode = GeometryCombineMode.Exclude; drawDC?.DrawGeometry(bgsolidColorBrush, bgpen, clipGeometry); CalcControlPoint(drawRect); SolidColorBrush solidColorBrush = DrawParam.PageSelectedRectFillBrush; Pen pen = DrawParam.PageSelectedRectLinePen; SolidColorBrush PointBrush = DrawParam.PageSelectedPointBorderBrush; Pen PointPen = DrawParam.PageSelectedPointPen; GetPointBrushAndPen(ref PointBrush, ref PointPen); switch (currentDrawMoveType) { case DrawMoveType.kDefault: break; case DrawMoveType.kReferenceLine: if (isMouseDown == true) { SolidColorBrush moveBrush = DrawParam.PDFEditMultiMoveBrush; Pen movepen = DrawParam.PDFEditMultiMovePen; GetMoveBrushAndPen(ref moveBrush, ref movepen); DrawMoveBounds(drawDC, hitControlType, movepen, moveBrush, drawRect); } drawDC?.DrawRectangle(solidColorBrush, pen, drawRect); break; default: break; } switch (currentDrawPointType) { case DrawPointType.Circle: DrawCirclePoint(drawDC, GetIgnorePoints(), pointSize, PointPen, PointBrush); break; case DrawPointType.Square: DrawSquarePoint(drawDC, GetIgnorePoints(), pointSize, PointPen, PointBrush); break; } drawDC?.Close(); drawDC = null; }); } public virtual void ClearDraw() { setDrawRect = drawRect = new Rect(); drawDC = RenderOpen(); drawDC?.Close(); drawDC = null; } private void GetMoveBrushAndPen(ref SolidColorBrush colorBrush, ref Pen pen) { colorBrush = DrawParam.PageSelectedMoveBrush; pen = DrawParam.PageSelectedMovePen; } private void GetBrushAndPen(ref SolidColorBrush colorBrush, ref Pen pen) { if (isHover) { colorBrush = DrawParam.PageSelectedRectFillHoverBrush; pen = DrawParam.PageSelectedRectLineHoverPen; } else { if (isSelected) { colorBrush = DrawParam.SPageSelectedRectFillBrush; pen = DrawParam.SPageSelectedRectLinePen; } else { colorBrush = DrawParam.PageSelectedRectFillBrush; pen = DrawParam.PageSelectedRectLinePen; } } } private void GetPointBrushAndPen(ref SolidColorBrush colorBrush, ref Pen pen) { if (isHover) { colorBrush = DrawParam.PageSelectedRectFillHoverBrush; pen = DrawParam.PageSelectedRectLineHoverPen; } else { if (isSelected) { colorBrush = DrawParam.SPageSelectedPointBorderBrush; pen = DrawParam.SPageSelectedPointPen; } else { colorBrush = DrawParam.PageSelectedPointBorderBrush; pen = DrawParam.PageSelectedPointHoverPen; } } } /// /// Inner drawing circle point /// /// /// Drawing context /// /// /// Dataset of ignored points. Collection of positions where points need to be drawn. /// /// /// Size of the point /// /// /// Point brush /// /// /// Border brush for drawing points /// protected void DrawCirclePoint(DrawingContext drawingContext, List ignoreList, int PointSize, Pen PointPen, SolidColorBrush BorderBrush) { GeometryGroup controlGroup = new GeometryGroup(); controlGroup.FillRule = FillRule.Nonzero; List ignorePointsList = new List(); // Get specific points foreach (PointControlType type in ignoreList) { if ((int)type < controlPoints.Count) { ignorePointsList.Add(controlPoints[(int)type]); } } for (int i = 0; i < controlPoints.Count; i++) { Point controlPoint = controlPoints[i]; if (ignorePointsList.Contains(controlPoint)) { continue; } EllipseGeometry circlPoint = new EllipseGeometry(controlPoint, PointSize, PointSize); controlGroup.Children.Add(circlPoint); } drawingContext?.DrawGeometry(BorderBrush, PointPen, controlGroup); } /// /// Inner drawing square /// /// /// Drawing context /// /// /// Collection of positions where points need to be drawn /// /// /// Collection of positions where points need to be drawn /// /// /// The brush for drawing points /// /// /// The brush for drawing the border of points /// protected void DrawSquarePoint(DrawingContext drawingContext, List ignoreList, int PointSize, Pen PointPen, SolidColorBrush BorderBrush) { GeometryGroup controlGroup = new GeometryGroup(); controlGroup.FillRule = FillRule.Nonzero; List ignorePointsList = new List(); // Get specific points foreach (PointControlType type in ignoreList) { if ((int)type < controlPoints.Count) { ignorePointsList.Add(controlPoints[(int)type]); } } for (int i = 0; i < controlPoints.Count; i++) { Point controlPoint = controlPoints[i]; if (ignorePointsList.Contains(controlPoint)) { continue; } RectangleGeometry rectPoint = new RectangleGeometry(new Rect(controlPoint.X - PointSize, controlPoint.Y - PointSize, PointSize * 2, PointSize * 2), 1, 1); controlGroup.Children.Add(rectPoint); } drawingContext?.DrawGeometry(BorderBrush, PointPen, controlGroup); } /// /// Draw the reference line in the moving state /// /// /// Drawing context handle /// /// /// Current selected control point type /// /// /// Line brush /// /// /// Rectangle brush /// /// /// Current rectangle to be drawn /// protected void DrawMoveBounds(DrawingContext drawDc, PointControlType controltype, Pen activePen, Brush moveBrush, Rect moveRect) { switch (controltype) { case PointControlType.LeftTop: drawDc?.DrawLine(activePen, new Point(0, moveRect.Top), new Point(PDFViewerActualWidth, moveRect.Top)); drawDc?.DrawLine(activePen, new Point(moveRect.Left, 0), new Point(moveRect.Left, PDFViewerActualHeight)); break; case PointControlType.LeftMiddle: drawDc?.DrawLine(activePen, new Point(moveRect.Left, 0), new Point(moveRect.Left, PDFViewerActualHeight)); break; case PointControlType.LeftBottom: drawDc?.DrawLine(activePen, new Point(0, moveRect.Bottom), new Point(PDFViewerActualWidth, moveRect.Bottom)); drawDc?.DrawLine(activePen, new Point(moveRect.Left, 0), new Point(moveRect.Left, PDFViewerActualHeight)); break; case PointControlType.MiddleBottom: drawDc?.DrawLine(activePen, new Point(0, moveRect.Bottom), new Point(PDFViewerActualWidth, moveRect.Bottom)); break; case PointControlType.RightBottom: drawDc?.DrawLine(activePen, new Point(0, moveRect.Bottom), new Point(PDFViewerActualWidth, moveRect.Bottom)); drawDc?.DrawLine(activePen, new Point(moveRect.Right, 0), new Point(moveRect.Right, PDFViewerActualHeight)); break; case PointControlType.RightMiddle: drawDc?.DrawLine(activePen, new Point(moveRect.Right, 0), new Point(moveRect.Right, PDFViewerActualHeight)); break; case PointControlType.RightTop: drawDc?.DrawLine(activePen, new Point(0, moveRect.Top), new Point(PDFViewerActualWidth, moveRect.Top)); drawDc?.DrawLine(activePen, new Point(moveRect.Right, 0), new Point(moveRect.Right, PDFViewerActualHeight)); break; case PointControlType.MiddleTop: drawDc?.DrawLine(activePen, new Point(0, moveRect.Top), new Point(PDFViewerActualWidth, moveRect.Top)); break; case PointControlType.Rotate: break; case PointControlType.Body: case PointControlType.Line: drawDc?.DrawLine(activePen, new Point(0, moveRect.Top), new Point(PDFViewerActualWidth, moveRect.Top)); drawDc?.DrawLine(activePen, new Point(0, moveRect.Bottom), new Point(PDFViewerActualWidth, moveRect.Bottom)); drawDc?.DrawLine(activePen, new Point(moveRect.Left, 0), new Point(moveRect.Left, PDFViewerActualHeight)); drawDc?.DrawLine(activePen, new Point(moveRect.Right, 0), new Point(moveRect.Right, PDFViewerActualHeight)); break; default: break; } drawDc?.DrawRectangle(moveBrush, null, moveRect); } /// /// Calculate the current control point /// /// /// Control point target rectangle /// protected void CalcControlPoint(Rect currentRect) { controlPoints.Clear(); int centerX = (int)(currentRect.Left + currentRect.Right) / 2; int centerY = (int)(currentRect.Top + currentRect.Bottom) / 2; controlPoints.Add(new Point(currentRect.Left, currentRect.Top)); controlPoints.Add(new Point(currentRect.Left, centerY)); controlPoints.Add(new Point(currentRect.Left, currentRect.Bottom)); controlPoints.Add(new Point(centerX, currentRect.Bottom)); controlPoints.Add(new Point(currentRect.Right, currentRect.Bottom)); controlPoints.Add(new Point(currentRect.Right, centerY)); controlPoints.Add(new Point(currentRect.Right, currentRect.Top)); controlPoints.Add(new Point(centerX, currentRect.Top)); } /// /// Calculate the movement of the hit point /// /// /// Current mouse position /// /// /// Return true if the calculation is successful /// protected bool CalcHitPointMove(Point mousePoint) { if (isMouseDown == false || hitControlType == PointControlType.None) { return false; } return NormalScaling(mousePoint); } /// /// Draw the algorithm of the normal scaling form (drag a point, only scale in one direction) /// /// /// Current mouse position /// /// /// Return true if the calculation is successful /// protected bool NormalScaling(Point mousePoint) { double mLeft = cacheRect.Left; double mRight = cacheRect.Right; double mUp = cacheRect.Top; double mDown = cacheRect.Bottom; double TmpLeft = mLeft, TmpRight = mRight, TmpUp = mUp, TmpDown = mDown; Point centerPoint = new Point((cacheRect.Right + cacheRect.Left) / 2, (cacheRect.Bottom + cacheRect.Top) / 2); Point moveVector = (Point)(mousePoint - centerPoint); moveVector = ProportionalScalingOffsetPos(moveVector); switch (hitControlType) { case PointControlType.LeftTop: TmpLeft = centerPoint.X + moveVector.X; TmpRight = cacheRect.Right; if (TmpLeft + rectMinWidth > TmpRight) { TmpLeft = TmpRight - rectMinWidth; } TmpUp = centerPoint.Y + moveVector.Y; TmpDown = cacheRect.Bottom; if (TmpUp + rectMinHeight > TmpDown) { TmpUp = TmpDown - rectMinHeight; } break; case PointControlType.LeftMiddle: TmpLeft = centerPoint.X + moveVector.X; TmpRight = cacheRect.Right; if (TmpLeft + rectMinWidth > TmpRight) { TmpLeft = TmpRight - rectMinWidth; } TmpUp = cacheRect.Top; TmpDown = cacheRect.Bottom; break; case PointControlType.LeftBottom: TmpLeft = centerPoint.X + moveVector.X; TmpRight = cacheRect.Right; if (TmpLeft + rectMinWidth > TmpRight) { TmpLeft = TmpRight - rectMinWidth; } TmpUp = cacheRect.Top; TmpDown = centerPoint.Y + moveVector.Y; if (TmpUp + rectMinHeight > TmpDown) { TmpDown = TmpUp + rectMinHeight; } break; case PointControlType.MiddleBottom: TmpLeft = cacheRect.Left; TmpRight = cacheRect.Right; TmpUp = cacheRect.Top; TmpDown = centerPoint.Y + moveVector.Y; if (TmpUp + rectMinHeight > TmpDown) { TmpDown = TmpUp + rectMinHeight; } break; case PointControlType.RightBottom: TmpLeft = cacheRect.Left; TmpRight = centerPoint.X + moveVector.X; if (TmpLeft + rectMinWidth > TmpRight) { TmpRight = TmpLeft + rectMinWidth; } TmpUp = cacheRect.Top; TmpDown = centerPoint.Y + moveVector.Y; if (TmpUp + rectMinHeight > TmpDown) { TmpDown = TmpUp + rectMinHeight; } break; case PointControlType.RightMiddle: TmpLeft = cacheRect.Left; TmpRight = centerPoint.X + moveVector.X; if (TmpLeft + rectMinWidth > TmpRight) { TmpRight = TmpLeft + rectMinWidth; } TmpUp = cacheRect.Top; TmpDown = cacheRect.Bottom; break; case PointControlType.RightTop: TmpLeft = cacheRect.Left; TmpRight = centerPoint.X + moveVector.X; if (TmpLeft + rectMinWidth > TmpRight) { TmpRight = TmpLeft + rectMinWidth; } TmpUp = centerPoint.Y + moveVector.Y; TmpDown = cacheRect.Bottom; if (TmpUp + rectMinHeight > TmpDown) { TmpUp = TmpDown - rectMinHeight; } break; case PointControlType.MiddleTop: TmpLeft = cacheRect.Left; TmpRight = cacheRect.Right; TmpUp = centerPoint.Y + moveVector.Y; TmpDown = cacheRect.Bottom; if (TmpUp + rectMinHeight > TmpDown) { TmpUp = TmpDown - rectMinHeight; } break; case PointControlType.Body: case PointControlType.Line: Point OffsetPos = CalcMoveBound(cacheRect, ((Point)(mousePoint - mouseDownPoint)), maxRect); TmpLeft = cacheRect.Left + OffsetPos.X; TmpRight = cacheRect.Right + OffsetPos.X; TmpUp = cacheRect.Top + OffsetPos.Y; TmpDown = cacheRect.Bottom + OffsetPos.Y; break; default: break; } if (TmpLeft < maxRect.Left) { TmpLeft = maxRect.Left; } if (TmpUp < maxRect.Top) { TmpUp = maxRect.Top; } if (TmpRight > maxRect.Right) { TmpRight = maxRect.Right; } if (TmpDown > maxRect.Bottom) { TmpDown = maxRect.Bottom; } if (TmpRight - TmpLeft < 0.0 || TmpDown - TmpUp < 0.0) { return false; } drawRect = new Rect(TmpLeft, TmpUp, TmpRight - TmpLeft, TmpDown - TmpUp); moveOffset = new Point(drawRect.X - cacheRect.X, drawRect.Y - cacheRect.Y); return true; } /// /// Proportional scaling offset calibration. /// /// /// Current mouse position /// /// /// Return the calibrated offset value /// protected Point ProportionalScalingOffsetPos(Point movePoint) { if (isProportionalScaling) { Point offsetPos = movePoint; double ratioX = cacheRect.Width > 0 ? cacheRect.Height / cacheRect.Width : 1; double ratioY = cacheRect.Height > 0 ? cacheRect.Width / cacheRect.Height : 1; switch (hitControlType) { case PointControlType.LeftTop: case PointControlType.RightBottom: offsetPos = new Point(movePoint.X, Math.Abs(movePoint.X) * ratioX * (movePoint.X < 0 ? -1 : 1)); break; case PointControlType.LeftBottom: case PointControlType.RightTop: offsetPos = new Point(movePoint.X, Math.Abs(movePoint.X) * ratioX * (movePoint.X < 0 ? 1 : -1)); break; case PointControlType.LeftMiddle: offsetPos = new Point(movePoint.X, Math.Abs(movePoint.X) * ratioX * (movePoint.X < 0 ? 1 : -1)); break; case PointControlType.RightMiddle: offsetPos = new Point(movePoint.X, Math.Abs(movePoint.X) * ratioX * (movePoint.X < 0 ? -1 : 1)); break; case PointControlType.MiddleBottom: offsetPos = new Point(Math.Abs(movePoint.Y) * ratioY * (movePoint.Y < 0 ? 1 : -1), movePoint.Y); break; case PointControlType.MiddleTop: offsetPos = new Point(Math.Abs(movePoint.Y) * ratioY * (movePoint.Y < 0 ? -1 : 1), movePoint.Y); break; default: break; } return offsetPos; } else { return movePoint; } } /// /// Calc the offset of the current rectangle in the maximum rectangle range /// /// /// The rectangle cached when pressed. /// /// /// Equivalent to the offset value when pressed. /// /// /// The maximum rectangle range. /// /// /// Return the offset value after the calculation. /// protected Point CalcMoveBound(Rect currentRect, Point offsetPoint, Rect maxRect) { double cLeft = currentRect.Left; double cRight = currentRect.Right; double cUp = currentRect.Top; double cDown = currentRect.Bottom; double TmpLeft = cLeft + offsetPoint.X; double TmpRight = cRight + offsetPoint.X; double TmpUp = cUp + offsetPoint.Y; double TmpDown = cDown + offsetPoint.Y; if (TmpLeft < maxRect.Left) { TmpRight = (cRight - cLeft) + maxRect.Left; TmpLeft = maxRect.Left; } if (TmpUp < maxRect.Top) { TmpDown = (cDown - cUp) + maxRect.Top; TmpUp = maxRect.Top; } if (TmpRight > maxRect.Right) { TmpLeft = maxRect.Right - (cRight - cLeft); TmpRight = maxRect.Right; } if (TmpDown > maxRect.Bottom) { TmpUp = maxRect.Bottom - (cDown - cUp); TmpDown = maxRect.Bottom; } offsetPoint = new Point(TmpLeft - cLeft, TmpUp - cUp); return offsetPoint; } /// /// Get which control point the coordinate is on /// /// /// The coordinate of the click /// /// /// Return the control point type /// public PointControlType GetHitControlIndex(Point point) { try { HitTestResult hitResult = VisualTreeHelper.HitTest(this, point); if (hitResult != null && hitResult.VisualHit is DrawingVisual) { List ignoreList = GetIgnorePoints(); List IgnorePointsList = new List(); foreach (PointControlType type in ignoreList) { if ((int)type < controlPoints.Count) { IgnorePointsList.Add(controlPoints[(int)type]); } } for (int i = 0; i < controlPoints.Count; i++) { Point checkPoint = controlPoints[i]; if (IgnorePointsList.Contains(checkPoint)) { continue; } switch (currentDrawPointType) { case DrawPointType.Circle: Vector checkVector = checkPoint - point; if (checkVector.Length < pointSize) { return (PointControlType)i; } break; case DrawPointType.Square: Rect checkRect = new Rect(Math.Max(checkPoint.X - pointSize, 0), Math.Max(checkPoint.Y - pointSize, 0), pointSize * 2, pointSize * 2); if (checkRect.Contains(point)) { return (PointControlType)i; } break; case DrawPointType.Crop: Rect cropRect = new Rect(Math.Max(checkPoint.X - pointSize, 0), Math.Max(checkPoint.Y - pointSize, 0), pointSize * 2, pointSize * 2); if (cropRect.Contains(point)) { return (PointControlType)i; } break; default: break; } } if (drawRect.Contains(point)) { Rect rect = new Rect(Math.Max(drawRect.X + rectPadding, 0), Math.Max(drawRect.Y + rectPadding, 0), drawRect.Width - 2 * rectPadding, drawRect.Height - 2 * rectPadding); if (rect.Contains(point)) { if (!ignoreList.Contains(PointControlType.Body)) { return PointControlType.Body; } } if (!ignoreList.Contains(PointControlType.Body)) { return PointControlType.Line; } } } } catch (Exception ex) { } return PointControlType.None; } /// /// Get the current set of ignored points /// /// The dataset of ignored points /// private List GetIgnorePoints() { List IgnorePointsList = new List(); foreach (PointControlType type in ignorePoints) { IgnorePointsList.Add(type); } return IgnorePointsList; } /// /// Notify events during/after drawing data /// /// /// Identifies whether the data has changed /// protected void InvokeDataChangEvent(bool isFinish) { if (isFinish) { DataChanged?.Invoke(this, drawRect); } else { DataChanging?.Invoke(this, drawRect); } } } }