From 52368af65b3306e749dc4f0436742d2d95387913 Mon Sep 17 00:00:00 2001 From: kriastans Date: Thu, 15 Aug 2024 22:01:54 +0800 Subject: [PATCH] =?UTF-8?q?[update]=20=E5=BD=A2=E7=8A=B6=E7=BB=98=E5=88=B6?= =?UTF-8?q?=EF=BC=8C=E5=A2=A8=E8=BF=B9=E7=A6=BB=E5=B1=8F=E5=81=9C=E6=AD=A2?= =?UTF-8?q?=E6=B8=B2=E6=9F=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../MainWindow_cs/MW_InkCanvas.cs | 68 ++++++++++++++++--- .../MainWindow_cs/MW_ShapeDrawingCore.cs | 26 ++++++- .../MW_ShapeDrawingLayer.xaml.cs | 4 +- 3 files changed, 84 insertions(+), 14 deletions(-) diff --git a/InkCanvasForClass/MainWindow_cs/MW_InkCanvas.cs b/InkCanvasForClass/MainWindow_cs/MW_InkCanvas.cs index 23e7b4e..14b37e1 100644 --- a/InkCanvasForClass/MainWindow_cs/MW_InkCanvas.cs +++ b/InkCanvasForClass/MainWindow_cs/MW_InkCanvas.cs @@ -17,6 +17,13 @@ namespace Ink_Canvas { public IccStroke(StylusPointCollection stylusPoints, DrawingAttributes drawingAttributes) : base(stylusPoints, drawingAttributes) { } + public IccStroke(StylusPointCollection stylusPoints, DrawingAttributes drawingAttributes, IccInkCanvas hostElement) + : base(stylusPoints, drawingAttributes) { + if (hostElement != null) _hostInkCanvas = hostElement; + } + + public IccInkCanvas _hostInkCanvas = null; + public static Guid StrokeShapeTypeGuid = new Guid("6537b29c-557f-487f-800b-cb30a8f1de78"); public static Guid StrokeIsShapeGuid = new Guid("40eff5db-9346-4e42-bd46-7b0eb19d0018"); @@ -25,9 +32,32 @@ namespace Ink_Canvas { public MainWindow.ShapeDrawingHelper.ArrowLineConfig ArrowLineConfig { get; set; } = new MainWindow.ShapeDrawingHelper.ArrowLineConfig(); + /// + /// 根据这个属性判断当前 Stroke 是否是原始输入 + /// + public bool IsRawStylusPoints = true; + + /// + /// 根据这个属性决定在绘制 Stroke 时是否需要在直线形状中,在两点构成直线上分布点,用于墨迹的范围框选。 + /// + public bool IsDistributePointsOnLineShape = true; + + /// + /// 指示该墨迹是否来自一个完整墨迹被擦除后的一部分墨迹,仅用于形状墨迹。 + /// + public bool IsErasedStrokePart = false; + + /// + /// 指示当墨迹在屏幕外部时,是否停止渲染 + /// + public bool IsStopOffScreenRender = true; + // 自定义的墨迹渲染 protected override void DrawCore(DrawingContext drawingContext, DrawingAttributes drawingAttributes) { + + if (IsStopOffScreenRender && new StrokeCollection(){this}.HitTest(new Rect(new Point(0,0), new Size(_hostInkCanvas.ActualWidth,_hostInkCanvas.ActualHeight)), 1).Count == 0) return; + if (!(this.ContainsPropertyData(StrokeIsShapeGuid) && (bool)this.GetPropertyData(StrokeIsShapeGuid) == true)) { base.DrawCore(drawingContext, drawingAttributes); @@ -43,8 +73,20 @@ namespace Ink_Canvas { base.DrawCore(drawingContext, drawingAttributes); return; } - StreamGeometry geometry = new StreamGeometry(); + var pts = new List(this.StylusPoints.ToPoints()); + if (IsDistributePointsOnLineShape && ( + (int)this.GetPropertyData(StrokeShapeTypeGuid) == (int)MainWindow.ShapeDrawingType.DashedLine || + (int)this.GetPropertyData(StrokeShapeTypeGuid) == (int)MainWindow.ShapeDrawingType.Line || + (int)this.GetPropertyData(StrokeShapeTypeGuid) == (int)MainWindow.ShapeDrawingType.DottedLine) && IsRawStylusPoints) { + IsRawStylusPoints = false; + RawStylusPointCollection = StylusPoints.Clone(); + var pointList = new List { new Point(StylusPoints[0].X, StylusPoints[0].Y) }; + pointList.AddRange(MainWindow.ShapeDrawingHelper.DistributePointsOnLine(new Point(StylusPoints[0].X, StylusPoints[0].Y),new Point(StylusPoints[1].X, StylusPoints[1].Y))); + pointList.Add(new Point(StylusPoints[1].X, StylusPoints[1].Y)); + StylusPoints = new StylusPointCollection(pointList); + } + StreamGeometry geometry = new StreamGeometry(); using (StreamGeometryContext ctx = geometry.Open()) { ctx.BeginFigure(pts[0], false , false); pts.RemoveAt(0); @@ -61,7 +103,8 @@ namespace Ink_Canvas { (int)this.GetPropertyData(StrokeShapeTypeGuid) != (int)MainWindow.ShapeDrawingType.ArrowTwoSide) pen.DashStyle = (int)this.GetPropertyData(StrokeShapeTypeGuid) == (int)MainWindow.ShapeDrawingType.DottedLine ? DashStyles.Dot : DashStyles.Dash; - if ((int)this.GetPropertyData(StrokeShapeTypeGuid) == (int)MainWindow.ShapeDrawingType.ArrowOneSide) { + if ((int)this.GetPropertyData(StrokeShapeTypeGuid) == (int)MainWindow.ShapeDrawingType.ArrowOneSide && IsRawStylusPoints) { + IsRawStylusPoints = false; pts = new List(this.StylusPoints.ToPoints()); RawStylusPointCollection = StylusPoints.Clone(); double w = ArrowLineConfig.ArrowWidth, h = ArrowLineConfig.ArrowHeight; @@ -70,11 +113,14 @@ namespace Ink_Canvas { var cost = Math.Cos(theta); var pointList = new List { new Point(pts[0].X, pts[0].Y), + }; + if (IsDistributePointsOnLineShape) pointList.AddRange(MainWindow.ShapeDrawingHelper.DistributePointsOnLine(new Point(pts[0].X, pts[0].Y),new Point(pts[1].X, pts[1].Y))); + pointList.AddRange(new List { new Point(pts[1].X, pts[1].Y), new Point(pts[1].X + (w * cost - h * sint), pts[1].Y + (w * sint + h * cost)), new Point(pts[1].X, pts[1].Y), new Point(pts[1].X + (w * cost + h * sint), pts[1].Y - (h * cost - w * sint)), - }; + }); StylusPoints = new StylusPointCollection(pointList); var _pts = new List(this.StylusPoints.ToPoints()); using (StreamGeometryContext ctx = geometry.Open()) { @@ -121,14 +167,16 @@ namespace Ink_Canvas { })); } - protected override void OnStrokeCollected(InkCanvasStrokeCollectedEventArgs e) - { - // Remove the original stroke and add a custom stroke. - this.Strokes.Remove(e.Stroke); - IccStroke customStroke = new IccStroke(e.Stroke.StylusPoints, e.Stroke.DrawingAttributes); - this.Strokes.Add(customStroke); + protected override void OnStrokeCollected(InkCanvasStrokeCollectedEventArgs e) { + IccStroke customStroke = new IccStroke(e.Stroke.StylusPoints, e.Stroke.DrawingAttributes, this); + if (e.Stroke is IccStroke) { + if ((e.Stroke as IccStroke)._hostInkCanvas == null) (e.Stroke as IccStroke)._hostInkCanvas = this; + this.Strokes.Add(e.Stroke); + } else { + this.Strokes.Remove(e.Stroke); + this.Strokes.Add(customStroke); + } - // Pass the custom stroke to base class' OnStrokeCollected method. InkCanvasStrokeCollectedEventArgs args = new InkCanvasStrokeCollectedEventArgs(customStroke); base.OnStrokeCollected(args); diff --git a/InkCanvasForClass/MainWindow_cs/MW_ShapeDrawingCore.cs b/InkCanvasForClass/MainWindow_cs/MW_ShapeDrawingCore.cs index b153e01..5fa1f3d 100644 --- a/InkCanvasForClass/MainWindow_cs/MW_ShapeDrawingCore.cs +++ b/InkCanvasForClass/MainWindow_cs/MW_ShapeDrawingCore.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Windows; using System.Windows.Ink; using System.Windows.Input; @@ -8,7 +9,7 @@ namespace Ink_Canvas { public partial class MainWindow : Window { - public StrokeCollection DrawShapeCore(PointCollection pts, ShapeDrawingType type) { + public StrokeCollection DrawShapeCore(PointCollection pts, ShapeDrawingType type, bool doNotDisturbutePoints) { // 线 if (type == MainWindow.ShapeDrawingType.Line || type == MainWindow.ShapeDrawingType.DashedLine || @@ -19,7 +20,9 @@ namespace Ink_Canvas { var stk = new IccStroke(new StylusPointCollection() { new StylusPoint(pts[0].X, pts[0].Y), new StylusPoint(pts[1].X, pts[1].Y), - }, inkCanvas.DefaultDrawingAttributes.Clone()); + }, inkCanvas.DefaultDrawingAttributes.Clone()) { + IsDistributePointsOnLineShape = !doNotDisturbutePoints + }; stk.AddPropertyData(IccStroke.StrokeIsShapeGuid, true); stk.AddPropertyData(IccStroke.StrokeShapeTypeGuid, (int)type); return new StrokeCollection() { stk }; @@ -51,6 +54,25 @@ namespace Ink_Canvas { return rotateAngle; } + + public static List DistributePointsOnLine(Point start, Point end, double interval=16) { + List points = new List(); + + double dx = end.X - start.X; + double dy = end.Y - start.Y; + double distance = Math.Sqrt(dx * dx + dy * dy); + int numPoints = (int)(distance / interval); + + for (int i = 0; i <= numPoints; i++) { + double ratio = (interval * i) / distance; + double x = start.X + ratio * dx; + double y = start.Y + ratio * dy; + points.Add(new Point(x, y)); + } + + return points; + } + public class ArrowLineConfig { public int ArrowWidth { get; set; } = 20; public int ArrowHeight { get; set; } = 7; diff --git a/InkCanvasForClass/MainWindow_cs/MW_ShapeDrawingLayer.xaml.cs b/InkCanvasForClass/MainWindow_cs/MW_ShapeDrawingLayer.xaml.cs index 11517cb..ddca00d 100644 --- a/InkCanvasForClass/MainWindow_cs/MW_ShapeDrawingLayer.xaml.cs +++ b/InkCanvasForClass/MainWindow_cs/MW_ShapeDrawingLayer.xaml.cs @@ -163,7 +163,7 @@ namespace Ink_Canvas { using (DrawingContext dc = DrawingVisualCanvas.DrawingVisual.RenderOpen()) {} if (points.Count >= 2) - MainWindow.inkCanvas.Strokes.Add(MainWindow.DrawShapeCore(points, (MainWindow.ShapeDrawingType)_shapeType)); + MainWindow.inkCanvas.Strokes.Add(MainWindow.DrawShapeCore(points, (MainWindow.ShapeDrawingType)_shapeType,false)); points.Clear(); AngleTooltip.Visibility = Visibility.Collapsed; LengthTooltip.Visibility = Visibility.Collapsed; @@ -181,7 +181,7 @@ namespace Ink_Canvas { _shapeType == MainWindow.ShapeDrawingType.DottedLine || _shapeType == MainWindow.ShapeDrawingType.ArrowOneSide || _shapeType == MainWindow.ShapeDrawingType.ArrowTwoSide) && points.Count >= 2) { - MainWindow.DrawShapeCore(points, (MainWindow.ShapeDrawingType)_shapeType).Draw(dc); + MainWindow.DrawShapeCore(points, (MainWindow.ShapeDrawingType)_shapeType,true).Draw(dc); var angle = MainWindow.ShapeDrawingHelper.CaculateRotateAngleByGivenTwoPoints(points[0], points[1]); if (AngleTooltip.Visibility == Visibility.Collapsed) AngleTooltip.Visibility = Visibility.Visible; AngleText.Text = $"{angle}°";