using System; using System.Collections.Generic; using System.Linq; using System.Windows; using System.Windows.Media; namespace ComPDFKit.Tool.DrawTool { public partial class SelectedRect { #region Properties /// /// Current control point drawing style. /// protected DrawPointType currentDrawPointType { get; set; } /// /// Current drag drawing style. /// protected DrawMoveType currentDrawMoveType { get; set; } /// /// Current click hit control point. /// protected PointControlType hitControlType { get; set; } /// /// Mouse down position information. /// protected Point mouseDownPoint { get; set; } /// /// Whether the mouse is pressed. /// protected bool isMouseDown { get; set; } protected bool isInRotate { get; set; } = false; protected bool isInScaling { get; set; } = false; /// /// Whether proportional scaling is required. /// protected bool isProportionalScaling { get; set; } = false; /// /// Current control point size. /// protected int pointSize { get; set; } = 4; /// /// Rectangular minimum width. /// public int RectMinWidth { get; set; } = 10; /// /// Rectangular minimum height. /// public int RectMinHeight { get; set; } = 10; /// /// Current set of ignore points. /// protected List ignorePoints { get; set; } = new List(); /// /// Current set of drawing rectangles (original data). /// protected Rect SetDrawRect { get; set; } = new Rect(0, 0, 0, 0); /// /// Current drawing rectangle (calculated during operation). /// protected Rect drawRect { get; set; } = new Rect(0, 0, 0, 0); /// /// Maximum range that can be drawn. /// protected Rect maxRect { get; set; } = new Rect(0, 0, 0, 0); /// /// Current center point of the drawing rectangle. /// protected Point drawCenterPoint { get; private set; } = new Point(0, 0); /// /// When the mouse is pressed, the cached rectangle. /// protected Rect cacheRect { get; set; } = new Rect(0, 0, 0, 0); /// /// Current control point coordinates. /// protected List controlPoints { get; set; } = new List(); protected Point centerPoint = new Point(); protected Point rotationPoint = new Point(); protected Point dragRotationPoint = new Point(); /// /// Move offset during movement. /// protected Point moveOffset { get; set; } = new Point(0, 0); /// /// Current drawing rectangle (calculated during operation). /// protected Thickness clipThickness = new Thickness(0, 0, 0, 0); private Pen editPen { get; set; } = new Pen(new SolidColorBrush(Color.FromRgb(71, 126, 222)), 2) { DashStyle = DashStyles.Dash }; private Pen editHoverPen { get; set; } = new Pen(new SolidColorBrush(Color.FromRgb(71, 126, 222)), 2) { DashStyle = DashStyles.Dash }; private bool showCreatTextRect = false; protected bool isOutSideScaling = false; /// /// Current actual display width and height of PDFVIewer. /// protected double PDFViewerActualWidth { get; set; } = 0; protected double PDFViewerActualHeight { get; set; } = 0; protected int rotateAngle { get; set; } = 0; protected int pageRotation { get; set; } = 0; protected double rectPadding = 6; protected double currentZoom = 1; protected SelectedAnnotData selectedRectData = new SelectedAnnotData(); protected bool disable = false; protected List rotateControlPoints = new List(); protected Rect rotateRect = new Rect(); #endregion #region Functions /// /// Calcuate the control points /// /// /// Control points in the target rectangle /// protected void CalcControlPoint(Rect currentRect) { controlPoints.Clear(); centerPoint.X = (int)(currentRect.Left + currentRect.Right) / 2; centerPoint.Y = (int)(currentRect.Top + currentRect.Bottom) / 2; controlPoints.Add(new Point(currentRect.Left, currentRect.Top)); controlPoints.Add(new Point(currentRect.Left, centerPoint.Y)); controlPoints.Add(new Point(currentRect.Left, currentRect.Bottom)); controlPoints.Add(new Point(centerPoint.X, currentRect.Bottom)); controlPoints.Add(new Point(currentRect.Right, currentRect.Bottom)); controlPoints.Add(new Point(currentRect.Right, centerPoint.Y)); controlPoints.Add(new Point(currentRect.Right, currentRect.Top)); controlPoints.Add(new Point(centerPoint.X, currentRect.Top)); if (canRotate) { rotationPoint = new Point(centerPoint.X, currentRect.Top - 30); switch (pageRotation) { case 0: rotationPoint = new Point(centerPoint.X, currentRect.Top - 30); break; case 1: rotationPoint = new Point(currentRect.Right + 30, centerPoint.Y); break; case 2: rotationPoint = new Point(centerPoint.X, currentRect.Bottom + 30); break; case 3: rotationPoint = new Point(currentRect.Left - 30, centerPoint.Y); break; default: break; } } } protected List GetControlPoint(Rect currentRect) { List controlCurrentPoints = new List(); controlCurrentPoints.Clear(); int centerX = (int)(currentRect.Left + currentRect.Right) / 2; int centerY = (int)(currentRect.Top + currentRect.Bottom) / 2; controlCurrentPoints.Add(new Point(currentRect.Left, currentRect.Top)); controlCurrentPoints.Add(new Point(currentRect.Left, centerY)); controlCurrentPoints.Add(new Point(currentRect.Left, currentRect.Bottom)); controlCurrentPoints.Add(new Point(centerX, currentRect.Bottom)); controlCurrentPoints.Add(new Point(currentRect.Right, currentRect.Bottom)); controlCurrentPoints.Add(new Point(currentRect.Right, centerY)); controlCurrentPoints.Add(new Point(currentRect.Right, currentRect.Top)); controlCurrentPoints.Add(new Point(centerX, currentRect.Top)); return controlCurrentPoints; } /// /// Calcuate 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. /// /// 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; } /// /// Calculate the movement of the hit point /// /// /// Current mouse position /// /// /// Whether the movement is successful /// protected bool CalcHitPointMove(Point mousePoint) { if (isMouseDown == false || hitControlType == PointControlType.None) { return false; } if (hitControlType == PointControlType.Rotate) { SetRotateByMousePoint(mousePoint); return false; } if (!isOutSideScaling) { if (selectedRectData.rotationAngle != 0) { return RotateScaling(mousePoint); } else { return NormalScaling(mousePoint); } } else { return OutSideScaling(mousePoint); } } public void SetOutSideScaling(bool IsOutSideScaling) { isOutSideScaling = IsOutSideScaling; } private Size GetProportionalScalingSize(double width, double height) { double minHeight = RectMinHeight + 2 * rectPadding * currentZoom; double minWidth = RectMinWidth + 2 * rectPadding * currentZoom; if (minWidth > width || minHeight > height) { if (cacheRect.Width >= cacheRect.Height) { width = cacheRect.Width * minHeight / cacheRect.Height; height = minHeight; } else { height = cacheRect.Height * minWidth / cacheRect.Width; width = minWidth; } } return new Size(width, height); } private void SetRotateByMousePoint(Point mousePoint) { dragRotationPoint = mousePoint; Vector moveVector = (mousePoint - centerPoint); rotateAngle = (int)(Math.Atan2(moveVector.X, -moveVector.Y) * 180 / Math.PI) - pageRotation * 90; } /// /// Draw the algorithm in the form of normal scaling (drag a point, only scale in one direction). /// /// Current mouse position. /// protected bool NormalScaling(Point mousePoint) { try { double left = 0, right = 0, top = 0, bottom = 0; double minHeight = RectMinHeight + 2 * rectPadding * currentZoom; double minWidth = RectMinWidth + 2 * rectPadding * currentZoom; 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: { left = centerPoint.X + moveVector.X; right = cacheRect.Right; top = centerPoint.Y + moveVector.Y; bottom = cacheRect.Bottom; if (isProportionalScaling) { Size size = GetProportionalScalingSize(right - left, bottom - top); left = right - size.Width; top = bottom - size.Height; if (left < maxRect.Left) { double tmpWidth = right - left; left = maxRect.Left; double width = right - left; double height = (bottom - top) * width / tmpWidth; top = bottom - height; } if (top < maxRect.Top) { double tmpHeight = bottom - top; top = maxRect.Top; double height = bottom - top; double width = (right - left) * height / tmpHeight; left = right - width; } } else { if (left + minWidth > right) { left = right - minWidth; } if (top + minHeight > bottom) { top = bottom - minHeight; } } } break; case PointControlType.LeftMiddle: { left = centerPoint.X + moveVector.X; right = cacheRect.Right; top = cacheRect.Top; bottom = cacheRect.Bottom; if (left + minWidth > right) { left = right - minWidth; } } break; case PointControlType.LeftBottom: { left = centerPoint.X + moveVector.X; right = cacheRect.Right; top = cacheRect.Top; bottom = centerPoint.Y + moveVector.Y; if (isProportionalScaling) { Size size = GetProportionalScalingSize(right - left, bottom - top); left = right - size.Width; bottom = top + size.Height; if (left < maxRect.Left) { double tmpWidth = right - left; left = maxRect.Left; double width = right - left; double height = (bottom - top) * width / tmpWidth; bottom = top + height; } if (bottom > maxRect.Bottom) { double tmpHeight = bottom - top; bottom = maxRect.Bottom; double height = bottom - top; double width = (right - left) * height / tmpHeight; left = right - width; } } else { if (left + minWidth > right) { left = right - minWidth; } if (top + minHeight > bottom) { bottom = top + minHeight; } } } break; case PointControlType.MiddleBottom: { left = cacheRect.Left; right = cacheRect.Right; top = cacheRect.Top; bottom = centerPoint.Y + moveVector.Y; if (top + minHeight > bottom) { bottom = top + minHeight; } } break; case PointControlType.RightBottom: { left = cacheRect.Left; right = centerPoint.X + moveVector.X; top = cacheRect.Top; bottom = centerPoint.Y + moveVector.Y; if (isProportionalScaling) { Size size = GetProportionalScalingSize(right - left, bottom - top); right = left + size.Width; bottom = top + size.Height; if (right > maxRect.Right) { double tmpWidth = right - left; right = maxRect.Right; double width = right - left; double height = (bottom - top) * width / tmpWidth; bottom = top + height; } if (bottom > maxRect.Bottom) { double tmpHeight = bottom - top; bottom = maxRect.Bottom; double height = bottom - top; double width = (right - left) * height / tmpHeight; right = left + width; } } else { if (left + minWidth > right) { right = left + minWidth; } if (top + minHeight > bottom) { bottom = top + minHeight; } } } break; case PointControlType.RightMiddle: { left = cacheRect.Left; right = centerPoint.X + moveVector.X; top = cacheRect.Top; bottom = cacheRect.Bottom; if (left + minWidth > right) { right = left + minWidth; } } break; case PointControlType.RightTop: { left = cacheRect.Left; right = centerPoint.X + moveVector.X; top = centerPoint.Y + moveVector.Y; bottom = cacheRect.Bottom; if (isProportionalScaling) { Size size = GetProportionalScalingSize(right - left, bottom - top); right = left + size.Width; top = bottom - size.Height; if (right > maxRect.Right) { double tmpWidth = right - left; right = maxRect.Right; double width = right - left; double height = (bottom - top) * width / tmpWidth; top = bottom - height; } if (top < maxRect.Top) { double tmpHeight = bottom - top; top = maxRect.Top; double height = bottom - top; double width = (right - left) * height / tmpHeight; right = left + width; } } else { if (left + minWidth > right) { right = left + minWidth; } if (top + minHeight > bottom) { top = bottom - minHeight; } } } break; case PointControlType.MiddleTop: { left = cacheRect.Left; right = cacheRect.Right; top = centerPoint.Y + moveVector.Y; bottom = cacheRect.Bottom; if (top + minHeight > bottom) { top = bottom - minHeight; } } break; case PointControlType.Body: case PointControlType.Line: { Point offsetPos = CalcMoveBound(cacheRect, ((Point)(mousePoint - mouseDownPoint)), maxRect); left = cacheRect.Left + offsetPos.X; right = cacheRect.Right + offsetPos.X; top = cacheRect.Top + offsetPos.Y; bottom = cacheRect.Bottom + offsetPos.Y; } break; default: break; } if (left < maxRect.Left) { left = maxRect.Left; } if (top < maxRect.Top) { top = maxRect.Top; } if (right > maxRect.Right) { right = maxRect.Right; } if (bottom > maxRect.Bottom) { bottom = maxRect.Bottom; } drawRect = new Rect(left, top, right - left, bottom - top); moveOffset = new Point(drawRect.X - cacheRect.X, drawRect.Y - cacheRect.Y); return true; } catch (Exception ex) { } return false; } protected bool RotateScaling(Point mouseMovePoint) { Point rotatePoint = new Point(); Point hitControlUIPos = new Point(); if (hitControlType < PointControlType.Body) { hitControlUIPos = rotateControlPoints[(int)hitControlType]; } hitControlUIPos = GetRotateUIPoint(hitControlUIPos); Point centerPoint = new Point((rotateRect.Left + rotateRect.Right) / 2, (rotateRect.Top + rotateRect.Bottom) / 2); Vector moveVector = mouseMovePoint - mouseDownPoint; Vector hitVector = hitControlUIPos - centerPoint; Rect tmpRect = cacheRect; if (hitControlType == PointControlType.LeftTop || hitControlType == PointControlType.LeftBottom || hitControlType == PointControlType.RightTop || hitControlType == PointControlType.RightBottom) { if (isProportionalScaling) { double vectorAngle = Vector.AngleBetween(moveVector, hitVector); double newLenght = Math.Cos(Math.PI / 180.0 * vectorAngle) * moveVector.Length; hitVector.Normalize(); hitVector.X *= newLenght; hitVector.Y *= newLenght; rotatePoint = new Point(hitControlUIPos.X + hitVector.X, hitControlUIPos.Y + hitVector.Y); } } switch (hitControlType) { case PointControlType.LeftTop: { Point rightBottomPoint = rotateControlPoints[(int)PointControlType.RightBottom]; Point rightBottomUIPos = GetRotateUIPoint(rightBottomPoint); centerPoint = new Point((rotatePoint.X + rightBottomUIPos.X) / 2, (rotatePoint.Y + rightBottomUIPos.Y) / 2); Matrix rotateMatrix = new Matrix(); rotateMatrix.RotateAt(-rotateAngle, centerPoint.X, centerPoint.Y); Point leftTopPoint = rotateMatrix.Transform(rotatePoint); rightBottomPoint = rotateMatrix.Transform(rightBottomUIPos); tmpRect = new Rect(leftTopPoint, rightBottomPoint); } break; case PointControlType.LeftBottom: { Point rightTopPoint = rotateControlPoints[(int)PointControlType.RightTop]; Point rightTopUIPos = GetRotateUIPoint(rightTopPoint); centerPoint = new Point((rotatePoint.X + rightTopUIPos.X) / 2, (rotatePoint.Y + rightTopUIPos.Y) / 2); Matrix rotateMatrix = new Matrix(); rotateMatrix.RotateAt(-rotateAngle, centerPoint.X, centerPoint.Y); Point leftBottomPoint = rotateMatrix.Transform(rotatePoint); rightTopPoint = rotateMatrix.Transform(rightTopUIPos); tmpRect = new Rect(leftBottomPoint, rightTopPoint); } break; case PointControlType.RightTop: { Point leftBottomPoint = rotateControlPoints[(int)PointControlType.LeftBottom]; Point leftBottomUIPos = GetRotateUIPoint(leftBottomPoint); centerPoint = new Point((rotatePoint.X + leftBottomUIPos.X) / 2, (rotatePoint.Y + leftBottomUIPos.Y) / 2); Matrix rotateMatrix = new Matrix(); rotateMatrix.RotateAt(-rotateAngle, centerPoint.X, centerPoint.Y); Point rightTopPoint = rotateMatrix.Transform(rotatePoint); leftBottomPoint = rotateMatrix.Transform(leftBottomUIPos); tmpRect = new Rect(leftBottomPoint, rightTopPoint); } break; case PointControlType.RightBottom: { Point leftTopPoint = rotateControlPoints[(int)PointControlType.LeftTop]; Point leftTopUIPos = GetRotateUIPoint(leftTopPoint); centerPoint = new Point((rotatePoint.X + leftTopUIPos.X) / 2, (rotatePoint.Y + leftTopUIPos.Y) / 2); Matrix rotateMatrix = new Matrix(); rotateMatrix.RotateAt(-rotateAngle, centerPoint.X, centerPoint.Y); Point rightBottomPoint = rotateMatrix.Transform(rotatePoint); leftTopPoint = rotateMatrix.Transform(leftTopUIPos); tmpRect = new Rect(leftTopPoint, rightBottomPoint); } break; case PointControlType.Body: case PointControlType.Line: { Point offsetPos = (Point)(mouseMovePoint - mouseDownPoint); double left = cacheRect.Left + offsetPos.X; double right = cacheRect.Right + offsetPos.X; double top = cacheRect.Top + offsetPos.Y; double bottom = cacheRect.Bottom + offsetPos.Y; tmpRect = new Rect(new Point(left,top), new Point(right,bottom)); } break; default: break; } List tempPoints = new List { new Point(tmpRect.Left, tmpRect.Top), new Point(tmpRect.Right, tmpRect.Top), new Point(tmpRect.Right, tmpRect.Bottom), new Point(tmpRect.Left, tmpRect.Bottom) }; List boundPoint = new List(); Point center = new Point((tmpRect.Left + tmpRect.Right) / 2, (tmpRect.Top + tmpRect.Bottom) / 2); foreach (Point point in tempPoints) { float x = (float)(center.X + (point.X - center.X) * Math.Cos(rotateAngle * Math.PI / 180) - (point.Y - center.Y) * Math.Sin(rotateAngle * Math.PI / 180)); float y = (float)(center.Y + (point.X - center.X) * Math.Sin(rotateAngle * Math.PI / 180) + (point.Y - center.Y) * Math.Cos(rotateAngle * Math.PI / 180)); boundPoint.Add(new Point(x, y)); } Rect boundRect = new Rect(new Point(boundPoint.Min(p => p.X), boundPoint.Min(p => p.Y)), new Point(boundPoint.Max(p => p.X), boundPoint.Max(p => p.Y))); if (maxRect.Contains(boundRect)) { drawRect = tmpRect; } else { if(hitControlType == PointControlType.Body || hitControlType == PointControlType.Line) { Point boundRectCenterPos = new Point((boundRect.Left + boundRect.Right) / 2, (boundRect.Top + boundRect.Bottom) / 2); Point maxRectCenterPos = new Point((maxRect.Left + maxRect.Right) / 2, (maxRect.Top + maxRect.Bottom) / 2); Vector moveCenterVector = boundRectCenterPos - maxRectCenterPos; Point moveOffsetPos = new Point(0, 0); if (Math.Abs(moveCenterVector.X) > (maxRect.Width - boundRect.Width) / 2) { double moveLength = maxRectCenterPos.X - boundRectCenterPos.X; moveOffsetPos.X = Math.Abs(moveLength) - (maxRect.Width - boundRect.Width) / 2; if (moveLength < 0) { moveOffsetPos.X *= -1; } } if (Math.Abs(moveCenterVector.Y) > (maxRect.Height - boundRect.Height) / 2) { double moveLength = maxRectCenterPos.Y - boundRectCenterPos.Y; moveOffsetPos.Y = Math.Abs(moveLength) - (maxRect.Height - boundRect.Height) / 2; if (moveLength < 0) { moveOffsetPos.Y *= -1; } } drawRect = new Rect(tmpRect.Left + moveOffsetPos.X, tmpRect.Top + moveOffsetPos.Y, tmpRect.Width, tmpRect.Height); } } moveOffset = new Point(drawRect.X - cacheRect.X, drawRect.Y - cacheRect.Y); return true; } private Point GetRotateUIPoint(Point point) { Point centerPoint = new Point((rotateRect.Left + rotateRect.Right) / 2, (rotateRect.Top + rotateRect.Bottom) / 2); Matrix rotateMatrix = new Matrix(); rotateMatrix.RotateAt(rotateAngle, centerPoint.X, centerPoint.Y); return rotateMatrix.Transform(point); } /// /// Provisional logic, to be further improved, not yet used: Draw the algorithm in the form of normal scaling (drag a point, only scale in one direction). /// /// Current mouse position. /// protected bool OutSideScaling(Point mousePoint) { try { double left = 0, right = 0, top = 0, bottom = 0; double minHeight = RectMinHeight + 2 * rectPadding * currentZoom; double minWidth = RectMinWidth + 2 * rectPadding * currentZoom; 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: { left = centerPoint.X + moveVector.X; right = cacheRect.Right; top = centerPoint.Y + moveVector.Y; bottom = cacheRect.Bottom; if (isProportionalScaling) { Size size = GetProportionalScalingSize(right - left, bottom - top); left = right - size.Width; top = bottom - size.Height; if (left < maxRect.Left) { double tmpWidth = right - left; left = maxRect.Left; double width = right - left; double height = (bottom - top) * width / tmpWidth; top = bottom - height; } if (top < maxRect.Top) { double tmpHeight = bottom - top; top = maxRect.Top; double height = bottom - top; double width = (right - left) * height / tmpHeight; left = right - width; } } else { if (left + minWidth > right) { left = right - minWidth; } if (top + minHeight > bottom) { top = bottom - minHeight; } } } break; case PointControlType.LeftMiddle: { left = centerPoint.X + moveVector.X; right = cacheRect.Right; top = cacheRect.Top; bottom = cacheRect.Bottom; if (left + minWidth > right) { left = right - minWidth; } } break; case PointControlType.LeftBottom: { left = centerPoint.X + moveVector.X; right = cacheRect.Right; top = cacheRect.Top; bottom = centerPoint.Y + moveVector.Y; if (isProportionalScaling) { Size size = GetProportionalScalingSize(right - left, bottom - top); left = right - size.Width; bottom = top + size.Height; if (left < maxRect.Left) { double tmpWidth = right - left; left = maxRect.Left; double width = right - left; double height = (bottom - top) * width / tmpWidth; bottom = top + height; } if (bottom > maxRect.Bottom) { double tmpHeight = bottom - top; bottom = maxRect.Bottom; double height = bottom - top; double width = (right - left) * height / tmpHeight; left = right - width; } } else { if (left + minWidth > right) { left = right - minWidth; } if (top + minHeight > bottom) { bottom = top + minHeight; } } } break; case PointControlType.MiddleBottom: { left = cacheRect.Left; right = cacheRect.Right; top = cacheRect.Top; bottom = centerPoint.Y + moveVector.Y; if (top + minHeight > bottom) { bottom = top + minHeight; } } break; case PointControlType.RightBottom: { left = cacheRect.Left; right = centerPoint.X + moveVector.X; top = cacheRect.Top; bottom = centerPoint.Y + moveVector.Y; if (isProportionalScaling) { Size size = GetProportionalScalingSize(right - left, bottom - top); right = left + size.Width; bottom = top + size.Height; if (right > maxRect.Right) { double tmpWidth = right - left; right = maxRect.Right; double width = right - left; double height = (bottom - top) * width / tmpWidth; bottom = top + height; } if (bottom > maxRect.Bottom) { double tmpHeight = bottom - top; bottom = maxRect.Bottom; double height = bottom - top; double width = (right - left) * height / tmpHeight; right = left + width; } } else { if (left + minWidth > right) { right = left + minWidth; } if (top + minHeight > bottom) { bottom = top + minHeight; } } } break; case PointControlType.RightMiddle: { left = cacheRect.Left; right = centerPoint.X + moveVector.X; top = cacheRect.Top; bottom = cacheRect.Bottom; if (left + minWidth > right) { right = left + minWidth; } } break; case PointControlType.RightTop: { left = cacheRect.Left; right = centerPoint.X + moveVector.X; top = centerPoint.Y + moveVector.Y; bottom = cacheRect.Bottom; if (isProportionalScaling) { Size size = GetProportionalScalingSize(right - left, bottom - top); right = left + size.Width; top = bottom - size.Height; if (right > maxRect.Right) { double tmpWidth = right - left; right = maxRect.Right; double width = right - left; double height = (bottom - top) * width / tmpWidth; top = bottom - height; } if (top < maxRect.Top) { double tmpHeight = bottom - top; top = maxRect.Top; double height = bottom - top; double width = (right - left) * height / tmpHeight; right = left + width; } } else { if (left + minWidth > right) { right = left + minWidth; } if (top + minHeight > bottom) { top = bottom - minHeight; } } } break; case PointControlType.MiddleTop: { left = cacheRect.Left; right = cacheRect.Right; top = centerPoint.Y + moveVector.Y; bottom = cacheRect.Bottom; if (top + minHeight > bottom) { top = bottom - minHeight; } } break; case PointControlType.Body: case PointControlType.Line: { double newleft = maxRect.Left - SetDrawRect.Width + 10; double newright = maxRect.Right + SetDrawRect.Width - 10; double newtop = maxRect.Top - SetDrawRect.Height + 10; double newbottom = maxRect.Bottom + SetDrawRect.Height - 10; if (newleft < 0) { newleft = 0; } Rect newMaxRect = new Rect(newleft, newtop, newright - newleft, newbottom - newtop); Point OffsetPos = CalcMoveBound(cacheRect, ((Point)(mousePoint - mouseDownPoint)), newMaxRect); left = cacheRect.Left + OffsetPos.X; right = cacheRect.Right + OffsetPos.X; top = cacheRect.Top + OffsetPos.Y; bottom = cacheRect.Bottom + OffsetPos.Y; } break; default: break; } //if (left < maxRect.Left) //{ // left = maxRect.Left; //} //if (top < maxRect.Top) //{ // top = maxRect.Top; //} if (right > maxRect.Right + SetDrawRect.Width - 10) { if (left > maxRect.Right - 10) { left = maxRect.Right - 10; } right = maxRect.Right + SetDrawRect.Width - 10; } if (bottom > maxRect.Bottom + SetDrawRect.Height - 10) { if (top > maxRect.Bottom - 10) { top = maxRect.Bottom - 10; } bottom = maxRect.Bottom + SetDrawRect.Height - 10; } drawRect = new Rect(left, top, right - left, bottom - top); moveOffset = new Point(drawRect.X - cacheRect.X, drawRect.Y - cacheRect.Y); return true; } catch (Exception ex) { } return false; } /// /// Proportional scaling offset calibration /// /// /// The current movement point /// /// /// The offset point after the proportional scaling /// 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; } } /// /// Inner drawing circle point /// /// /// Drawing context /// /// /// Collection of positions that need to be drawn /// /// /// Size of the point /// /// /// Brush for drawing points /// /// /// 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 that need to be drawn /// /// /// Size of the point /// /// /// Brush for drawing points /// /// /// Border brush for drawing points /// protected void DrawSquarePoint(DrawingContext drawingContext, List ignoreList, int PointSize, Pen PointPen, SolidColorBrush BorderBrush) { RotateTransform rotateTransform = new RotateTransform(rotateAngle, centerPoint.X, centerPoint.Y); if (canRotate && !isInScaling) { Point currentRotationPoint = isInRotate ? dragRotationPoint : rotationPoint; double angleInRadians = rotateAngle * (Math.PI / 180); double sinValue = Math.Sin(angleInRadians); double cosValue = Math.Cos(angleInRadians); double rotatedX = 0; double rotatedY = 0; switch (pageRotation) { case 0: rotatedX = currentRotationPoint.X - pointSize * sinValue; rotatedY = currentRotationPoint.Y + pointSize * cosValue; break; case 1: rotatedX = currentRotationPoint.X - pointSize * cosValue; rotatedY = currentRotationPoint.Y + pointSize * sinValue; break; case 2: rotatedX = currentRotationPoint.X + pointSize * sinValue; rotatedY = currentRotationPoint.Y - pointSize * cosValue; break; case 3: rotatedX = currentRotationPoint.X + pointSize * sinValue; rotatedY = currentRotationPoint.Y - pointSize * cosValue; break; default: break; } GeometryGroup rotateGroup = new GeometryGroup(); LineGeometry moveLineGeometry = new LineGeometry(centerPoint, new Point(rotatedX, rotatedY)); EllipseGeometry ellipseGeometry = new EllipseGeometry(currentRotationPoint, PointSize, pointSize); rotateGroup.Children.Add(moveLineGeometry); rotateGroup.Children.Add(ellipseGeometry); if (!isInRotate) { rotateGroup.Children.Remove(moveLineGeometry); LineGeometry stopLineGeometry = new LineGeometry(centerPoint, new Point(currentRotationPoint.X, currentRotationPoint.Y + pointSize)); switch (pageRotation) { case 0: stopLineGeometry = new LineGeometry(centerPoint, new Point(currentRotationPoint.X, currentRotationPoint.Y + pointSize)); break; case 1: stopLineGeometry = new LineGeometry(centerPoint, new Point(currentRotationPoint.X - pointSize, currentRotationPoint.Y )); break; case 2: stopLineGeometry = new LineGeometry(centerPoint, new Point(currentRotationPoint.X, currentRotationPoint.Y - pointSize)); break; case 3: stopLineGeometry = new LineGeometry(centerPoint, new Point(currentRotationPoint.X + pointSize, currentRotationPoint.Y)); break; default: break; } rotateGroup.Children.Add(stopLineGeometry); drawingContext.PushTransform(rotateTransform); } drawingContext?.DrawGeometry(BorderBrush, PointPen, rotateGroup); if (!isInRotate) { drawingContext.Pop(); } } if (!isInRotate) { 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.PushTransform(rotateTransform); drawingContext?.DrawGeometry(BorderBrush, PointPen, controlGroup); drawingContext.Pop(); } } protected void DrawCropPoint(DrawingContext drawingContext, List ignoreList, int PointSize, Pen PointPen, SolidColorBrush BorderBrush) { //GeometryGroup controlGroup = new GeometryGroup(); //controlGroup.FillRule = FillRule.Nonzero; clipThickness.Left = (SetDrawRect.Left - drawRect.Left) / currentZoom; clipThickness.Top = (SetDrawRect.Top - drawRect.Top) / currentZoom; clipThickness.Right = (SetDrawRect.Right - drawRect.Right) / currentZoom; clipThickness.Bottom = (SetDrawRect.Bottom - drawRect.Bottom) / currentZoom; List controlCurrentPoints = GetControlPoint(drawRect); CombinedGeometry controlGroup = new CombinedGeometry(); RectangleGeometry paintGeometry = new RectangleGeometry(); paintGeometry.Rect = SetDrawRect; controlGroup.Geometry1 = paintGeometry; RectangleGeometry moveGeometry = new RectangleGeometry(); Rect clippedBorder = drawRect; if (clippedBorder.IsEmpty == false) { moveGeometry.Rect = drawRect; } controlGroup.Geometry2 = moveGeometry; controlGroup.GeometryCombineMode = GeometryCombineMode.Exclude; //Left Top Corner if (!ignoreList.Contains(PointControlType.LeftTop)) { drawingContext?.DrawRectangle(BorderBrush, null, new Rect(controlCurrentPoints[0].X - PointSize, controlCurrentPoints[0].Y - PointSize, PointSize, PointSize * 4)); drawingContext?.DrawRectangle(BorderBrush, null, new Rect(controlCurrentPoints[0].X - PointSize, controlCurrentPoints[0].Y - PointSize, PointSize * 4, PointSize)); } //Left Center if (!ignoreList.Contains(PointControlType.LeftMiddle)) { drawingContext?.DrawRectangle(BorderBrush, null, new Rect(controlCurrentPoints[1].X - PointSize, (controlCurrentPoints[1].Y + controlCurrentPoints[1].Y - PointSize * 5) / 2, PointSize, PointSize * 5)); } //Left Bottom Corner if (!ignoreList.Contains(PointControlType.LeftBottom)) { drawingContext?.DrawRectangle(BorderBrush, null, new Rect(controlCurrentPoints[2].X - PointSize, controlCurrentPoints[2].Y - PointSize * 3, PointSize, PointSize * 4)); drawingContext?.DrawRectangle(BorderBrush, null, new Rect(controlCurrentPoints[2].X - PointSize, controlCurrentPoints[2].Y, PointSize * 4, PointSize)); } //Bottom Center if (!ignoreList.Contains(PointControlType.MiddleBottom)) { drawingContext?.DrawRectangle(BorderBrush, null, new Rect((controlCurrentPoints[3].X + controlCurrentPoints[3].X - PointSize * 5) / 2, controlCurrentPoints[3].Y, PointSize * 5, PointSize)); } //Bottom Right Corner if (!ignoreList.Contains(PointControlType.RightBottom)) { drawingContext?.DrawRectangle(BorderBrush, null, new Rect(controlCurrentPoints[4].X, controlCurrentPoints[4].Y - PointSize * 3, PointSize, PointSize * 4)); drawingContext?.DrawRectangle(BorderBrush, null, new Rect(controlCurrentPoints[4].X - PointSize * 3, controlCurrentPoints[4].Y, PointSize * 4, PointSize)); } //Right Center if (!ignoreList.Contains(PointControlType.RightMiddle)) { drawingContext?.DrawRectangle(BorderBrush, null, new Rect(controlCurrentPoints[5].X, (controlCurrentPoints[5].Y + controlCurrentPoints[5].Y - PointSize * 5) / 2, PointSize, PointSize * 5)); } //Right Top Corner if (!ignoreList.Contains(PointControlType.RightTop)) { drawingContext?.DrawRectangle(BorderBrush, null, new Rect(controlCurrentPoints[6].X, controlCurrentPoints[6].Y - PointSize, PointSize, PointSize * 4)); drawingContext?.DrawRectangle(BorderBrush, null, new Rect(controlCurrentPoints[6].X - PointSize * 4, controlCurrentPoints[6].Y - PointSize, PointSize * 4, PointSize)); } //Top Center if (!ignoreList.Contains(PointControlType.MiddleTop)) { drawingContext?.DrawRectangle(BorderBrush, null, new Rect((controlCurrentPoints[7].X + controlCurrentPoints[7].X - PointSize * 5) / 2, controlCurrentPoints[7].Y - PointSize, PointSize * 5, PointSize)); } BorderBrush = new SolidColorBrush(Color.FromArgb(0x3F, 0x00, 0x00, 0x00)); drawingContext?.DrawGeometry(BorderBrush, PointPen, controlGroup); } /// /// Draw the reference line in the moving state /// /// /// Draw context handle /// /// /// Current selected control point type /// /// /// Brush for drawing lines /// /// /// Brush for drawing rectangles /// /// /// Current rectangle to draw /// protected void DrawMoveBounds(DrawingContext drawDc, PointControlType controltype, Pen activePen, Brush moveBrush, Rect moveRect, Pen RectPen = null) { 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: drawDc?.DrawLine(activePen, new Point(0, moveRect.Top), new Point(moveRect.Left, moveRect.Top)); drawDc?.DrawLine(activePen, new Point(moveRect.Right, moveRect.Top), new Point(PDFViewerActualWidth, moveRect.Top)); drawDc?.DrawLine(activePen, new Point(moveRect.Left, moveRect.Top), new Point(moveRect.Left, 0)); drawDc?.DrawLine(activePen, new Point(moveRect.Right, moveRect.Top), new Point(moveRect.Right, 0)); drawDc?.DrawLine(activePen, new Point(0, moveRect.Bottom), new Point(moveRect.Left, moveRect.Bottom)); drawDc?.DrawLine(activePen, new Point(moveRect.Right, moveRect.Bottom), new Point(PDFViewerActualWidth, moveRect.Bottom)); drawDc?.DrawLine(activePen, new Point(moveRect.Left, moveRect.Bottom), new Point(moveRect.Left, PDFViewerActualHeight)); drawDc?.DrawLine(activePen, new Point(moveRect.Right, moveRect.Bottom), new Point(moveRect.Right, PDFViewerActualHeight)); break; case PointControlType.Body: case PointControlType.Line: drawDc?.DrawLine(activePen, new Point(0, moveRect.Top), new Point(moveRect.Left, moveRect.Top)); drawDc?.DrawLine(activePen, new Point(moveRect.Right, moveRect.Top), new Point(PDFViewerActualWidth, moveRect.Top)); drawDc?.DrawLine(activePen, new Point(moveRect.Left, moveRect.Top), new Point(moveRect.Left, 0)); drawDc?.DrawLine(activePen, new Point(moveRect.Right, moveRect.Top), new Point(moveRect.Right, 0)); drawDc?.DrawLine(activePen, new Point(0, moveRect.Bottom), new Point(moveRect.Left, moveRect.Bottom)); drawDc?.DrawLine(activePen, new Point(moveRect.Right, moveRect.Bottom), new Point(PDFViewerActualWidth, moveRect.Bottom)); drawDc?.DrawLine(activePen, new Point(moveRect.Left, moveRect.Bottom), new Point(moveRect.Left, PDFViewerActualHeight)); drawDc?.DrawLine(activePen, new Point(moveRect.Right, moveRect.Bottom), new Point(moveRect.Right, PDFViewerActualHeight)); break; default: break; } drawDc?.DrawRectangle(moveBrush, RectPen, moveRect); } /// /// Notify the event during/after the drawing data /// /// /// Identifies whether the data change is complete /// protected void InvokeDataChangEvent(bool isFinish) { selectedRectData.Square = GetRect(); selectedRectData.rotationAngle = rotateAngle; if (isFinish) { DataChanged?.Invoke(this, selectedRectData); } else { DataChanging?.Invoke(this, selectedRectData); } } /// /// Align the rectangle drawing /// /// /// Move distance required for the aligned algorithm to obtain the rectangle /// private void DrawAlignRect(Point RectMovePoint) { double TmpLeft, TmpRight, TmpUp, TmpDown; Point OffsetPos = CalcMoveBound(drawRect, RectMovePoint, maxRect); TmpLeft = drawRect.Left + OffsetPos.X; TmpRight = drawRect.Right + OffsetPos.X; TmpUp = drawRect.Top + OffsetPos.Y; TmpDown = drawRect.Bottom + OffsetPos.Y; SetDrawRect = drawRect = new Rect(TmpLeft, TmpUp, TmpRight - TmpLeft, TmpDown - TmpUp); Draw(); } /// /// Get the current set of ignore points /// /// /// Data set of ignored points /// private List GetIgnorePoints() { List IgnorePointsList = new List(); foreach (PointControlType type in ignorePoints) { IgnorePointsList.Add(type); } return IgnorePointsList; } #endregion } }