/// <summary> /// create the path points /// </summary> /// <param name="stroke">the stroke</param> /// <returns>the path points</returns> public static SKPoint[] CreatePathPoints(XInkStroke stroke) { if (stroke == null) { throw new ArgumentNullException(nameof(stroke)); } var inkPoints = stroke.GetInkPoints().ToArray(); if (inkPoints.Length < 2) { return(null); } var pointCount = inkPoints.Length * 2 + 2; var allPoints = new SKPoint[pointCount]; double angle = 0.0; for (var i = 0; i < inkPoints.Length; i++) { var point1 = inkPoints[i]; if (i < inkPoints.Length - 1) { var point2 = inkPoints[i + 1]; var x = point2.Position.X - point1.Position.X; var y = point2.Position.Y - point1.Position.Y; angle = Math.Atan2(y, x) - Math.PI / 2; } var h = stroke.DrawingAttributes.Size * 0.5; if (!stroke.DrawingAttributes.IgnorePressure) { h *= point1.Pressure; } var leftX = point1.Position.X + (Math.Cos(angle) * h); var leftY = point1.Position.Y + (Math.Sin(angle) * h); var rightX = point1.Position.X - (Math.Cos(angle) * h); var rightY = point1.Position.Y - (Math.Sin(angle) * h); allPoints[i + 1] = new Point(leftX, leftY).ToSKPoint(); allPoints[pointCount - i - 1] = new Point(rightX, rightY).ToSKPoint(); } allPoints[0] = GetModifiedFirstPoint(stroke, inkPoints).ToSKPoint(); allPoints[inkPoints.Length + 1] = GetModifiedLastPoint(stroke, inkPoints).ToSKPoint(); return(allPoints); }
/// <summary> /// create a path for the stroke /// </summary> /// <param name="stroke">the stroke</param> /// <returns>a new path</returns> public static SKPath CreatePath(this XInkStroke stroke) { if (stroke == null) { throw new ArgumentNullException(nameof(stroke)); } var path = new SKPath(); var inkPoints = stroke.GetInkPoints(); var points = from point in inkPoints let x = (float)point.Position.X let y = (float)point.Position.Y select new SKPoint(x, y); var count = points.Count(); //path.AddPoly(points.ToArray(), false); if (count > 1) { var firstPoints = new Point[count - 1]; var secondPoints = new Point[count - 1]; var controlPoints = (from item in inkPoints select item.Position).ToArray(); BezierSpline.GetCurveControlPoints(controlPoints, out firstPoints, out secondPoints); path.MoveTo(controlPoints.First().ToSKPoint()); for (var i = 1; i < count; i++) { path.CubicTo(firstPoints[i - 1].ToSKPoint(), secondPoints[i - 1].ToSKPoint(), points.ElementAt(i)); } } return(path); }
/// <summary> /// Convert a Xamarin Ink Stroke to a UWP InkStroke /// </summary> /// <param name="xInkStroke">a Xamarin Ink Stroke</param> /// <returns>a UWP Ink Stroke</returns> public static InkStroke ToInkStroke(this XInkStroke xInkStroke) { if (xInkStroke == null) { throw new ArgumentNullException(nameof(xInkStroke)); } var builder = new InkStrokeBuilder(); var inkPoints = from item in xInkStroke.GetInkPoints() select new InkPoint(new Point(item.Position.X, item.Position.Y), item.Pressure); if (!inkPoints.Any()) { return(null); } var stroke = builder.CreateStrokeFromInkPoints(inkPoints, Matrix3x2.Identity); stroke.DrawingAttributes = xInkStroke.DrawingAttributes.ToInkDrawingAttributes(); return(stroke); }
/// <summary> /// Draw an ink stroke /// </summary> /// <param name="canvas">the canvas</param> /// <param name="stroke">the stroke</param> /// <param name="useCache">true to use cached data</param> public static void Draw(this SKCanvas canvas, XInkStroke stroke, bool useCache) { _ = canvas ?? throw new ArgumentNullException(nameof(canvas)); _ = stroke ?? throw new ArgumentNullException(nameof(stroke)); var inkPoints = stroke.GetInkPoints(); if (useCache) { if (inkPoints.Count == 1) { if (stroke.Paint == null) { var paintResult = stroke.CreatePaint(SKPaintStyle.Fill); stroke.Paint = paintResult.Item1; stroke.Resources = paintResult.Item2; } canvas.DrawCircle( stroke.GetInkPoints()[0].Position.ToSKPoint(), stroke.DrawingAttributes.Size / 4.0f, stroke.Paint); } else { stroke.Path ??= stroke.DrawingAttributes.IgnorePressure ? stroke.CreatePath() : stroke.CreateVariableThicknessPath(); if (stroke.Paint == null) { var paintResult = stroke.CreatePaint(); stroke.Resources = paintResult.Item2; stroke.Paint = paintResult.Item1; } if (stroke.Path != null) { canvas.DrawPath(stroke.Path, stroke.Paint); } } } else { if (inkPoints.Count == 1) { var paintResult = stroke.CreatePaint(SKPaintStyle.Fill); using (var paint = paintResult.Item1) { paint.IsStroke = false; var radius = stroke.DrawingAttributes.Size / 4.0f; //System.Diagnostics.Debug.WriteLine($"Drawing dot radius {radius}"); canvas.DrawCircle( inkPoints[0].Position.ToSKPoint(), radius, paint); } if (paintResult.Item2 != null) { foreach (var item in paintResult.Item2) { item.Dispose(); } } } else { using var path = stroke.DrawingAttributes.IgnorePressure ? stroke.CreatePath() : stroke.CreateVariableThicknessPath(); if (path == null) { return; } var paintResult = stroke.CreatePaint(); using (var paint = paintResult.Item1) { canvas.DrawPath(path, paint); } if (paintResult.Item2 != null) { foreach (var item in paintResult.Item2) { item.Dispose(); } } } } }