using PaintDotNet.Annotation.Enum; using PaintDotNet.Base.CommTool; using System; using System.Collections.Generic; using System.Drawing; using System.Drawing.Drawing2D; using System.Windows.Forms; /* * 视场, * 全部图形构成基于点阵(Points)拟合. * 图形变换,对外属性均依赖于点阵的换算. * 点阵集合继承DrawObject 的 pointArrayList 字段 * 全部接口数值皆为原始数值并未进行缩放处理. */ namespace PaintDotNet.Annotation.FieldView { public abstract class ViewBase : DrawObject { /// /// 鼠标形状 /// public static Cursor m_rotateCursor = new Cursor(PdnResources.GetResourceStream("Cursors.AnnotationRotateHandle.cur")); public static Cursor m_resizeCursor = new Cursor(PdnResources.GetResourceStream("Cursors.AnnotationResizeHandle.cur")); public override double Width { get => Rectangle.Width; set { } } public override double Height { get => Rectangle.Height; set { } } #region Points public virtual List Points { get { if (pointArrayList == null) pointArrayList = new List(); return pointArrayList; } set { pointArrayList = new List(); foreach (var p in value) { pointArrayList.Add(p); } } } public void AddPoint(int x, int y) { AddPoint(new PointF(x, y)); } protected void AddPoint(PointF point) { Points.Add(point); } public override List GetPoints() { return Points; } #endregion #region Bounding Rectangle public override RectangleF Rectangle { get { return GetBoundingBox(); } } /// /// 外接矩形 /// public override RectangleF GetBoundingBox() { float minx = 0, maxx = 0, miny = 0, maxy = 0; for (int i = 0; i < Points.Count; i++) { if (i == 0) { minx = maxx = Points[i].X; miny = maxy = Points[i].Y; } else { if (Points[i].X > maxx) maxx = Points[i].X; if (Points[i].X < minx) minx = Points[i].X; if (Points[i].Y > maxy) maxy = Points[i].Y; if (Points[i].Y < miny) miny = Points[i].Y; } } return new RectangleF(minx, miny, maxx - minx, maxy - miny); } #endregion #region Draw /// /// 指定如何组合不同的剪辑区域 /// 用于存储是合并视场、还是剪切视场 /// public CombineMode combineMode; /// /// Draw rectangle /// /// public override void Draw(Graphics g) { Region reg = g.Clip; ViewBase view = null; for (int i = ISurfaceBox.GraphicsList.Count - 1; ;) { if (ISurfaceBox.GraphicsList[i].objectType == DrawClass.View) { view = (ViewBase)ISurfaceBox.GraphicsList[i]; if (view.combineMode == CombineMode.Union) { break; } } i--; if (i < 0) { view.combineMode = CombineMode.Union; break; } } //获取所有合并的视场 Region union = GetUnionOrDeleteView(CombineMode.Union); //获取所有删除的视场 Region delete = GetUnionOrDeleteView(CombineMode.Complement); if (union != null) { reg.Xor(union); } if (delete != null) { reg.Union(delete); } SolidBrush sb = new SolidBrush(Color.FromArgb(180, 0, 0, 0)); g.FillRegion(sb, reg); } /// /// 获取所有合并或删除的视场 /// /// private Region GetUnionOrDeleteView(CombineMode combineMode) { Region region = null; if (ISurfaceBox.GraphicsList != null && ISurfaceBox.GraphicsList.Count > 0) { for (int i = 0; i < ISurfaceBox.GraphicsList.Count; i++) { if (ISurfaceBox.GraphicsList[i].objectType == DrawClass.View) { ViewBase view = (ViewBase)ISurfaceBox.GraphicsList[i]; GraphicsPath path = new GraphicsPath(); switch (view.drawToolType) { case DrawToolType.ViewOval: path.AddClosedCurve(ISurfaceBox.GraphicsList[i].GetPoints().ToArray()); break; case DrawToolType.ViewCircle: path.AddEllipse(ISurfaceBox.GraphicsList[i].Rectangle); break; case DrawToolType.ViewSquare: case DrawToolType.ViewRectangle: case DrawToolType.ViewTriangle: case DrawToolType.ViewPolygon: case DrawToolType.ViewTriangleEx: case DrawToolType.ViewRectangleEx: if ((ISurfaceBox.GraphicsList[i]).GetPoints().Count > 2) { path.AddPolygon((ISurfaceBox.GraphicsList[i]).GetPoints().ToArray()); } break; } if (view.combineMode == combineMode) { if (region == null) region = new Region(path); else region.Union(path); } } } } return region; } public override void DrawTracker(Graphics g) { if (!Selected) return; SolidBrush brush = new SolidBrush(Color.FromArgb(184, Color.Black)); var pen = new Pen(Color.FromArgb(0, 148, 255)); switch (drawToolType) { case DrawToolType.ViewOval: g.DrawClosedCurve(pen, GetPoints().ToArray()); break; case DrawToolType.ViewCircle: g.DrawEllipse(pen, Rectangle); break; case DrawToolType.ViewSquare: case DrawToolType.ViewRectangle: case DrawToolType.ViewTriangle: case DrawToolType.ViewPolygon: case DrawToolType.ViewTriangleEx: case DrawToolType.ViewRectangleEx: if (GetPoints().Count > 2) { g.DrawPolygon(pen, GetPoints().ToArray()); } break; } if (Rotatable && Points.Count > 2) { for (int i = 1; i <= HandleCount - 1; i++) { g.FillRectangle(brush, GetHandleRectangle(i)); g.DrawRectangle(pen, GetHandleRectangle(i)); } brush = new SolidBrush(Color.Red); g.FillEllipse(brush, GetHandleRectangle(HandleCount)); brush.Dispose(); } else { for (int i = 1; i <= HandleCount; i++) { g.FillRectangle(brush, GetHandleRectangle(i)); g.DrawRectangle(pen, GetHandleRectangle(i)); } } } #endregion #region Rotate protected PointF _lastPoint; protected PointF _lastCenter; protected bool _isRotating; /// /// 设置可旋转性,用于显示旋转Handle /// public bool Rotatable = false; /// /// 图形斜率,用于旋转 /// public double K { get; set; } = 0; public virtual void SetK() { } public virtual PointF Center { get { var centerX = Rectangle.X + Math.Abs(Rectangle.Width / 2); var centerY = Rectangle.Y + Math.Abs(Rectangle.Height / 2); return new PointF(centerX, centerY); } set { } } protected virtual void StartRotate() { _isRotating = true; _lastCenter = Center; } protected virtual void EndRotate() { _isRotating = false; SetK(); } protected virtual void MoveRotate(PointF point) { if (!_isRotating) { StartRotate(); _lastPoint = point; } double angle = BasicCalculationHelper.CalculateAngle(_lastCenter.X, _lastCenter.Y, _lastPoint.X, _lastPoint.Y, point.X, point.Y); _lastPoint = point; for (int i = 0; i < Points.Count; i++) { Points[i] = BasicCalculationHelper.GetAnglePoint(Points[i], _lastCenter, angle); } } /// /// 标准化外接矩形 /// public override void Normalize() { Console.WriteLine("Normalize"); if (_isRotating) EndRotate(); } #endregion #region Select /// /// Hit test. /// Return value: -1 - no hit /// 0 - hit anywhere /// > 1 - handle number /// /// /// public override int HitTest(Point point) { if (Selected) { for (int i = 1; i <= HandleCount; i++) { if (GetHandleRectangle(i).Contains(point)) return i; } } if (PointInObject(point)) return 0; return -1; } protected override bool PointInObject(Point point) { int counter = 0; int i; double xinters; PointF p1, p2; int pointCount = Points.Count; p1 = Points[0]; for (i = 1; i <= pointCount; i++) { p2 = Points[i % pointCount]; if (point.Y > Math.Min(p1.Y, p2.Y)//校验点的Y大于线段端点的最小Y && point.Y <= Math.Max(p1.Y, p2.Y))//校验点的Y小于线段端点的最大Y { if (point.X <= Math.Max(p1.X, p2.X))//校验点的X小于等线段端点的最大X(使用校验点的左射线判断). { if (p1.Y != p2.Y)//线段不平行于X轴 { xinters = (point.Y - p1.Y) * (p2.X - p1.X) / (p2.Y - p1.Y) + p1.X; if (p1.X == p2.X || point.X <= xinters) { counter++; } } } } p1 = p2; } return counter % 2 != 0; } public override bool IntersectsWith(Rectangle rectangle) { return Rectangle.IntersectsWith(rectangle); } #endregion public override void Move(int x, int y) { for (int i = 0; i < Points.Count; i++) { PointF p = Points[i]; p.X += x; p.Y += y; Points[i] = p; } OnPropertyChanged(); } /// /// 获取视场面积 /// /// public virtual double Getacreage() { var count = Points.Count; double area0 = 0; double area1 = 0; for (int i = 0; i < count; i++) { var x = Points[i].X; var y = i + 1 < count ? Points[i + 1].Y : Points[0].Y; area0 += x * y; x = Points[i].Y; y = i + 1 < count ? Points[i + 1].X : Points[0].X; area1 += x * y; } return Math.Abs(0.5 * (area0 - area1)); } } }