コード例 #1
0
        /// <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);
        }
コード例 #2
0
        /// <summary>
        /// Add a stroke
        /// </summary>
        /// <param name="inkStroke">the ink stroke to add</param>
        public void Add(XInkStroke inkStroke)
        {
            var newStroke = inkStroke.ToInkStroke();

            if (newStroke == null)
            {
                return;
            }

            NativeStrokeContainer.AddStroke(newStroke);

            InkChanged?.Invoke(this, new EventArgs());
        }
コード例 #3
0
        /// <summary>
        /// Create a variable thickness path
        /// </summary>
        /// <param name="stroke">the stroke</param>
        /// <returns>a variable thickness path</returns>
        public static SKPath CreateVariableThicknessPath(this XInkStroke stroke)
        {
            var pathPoints = CreatePathPoints(stroke);

            if (pathPoints == null || pathPoints.Length == 0)
            {
                return(null);
            }

            var newPath = new SKPath();

            newPath.AddPoly(pathPoints);

            return(newPath);
        }
コード例 #4
0
        /// <summary>
        /// Remove an ink stroke
        /// </summary>
        /// <param name="item">the stroke to remove</param>
        public void Remove(XInkStroke item)
        {
            if (item == null)
            {
                throw new ArgumentNullException(nameof(item));
            }

            foreach (var stroke in NativeStrokeContainer.GetStrokes())
            {
                if (stroke.Id.ToString(CultureInfo.InvariantCulture) == item.Id)
                {
                    stroke.Selected = true;
                }
            }

            NativeStrokeContainer.DeleteSelected();

            InkChanged?.Invoke(this, new EventArgs());
        }
コード例 #5
0
        /// <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);
        }
コード例 #6
0
        /// <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);
        }
コード例 #7
0
        private static Point GetModifiedLastPoint(XInkStroke stroke, XInkPoint[] inkPoints)
        {
            var lastPoint       = inkPoints[inkPoints.Length - 1];
            var secondLastPoint = inkPoints[inkPoints.Length - 2];

            var x1 = lastPoint.Position.X - secondLastPoint.Position.X;
            var y1 = lastPoint.Position.Y - secondLastPoint.Position.Y;

            var angle1 = Math.Atan2(y1, x1);

            var h1 = stroke.DrawingAttributes.Size * 0.5;

            if (!stroke.DrawingAttributes.IgnorePressure)
            {
                h1 *= lastPoint.Pressure;
            }

            var lastX = lastPoint.Position.X + (Math.Cos(angle1) * h1);
            var lastY = lastPoint.Position.Y + (Math.Sin(angle1) * h1);

            var modifiedLastPoint = new Point(lastX, lastY);

            return(modifiedLastPoint);
        }
コード例 #8
0
        public static Tuple <SKPaint, IEnumerable <IDisposable> > CreatePaint(this XInkStroke stroke, SKPaintStyle paintStyle = SKPaintStyle.Stroke, SKBlendMode blendMode = SKBlendMode.SrcATop)
        {
            if (stroke == null)
            {
                throw new ArgumentNullException(nameof(stroke));
            }

            var disposables = new List <IDisposable>();

            SKShader shader = null;

            if (stroke.DrawingAttributes.Kind == XInkDrawingAttributesKind.Pencil)
            {
                var perlin = SKShader.CreatePerlinNoiseFractalNoise(0.01f, 0.01f, 1, 1.0f);
                var color  = SKShader.CreateColor(stroke.DrawingAttributes.Color.ToSKColor().WithAlpha(0x7F));

                disposables.Add(perlin);
                disposables.Add(color);

                shader = SKShader.CreateCompose(
                    perlin,
                    color,
                    blendMode);
            }

            Tuple <SKPaint, IEnumerable <IDisposable> > tuple = null;
            SKPaint paint = null;

            if (!stroke.DrawingAttributes.IgnorePressure)
            {
                paintStyle = SKPaintStyle.Fill;
            }

            try
            {
                paint = new SKPaint
                {
                    Color       = stroke.DrawingAttributes.Kind == XInkDrawingAttributesKind.Default ? stroke.DrawingAttributes.Color.ToSKColor() : new SKColor(),
                    StrokeWidth = stroke.DrawingAttributes.IgnorePressure? stroke.DrawingAttributes.Size : 0.0f,
                    Style       = paintStyle,
                    IsAntialias = true,
                    StrokeCap   = stroke.DrawingAttributes.PenTip == Inking.XPenTipShape.Circle ? SKStrokeCap.Round : SKStrokeCap.Butt,
                    PathEffect  = SKPathEffect.CreateCorner(100)
                };

                if (shader != null)
                {
                    paint.Shader = shader;
                }

                tuple = Tuple.Create(paint, disposables as IEnumerable <IDisposable>);

                paint = null;
            }
            finally
            {
                paint?.Dispose();
            }

            return(tuple);
        }
コード例 #9
0
        /// <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();
                        }
                    }
                }
            }
        }
コード例 #10
0
 public void TestCreatePathPointsEmpty()
 {
     using var inkStroke = new XInkStroke();
     InkRenderer.CreatePathPoints(inkStroke);
 }